TombEngine/TR5Main/Renderer/Renderer11.cpp

7402 lines
230 KiB
C++
Raw Normal View History

2019-01-13 21:57:16 +01:00
#include "Renderer11.h"
2019-02-02 15:40:44 +01:00
#include "..\Specific\input.h"
#include "..\Specific\winmain.h"
#include "..\Specific\roomload.h"
#include "..\Specific\game.h"
#include "..\Specific\configuration.h"
2019-02-02 15:40:44 +01:00
2019-01-13 21:57:16 +01:00
#include "..\Game\draw.h"
2019-02-02 15:40:44 +01:00
#include "..\Game\healt.h"
#include "..\Game\pickup.h"
#include "..\Game\inventory.h"
#include "..\Game\gameflow.h"
2019-11-21 07:43:34 +01:00
#include "..\Game\Lara.h"
#include "..\Game\effect2.h"
2019-02-02 15:40:44 +01:00
#include "..\Game\rope.h"
#include "..\Game\items.h"
2019-11-21 07:43:34 +01:00
#include "..\Game\Camera.h"
#include "..\Game\healt.h"
#include "../Game/tomb4fx.h"
#include "math.h"
2019-01-13 21:57:16 +01:00
#include <D3Dcompiler.h>
#include <chrono>
2019-01-13 21:57:16 +01:00
#include <stack>
#include "../Game/misc.h"
#include "../Game/footprint.h"
2019-01-13 21:57:16 +01:00
using ns = chrono::nanoseconds;
using get_time = chrono::steady_clock;
extern std::deque<FOOTPRINT_STRUCT> footprints;
2019-12-02 09:11:21 +01:00
int SortLightsFunction(RendererLight* a, RendererLight* b)
2019-01-16 20:54:45 +01:00
{
if (a->Dynamic > b->Dynamic)
return -1;
return 0;
}
bool SortRoomsFunction(RendererRoom* a, RendererRoom* b)
{
return (a->Distance < b->Distance);
}
2019-12-02 09:11:21 +01:00
int SortRoomsFunctionNonStd(RendererRoom* a, RendererRoom* b)
{
return (a->Distance - b->Distance);
}
2019-01-13 21:57:16 +01:00
Renderer11::Renderer11()
{
initialiseHairRemaps();
m_blinkColorDirection = 1;
2019-01-13 21:57:16 +01:00
}
Renderer11::~Renderer11()
{
FreeRendererData();
2019-01-13 21:57:16 +01:00
DX11_RELEASE(m_backBufferRTV);
DX11_RELEASE(m_backBufferTexture);
DX11_RELEASE(m_depthStencilState);
DX11_RELEASE(m_depthStencilTexture);
DX11_RELEASE(m_depthStencilView);
DX11_DELETE(m_primitiveBatch);
2019-01-13 21:57:16 +01:00
DX11_DELETE(m_spriteBatch);
DX11_DELETE(m_gameFont);
DX11_DELETE(m_states);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_CAUSTICS_TEXTURES; i++)
DX11_DELETE(m_caustics[i]);
DX11_DELETE(m_titleScreen);
DX11_DELETE(m_binocularsTexture);
DX11_DELETE(m_whiteTexture);
DX11_DELETE(m_logo);
DX11_RELEASE(m_vsRooms);
DX11_RELEASE(m_psRooms);
DX11_RELEASE(m_vsItems);
DX11_RELEASE(m_psItems);
DX11_RELEASE(m_vsStatics);
DX11_RELEASE(m_psStatics);
DX11_RELEASE(m_vsHairs);
DX11_RELEASE(m_psHairs);
DX11_RELEASE(m_vsSky);
DX11_RELEASE(m_psSky);
DX11_RELEASE(m_vsSprites);
DX11_RELEASE(m_psSprites);
DX11_RELEASE(m_vsSolid);
DX11_RELEASE(m_psSolid);
DX11_RELEASE(m_vsInventory);
DX11_RELEASE(m_psInventory);
DX11_RELEASE(m_vsFullScreenQuad);
DX11_RELEASE(m_psFullScreenQuad);
DX11_RELEASE(m_cbCameraMatrices);
DX11_RELEASE(m_cbItem);
DX11_RELEASE(m_cbStatic);
DX11_RELEASE(m_cbLights);
DX11_RELEASE(m_cbMisc);
DX11_DELETE(m_renderTarget);
DX11_DELETE(m_dumpScreenRenderTarget);
DX11_DELETE(m_shadowMap);
DX11_RELEASE(m_swapChain);
DX11_RELEASE(m_context);
DX11_RELEASE(m_device);
2019-01-13 21:57:16 +01:00
}
void Renderer11::FreeRendererData()
{
m_meshPointersToMesh.clear();
2019-12-02 09:11:21 +01:00
for (int i = 0; i < ID_NUMBER_OBJECTS; i++)
DX11_DELETE(m_moveableObjects[i]);
free(m_moveableObjects);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < g_NumSprites; i++)
DX11_DELETE(m_sprites[i]);
free(m_sprites);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < ID_NUMBER_OBJECTS; i++)
DX11_DELETE(m_spriteSequences[i]);
free(m_spriteSequences);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_STATICS; i++)
DX11_DELETE(m_staticObjects[i]);
free(m_staticObjects);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_ROOMS; i++)
DX11_DELETE(m_rooms[i]);
free(m_rooms);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_numAnimatedTextureSets; i++)
DX11_DELETE(m_animatedTextureSets[i]);
free(m_animatedTextureSets);
2019-01-13 21:57:16 +01:00
DX11_DELETE(m_textureAtlas);
DX11_DELETE(m_skyTexture);
DX11_DELETE(m_roomsVertexBuffer);
DX11_DELETE(m_roomsIndexBuffer);
DX11_DELETE(m_moveablesVertexBuffer);
DX11_DELETE(m_moveablesIndexBuffer);
DX11_DELETE(m_staticsVertexBuffer);
DX11_DELETE(m_staticsIndexBuffer);
2019-01-13 21:57:16 +01:00
}
bool Renderer11::Create()
{
D3D_FEATURE_LEVEL levels[1] = { D3D_FEATURE_LEVEL_10_0 };
D3D_FEATURE_LEVEL featureLevel;
HRESULT res;
#ifdef _RELEASE
res = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, levels, 1, D3D11_SDK_VERSION, &m_device, &featureLevel, &m_context);
#else
res = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, levels, 1, D3D11_SDK_VERSION, &m_device, &featureLevel, &m_context); // D3D11_CREATE_DEVICE_DEBUG
#endif
if (FAILED(res))
return false;
2019-01-13 21:57:16 +01:00
return true;
}
bool Renderer11::EnumerateVideoModes()
{
HRESULT res;
IDXGIFactory* dxgiFactory = NULL;
res = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&dxgiFactory);
if (FAILED(res))
return false;
IDXGIAdapter* dxgiAdapter = NULL;
for (int i = 0; dxgiFactory->EnumAdapters(i, &dxgiAdapter) != DXGI_ERROR_NOT_FOUND; i++)
{
DXGI_ADAPTER_DESC adapterDesc;
UINT stringLength;
char videoCardDescription[128];
dxgiAdapter->GetDesc(&adapterDesc);
2019-12-02 09:11:21 +01:00
int error = wcstombs_s(&stringLength, videoCardDescription, 128, adapterDesc.Description, 128);
RendererVideoAdapter adapter;
adapter.Index = i;
adapter.Name = videoCardDescription;
printf("Adapter %d\n", i);
printf("\t Device Name: %s\n", videoCardDescription);
IDXGIOutput* output = NULL;
res = dxgiAdapter->EnumOutputs(0, &output);
if (FAILED(res))
return false;
UINT numModes = 0;
DXGI_MODE_DESC* displayModes = NULL;
DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
// Get the number of elements
res = output->GetDisplayModeList(format, 0, &numModes, NULL);
if (FAILED(res))
return false;
// Get the list
displayModes = new DXGI_MODE_DESC[numModes];
res = output->GetDisplayModeList(format, 0, &numModes, displayModes);
if (FAILED(res))
{
delete displayModes;
return false;
}
2019-12-02 09:11:21 +01:00
for (int j = 0; j < numModes; j++)
{
DXGI_MODE_DESC* mode = &displayModes[j];
RendererDisplayMode newMode;
// discard lower resolutions
if (mode->Width < 1024 || mode->Height < 768)
continue;
newMode.Width = mode->Width;
newMode.Height = mode->Height;
newMode.RefreshRate = mode->RefreshRate.Numerator / mode->RefreshRate.Denominator;
bool found = false;
2019-12-02 09:11:21 +01:00
for (int k = 0; k < adapter.DisplayModes.size(); k++)
{
RendererDisplayMode* currentMode = &adapter.DisplayModes[k];
if (currentMode->Width == newMode.Width && currentMode->Height == newMode.Height &&
currentMode->RefreshRate == newMode.RefreshRate)
{
found = true;
break;
}
}
if (found)
continue;
adapter.DisplayModes.push_back(newMode);
printf("\t\t %d x %d %d Hz\n", newMode.Width, newMode.Height, newMode.RefreshRate);
}
m_adapters.push_back(adapter);
delete displayModes;
}
dxgiFactory->Release();
2019-01-13 21:57:16 +01:00
return true;
}
2019-12-02 09:11:21 +01:00
bool Renderer11::initialiseScreen(int w, int h, int refreshRate, bool windowed, HWND handle, bool reset)
2019-01-13 21:57:16 +01:00
{
HRESULT res;
DXGI_SWAP_CHAIN_DESC sd;
sd.BufferDesc.Width = w;
sd.BufferDesc.Height = h;
2019-01-13 21:57:16 +01:00
sd.BufferDesc.RefreshRate.Numerator = refreshRate;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_STRETCHED;
sd.Windowed = windowed;
2019-01-13 21:57:16 +01:00
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
sd.OutputWindow = handle;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.BufferCount = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2019-01-13 21:57:16 +01:00
IDXGIDevice* dxgiDevice = NULL;
res = m_device->QueryInterface(__uuidof(IDXGIDevice), (void**)& dxgiDevice);
2019-01-13 21:57:16 +01:00
if (FAILED(res))
return false;
IDXGIAdapter* dxgiAdapter = NULL;
res = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)& dxgiAdapter);
2019-01-13 21:57:16 +01:00
if (FAILED(res))
return false;
IDXGIFactory* dxgiFactory = NULL;
res = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)& dxgiFactory);
2019-01-13 21:57:16 +01:00
if (FAILED(res))
return false;
if (reset)
{
// Always return to windowed mode otherwise crash will happen
m_swapChain->SetFullscreenState(false, NULL);
m_swapChain->Release();
}
2019-01-13 21:57:16 +01:00
m_swapChain = NULL;
res = dxgiFactory->CreateSwapChain(m_device, &sd, &m_swapChain);
if (FAILED(res))
return false;
dxgiFactory->MakeWindowAssociation(handle, 0);
res = m_swapChain->SetFullscreenState(!windowed, NULL);
2019-01-13 21:57:16 +01:00
dxgiDevice->Release();
dxgiAdapter->Release();
dxgiFactory->Release();
// Initialise the back buffer
m_backBufferTexture = NULL;
res = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast <void**>(&m_backBufferTexture));
if (FAILED(res))
return false;
m_backBufferRTV = NULL;
res = m_device->CreateRenderTargetView(m_backBufferTexture, NULL, &m_backBufferRTV);
if (FAILED(res))
return false;
D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = w;
depthStencilDesc.Height = h;
2019-01-13 21:57:16 +01:00
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;
m_depthStencilTexture = NULL;
res = m_device->CreateTexture2D(&depthStencilDesc, NULL, &m_depthStencilTexture);
if (FAILED(res))
return false;
m_depthStencilView = NULL;
res = m_device->CreateDepthStencilView(m_depthStencilTexture, NULL, &m_depthStencilView);
if (FAILED(res))
return false;
// Bind the back buffer and the depth stencil
m_context->OMSetRenderTargets(1, &m_backBufferRTV, m_depthStencilView);
// Initialise sprites and font
m_spriteBatch = new SpriteBatch(m_context);
m_gameFont = new SpriteFont(m_device, L"Font.spritefont");
m_primitiveBatch = new PrimitiveBatch<RendererVertex>(m_context);
2019-01-13 21:57:16 +01:00
// Initialise buffers
m_renderTarget = RenderTarget2D::Create(m_device, w, h, DXGI_FORMAT_R8G8B8A8_UNORM);
m_dumpScreenRenderTarget = RenderTarget2D::Create(m_device, w, h, DXGI_FORMAT_R8G8B8A8_UNORM);
m_shadowMap = RenderTarget2D::Create(m_device, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, DXGI_FORMAT_R32_FLOAT);
2020-01-03 06:48:15 +01:00
// Shadow map
/*D3D11_TEXTURE2D_DESC depthTexDesc;
ZeroMemory(&depthTexDesc, sizeof(D3D11_TEXTURE2D_DESC));
depthTexDesc.Width = SHADOW_MAP_SIZE;
depthTexDesc.Height = SHADOW_MAP_SIZE;
depthTexDesc.MipLevels = 1;
depthTexDesc.ArraySize = 1;
depthTexDesc.SampleDesc.Count = 1;
depthTexDesc.SampleDesc.Quality = 0;
depthTexDesc.Format = DXGI_FORMAT_R32_TYPELESS;
depthTexDesc.Usage = D3D11_USAGE_DEFAULT;
depthTexDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
depthTexDesc.CPUAccessFlags = 0;
depthTexDesc.MiscFlags = 0;
res = m_device->CreateTexture2D(&depthTexDesc, NULL, &m_shadowMapTexture);
if (FAILED(res))
return false;
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
ZeroMemory(&dsvDesc, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
dsvDesc.Format = depthTexDesc.Format;
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
dsvDesc.Texture2D.MipSlice = 0;
m_shadowMapDSV = NULL;
res = m_device->CreateDepthStencilView(m_shadowMapTexture, &dsvDesc, &m_shadowMapDSV);
if (FAILED(res))
return false;
D3D11_SHADER_RESOURCE_VIEW_DESC shaderDesc;
shaderDesc.Format = DXGI_FORMAT_R32_FLOAT;
shaderDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
shaderDesc.Texture2D.MostDetailedMip = 0;
shaderDesc.Texture2D.MipLevels = 1;
res = m_device->CreateShaderResourceView(m_shadowMapTexture, &shaderDesc, &m_shadowMapRV);
if (FAILED(res))
return false;*/
// Initialise viewport
m_viewport.TopLeftX = 0;
m_viewport.TopLeftY = 0;
m_viewport.Width = w;
m_viewport.Height = h;
m_viewport.MinDepth = 0.0f;
m_viewport.MaxDepth = 1.0f;
m_shadowMapViewport.TopLeftX = 0;
m_shadowMapViewport.TopLeftY = 0;
m_shadowMapViewport.Width = SHADOW_MAP_SIZE;
m_shadowMapViewport.Height = SHADOW_MAP_SIZE;
m_shadowMapViewport.MinDepth = 0.0f;
m_shadowMapViewport.MaxDepth = 1.0f;
m_viewportToolkit = new Viewport(m_viewport.TopLeftX, m_viewport.TopLeftY, m_viewport.Width, m_viewport.Height,
m_viewport.MinDepth, m_viewport.MaxDepth);
if (windowed)
{
SetWindowLong(WindowsHandle, GWL_STYLE, WS_OVERLAPPEDWINDOW);
SetWindowPos(WindowsHandle, HWND_TOP, 0, 0, g_Configuration.Width, g_Configuration.Height,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
else
{
SetWindowLong(WindowsHandle, GWL_STYLE, WS_POPUPWINDOW);
SetWindowPos(WindowsHandle, HWND_TOP, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
UpdateWindow(handle);
return true;
}
2019-12-02 09:11:21 +01:00
bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND handle)
{
HRESULT res;
DB_Log(2, "Renderer::Initialise - DLL");
printf("Initialising DX11\n");
CoInitialize(NULL);
ScreenWidth = w;
ScreenHeight = h;
Windowed = windowed;
if (!initialiseScreen(w, h, refreshRate, windowed, handle, false))
return false;
2019-01-13 21:57:16 +01:00
// Initialise render states
m_states = new CommonStates(m_device);
// Load caustics
const char* causticsNames[NUM_CAUSTICS_TEXTURES] = {
2019-01-13 21:57:16 +01:00
"CausticsRender_001.bmp",
"CausticsRender_002.bmp",
"CausticsRender_003.bmp",
"CausticsRender_004.bmp",
"CausticsRender_005.bmp",
"CausticsRender_006.bmp",
"CausticsRender_007.bmp",
"CausticsRender_008.bmp",
"CausticsRender_009.bmp",
"CausticsRender_010.bmp",
"CausticsRender_011.bmp",
"CausticsRender_012.bmp",
"CausticsRender_013.bmp",
"CausticsRender_014.bmp",
"CausticsRender_015.bmp",
"CausticsRender_016.bmp"
};
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_CAUSTICS_TEXTURES; i++)
2019-01-13 21:57:16 +01:00
{
m_caustics[i] = Texture2D::LoadFromFile(m_device, causticsNames[i]);
if (m_caustics[i] == NULL)
return false;
}
m_titleScreen = Texture2D::LoadFromFile(m_device, (char*)g_GameFlow->GetLevel(0)->Background.c_str());
if (m_titleScreen == NULL)
return false;
2019-01-13 21:57:16 +01:00
m_binocularsTexture = Texture2D::LoadFromFile(m_device, "Binoculars.png");
if (m_binocularsTexture == NULL)
return false;
m_whiteTexture = Texture2D::LoadFromFile(m_device, "WhiteSprite.png");
if (m_whiteTexture == NULL)
return false;
m_logo = Texture2D::LoadFromFile(m_device, "Logo.png");
if (m_logo == NULL)
return false;
2019-01-13 21:57:16 +01:00
// Load shaders
ID3D10Blob* blob;
2019-01-13 21:57:16 +01:00
m_vsRooms = compileVertexShader("Shaders\\DX11_Rooms.fx", "VS", "vs_4_0", &blob);
if (m_vsRooms == NULL)
2019-01-13 21:57:16 +01:00
return false;
// Initialise input layout using the first vertex shader
D3D11_INPUT_ELEMENT_DESC inputLayout[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"BLENDINDICES", 0, DXGI_FORMAT_R32_FLOAT, 0, 48, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
m_inputLayout = NULL;
res = m_device->CreateInputLayout(inputLayout, 5, blob->GetBufferPointer(), blob->GetBufferSize(), &m_inputLayout);
2019-01-13 21:57:16 +01:00
if (FAILED(res))
return false;
m_psRooms = compilePixelShader("Shaders\\DX11_Rooms.fx", "PS", "ps_4_0", &blob);
if (m_psRooms == NULL)
return false;
m_vsItems = compileVertexShader("Shaders\\DX11_Items.fx", "VS", "vs_4_0", &blob);
if (m_vsItems == NULL)
return false;
m_psItems = compilePixelShader("Shaders\\DX11_Items.fx", "PS", "ps_4_0", &blob);
if (m_psItems == NULL)
return false;
m_vsStatics = compileVertexShader("Shaders\\DX11_Statics.fx", "VS", "vs_4_0", &blob);
if (m_vsStatics == NULL)
return false;
m_psStatics = compilePixelShader("Shaders\\DX11_Statics.fx", "PS", "ps_4_0", &blob);
if (m_psStatics == NULL)
return false;
m_vsHairs = compileVertexShader("Shaders\\DX11_Hairs.fx", "VS", "vs_4_0", &blob);
if (m_vsHairs == NULL)
return false;
m_psHairs = compilePixelShader("Shaders\\DX11_Hairs.fx", "PS", "ps_4_0", &blob);
if (m_psHairs == NULL)
return false;
m_vsSky = compileVertexShader("Shaders\\DX11_Sky.fx", "VS", "vs_4_0", &blob);
if (m_vsSky == NULL)
return false;
m_psSky = compilePixelShader("Shaders\\DX11_Sky.fx", "PS", "ps_4_0", &blob);
if (m_psSky == NULL)
return false;
m_vsSprites = compileVertexShader("Shaders\\DX11_Sprites.fx", "VS", "vs_4_0", &blob);
if (m_vsSprites == NULL)
return false;
m_psSprites = compilePixelShader("Shaders\\DX11_Sprites.fx", "PS", "ps_4_0", &blob);
if (m_psSprites == NULL)
2019-01-13 21:57:16 +01:00
return false;
m_vsSolid = compileVertexShader("Shaders\\DX11_Solid.fx", "VS", "vs_4_0", &blob);
if (m_vsSolid == NULL)
return false;
m_psSolid = compilePixelShader("Shaders\\DX11_Solid.fx", "PS", "ps_4_0", &blob);
if (m_psSolid == NULL)
return false;
2019-02-02 15:40:44 +01:00
m_vsInventory = compileVertexShader("Shaders\\DX11_Inventory.fx", "VS", "vs_4_0", &blob);
if (m_vsInventory == NULL)
return false;
m_psInventory = compilePixelShader("Shaders\\DX11_Inventory.fx", "PS", "ps_4_0", &blob);
if (m_psInventory == NULL)
return false;
m_vsFullScreenQuad = compileVertexShader("Shaders\\DX11_FullScreenQuad.fx", "VS", "vs_4_0", &blob);
if (m_vsFullScreenQuad == NULL)
return false;
m_psFullScreenQuad = compilePixelShader("Shaders\\DX11_FullScreenQuad.fx", "PS", "ps_4_0", &blob);
if (m_psFullScreenQuad == NULL)
return false;
m_vsShadowMap = compileVertexShader("Shaders\\DX11_ShadowMap.fx", "VS", "vs_4_0", &blob);
if (m_vsShadowMap == NULL)
return false;
m_psShadowMap = compilePixelShader("Shaders\\DX11_ShadowMap.fx", "PS", "ps_4_0", &blob);
if (m_psShadowMap == NULL)
return false;
2019-01-13 21:57:16 +01:00
// Initialise constant buffers
m_cbCameraMatrices = createConstantBuffer(sizeof(CCameraMatrixBuffer));
m_cbItem = createConstantBuffer(sizeof(CItemBuffer));
m_cbStatic = createConstantBuffer(sizeof(CStaticBuffer));
m_cbLights = createConstantBuffer(sizeof(CLightBuffer));
m_cbMisc = createConstantBuffer(sizeof(CMiscBuffer));
m_cbShadowMap = createConstantBuffer(sizeof(CShadowLightBuffer));
m_cbRoom = createConstantBuffer(sizeof(CRoomBuffer));
2019-03-18 23:30:41 +01:00
m_currentCausticsFrame = 0;
m_firstWeather = true;
2019-03-18 23:30:41 +01:00
// Preallocate lists
m_roomsToDraw.Reserve(NUM_ROOMS);
m_itemsToDraw.Reserve(NUM_ITEMS);
m_effectsToDraw.Reserve(NUM_ITEMS);
m_lightsToDraw.Reserve(MAX_LIGHTS_DRAW);
m_dynamicLights.Reserve(MAX_DYNAMIC_LIGHTS);
m_staticsToDraw.Reserve(MAX_DRAW_STATICS);
m_spritesToDraw.Reserve(MAX_SPRITES);
m_lines3DToDraw.Reserve(MAX_LINES_3D);
m_lines2DToDraw.Reserve(MAX_LINES_2D);
m_tempItemLights.Reserve(MAX_LIGHTS);
m_spritesBuffer = (RendererSpriteToDraw*)malloc(sizeof(RendererSpriteToDraw) * MAX_SPRITES);
m_lines3DBuffer = (RendererLine3D*)malloc(sizeof(RendererLine3D) * MAX_LINES_3D);
m_lines2DBuffer = (RendererLine2D*)malloc(sizeof(RendererLine2D) * MAX_LINES_2D);
m_pickupRotation = 0;
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_ITEMS; i++)
{
m_items[i].Lights.Reserve(MAX_LIGHTS_PER_ITEM);
m_effects[i].Lights.Reserve(MAX_LIGHTS_PER_ITEM);
}
m_textureAtlas = NULL;
m_skyTexture = NULL;
2020-01-07 16:19:54 +01:00
D3D11_BLEND_DESC blendStateDesc{};
blendStateDesc.AlphaToCoverageEnable = FALSE;
blendStateDesc.IndependentBlendEnable = FALSE;
blendStateDesc.RenderTarget[0].BlendEnable = TRUE;
blendStateDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendStateDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendStateDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_REV_SUBTRACT;
blendStateDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
blendStateDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
blendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendStateDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
m_device->CreateBlendState(&blendStateDesc,&m_subtractiveBlendState);
2019-01-13 21:57:16 +01:00
return true;
}
2019-12-02 09:11:21 +01:00
int Renderer11::Draw()
2019-01-13 21:57:16 +01:00
{
drawScene(false);
drawFinalPass();
2019-01-13 21:57:16 +01:00
return 0;
}
void Renderer11::UpdateCameraMatrices(float posX, float posY, float posZ, float targetX, float targetY, float targetZ, float roll, float fov)
{
g_Configuration.MaxDrawDistance = 200;
Vector3 up = -Vector3::UnitY;
Matrix upRotation = Matrix::CreateFromYawPitchRoll(0.0f, 0.0f, roll);
up = Vector3::Transform(up, upRotation);
2019-01-13 21:57:16 +01:00
FieldOfView = fov;
View = Matrix::CreateLookAt(Vector3(posX, posY, posZ), Vector3(targetX, targetY, targetZ), up);
2019-01-13 21:57:16 +01:00
Projection = Matrix::CreatePerspectiveFieldOfView(fov, ScreenWidth / (float)ScreenHeight, 20.0f, g_Configuration.MaxDrawDistance * 1024.0f);
m_stCameraMatrices.View = View;
m_stCameraMatrices.Projection = Projection;
}
2019-12-02 09:11:21 +01:00
bool Renderer11::drawAmbientCubeMap(short roomNumber)
{
return true;
2019-01-13 21:57:16 +01:00
}
2019-01-16 20:54:45 +01:00
void Renderer11::clearSceneItems()
{
m_roomsToDraw.Clear();
m_itemsToDraw.Clear();
m_effectsToDraw.Clear();
m_lightsToDraw.Clear();
m_staticsToDraw.Clear();
m_spritesToDraw.Clear();
m_lines3DToDraw.Clear();
m_lines2DToDraw.Clear();
2019-01-16 20:54:45 +01:00
}
bool Renderer11::drawHorizonAndSky()
2019-01-13 21:57:16 +01:00
{
// Update the sky
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
Vector4 color = Vector4(SkyColor1.r / 255.0f, SkyColor1.g / 255.0f, SkyColor1.b / 255.0f, 1.0f);
if (!level->Horizon)
return true;
if (BinocularRange)
AlterFOV(14560 - BinocularRange);
2019-01-16 20:54:45 +01:00
// Storm
if (level->Storm)
{
if (Unk_00E6D74C || Unk_00E6D73C)
{
UpdateStorm();
if (StormTimer > -1)
StormTimer--;
if (!StormTimer)
SoundEffect(SFX_THUNDER_RUMBLE, NULL, 0);
}
else if (!(rand() & 0x7F))
{
Unk_00E6D74C = (rand() & 0x1F) + 16;
Unk_00E6E4DC = rand() + 256;
StormTimer = (rand() & 3) + 12;
}
color = Vector4((SkyStormColor[0]) / 255.0f, SkyStormColor[1] / 255.0f, SkyStormColor[2] / 255.0f, 1.0f);
}
ID3D11SamplerState* sampler;
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
// Draw the sky
Matrix rotation = Matrix::CreateRotationX(PI);
RendererVertex vertices[4];
float size = 9728.0f;
vertices[0].Position.x = -size / 2.0f;
vertices[0].Position.y = 0.0f;
vertices[0].Position.z = size / 2.0f;
vertices[0].UV.x = 0.0f;
vertices[0].UV.y = 0.0f;
vertices[0].Color.x = 1.0f;
vertices[0].Color.y = 1.0f;
vertices[0].Color.z = 1.0f;
vertices[0].Color.w = 1.0f;
vertices[1].Position.x = size / 2.0f;
vertices[1].Position.y = 0.0f;
vertices[1].Position.z = size / 2.0f;
vertices[1].UV.x = 1.0f;
vertices[1].UV.y = 0.0f;
vertices[1].Color.x = 1.0f;
vertices[1].Color.y = 1.0f;
vertices[1].Color.z = 1.0f;
vertices[1].Color.w = 1.0f;
2019-01-13 21:57:16 +01:00
vertices[2].Position.x = size / 2.0f;
vertices[2].Position.y = 0.0f;
vertices[2].Position.z = -size / 2.0f;
vertices[2].UV.x = 1.0f;
vertices[2].UV.y = 1.0f;
vertices[2].Color.x = 1.0f;
vertices[2].Color.y = 1.0f;
vertices[2].Color.z = 1.0f;
vertices[2].Color.w = 1.0f;
2019-01-13 21:57:16 +01:00
vertices[3].Position.x = -size / 2.0f;
vertices[3].Position.y = 0.0f;
vertices[3].Position.z = -size / 2.0f;
vertices[3].UV.x = 0.0f;
vertices[3].UV.y = 1.0f;
vertices[3].Color.x = 1.0f;
vertices[3].Color.y = 1.0f;
vertices[3].Color.z = 1.0f;
vertices[3].Color.w = 1.0f;
m_context->VSSetShader(m_vsSky, NULL, 0);
m_context->PSSetShader(m_psSky, NULL, 0);
m_stCameraMatrices.View = View.Transpose();
m_stCameraMatrices.Projection = Projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
m_stMisc.AlphaTest = true;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
m_context->PSSetShaderResources(0, 1, &m_skyTexture->ShaderResourceView);
sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < 2; i++)
{
Matrix translation = Matrix::CreateTranslation(Camera.pos.x + SkyPos1 - i * 9728.0f, Camera.pos.y - 1536.0f, Camera.pos.z);
Matrix world = rotation * translation;
m_stStatic.World = (rotation * translation).Transpose();
m_stStatic.Color = color;
updateConstantBuffer(m_cbStatic, &m_stStatic, sizeof(CStaticBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbStatic);
m_context->PSSetConstantBuffers(1, 1, &m_cbStatic);
m_primitiveBatch->Begin();
m_primitiveBatch->DrawQuad(vertices[0], vertices[1], vertices[2], vertices[3]);
m_primitiveBatch->End();
}
// Draw horizon
if (m_moveableObjects[ID_HORIZON] != NULL)
{
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
2019-01-13 21:57:16 +01:00
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
2019-01-13 21:57:16 +01:00
RendererObject* moveableObj = m_moveableObjects[ID_HORIZON];
m_stStatic.World = Matrix::CreateTranslation(Camera.pos.x, Camera.pos.y, Camera.pos.z).Transpose();
m_stStatic.Position = Vector4::Zero;
m_stStatic.Color = Vector4::One;
updateConstantBuffer(m_cbStatic, &m_stStatic, sizeof(CStaticBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbStatic);
m_context->PSSetConstantBuffers(1, 1, &m_cbStatic);
m_stMisc.AlphaTest = true;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
2019-12-02 09:11:21 +01:00
for (int k = 0; k < moveableObj->ObjectMeshes.size(); k++)
{
RendererMesh* mesh = moveableObj->ObjectMeshes[k];
2019-12-02 09:11:21 +01:00
for (int j = 0; j < NUM_BUCKETS; j++)
{
RendererBucket* bucket = &mesh->Buckets[j];
if (bucket->Vertices.size() == 0)
continue;
if (j == RENDERER_BUCKET_SOLID_DS || j == RENDERER_BUCKET_TRANSPARENT_DS)
m_context->RSSetState(m_states->CullNone());
else
m_context->RSSetState(m_states->CullCounterClockwise());
if (j == RENDERER_BUCKET_TRANSPARENT || j == RENDERER_BUCKET_TRANSPARENT_DS)
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
else
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
}
}
// Clear just the Z-buffer so we can start drawing on top of the horizon
m_context->ClearDepthStencilView(m_currentRenderTarget->DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
2019-01-13 21:57:16 +01:00
return true;
}
bool Renderer11::drawRooms(bool transparent, bool animated)
{
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
2019-12-02 09:11:21 +01:00
int firstBucket = (transparent ? 2 : 0);
int lastBucket = (transparent ? 4 : 2);
if (!animated)
{
// Set vertex buffer
m_context->IASetVertexBuffers(0, 1, &m_roomsVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_roomsIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
}
2019-01-13 21:57:16 +01:00
// Set shaders
m_context->VSSetShader(m_vsRooms, NULL, 0);
m_context->PSSetShader(m_psRooms, NULL, 0);
2020-01-03 11:31:54 +01:00
// Set texture
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
ID3D11SamplerState* sampler = m_states->AnisotropicWrap();
ID3D11SamplerState* shadowSampler = m_states->PointClamp();
m_context->PSSetSamplers(0, 1, &sampler);
2019-03-18 23:30:41 +01:00
m_context->PSSetShaderResources(1, 1, &m_caustics[m_currentCausticsFrame / 2]->ShaderResourceView);
m_context->PSSetSamplers(1, 1, &shadowSampler);
m_context->PSSetShaderResources(2, 1, &m_shadowMap->ShaderResourceView);
2020-01-03 11:31:54 +01:00
// Set camera matrices
m_stCameraMatrices.View = View.Transpose();
m_stCameraMatrices.Projection = Projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
// Set shadow map data
2020-01-03 11:31:54 +01:00
if (m_shadowLight != NULL)
{
memcpy(&m_stShadowMap.Light, m_shadowLight, sizeof(ShaderLight));
2020-01-03 11:31:54 +01:00
m_stShadowMap.CastShadows = true;
//m_stShadowMap.ViewProjectionInverse = ViewProjection.Invert().Transpose();
}
else
2020-01-03 11:31:54 +01:00
{
m_stShadowMap.CastShadows = false;
}
updateConstantBuffer(m_cbShadowMap, &m_stShadowMap, sizeof(CShadowLightBuffer));
m_context->VSSetConstantBuffers(4, 1, &m_cbShadowMap);
m_context->PSSetConstantBuffers(4, 1, &m_cbShadowMap);
if (animated)
m_primitiveBatch->Begin();
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_roomsToDraw.Size(); i++)
{
2019-01-16 20:54:45 +01:00
RendererRoom* room = m_roomsToDraw[i];
2019-03-18 23:30:41 +01:00
m_stLights.NumLights = room->LightsToDraw.Size();
2019-12-02 09:11:21 +01:00
for (int j = 0; j < room->LightsToDraw.Size(); j++)
memcpy(&m_stLights.Lights[j], room->LightsToDraw[j], sizeof(ShaderLight));
updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer));
m_context->PSSetConstantBuffers(1, 1, &m_cbLights);
2019-03-18 23:30:41 +01:00
m_stMisc.Caustics = (room->Room->flags & ENV_FLAG_WATER);
m_stMisc.AlphaTest = !transparent;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
m_stRoom.AmbientColor = room->AmbientLight;
updateConstantBuffer(m_cbRoom, &m_stRoom, sizeof(CRoomBuffer));
m_context->PSSetConstantBuffers(5, 1, &m_cbRoom);
2019-12-02 09:11:21 +01:00
for (int j = firstBucket; j < lastBucket; j++)
2019-01-13 21:57:16 +01:00
{
RendererBucket* bucket;
if (!animated)
bucket = &room->Buckets[j];
else
bucket = &room->AnimatedBuckets[j];
2019-01-13 21:57:16 +01:00
if (bucket->Vertices.size() == 0)
continue;
if (!animated)
if (j == RENDERER_BUCKET_SOLID_DS || j == RENDERER_BUCKET_TRANSPARENT_DS)
m_context->RSSetState(m_states->CullNone());
else
m_context->RSSetState(m_states->CullCounterClockwise());
2019-01-13 21:57:16 +01:00
if (!animated)
{
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
else
{
2019-12-02 09:11:21 +01:00
for (int k = 0; k < bucket->Polygons.size(); k++)
{
RendererPolygon* poly = &bucket->Polygons[k];
if (poly->Shape == SHAPE_RECTANGLE)
{
m_primitiveBatch->DrawQuad(bucket->Vertices[poly->Indices[0]], bucket->Vertices[poly->Indices[1]],
bucket->Vertices[poly->Indices[2]], bucket->Vertices[poly->Indices[3]]);
}
else
{
m_primitiveBatch->DrawTriangle(bucket->Vertices[poly->Indices[0]], bucket->Vertices[poly->Indices[1]],
bucket->Vertices[poly->Indices[2]]);
}
}
}
2019-01-13 21:57:16 +01:00
}
}
if (animated)
m_primitiveBatch->End();
return true;
}
bool Renderer11::drawStatics(bool transparent)
{
//return true;
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
2019-12-02 09:11:21 +01:00
int firstBucket = (transparent ? 2 : 0);
int lastBucket = (transparent ? 4 : 2);
2019-01-13 21:57:16 +01:00
m_context->IASetVertexBuffers(0, 1, &m_staticsVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_staticsIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
// Set shaders
m_context->VSSetShader(m_vsStatics, NULL, 0);
m_context->PSSetShader(m_psStatics, NULL, 0);
// Set texture
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
// Set camera matrices
m_stCameraMatrices.View = View.Transpose();
m_stCameraMatrices.Projection = Projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_staticsToDraw.Size(); i++)
2019-01-13 21:57:16 +01:00
{
2019-01-16 20:54:45 +01:00
MESH_INFO* msh = m_staticsToDraw[i]->Mesh;
2019-03-18 22:50:41 +01:00
if (!(msh->Flags & 1))
continue;
RendererRoom* room = m_rooms[m_staticsToDraw[i]->RoomIndex];
2019-01-13 21:57:16 +01:00
2019-01-16 20:54:45 +01:00
RendererObject* staticObj = m_staticObjects[msh->staticNumber];
RendererMesh* mesh = staticObj->ObjectMeshes[0];
2019-01-13 21:57:16 +01:00
m_stStatic.World = (Matrix::CreateRotationY(TR_ANGLE_TO_RAD(msh->yRot)) * Matrix::CreateTranslation(msh->x, msh->y, msh->z)).Transpose();
m_stStatic.Color = Vector4(((msh->shade >> 10) & 0xFF) / 255.0f, ((msh->shade >> 5) & 0xFF) / 255.0f, ((msh->shade >> 0) & 0xFF) / 255.0f, 1.0f);
updateConstantBuffer(m_cbStatic, &m_stStatic, sizeof(CStaticBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbStatic);
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
for (int j = firstBucket; j < lastBucket; j++)
{
if (j == RENDERER_BUCKET_SOLID_DS || j == RENDERER_BUCKET_TRANSPARENT_DS)
m_context->RSSetState(m_states->CullNone());
else
m_context->RSSetState(m_states->CullCounterClockwise());
RendererBucket* bucket = &mesh->Buckets[j];
if (bucket->Vertices.size() == 0)
continue;
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
}
return true;
}
bool Renderer11::drawAnimatingItem(RendererItem* item, bool transparent, bool animated)
{
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
2019-12-02 09:11:21 +01:00
int firstBucket = (transparent ? 2 : 0);
int lastBucket = (transparent ? 4 : 2);
RendererRoom* room = m_rooms[item->Item->roomNumber];
if (room == NULL)
return true;
RendererObject* moveableObj = m_moveableObjects[item->Item->objectNumber];
m_stItem.World = item->World.Transpose();
m_stItem.Position = Vector4(item->Item->pos.xPos, item->Item->pos.yPos, item->Item->pos.zPos, 1.0f);
m_stItem.AmbientLight = room->AmbientLight;
memcpy(m_stItem.BonesMatrices, item->AnimationTransforms, sizeof(Matrix) * 32);
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
m_stLights.NumLights = item->Lights.Size();
2019-12-02 09:11:21 +01:00
for (int j = 0; j < item->Lights.Size(); j++)
memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight));
updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer));
m_context->PSSetConstantBuffers(2, 1, &m_cbLights);
m_stMisc.AlphaTest = !transparent;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
2019-12-02 09:11:21 +01:00
for (int k = 0; k < moveableObj->ObjectMeshes.size(); k++)
{
RendererMesh* mesh = moveableObj->ObjectMeshes[k];
2019-12-02 09:11:21 +01:00
for (int j = firstBucket; j < lastBucket; j++)
2019-01-16 20:54:45 +01:00
{
RendererBucket* bucket = &mesh->Buckets[j];
2019-01-13 21:57:16 +01:00
2019-01-16 20:54:45 +01:00
if (bucket->Vertices.size() == 0)
continue;
2019-01-13 21:57:16 +01:00
if (j == RENDERER_BUCKET_SOLID_DS || j == RENDERER_BUCKET_TRANSPARENT_DS)
m_context->RSSetState(m_states->CullNone());
else
m_context->RSSetState(m_states->CullCounterClockwise());
2019-01-16 20:54:45 +01:00
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
2019-01-13 21:57:16 +01:00
}
}
return true;
}
bool Renderer11::drawWaterfalls()
{
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
// Draw waterfalls
m_context->RSSetState(m_states->CullCounterClockwise());
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_itemsToDraw.Size(); i++)
{
RendererItem* item = m_itemsToDraw[i];
RendererRoom* room = m_rooms[item->Item->roomNumber];
RendererObject* moveableObj = m_moveableObjects[item->Item->objectNumber];
2019-12-02 09:11:21 +01:00
short objectNumber = item->Item->objectNumber;
if (objectNumber >= ID_WATERFALL1 && objectNumber <= ID_WATERFALLSS2)
{
RendererRoom* room = m_rooms[item->Item->roomNumber];
RendererObject* moveableObj = m_moveableObjects[item->Item->objectNumber];
m_stItem.World = item->World.Transpose();
m_stItem.Position = Vector4(item->Item->pos.xPos, item->Item->pos.yPos, item->Item->pos.zPos, 1.0f);
m_stItem.AmbientLight = room->AmbientLight; //Vector4::One * 0.1f; // room->AmbientLight;
memcpy(m_stItem.BonesMatrices, item->AnimationTransforms, sizeof(Matrix) * 32);
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
m_stLights.NumLights = item->Lights.Size();
2019-12-02 09:11:21 +01:00
for (int j = 0; j < item->Lights.Size(); j++)
memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight));
updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer));
m_context->PSSetConstantBuffers(2, 1, &m_cbLights);
m_stMisc.AlphaTest = false;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
m_primitiveBatch->Begin();
2019-12-02 09:11:21 +01:00
for (int k = 0; k < moveableObj->ObjectMeshes.size(); k++)
{
RendererMesh* mesh = moveableObj->ObjectMeshes[k];
2019-12-02 09:11:21 +01:00
for (int b = 0; b < NUM_BUCKETS; b++)
{
RendererBucket* bucket = &mesh->Buckets[b];
if (bucket->Vertices.size() == 0)
continue;
2019-12-02 09:11:21 +01:00
for (int p = 0; p < bucket->Polygons.size(); p++)
{
RendererPolygon* poly = &bucket->Polygons[p];
OBJECT_TEXTURE* texture = &ObjectTextures[poly->TextureId];
2019-12-02 09:11:21 +01:00
int tile = texture->tileAndFlag & 0x7FFF;
if (poly->Shape == SHAPE_RECTANGLE)
{
bucket->Vertices[poly->Indices[0]].UV.y = (texture->vertices[0].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
bucket->Vertices[poly->Indices[1]].UV.y = (texture->vertices[1].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
bucket->Vertices[poly->Indices[2]].UV.y = (texture->vertices[2].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
bucket->Vertices[poly->Indices[3]].UV.y = (texture->vertices[3].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
m_primitiveBatch->DrawQuad(bucket->Vertices[poly->Indices[0]],
bucket->Vertices[poly->Indices[1]],
bucket->Vertices[poly->Indices[2]],
bucket->Vertices[poly->Indices[3]]);
}
else
{
bucket->Vertices[poly->Indices[0]].UV.y = (texture->vertices[0].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
bucket->Vertices[poly->Indices[1]].UV.y = (texture->vertices[1].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
bucket->Vertices[poly->Indices[2]].UV.y = (texture->vertices[2].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
m_primitiveBatch->DrawTriangle(bucket->Vertices[poly->Indices[0]],
bucket->Vertices[poly->Indices[1]],
bucket->Vertices[poly->Indices[2]]);
}
}
}
}
m_primitiveBatch->End();
}
else
{
continue;
}
}
return true;
}
bool Renderer11::drawItems(bool transparent, bool animated)
{
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
2019-12-02 09:11:21 +01:00
int firstBucket = (transparent ? 2 : 0);
int lastBucket = (transparent ? 4 : 2);
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
RendererItem* item = &m_items[Lara.itemNumber];
// Set shaders
m_context->VSSetShader(m_vsItems, NULL, 0);
m_context->PSSetShader(m_psItems, NULL, 0);
// Set texture
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
// Set camera matrices
m_stCameraMatrices.View = View.Transpose();
m_stCameraMatrices.Projection = Projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
m_stMisc.AlphaTest = !transparent;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_itemsToDraw.Size(); i++)
{
RendererItem* item = m_itemsToDraw[i];
RendererRoom* room = m_rooms[item->Item->roomNumber];
RendererObject* moveableObj = m_moveableObjects[item->Item->objectNumber];
2019-12-02 09:11:21 +01:00
short objectNumber = item->Item->objectNumber;
if (moveableObj->DoNotDraw)
{
continue;
}
else if (objectNumber >= ID_WATERFALL1 && objectNumber <= ID_WATERFALLSS2)
{
// We'll draw waterfalls later
continue;
}
else
{
drawAnimatingItem(item, transparent, animated);
}
}
return true;
}
bool Renderer11::drawEffects(bool transparent)
{
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
2019-12-02 09:11:21 +01:00
int firstBucket = (transparent ? 2 : 0);
int lastBucket = (transparent ? 4 : 2);
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_effectsToDraw.Size(); i++)
{
RendererEffect* effect = m_effectsToDraw[i];
RendererRoom* room = m_rooms[effect->Effect->roomNumber];
OBJECT_INFO* obj = &Objects[effect->Effect->objectNumber];
drawEffect(effect, transparent);
if (obj->nmeshes > 0)
{
}
else
{
}
}
return true;
}
bool Renderer11::drawEffect(RendererEffect* effect, bool transparent)
{
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
2019-12-02 09:11:21 +01:00
int firstBucket = (transparent ? 2 : 0);
int lastBucket = (transparent ? 4 : 2);
RendererRoom * room = m_rooms[effect->Effect->roomNumber];
RendererObject * moveableObj = m_moveableObjects[effect->Effect->objectNumber];
m_stItem.World = effect->World.Transpose();
m_stItem.Position = Vector4(effect->Effect->pos.xPos, effect->Effect->pos.yPos, effect->Effect->pos.zPos, 1.0f);
m_stItem.AmbientLight = room->AmbientLight;
Matrix matrices[1] = { Matrix::Identity };
memcpy(m_stItem.BonesMatrices, matrices, sizeof(Matrix));
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
m_stLights.NumLights = effect->Lights.Size();
2019-12-02 09:11:21 +01:00
for (int j = 0; j < effect->Lights.Size(); j++)
memcpy(&m_stLights.Lights[j], effect->Lights[j], sizeof(ShaderLight));
updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer));
m_context->PSSetConstantBuffers(2, 1, &m_cbLights);
m_stMisc.AlphaTest = !transparent;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
RendererMesh* mesh = effect->Mesh;
2019-12-02 09:11:21 +01:00
for (int j = firstBucket; j < lastBucket; j++)
{
RendererBucket* bucket = &mesh->Buckets[j];
if (bucket->Vertices.size() == 0)
continue;
if (j == RENDERER_BUCKET_SOLID_DS || j == RENDERER_BUCKET_TRANSPARENT_DS)
m_context->RSSetState(m_states->CullNone());
else
m_context->RSSetState(m_states->CullCounterClockwise());
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
return true;
}
bool Renderer11::drawLara(bool transparent, bool shadowMap)
{
// Don't draw Lara if binoculars or sniper
if (BinocularRange || SpotcamOverlay || SpotcamDontDrawLara || CurrentLevel == 0)
return true;
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
2019-12-02 09:11:21 +01:00
int firstBucket = (transparent ? 2 : 0);
int lastBucket = (transparent ? 4 : 2);
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
RendererItem* item = &m_items[Lara.itemNumber];
// Set shaders
if (shadowMap)
{
m_context->VSSetShader(m_vsShadowMap, NULL, 0);
m_context->PSSetShader(m_psShadowMap, NULL, 0);
}
else
{
m_context->VSSetShader(m_vsItems, NULL, 0);
m_context->PSSetShader(m_psItems, NULL, 0);
}
// Set texture
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
// Set camera matrices
m_stCameraMatrices.View = View.Transpose();
m_stCameraMatrices.Projection = Projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
m_stMisc.AlphaTest = !transparent;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
RendererObject* laraObj = m_moveableObjects[ID_LARA];
RendererObject* laraSkin = m_moveableObjects[ID_LARA_SKIN];
RendererRoom* room = m_rooms[LaraItem->roomNumber];
m_stItem.World = m_LaraWorldMatrix.Transpose();
m_stItem.Position = Vector4(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos, 1.0f);
m_stItem.AmbientLight = room->AmbientLight;
memcpy(m_stItem.BonesMatrices, laraObj->AnimationTransforms.data(), sizeof(Matrix) * 32);
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
m_context->PSSetConstantBuffers(1, 1, &m_cbItem);
if (!shadowMap)
{
m_stLights.NumLights = item->Lights.Size();
2019-12-02 09:11:21 +01:00
for (int j = 0; j < item->Lights.Size(); j++)
memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight));
updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer));
m_context->PSSetConstantBuffers(2, 1, &m_cbLights);
}
2019-12-02 09:11:21 +01:00
for (int k = 0; k < laraSkin->ObjectMeshes.size(); k++)
{
RendererMesh* mesh = m_meshPointersToMesh[reinterpret_cast<unsigned int>(Lara.meshPtrs[k])];
2019-12-02 09:11:21 +01:00
for (int j = firstBucket; j < lastBucket; j++)
{
RendererBucket* bucket = &mesh->Buckets[j];
if (bucket->Vertices.size() == 0)
continue;
if (j == RENDERER_BUCKET_SOLID_DS || j == RENDERER_BUCKET_TRANSPARENT_DS)
m_context->RSSetState(m_states->CullNone());
else
m_context->RSSetState(m_states->CullCounterClockwise());
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
}
if (m_moveableObjects[ID_LARA_SKIN_JOINTS] != NULL)
{
RendererObject* laraSkinJoints = m_moveableObjects[ID_LARA_SKIN_JOINTS];
2019-12-02 09:11:21 +01:00
for (int k = 0; k < laraSkinJoints->ObjectMeshes.size(); k++)
{
RendererMesh* mesh = laraSkinJoints->ObjectMeshes[k];
2019-12-02 09:11:21 +01:00
for (int j = firstBucket; j < lastBucket; j++)
{
RendererBucket* bucket = &mesh->Buckets[j];
if (bucket->Vertices.size() == 0)
continue;
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
}
}
if (!transparent)
{
2019-12-02 09:11:21 +01:00
for (int k = 0; k < laraSkin->ObjectMeshes.size(); k++)
{
RendererMesh* mesh = laraSkin->ObjectMeshes[k];
2019-12-02 09:11:21 +01:00
for (int j = 0; j < NUM_BUCKETS; j++)
{
RendererBucket* bucket = &mesh->Buckets[j];
if (bucket->Vertices.size() == 0)
continue;
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
}
2019-03-17 19:28:25 +01:00
// Hairs are pre-transformed
Matrix matrices[8] = { Matrix::Identity, Matrix::Identity, Matrix::Identity, Matrix::Identity,
Matrix::Identity, Matrix::Identity, Matrix::Identity, Matrix::Identity };
memcpy(m_stItem.BonesMatrices, matrices, sizeof(Matrix) * 8);
m_stItem.World = Matrix::Identity;
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
if (m_moveableObjects[ID_LARA_HAIR] != NULL)
{
m_primitiveBatch->Begin();
m_primitiveBatch->DrawIndexed(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, (const uint16_t*)m_hairIndices.data(), m_numHairIndices, m_hairVertices.data(), m_numHairVertices);
m_primitiveBatch->End();
2019-03-17 19:28:25 +01:00
}
}
return true;
}
bool Renderer11::drawScene(bool dump)
{
m_timeUpdate = 0;
m_timeDraw = 0;
m_timeFrame = 0;
m_numDrawCalls = 0;
m_nextLight = 0;
m_nextSprite = 0;
m_nextLine3D = 0;
m_nextLine2D = 0;
2019-03-18 23:30:41 +01:00
m_currentCausticsFrame++;
m_currentCausticsFrame %= 32;
m_strings.clear();
2019-02-02 15:40:44 +01:00
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
ViewProjection = View * Projection;
m_stLights.CameraPosition = Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z);
// Prepare the scene to draw
auto time1 = chrono::high_resolution_clock::now();
clearSceneItems();
collectRooms();
updateLaraAnimations();
updateItemsAnimations();
updateEffects();
m_items[Lara.itemNumber].Item = LaraItem;
collectLightsForItem(LaraItem->roomNumber, &m_items[Lara.itemNumber]);
// Update animated textures every 2 frames
if (GnFrameCounter % 2 == 0)
updateAnimatedTextures();
auto time2 = chrono::high_resolution_clock::now();
m_timeUpdate = (chrono::duration_cast<ns>(time2 - time1)).count() / 1000000;
time1 = time2;
// Draw shadow map
if (g_Configuration.EnableShadows)
drawShadowMap();
// Reset GPU state
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->RSSetState(m_states->CullCounterClockwise());
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
// Bind and clear render target
m_currentRenderTarget = (dump ? m_dumpScreenRenderTarget : m_renderTarget);
m_context->ClearRenderTargetView(m_currentRenderTarget->RenderTargetView, Colors::Black);
m_context->ClearDepthStencilView(m_currentRenderTarget->DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
m_context->OMSetRenderTargets(1, &m_currentRenderTarget->RenderTargetView, m_currentRenderTarget->DepthStencilView);
m_context->RSSetViewports(1, &m_viewport);
drawHorizonAndSky();
// Opaque geometry
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
drawRooms(false, false);
drawRooms(false, true);
drawStatics(false);
drawLara(false, false);
drawItems(false, false);
drawItems(false, true);
drawEffects(false);
2019-03-17 23:45:00 +01:00
drawGunFlashes();
drawGunShells();
2019-03-18 22:57:32 +01:00
drawDebris(false);
drawBats();
drawRats();
drawSpiders();
2019-03-18 22:57:32 +01:00
// Transparent geometry
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
m_context->OMSetDepthStencilState(m_states->DepthRead(), 0);
drawRooms(true, false);
drawRooms(true, true);
drawStatics(true);
drawLara(true, false);
drawItems(true, false);
drawItems(true, true);
drawEffects(true);
drawWaterfalls();
2019-03-18 22:50:41 +01:00
drawDebris(true);
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
// Do special effects and weather
drawFires();
drawSmokes();
2020-01-07 16:19:54 +01:00
drawFootprints();
drawBlood();
drawSparks();
drawBubbles();
drawDrips();
drawRipples();
drawUnderwaterDust();
drawSplahes();
drawShockwaves();
2020-01-07 16:19:54 +01:00
2019-12-15 16:19:01 +01:00
switch (level->Weather)
{
case WEATHER_NORMAL:
// no weather in normal
break;
case WEATHER_RAIN:
doRain();
break;
case WEATHER_SNOW:
doSnow();
break;
}
drawRopes();
drawSprites();
drawLines3D();
time2 = chrono::high_resolution_clock::now();
m_timeFrame = (chrono::duration_cast<ns>(time2 - time1)).count() / 1000000;
time1 = time2;
// Bars
int flash = FlashIt();
if (DashTimer < 120)
DrawBar(630, 32, 150, 12, 100 * (unsigned short)DashTimer / 120, 0xA0A000, 0xA000);
UpdateHealtBar(flash);
UpdateAirBar(flash);
DrawAllPickups();
drawLines2D();
if (CurrentLevel != 0)
{
// Draw binoculars or lasersight
drawOverlays();
m_currentY = 60;
#ifdef _DEBUG
ROOM_INFO* r = &Rooms[LaraItem->roomNumber];
printDebugMessage("Update time: %d", m_timeUpdate);
printDebugMessage("Frame time: %d", m_timeFrame);
printDebugMessage("Draw calls: %d", m_numDrawCalls);
printDebugMessage("Rooms: %d", m_roomsToDraw.Size());
printDebugMessage("Items: %d", m_itemsToDraw.Size());
printDebugMessage("Statics: %d", m_staticsToDraw.Size());
printDebugMessage("Lights: %d", m_lightsToDraw.Size());
printDebugMessage("Lara.roomNumber: %d", LaraItem->roomNumber);
printDebugMessage("Lara.pos: %d %d %d", LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos);
printDebugMessage("Lara.rot: %d %d %d", LaraItem->pos.xRot, LaraItem->pos.yRot, LaraItem->pos.zRot);
printDebugMessage("Lara.animNumber: %d", LaraItem->animNumber);
printDebugMessage("Lara.frameNumber: %d", LaraItem->frameNumber);
printDebugMessage("Lara.currentAnimState: %d", LaraItem->currentAnimState);
printDebugMessage("Lara.requiredAnimState: %d", LaraItem->requiredAnimState);
printDebugMessage("Lara.goalAnimState: %d", LaraItem->goalAnimState);
printDebugMessage("Room: %d %d %d %d", r->x, r->z, r->x + r->xSize * WALL_SIZE, r->z + r->ySize * WALL_SIZE);
printDebugMessage("Camera.pos: %d %d %d", Camera.pos.x, Camera.pos.y, Camera.pos.z);
printDebugMessage("Camera.target: %d %d %d", Camera.target.x, Camera.target.y, Camera.target.z);
#endif
2020-01-03 11:31:54 +01:00
}
2020-01-03 06:48:15 +01:00
drawAllStrings();
2020-01-03 06:48:15 +01:00
/*m_spriteBatch->Begin();
2020-01-03 10:49:15 +01:00
RECT rect; rect.top = rect.left = 0; rect.right = rect.bottom = 128;
m_spriteBatch->Draw(m_shadowMap->ShaderResourceView, rect, Colors::White);
m_spriteBatch->End();*/
if (!dump)
m_swapChain->Present(0, 0);
2019-01-13 21:57:16 +01:00
return true;
}
2019-12-02 09:11:21 +01:00
int Renderer11::DumpGameScene()
2019-01-13 21:57:16 +01:00
{
drawScene(true);
2019-02-02 15:40:44 +01:00
return 0;
2019-01-13 21:57:16 +01:00
}
2019-12-02 09:11:21 +01:00
int Renderer11::DrawInventory()
2019-01-13 21:57:16 +01:00
{
if (CurrentLevel == 0 && g_GameFlow->TitleType == TITLE_FLYBY)
drawScene(true);
drawInventoryScene();
drawFinalPass();
return 0;
2019-01-13 21:57:16 +01:00
}
2019-12-02 09:11:21 +01:00
int Renderer11::SyncRenderer()
2019-01-13 21:57:16 +01:00
{
// Sync the renderer
2019-12-02 09:11:21 +01:00
int nf = Sync();
2019-01-13 21:57:16 +01:00
if (nf < 2)
{
2019-12-02 09:11:21 +01:00
int i = 2 - nf;
2019-01-13 21:57:16 +01:00
nf = 2;
do
{
while (!Sync());
i--;
} while (i);
}
GnFrameCounter++;
return nf;
}
2019-12-02 09:11:21 +01:00
bool Renderer11::PrintString(int x, int y, char* string, D3DCOLOR color, int flags)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
int realX = x;
int realY = y;
2019-01-13 21:57:16 +01:00
float factorX = ScreenWidth / 800.0f;
float factorY = ScreenHeight / 600.0f;
RECT rect = { 0, 0, 0, 0 };
// Convert the string to wstring
2019-12-02 09:11:21 +01:00
int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, string, strlen(string), NULL, 0);
2019-01-13 21:57:16 +01:00
std::wstring wstr(sizeNeeded, 0);
MultiByteToWideChar(CP_UTF8, 0, string, strlen(string), &wstr[0], sizeNeeded);
// Prepare the structure for the renderer
RendererStringToDraw str;
str.String = wstr;
str.Flags = flags;
str.X = 0;
str.Y = 0;
str.Color = Vector3((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF);
// Measure the string
Vector2 size = m_gameFont->MeasureString(wstr.c_str());
if (flags & PRINTSTRING_CENTER)
{
2019-12-02 09:11:21 +01:00
int width = size.x;
2019-01-13 21:57:16 +01:00
rect.left = x * factorX - width / 2;
rect.right = x * factorX + width / 2;
rect.top += y * factorY;
rect.bottom += y * factorY;
}
else
{
rect.left = x * factorX;
rect.right += x * factorX;
rect.top = y * factorY;
rect.bottom += y * factorY;
}
str.X = rect.left;
str.Y = rect.top;
2019-01-13 21:57:16 +01:00
if (flags & PRINTSTRING_BLINK)
{
str.Color = Vector3(m_blinkColorValue, m_blinkColorValue, m_blinkColorValue);
if (!(flags & PRINTSTRING_DONT_UPDATE_BLINK))
{
m_blinkColorValue += m_blinkColorDirection * 16;
if (m_blinkColorValue < 0)
{
m_blinkColorValue = 0;
m_blinkColorDirection = 1;
}
if (m_blinkColorValue > 255)
{
m_blinkColorValue = 255;
m_blinkColorDirection = -1;
}
}
}
m_strings.push_back(str);
return true;
}
2019-12-02 09:11:21 +01:00
int Renderer11::drawFinalPass()
{
// Update fade status
if (m_fadeStatus == RENDERER_FADE_STATUS::FADE_IN && m_fadeFactor > 0.99f)
m_fadeStatus = RENDERER_FADE_STATUS::NO_FADE;
if (m_fadeStatus == RENDERER_FADE_STATUS::FADE_OUT && m_fadeFactor <= 0.01f)
m_fadeStatus = RENDERER_FADE_STATUS::NO_FADE;
// Reset GPU state
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->RSSetState(m_states->CullCounterClockwise());
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
m_context->ClearRenderTargetView(m_backBufferRTV, Colors::Black);
m_context->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
m_context->OMSetRenderTargets(1, &m_backBufferRTV, m_depthStencilView);
2019-03-20 00:05:00 +01:00
drawFullScreenQuad(m_renderTarget->ShaderResourceView, Vector3(m_fadeFactor, m_fadeFactor, m_fadeFactor), m_enableCinematicBars);
m_swapChain->Present(0, 0);
// Update fade status
if (m_fadeStatus == RENDERER_FADE_STATUS::FADE_IN)
m_fadeFactor += FADE_FACTOR;
if (m_fadeStatus == RENDERER_FADE_STATUS::FADE_OUT)
m_fadeFactor -= FADE_FACTOR;
return 0;
}
2019-05-09 13:50:55 +02:00
bool Renderer11::drawFullScreenImage(ID3D11ShaderResourceView* texture, float fade)
{
// Reset GPU state
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->RSSetState(m_states->CullCounterClockwise());
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
m_context->ClearRenderTargetView(m_backBufferRTV, Colors::White);
m_context->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
m_context->OMSetRenderTargets(1, &m_backBufferRTV, m_depthStencilView);
m_context->RSSetViewports(1, &m_viewport);
drawFullScreenQuad(texture, Vector3(fade, fade, fade), false);
m_swapChain->Present(0, 0);
return true;
}
2019-01-13 21:57:16 +01:00
bool Renderer11::drawAllStrings()
{
m_spriteBatch->Begin();
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_strings.size(); i++)
2019-01-13 21:57:16 +01:00
{
RendererStringToDraw* str = &m_strings[i];
// Draw shadow if needed
if (str->Flags & PRINTSTRING_OUTLINE)
m_gameFont->DrawString(m_spriteBatch, str->String.c_str(), Vector2(str->X + 1, str->Y + 1),
Vector4(0.0f, 0.0f, 0.0f, 1.0f));
2019-01-13 21:57:16 +01:00
// Draw string
m_gameFont->DrawString(m_spriteBatch, str->String.c_str(), Vector2(str->X, str->Y),
Vector4(str->Color.x / 255.0f, str->Color.y / 255.0f, str->Color.z / 255.0f, 1.0f));
2019-01-13 21:57:16 +01:00
}
m_spriteBatch->End();
return true;
}
bool Renderer11::PrepareDataForTheRenderer()
{
m_moveableObjects = (RendererObject**)malloc(sizeof(RendererObject*) * ID_NUMBER_OBJECTS);
ZeroMemory(m_moveableObjects, sizeof(RendererObject*) * ID_NUMBER_OBJECTS);
m_spriteSequences = (RendererSpriteSequence**)malloc(sizeof(RendererSpriteSequence*) * ID_NUMBER_OBJECTS);
ZeroMemory(m_spriteSequences, sizeof(RendererSpriteSequence*) * ID_NUMBER_OBJECTS);
m_staticObjects = (RendererObject**)malloc(sizeof(RendererObject*) * NUM_STATICS);
ZeroMemory(m_staticObjects, sizeof(RendererObject*) * NUM_STATICS);
m_rooms = (RendererRoom**)malloc(sizeof(RendererRoom*) * NUM_ROOMS);
ZeroMemory(m_rooms, sizeof(RendererRoom*) * NUM_ROOMS);
m_meshes.clear();
// Step 0: prepare animated textures
2019-12-02 09:11:21 +01:00
short numSets = *AnimatedTextureRanges;
short* animatedPtr = AnimatedTextureRanges;
animatedPtr++;
m_animatedTextureSets = (RendererAnimatedTextureSet**)malloc(sizeof(RendererAnimatedTextureSet*) * NUM_ANIMATED_SETS);
m_numAnimatedTextureSets = numSets;
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numSets; i++)
2019-01-13 21:57:16 +01:00
{
RendererAnimatedTextureSet* set = new RendererAnimatedTextureSet();
2019-12-02 09:11:21 +01:00
short numTextures = *animatedPtr + 1;
2019-01-13 21:57:16 +01:00
animatedPtr++;
set->Textures = (RendererAnimatedTexture**)malloc(sizeof(RendererAnimatedTexture) * numTextures);
set->NumTextures = numTextures;
2019-12-02 09:11:21 +01:00
for (int j = 0; j < numTextures; j++)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
short textureId = *animatedPtr;
2019-01-13 21:57:16 +01:00
animatedPtr++;
OBJECT_TEXTURE* texture = &ObjectTextures[textureId];
2019-12-02 09:11:21 +01:00
int tile = texture->tileAndFlag & 0x7FFF;
2019-01-13 21:57:16 +01:00
RendererAnimatedTexture* newTexture = new RendererAnimatedTexture();
newTexture->Id = textureId;
2019-12-02 09:11:21 +01:00
for (int k = 0; k < 4; k++)
2019-01-13 21:57:16 +01:00
{
float x = (texture->vertices[k].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
float y = (texture->vertices[k].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
newTexture->UV[k] = Vector2(x, y);
}
set->Textures[j] = newTexture;
2019-01-13 21:57:16 +01:00
}
m_animatedTextureSets[i] = set;
2019-01-13 21:57:16 +01:00
}
// Step 1: create the texture atlas
byte* buffer = (byte*)malloc(TEXTURE_ATLAS_SIZE * TEXTURE_ATLAS_SIZE * 4);
ZeroMemory(buffer, TEXTURE_ATLAS_SIZE * TEXTURE_ATLAS_SIZE * 4);
2019-12-02 09:11:21 +01:00
int blockX = 0;
int blockY = 0;
2019-01-13 21:57:16 +01:00
if (g_GameFlow->GetLevel(CurrentLevel)->LaraType == LARA_YOUNG)
2019-01-13 21:57:16 +01:00
{
memcpy(m_laraSkinJointRemap, m_youngLaraSkinJointRemap, 15 * 32 * 2);
2019-01-13 21:57:16 +01:00
}
else
{
memcpy(m_laraSkinJointRemap, m_normalLaraSkinJointRemap, 15 * 32 * 2);
2019-01-13 21:57:16 +01:00
}
for (int p = 0; p < NumTexturePages; p++)
{
for (int y = 0; y < 256; y++)
{
for (int x = 0; x < 256; x++)
{
2019-12-02 09:11:21 +01:00
int pixelIndex = blockY * TEXTURE_PAGE_SIZE * NUM_TEXTURE_PAGES_PER_ROW + y * 256 * NUM_TEXTURE_PAGES_PER_ROW * 4 + blockX * 256 * 4 + x * 4;
int oldPixelIndex = p * TEXTURE_PAGE_SIZE + y * 256 * 4 + x * 4;
2019-01-13 21:57:16 +01:00
byte r = Texture32[oldPixelIndex];
byte g = Texture32[oldPixelIndex + 1];
byte b = Texture32[oldPixelIndex + 2];
byte a = Texture32[oldPixelIndex + 3];
buffer[pixelIndex + 2] = r;
buffer[pixelIndex + 1] = g;
buffer[pixelIndex + 0] = b;
buffer[pixelIndex + 3] = a;
}
}
blockX++;
if (blockX == NUM_TEXTURE_PAGES_PER_ROW)
{
blockX = 0;
blockY++;
}
}
if (m_textureAtlas != NULL)
delete m_textureAtlas;
2019-01-13 21:57:16 +01:00
m_textureAtlas = Texture2D::LoadFromByteArray(m_device, TEXTURE_ATLAS_SIZE, TEXTURE_ATLAS_SIZE, &buffer[0]);
if (m_textureAtlas == NULL)
return false;
free(buffer);
buffer = (byte*)malloc(256 * 256 * 4);
memcpy(buffer, MiscTextures + 256 * 512 * 4, 256 * 256 * 4);
m_skyTexture = Texture2D::LoadFromByteArray(m_device, 256, 256, &buffer[0]);
if (m_skyTexture == NULL)
return false;
//D3DX11SaveTextureToFileA(m_context, m_skyTexture->Texture, D3DX11_IFF_PNG, "H:\\sky.png");
2019-01-13 21:57:16 +01:00
free(buffer);
// Step 2: prepare rooms
vector<RendererVertex> roomVertices;
2019-12-02 09:11:21 +01:00
vector<int> roomIndices;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
int baseRoomVertex = 0;
int baseRoomIndex = 0;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NumberRooms; i++)
2019-01-13 21:57:16 +01:00
{
ROOM_INFO* room = &Rooms[i];
RendererRoom* r = new RendererRoom();
2019-01-16 20:54:45 +01:00
r->RoomNumber = i;
2019-01-13 21:57:16 +01:00
r->Room = room;
r->AmbientLight = Vector4(room->ambient.b / 255.0f, room->ambient.g / 255.0f, room->ambient.r / 255.0f, 1.0f);
r->LightsToDraw.Reserve(32);
m_rooms[i] = r;
2019-01-13 21:57:16 +01:00
if (room->NumVertices == 0)
continue;
2019-12-02 09:11:21 +01:00
int lastRectangle = 0;
int lastTriangle = 0;
2019-01-13 21:57:16 +01:00
tr5_room_layer* layers = (tr5_room_layer*)room->LayerOffset;
2019-12-02 09:11:21 +01:00
for (int l = 0; l < room->NumLayers; l++)
2019-01-13 21:57:16 +01:00
{
tr5_room_layer* layer = &layers[l];
if (layer->NumLayerVertices == 0)
continue;
byte* polygons = (byte*)layer->PolyOffset;
tr5_room_vertex* vertices = (tr5_room_vertex*)layer->VerticesOffset;
if (layer->NumLayerRectangles > 0)
{
for (int n = 0; n < layer->NumLayerRectangles; n++)
{
tr4_mesh_face4* poly = (tr4_mesh_face4*)polygons;
// Get the real texture index and if double sided
2019-12-02 09:11:21 +01:00
short textureIndex = poly->Texture & 0x3FFF;
2019-01-13 21:57:16 +01:00
bool doubleSided = (poly->Texture & 0x8000) >> 15;
// Get the object texture
OBJECT_TEXTURE* texture = &ObjectTextures[textureIndex];
2019-12-02 09:11:21 +01:00
int tile = texture->tileAndFlag & 0x7FFF;
2019-01-13 21:57:16 +01:00
// Create vertices
RendererBucket* bucket;
2019-12-02 09:11:21 +01:00
int animatedSetIndex = getAnimatedTextureInfo(textureIndex);
int bucketIndex = RENDERER_BUCKET_SOLID;
2019-01-13 21:57:16 +01:00
if (!doubleSided)
{
if (texture->attribute == 2)
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
else
bucketIndex = RENDERER_BUCKET_SOLID;
}
else
{
if (texture->attribute == 2)
bucketIndex = RENDERER_BUCKET_TRANSPARENT_DS;
else
bucketIndex = RENDERER_BUCKET_SOLID_DS;
}
if (animatedSetIndex == -1)
{
bucket = &r->Buckets[bucketIndex];
}
else
{
bucket = &r->AnimatedBuckets[bucketIndex];
}
// Calculate face normal
Vector3 p0 = Vector3(vertices[poly->Vertices[0]].Vertex.x,
vertices[poly->Vertices[0]].Vertex.y,
vertices[poly->Vertices[0]].Vertex.z);
Vector3 p1 = Vector3(vertices[poly->Vertices[1]].Vertex.x,
vertices[poly->Vertices[1]].Vertex.y,
vertices[poly->Vertices[1]].Vertex.z);
Vector3 p2 = Vector3(vertices[poly->Vertices[2]].Vertex.x,
vertices[poly->Vertices[2]].Vertex.y,
vertices[poly->Vertices[2]].Vertex.z);
Vector3 e1 = p1 - p0;
Vector3 e2 = p1 - p2;
Vector3 normal = e1.Cross(e2);
normal.Normalize();
2019-12-02 09:11:21 +01:00
int baseVertices = bucket->NumVertices;
for (int v = 0; v < 4; v++)
2019-01-13 21:57:16 +01:00
{
RendererVertex vertex;
vertex.Position.x = room->x + vertices[poly->Vertices[v]].Vertex.x;
vertex.Position.y = room->y + vertices[poly->Vertices[v]].Vertex.y;
vertex.Position.z = room->z + vertices[poly->Vertices[v]].Vertex.z;
vertex.Normal.x = vertices[poly->Vertices[v]].Normal.x;
vertex.Normal.y = vertices[poly->Vertices[v]].Normal.y;
vertex.Normal.z = vertices[poly->Vertices[v]].Normal.z;
vertex.UV.x = (texture->vertices[v].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.UV.y = (texture->vertices[v].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.Color.x = ((vertices[poly->Vertices[v]].Colour >> 16) & 0xFF) / 255.0f;
vertex.Color.y = ((vertices[poly->Vertices[v]].Colour >> 8) & 0xFF) / 255.0f;
vertex.Color.z = ((vertices[poly->Vertices[v]].Colour >> 0) & 0xFF) / 255.0f;
vertex.Color.w = 1.0f;
vertex.Bone = 0;
bucket->NumVertices++;
bucket->Vertices.push_back(vertex);
}
bucket->Indices.push_back(baseVertices);
bucket->Indices.push_back(baseVertices + 1);
bucket->Indices.push_back(baseVertices + 3);
bucket->Indices.push_back(baseVertices + 2);
bucket->Indices.push_back(baseVertices + 3);
bucket->Indices.push_back(baseVertices + 1);
bucket->NumIndices += 6;
RendererPolygon newPolygon;
newPolygon.Shape = SHAPE_RECTANGLE;
newPolygon.AnimatedSet = animatedSetIndex;
newPolygon.TextureId = textureIndex;
newPolygon.Indices[0] = baseVertices;
newPolygon.Indices[1] = baseVertices + 1;
newPolygon.Indices[2] = baseVertices + 2;
newPolygon.Indices[3] = baseVertices + 3;
bucket->Polygons.push_back(newPolygon);
polygons += sizeof(tr4_mesh_face4);
}
}
if (layer->NumLayerTriangles > 0)
{
for (int n = 0; n < layer->NumLayerTriangles; n++)
{
tr4_mesh_face3* poly = (tr4_mesh_face3*)polygons;
// Get the real texture index and if double sided
2019-12-02 09:11:21 +01:00
short textureIndex = poly->Texture & 0x3FFF;
2019-01-13 21:57:16 +01:00
bool doubleSided = (poly->Texture & 0x8000) >> 15;
// Get the object texture
OBJECT_TEXTURE* texture = &ObjectTextures[textureIndex];
2019-12-02 09:11:21 +01:00
int tile = texture->tileAndFlag & 0x7FFF;
2019-01-13 21:57:16 +01:00
// Create vertices
RendererBucket* bucket;
2019-12-02 09:11:21 +01:00
int animatedSetIndex = getAnimatedTextureInfo(textureIndex);
int bucketIndex = RENDERER_BUCKET_SOLID;
2019-01-13 21:57:16 +01:00
if (!doubleSided)
{
if (texture->attribute == 2)
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
else
bucketIndex = RENDERER_BUCKET_SOLID;
}
else
{
if (texture->attribute == 2)
bucketIndex = RENDERER_BUCKET_TRANSPARENT_DS;
else
bucketIndex = RENDERER_BUCKET_SOLID_DS;
}
if (animatedSetIndex == -1)
{
bucket = &r->Buckets[bucketIndex];
}
else
{
bucket = &r->AnimatedBuckets[bucketIndex];
}
// Calculate face normal
Vector3 p0 = Vector3(vertices[poly->Vertices[0]].Vertex.x,
vertices[poly->Vertices[0]].Vertex.y,
vertices[poly->Vertices[0]].Vertex.z);
Vector3 p1 = Vector3(vertices[poly->Vertices[1]].Vertex.x,
vertices[poly->Vertices[1]].Vertex.y,
vertices[poly->Vertices[1]].Vertex.z);
Vector3 p2 = Vector3(vertices[poly->Vertices[2]].Vertex.x,
vertices[poly->Vertices[2]].Vertex.y,
vertices[poly->Vertices[2]].Vertex.z);
Vector3 e1 = p1 - p0;
Vector3 e2 = p1 - p2;
Vector3 normal = e1.Cross(e2);
normal.Normalize();
2019-12-02 09:11:21 +01:00
int baseVertices = bucket->NumVertices;
for (int v = 0; v < 3; v++)
2019-01-13 21:57:16 +01:00
{
RendererVertex vertex;
2019-01-13 21:57:16 +01:00
vertex.Position.x = room->x + vertices[poly->Vertices[v]].Vertex.x;
vertex.Position.y = room->y + vertices[poly->Vertices[v]].Vertex.y;
vertex.Position.z = room->z + vertices[poly->Vertices[v]].Vertex.z;
vertex.Normal.x = vertices[poly->Vertices[v]].Normal.x;
vertex.Normal.y = vertices[poly->Vertices[v]].Normal.y;
vertex.Normal.z = vertices[poly->Vertices[v]].Normal.z;
vertex.UV.x = (texture->vertices[v].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.UV.y = (texture->vertices[v].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.Color.x = ((vertices[poly->Vertices[v]].Colour >> 16) & 0xFF) / 255.0f;
vertex.Color.y = ((vertices[poly->Vertices[v]].Colour >> 8) & 0xFF) / 255.0f;
vertex.Color.z = ((vertices[poly->Vertices[v]].Colour >> 0) & 0xFF) / 255.0f;
vertex.Color.w = 1.0f;
vertex.Bone = 0;
bucket->NumVertices++;
bucket->Vertices.push_back(vertex);
}
bucket->Indices.push_back(baseVertices);
bucket->Indices.push_back(baseVertices + 1);
bucket->Indices.push_back(baseVertices + 2);
bucket->NumIndices += 3;
RendererPolygon newPolygon;
newPolygon.Shape = SHAPE_TRIANGLE;
newPolygon.AnimatedSet = animatedSetIndex;
newPolygon.TextureId = textureIndex;
newPolygon.Indices[0] = baseVertices;
newPolygon.Indices[1] = baseVertices + 1;
newPolygon.Indices[2] = baseVertices + 2;
bucket->Polygons.push_back(newPolygon);
polygons += sizeof(tr4_mesh_face3);
}
}
2019-01-16 20:54:45 +01:00
}
2019-01-16 20:54:45 +01:00
if (room->numLights != 0)
{
tr5_room_light* oldLight = room->light;
2019-12-02 09:11:21 +01:00
for (int l = 0; l < room->numLights; l++)
2019-01-16 20:54:45 +01:00
{
RendererLight light;
if (oldLight->LightType == LIGHT_TYPES::LIGHT_TYPE_SUN)
{
light.Color = Vector3(oldLight->r, oldLight->g, oldLight->b);
2019-01-16 20:54:45 +01:00
light.Direction = Vector4(oldLight->dx, oldLight->dy, oldLight->dz, 1.0f);
light.Type = LIGHT_TYPES::LIGHT_TYPE_SUN;
light.Intensity = 1.0f;
2019-01-16 20:54:45 +01:00
r->Lights.push_back(light);
}
else if (oldLight->LightType == LIGHT_TYPE_POINT)
{
light.Position = Vector3(oldLight->x, oldLight->y, oldLight->z);
light.Color = Vector3(oldLight->r, oldLight->g, oldLight->b);
2019-01-16 20:54:45 +01:00
light.Direction = Vector4(oldLight->dx, oldLight->dy, oldLight->dz, 1.0f);
light.Intensity = 1.0f;
light.In = oldLight->In;
light.Out = oldLight->Out;
light.Type = LIGHT_TYPE_POINT;
r->Lights.push_back(light);
}
2019-01-16 20:54:45 +01:00
else if (oldLight->LightType == LIGHT_TYPE_SHADOW)
{
light.Position = Vector3(oldLight->x, oldLight->y, oldLight->z);
light.Color = Vector3(oldLight->r, oldLight->g, oldLight->b);
2019-01-16 20:54:45 +01:00
light.In = oldLight->In;
light.Out = oldLight->Out;
light.Type = LIGHT_TYPE_SHADOW;
light.Intensity = 1.0f;
2019-01-16 20:54:45 +01:00
r->Lights.push_back(light);
}
else if (oldLight->LightType == LIGHT_TYPE_SPOT)
{
light.Position = Vector3(oldLight->x, oldLight->y, oldLight->z);
light.Color = Vector3(oldLight->r, oldLight->g, oldLight->b);
light.Direction = Vector4(oldLight->dx, oldLight->dy, oldLight->dz, 1.0f);
2019-01-16 20:54:45 +01:00
light.Intensity = 1.0f;
light.In = oldLight->In;
light.Out = oldLight->Out;
2019-01-16 20:54:45 +01:00
light.Range = oldLight->Range;
light.Type = LIGHT_TYPE_SPOT;
r->Lights.push_back(light);
}
oldLight++;
2019-01-16 20:54:45 +01:00
}
}
MESH_INFO* mesh = room->mesh;
2019-12-02 09:11:21 +01:00
for (int j = 0; j < room->numMeshes; j++)
2019-01-16 20:54:45 +01:00
{
RendererStatic obj;
obj.Mesh = mesh;
obj.RoomIndex = i;
r->Statics.push_back(obj);
}
2019-01-13 21:57:16 +01:00
// Merge vertices and indices in a single list
2019-12-02 09:11:21 +01:00
for (int j = 0; j < NUM_BUCKETS; j++)
2019-01-13 21:57:16 +01:00
{
RendererBucket* bucket = &r->Buckets[j];
bucket->StartVertex = baseRoomVertex;
bucket->StartIndex = baseRoomIndex;
2019-12-02 09:11:21 +01:00
for (int k = 0; k < bucket->Vertices.size(); k++)
2019-01-13 21:57:16 +01:00
roomVertices.push_back(bucket->Vertices[k]);
2019-12-02 09:11:21 +01:00
for (int k = 0; k < bucket->Indices.size(); k++)
2019-01-13 21:57:16 +01:00
roomIndices.push_back(baseRoomVertex + bucket->Indices[k]);
baseRoomVertex += bucket->Vertices.size();
baseRoomIndex += bucket->Indices.size();
}
}
// Create a single vertex buffer and a single index buffer for all rooms
// NOTICE: in theory, a 1,000,000 vertices scene should have a VB of 52 MB and an IB of 4 MB
m_roomsVertexBuffer = VertexBuffer::Create(m_device, roomVertices.size(), roomVertices.data());
m_roomsIndexBuffer = IndexBuffer::Create(m_device, roomIndices.size(), roomIndices.data());
m_numHairVertices = 0;
m_numHairIndices = 0;
vector<RendererVertex> moveablesVertices;
2019-12-02 09:11:21 +01:00
vector<int> moveablesIndices;
int baseMoveablesVertex = 0;
int baseMoveablesIndex = 0;
2019-01-13 21:57:16 +01:00
// Step 3: prepare moveables
2019-12-02 09:11:21 +01:00
for (int i = 0; i < MoveablesIds.size(); i++)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
int objNum = MoveablesIds[i];
2019-01-13 21:57:16 +01:00
OBJECT_INFO* obj = &Objects[objNum];
if (obj->nmeshes > 0)
{
RendererObject* moveable = new RendererObject();
moveable->Id = MoveablesIds[i];
// Assign the draw routine
if (objNum == ID_FLAME || objNum == ID_FLAME_EMITTER || objNum == ID_FLAME_EMITTER2 || objNum == ID_FLAME_EMITTER3 ||
objNum == ID_TRIGGER_TRIGGERER || objNum == ID_TIGHT_ROPE || objNum == ID_AI_AMBUSH ||
objNum == ID_AI_FOLLOW || objNum == ID_AI_GUARD || objNum == ID_AI_MODIFY ||
objNum == ID_AI_PATROL1 || objNum == ID_AI_PATROL2 || objNum == ID_AI_X1 ||
objNum == ID_AI_X2 || objNum == ID_DART_EMITTER || objNum == ID_HOMING_DART_EMITTER ||
objNum == ID_ROPE || objNum == ID_KILL_ALL_TRIGGERS || objNum == ID_EARTHQUAKE ||
objNum == ID_CAMERA_TARGET || objNum == ID_WATERFALLMIST || objNum == ID_SMOKE_EMITTER_BLACK ||
objNum == ID_SMOKE_EMITTER_WHITE)
{
moveable->DoNotDraw = true;
}
else
{
moveable->DoNotDraw = false;
}
2019-12-02 09:11:21 +01:00
for (int j = 0; j < obj->nmeshes; j++)
2019-01-13 21:57:16 +01:00
{
// HACK: mesh pointer 0 is the placeholder for Lara's body parts and is right hand with pistols
// We need to override the bone index because the engine will take mesh 0 while drawing pistols anim,
// and vertices have bone index 0 and not 10
2019-12-02 09:11:21 +01:00
int meshPtrIndex = RawMeshPointers[obj->meshIndex / 2 + j] / 2;
2019-12-15 16:19:01 +01:00
int boneIndex = (meshPtrIndex == 0 ? LM_RHAND : j);
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
short* meshPtr = &RawMeshData[meshPtrIndex];
2019-01-13 21:57:16 +01:00
RendererMesh* mesh = getRendererMeshFromTrMesh(moveable,
meshPtr,
Meshes[obj->meshIndex + 2 * j],
boneIndex, MoveablesIds[i] == ID_LARA_SKIN_JOINTS,
MoveablesIds[i] == ID_LARA_HAIR);
2019-01-13 21:57:16 +01:00
moveable->ObjectMeshes.push_back(mesh);
}
2019-12-02 09:11:21 +01:00
int* bone = &Bones[obj->boneIndex];
2019-01-13 21:57:16 +01:00
stack<RendererBone*> stack;
for (int j = 0; j < obj->nmeshes; j++)
{
moveable->LinearizedBones.push_back(new RendererBone(j));
moveable->AnimationTransforms.push_back(Matrix::Identity);
moveable->BindPoseTransforms.push_back(Matrix::Identity);
}
RendererBone* currentBone = moveable->LinearizedBones[0];
RendererBone* stackBone = moveable->LinearizedBones[0];
for (int mi = 0; mi < obj->nmeshes - 1; mi++)
{
int j = mi + 1;
2019-12-02 09:11:21 +01:00
int opcode = *(bone++);
2019-01-13 21:57:16 +01:00
int linkX = *(bone++);
int linkY = *(bone++);
int linkZ = *(bone++);
byte flags = opcode & 0x1C;
moveable->LinearizedBones[j]->ExtraRotationFlags = flags;
switch (opcode & 0x03)
{
case 0:
moveable->LinearizedBones[j]->Parent = currentBone;
moveable->LinearizedBones[j]->Translation = Vector3(linkX, linkY, linkZ);
currentBone->Children.push_back(moveable->LinearizedBones[j]);
currentBone = moveable->LinearizedBones[j];
break;
case 1:
if (stack.empty())
continue;
currentBone = stack.top();
stack.pop();
moveable->LinearizedBones[j]->Parent = currentBone;
moveable->LinearizedBones[j]->Translation = Vector3(linkX, linkY, linkZ);
currentBone->Children.push_back(moveable->LinearizedBones[j]);
currentBone = moveable->LinearizedBones[j];
break;
case 2:
stack.push(currentBone);
moveable->LinearizedBones[j]->Translation = Vector3(linkX, linkY, linkZ);
moveable->LinearizedBones[j]->Parent = currentBone;
currentBone->Children.push_back(moveable->LinearizedBones[j]);
currentBone = moveable->LinearizedBones[j];
break;
case 3:
if (stack.empty())
continue;
RendererBone* theBone = stack.top();
stack.pop();
moveable->LinearizedBones[j]->Translation = Vector3(linkX, linkY, linkZ);
moveable->LinearizedBones[j]->Parent = theBone;
theBone->Children.push_back(moveable->LinearizedBones[j]);
currentBone = moveable->LinearizedBones[j];
stack.push(theBone);
break;
}
}
for (int n = 0; n < obj->nmeshes; n++)
moveable->LinearizedBones[n]->Transform = Matrix::CreateTranslation(
moveable->LinearizedBones[n]->Translation.x,
moveable->LinearizedBones[n]->Translation.y,
moveable->LinearizedBones[n]->Translation.z);
moveable->Skeleton = moveable->LinearizedBones[0];
buildHierarchy(moveable);
// Fix Lara skin joints and hairs
if (MoveablesIds[i] == ID_LARA_SKIN_JOINTS)
{
RendererObject* objSkin = m_moveableObjects[ID_LARA_SKIN];
2019-12-02 09:11:21 +01:00
for (int j = 1; j < obj->nmeshes; j++)
2019-01-13 21:57:16 +01:00
{
RendererMesh* jointMesh = moveable->ObjectMeshes[j];
RendererBone* jointBone = moveable->LinearizedBones[j];
2019-12-02 09:11:21 +01:00
for (int b1 = 0; b1 < NUM_BUCKETS; b1++)
2019-01-13 21:57:16 +01:00
{
RendererBucket* jointBucket = &jointMesh->Buckets[b1];
2019-12-02 09:11:21 +01:00
for (int v1 = 0; v1 < jointBucket->Vertices.size(); v1++)
2019-01-13 21:57:16 +01:00
{
RendererVertex* jointVertex = &jointBucket->Vertices[v1];
if (jointVertex->Bone != j)
{
RendererMesh* skinMesh = objSkin->ObjectMeshes[jointVertex->Bone];
RendererBone* skinBone = objSkin->LinearizedBones[jointVertex->Bone];
2019-12-02 09:11:21 +01:00
for (int b2 = 0; b2 < NUM_BUCKETS; b2++)
2019-01-13 21:57:16 +01:00
{
RendererBucket* skinBucket = &skinMesh->Buckets[b2];
2019-12-02 09:11:21 +01:00
for (int v2 = 0; v2 < skinBucket->Vertices.size(); v2++)
2019-01-13 21:57:16 +01:00
{
RendererVertex* skinVertex = &skinBucket->Vertices[v2];
2019-12-02 09:11:21 +01:00
int x1 = jointBucket->Vertices[v1].Position.x + jointBone->GlobalTranslation.x;
int y1 = jointBucket->Vertices[v1].Position.y + jointBone->GlobalTranslation.y;
int z1 = jointBucket->Vertices[v1].Position.z + jointBone->GlobalTranslation.z;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
int x2 = skinBucket->Vertices[v2].Position.x + skinBone->GlobalTranslation.x;
int y2 = skinBucket->Vertices[v2].Position.y + skinBone->GlobalTranslation.y;
int z2 = skinBucket->Vertices[v2].Position.z + skinBone->GlobalTranslation.z;
2019-01-13 21:57:16 +01:00
if (abs(x1 - x2) < 2 && abs(y1 - y2) < 2 && abs(z1 - z2) < 2)
{
jointVertex->Position.x = skinVertex->Position.x;
jointVertex->Position.y = skinVertex->Position.y;
jointVertex->Position.z = skinVertex->Position.z;
}
}
}
}
}
}
}
}
if (MoveablesIds[i] == ID_LARA_HAIR)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
for (int j = 0; j < moveable->ObjectMeshes.size(); j++)
2019-01-13 21:57:16 +01:00
{
RendererMesh* mesh = moveable->ObjectMeshes[j];
2019-12-02 09:11:21 +01:00
for (int n = 0; n < NUM_BUCKETS; n++)
2019-01-13 21:57:16 +01:00
{
m_numHairVertices += mesh->Buckets[n].NumVertices;
m_numHairIndices += mesh->Buckets[n].NumIndices;
}
}
m_hairVertices.clear();
m_hairIndices.clear();
RendererVertex vertex;
2019-12-02 09:11:21 +01:00
for (int m = 0; m < m_numHairVertices * 2; m++)
2019-01-13 21:57:16 +01:00
m_hairVertices.push_back(vertex);
2019-12-02 09:11:21 +01:00
for (int m = 0; m < m_numHairIndices * 2; m++)
2019-01-13 21:57:16 +01:00
m_hairIndices.push_back(0);
}
m_moveableObjects[MoveablesIds[i]] = moveable;
2019-01-13 21:57:16 +01:00
// Merge vertices and indices in a single list
2019-12-02 09:11:21 +01:00
for (int m = 0; m < moveable->ObjectMeshes.size(); m++)
2019-01-13 21:57:16 +01:00
{
RendererMesh* msh = moveable->ObjectMeshes[m];
2019-12-02 09:11:21 +01:00
for (int j = 0; j < NUM_BUCKETS; j++)
2019-01-13 21:57:16 +01:00
{
RendererBucket* bucket = &msh->Buckets[j];
bucket->StartVertex = baseMoveablesVertex;
bucket->StartIndex = baseMoveablesIndex;
2019-12-02 09:11:21 +01:00
for (int k = 0; k < bucket->Vertices.size(); k++)
2019-01-13 21:57:16 +01:00
moveablesVertices.push_back(bucket->Vertices[k]);
2019-12-02 09:11:21 +01:00
for (int k = 0; k < bucket->Indices.size(); k++)
2019-01-13 21:57:16 +01:00
moveablesIndices.push_back(baseMoveablesVertex + bucket->Indices[k]);
baseMoveablesVertex += bucket->Vertices.size();
baseMoveablesIndex += bucket->Indices.size();
}
}
}
}
// Create a single vertex buffer and a single index buffer for all moveables
m_moveablesVertexBuffer = VertexBuffer::Create(m_device, moveablesVertices.size(), moveablesVertices.data());
m_moveablesIndexBuffer = IndexBuffer::Create(m_device, moveablesIndices.size(), moveablesIndices.data());
// Step 4: prepare static meshes
vector<RendererVertex> staticsVertices;
2019-12-02 09:11:21 +01:00
vector<int> staticsIndices;
int baseStaticsVertex = 0;
int baseStaticsIndex = 0;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
for (int i = 0; i < StaticObjectsIds.size(); i++)
2019-01-13 21:57:16 +01:00
{
STATIC_INFO* obj = &StaticObjects[StaticObjectsIds[i]];
RendererObject* staticObject = new RendererObject();
staticObject->Id = StaticObjectsIds[i];
2019-12-02 09:11:21 +01:00
short* meshPtr = &RawMeshData[RawMeshPointers[obj->meshNumber / 2] / 2];
2019-01-13 21:57:16 +01:00
RendererMesh* mesh = getRendererMeshFromTrMesh(staticObject, meshPtr, Meshes[obj->meshNumber], 0, false, false);
staticObject->ObjectMeshes.push_back(mesh);
m_staticObjects[StaticObjectsIds[i]] = staticObject;
2019-01-13 21:57:16 +01:00
// Merge vertices and indices in a single list
RendererMesh* msh = staticObject->ObjectMeshes[0];
2019-12-02 09:11:21 +01:00
for (int j = 0; j < NUM_BUCKETS; j++)
2019-01-13 21:57:16 +01:00
{
RendererBucket* bucket = &msh->Buckets[j];
bucket->StartVertex = baseStaticsVertex;
bucket->StartIndex = baseStaticsIndex;
2019-12-02 09:11:21 +01:00
for (int k = 0; k < bucket->Vertices.size(); k++)
2019-01-13 21:57:16 +01:00
staticsVertices.push_back(bucket->Vertices[k]);
2019-12-02 09:11:21 +01:00
for (int k = 0; k < bucket->Indices.size(); k++)
2019-01-13 21:57:16 +01:00
staticsIndices.push_back(baseStaticsVertex + bucket->Indices[k]);
baseStaticsVertex += bucket->Vertices.size();
baseStaticsIndex += bucket->Indices.size();
}
}
// Create missing meshes (effect objects like ID_BODY_PART have nmeshes = 0 and they are "lost" with current procedures)
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NumMeshPointers; i++)
{
2019-12-02 09:11:21 +01:00
unsigned int mp = reinterpret_cast<unsigned int>(Meshes[i * 2]);
RendererMesh* mesh = m_meshPointersToMesh[mp];
if (mesh == NULL)
{
2019-12-02 09:11:21 +01:00
int meshPtrIndex = RawMeshPointers[i] / 2;
short* meshPtr = &RawMeshData[meshPtrIndex];
RendererMesh* mesh = getRendererMeshFromTrMesh(NULL,
meshPtr,
Meshes[i * 2],
0,
false,
false);
}
}
2019-01-13 21:57:16 +01:00
// Create a single vertex buffer and a single index buffer for all statics
m_staticsVertexBuffer = VertexBuffer::Create(m_device, staticsVertices.size(), staticsVertices.data());
m_staticsIndexBuffer = IndexBuffer::Create(m_device, staticsIndices.size(), staticsIndices.data());
// Step 5: prepare sprites
m_sprites = (RendererSprite**)malloc(sizeof(RendererSprite*) * g_NumSprites);
ZeroMemory(m_sprites, sizeof(RendererSprite*) * g_NumSprites);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < g_NumSprites; i++)
{
SPRITE* oldSprite = &Sprites[i];
RendererSprite* sprite = new RendererSprite();
sprite->Width = (oldSprite->right - oldSprite->left)*256.0f;
sprite->Height = (oldSprite->bottom - oldSprite->top)*256.0f;
float left = (oldSprite->left * 256.0f + GET_ATLAS_PAGE_X(oldSprite->tile - 1));
float top = (oldSprite->top * 256.0f + GET_ATLAS_PAGE_Y(oldSprite->tile - 1));
float right = (oldSprite->right * 256.0f + GET_ATLAS_PAGE_X(oldSprite->tile - 1));
float bottom = (oldSprite->bottom * 256.0f + GET_ATLAS_PAGE_Y(oldSprite->tile - 1));
sprite->UV[0] = Vector2(left / (float)TEXTURE_ATLAS_SIZE, top / (float)TEXTURE_ATLAS_SIZE);
sprite->UV[1] = Vector2(right / (float)TEXTURE_ATLAS_SIZE, top / (float)TEXTURE_ATLAS_SIZE);
sprite->UV[2] = Vector2(right / (float)TEXTURE_ATLAS_SIZE, bottom / (float)TEXTURE_ATLAS_SIZE);
sprite->UV[3] = Vector2(left / (float)TEXTURE_ATLAS_SIZE, bottom / (float)TEXTURE_ATLAS_SIZE);
m_sprites[i] = sprite;
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < MoveablesIds.size(); i++)
{
OBJECT_INFO* obj = &Objects[MoveablesIds[i]];
if (obj->nmeshes < 0)
{
2019-12-02 09:11:21 +01:00
short numSprites = abs(obj->nmeshes);
short baseSprite = obj->meshIndex;
RendererSpriteSequence* sequence = new RendererSpriteSequence(MoveablesIds[i], numSprites);
2019-12-02 09:11:21 +01:00
for (int j = baseSprite; j < baseSprite + numSprites; j++)
{
sequence->SpritesList[j - baseSprite] = m_sprites[j];
}
m_spriteSequences[MoveablesIds[i]] = sequence;
}
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < 6; i++)
{
if (Objects[ID_WATERFALL1 + i].loaded)
{
// Get the first textured bucket
RendererBucket* bucket = NULL;
2019-12-02 09:11:21 +01:00
for (int j = 0; j < NUM_BUCKETS; j++)
if (m_moveableObjects[ID_WATERFALL1 + i]->ObjectMeshes[0]->Buckets[j].Polygons.size() > 0)
bucket = &m_moveableObjects[ID_WATERFALL1 + i]->ObjectMeshes[0]->Buckets[j];
if (bucket == NULL)
continue;
OBJECT_TEXTURE* texture = &ObjectTextures[bucket->Polygons[0].TextureId];
WaterfallTextures[i] = texture;
WaterfallY[i] = texture->vertices[0].y;
}
}
2019-01-13 21:57:16 +01:00
return true;
}
ID3D11VertexShader* Renderer11::compileVertexShader(const char* fileName, const char* function, const char* model, ID3D10Blob** bytecode)
2019-01-13 21:57:16 +01:00
{
HRESULT res;
*bytecode = NULL;
2019-01-13 21:57:16 +01:00
ID3DBlob* errors = NULL;
printf("Compiling vertex shader: %s\n", fileName);
res = D3DX11CompileFromFileA(fileName, NULL, NULL, function, model, D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, bytecode, &errors, NULL);
2019-01-13 21:57:16 +01:00
if (FAILED(res))
{
printf("Compilation failed: %s\n", errors->GetBufferPointer());
2019-01-13 21:57:16 +01:00
return NULL;
}
2019-01-13 21:57:16 +01:00
ID3D11VertexShader* shader = NULL;
res = m_device->CreateVertexShader((*bytecode)->GetBufferPointer(), (*bytecode)->GetBufferSize(), NULL, &shader);
2019-01-13 21:57:16 +01:00
if (FAILED(res))
return NULL;
return shader;
}
ID3D11PixelShader* Renderer11::compilePixelShader(const char* fileName, const char* function, const char* model, ID3D10Blob** bytecode)
2019-01-13 21:57:16 +01:00
{
HRESULT res;
*bytecode = NULL;
2019-01-13 21:57:16 +01:00
ID3DBlob* errors = NULL;
printf("Compiling pixel shader: %s\n", fileName);
res = D3DX11CompileFromFileA(fileName, NULL, NULL, function, model, D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, bytecode, &errors, NULL);
2019-01-13 21:57:16 +01:00
if (FAILED(res))
{
printf("Compilation failed: %s\n", errors->GetBufferPointer());
2019-01-13 21:57:16 +01:00
return NULL;
}
2019-01-13 21:57:16 +01:00
ID3D11PixelShader* shader = NULL;
res = m_device->CreatePixelShader((*bytecode)->GetBufferPointer(), (*bytecode)->GetBufferSize(), NULL, &shader);
2019-01-13 21:57:16 +01:00
if (FAILED(res))
return NULL;
return shader;
}
ID3D11GeometryShader* Renderer11::compileGeometryShader(const char* fileName)
2019-01-13 21:57:16 +01:00
{
HRESULT res;
ID3DBlob* bytecode = NULL;
ID3DBlob* errors = NULL;
res = D3DX11CompileFromFileA(fileName, NULL, NULL, NULL, "gs_4_0", D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, &bytecode, &errors, NULL);
if (FAILED(res))
return NULL;
ID3D11GeometryShader* shader = NULL;
res = m_device->CreateGeometryShader(bytecode->GetBufferPointer(), bytecode->GetBufferSize(), NULL, &shader);
if (FAILED(res))
return NULL;
return shader;
}
ID3D11ComputeShader* Renderer11::compileComputeShader(const char* fileName)
2019-01-13 21:57:16 +01:00
{
HRESULT res;
ID3DBlob* bytecode = NULL;
ID3DBlob* errors = NULL;
res = D3DX11CompileFromFileA(fileName, NULL, NULL, NULL, "gs_4_0", D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, &bytecode, &errors, NULL);
if (FAILED(res))
return NULL;
ID3D11ComputeShader* shader = NULL;
res = m_device->CreateComputeShader(bytecode->GetBufferPointer(), bytecode->GetBufferSize(), NULL, &shader);
if (FAILED(res))
return NULL;
return shader;
}
void Renderer11::ClearDynamicLights()
{
m_dynamicLights.Clear();
2019-01-13 21:57:16 +01:00
}
2019-12-02 09:11:21 +01:00
void Renderer11::AddDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b)
2019-01-13 21:57:16 +01:00
{
2019-01-16 21:21:14 +01:00
if (m_nextLight >= MAX_LIGHTS)
return;
2019-01-13 21:57:16 +01:00
2019-01-16 21:21:14 +01:00
RendererLight* dynamicLight = &m_lights[m_nextLight++];
dynamicLight->Position = Vector3(float(x), float(y), float(z));
dynamicLight->Color = Vector3(r / 255.0f, g / 255.0f, b / 255.0f);
2019-01-16 21:21:14 +01:00
dynamicLight->Out = falloff * 256.0f;
dynamicLight->Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
dynamicLight->Dynamic = 1;
2019-01-16 21:21:14 +01:00
dynamicLight->Intensity = 2.0f;
m_dynamicLights.Add(dynamicLight);
//NumDynamics++;
2019-01-13 21:57:16 +01:00
}
void Renderer11::EnableCinematicBars(bool value)
{
2019-03-20 00:05:00 +01:00
m_enableCinematicBars = value;
2019-01-13 21:57:16 +01:00
}
void Renderer11::FadeIn()
{
m_fadeStatus = RENDERER_FADE_STATUS::FADE_IN;
m_fadeFactor = 0.0f;
2019-01-13 21:57:16 +01:00
}
void Renderer11::FadeOut()
{
m_fadeStatus = RENDERER_FADE_STATUS::FADE_OUT;
m_fadeFactor = 1.0f;
2019-01-13 21:57:16 +01:00
}
void Renderer11::DrawLoadingScreen(char* fileName)
{
return;
Texture2D* texture = Texture2D::LoadFromFile(m_device, fileName);
if (texture == NULL)
return;
m_fadeStatus = RENDERER_FADE_STATUS::FADE_IN;
m_fadeFactor = 0.0f;
while (true)
{
if (m_fadeStatus == RENDERER_FADE_STATUS::FADE_IN && m_fadeFactor < 1.0f)
m_fadeFactor += FADE_FACTOR;
if (m_fadeStatus == RENDERER_FADE_STATUS::FADE_OUT && m_fadeFactor > 0.0f)
m_fadeFactor -= FADE_FACTOR;
// Set basic render states
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
m_context->RSSetState(m_states->CullCounterClockwise());
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
// Clear screen
m_context->ClearRenderTargetView(m_backBufferRTV, Colors::Black);
m_context->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
// Bind the back buffer
m_context->OMSetRenderTargets(1, &m_backBufferRTV, m_depthStencilView);
m_context->RSSetViewports(1, &m_viewport);
// Draw the full screen background
2019-03-20 00:05:00 +01:00
drawFullScreenQuad(texture->ShaderResourceView, Vector3(m_fadeFactor, m_fadeFactor, m_fadeFactor), false);
m_context->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
m_swapChain->Present(0, 0);
if (m_fadeStatus == RENDERER_FADE_STATUS::FADE_IN && m_fadeFactor >= 1.0f)
{
m_fadeStatus = RENDERER_FADE_STATUS::NO_FADE;
m_fadeFactor = 1.0f;
}
if (m_fadeStatus == RENDERER_FADE_STATUS::NO_FADE && m_progress == 100)
{
m_fadeStatus = RENDERER_FADE_STATUS::FADE_OUT;
m_fadeFactor = 1.0f;
}
if (m_fadeStatus == RENDERER_FADE_STATUS::FADE_OUT && m_fadeFactor <= 0.0f)
{
break;
}
}
delete texture;
2019-01-13 21:57:16 +01:00
}
void Renderer11::UpdateProgress(float value)
{
m_progress = value;
2019-01-13 21:57:16 +01:00
}
bool Renderer11::IsFading()
{
return (m_fadeStatus != FADEMODE_NONE);
2019-01-13 21:57:16 +01:00
}
2019-12-02 09:11:21 +01:00
void Renderer11::GetLaraBonePosition(Vector3* pos, int bone)
2019-01-13 21:57:16 +01:00
{
}
bool Renderer11::ToggleFullScreen()
{
return true;
}
bool Renderer11::IsFullsScreen()
{
2019-04-30 20:39:03 +02:00
return (!Windowed);
2019-01-13 21:57:16 +01:00
}
2019-12-02 09:11:21 +01:00
bool Renderer11::ChangeScreenResolution(int width, int height, int frequency, bool windowed)
2019-01-13 21:57:16 +01:00
{
2019-04-30 20:39:03 +02:00
HRESULT res;
/*if (windowed && !Windowed)
2019-04-30 20:39:03 +02:00
{
res = m_swapChain->SetFullscreenState(false, NULL);
if (FAILED(res))
return false;
}
else if (!windowed && Windowed)
{
res = m_swapChain->SetFullscreenState(true, NULL);
if(FAILED(res))
return false;
}
IDXGIOutput* output;
res = m_swapChain->GetContainingOutput(&output);
if(FAILED(res))
return false;
DXGI_SWAP_CHAIN_DESC scd;
res = m_swapChain->GetDesc(&scd);
if (FAILED(res))
return false;
UINT numModes = 1024;
DXGI_MODE_DESC modes[1024];
res = output->GetDisplayModeList(scd.BufferDesc.Format, 0, &numModes, modes);
if (FAILED(res))
return false;
DXGI_MODE_DESC* mode = &modes[0];
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numModes; i++)
2019-04-30 20:39:03 +02:00
{
mode = &modes[i];
if (mode->Width == width && mode->Height == height)
break;
}
ID3D11RenderTargetView* nullViews[] = { nullptr };
m_context->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
m_backBufferRTV->Release(); // Microsoft::WRL::ComPtr here does a Release();
m_depthStencilView->Release();
m_context->Flush();
res = m_swapChain->ResizeBuffers(2, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
2019-04-30 20:39:03 +02:00
res = m_swapChain->ResizeTarget(mode);
if (FAILED(res))
return false;
RECT rect;
GetClientRect(WindowsHandle, &rect);
UINT w = static_cast<UINT>(rect.right);
UINT h = static_cast<UINT>(rect.bottom);
m_context->ClearState();
m_backBufferRTV->Release();
m_depthStencilView->Release();
m_depthStencilTexture->Release();
res = m_swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
if (FAILED(res))
return false;
// Recreate render target
res = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&m_backBufferTexture);
if (FAILED(res))
return false;
m_device->CreateRenderTargetView(m_backBufferTexture, NULL, &m_backBufferRTV);
D3D11_TEXTURE2D_DESC backBufferDesc;
m_backBufferTexture->GetDesc(&backBufferDesc);
m_backBufferTexture->Release();
D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = width;
depthStencilDesc.Height = height;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;
m_depthStencilTexture = NULL;
res = m_device->CreateTexture2D(&depthStencilDesc, NULL, &m_depthStencilTexture);
if (FAILED(res))
return false;
m_depthStencilView = NULL;
res = m_device->CreateDepthStencilView(m_depthStencilTexture, NULL, &m_depthStencilView);
if (FAILED(res))
return false;
DX11_DELETE(m_renderTarget);
DX11_DELETE(m_dumpScreenRenderTarget);
DX11_DELETE(m_shadowMap);
m_renderTarget = RenderTarget2D::Create(m_device, width, height, DXGI_FORMAT_R8G8B8A8_UNORM);
m_dumpScreenRenderTarget = RenderTarget2D::Create(m_device, width, height, DXGI_FORMAT_R8G8B8A8_UNORM);
m_shadowMap = RenderTarget2D::Create(m_device, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, DXGI_FORMAT_R32_FLOAT);
DX11_DELETE(m_gameFont);
DX11_DELETE(m_spriteBatch);
DX11_DELETE(m_primitiveBatch);
m_spriteBatch = new SpriteBatch(m_context);
m_gameFont = new SpriteFont(m_device, L"Font.spritefont");
m_primitiveBatch = new PrimitiveBatch<RendererVertex>(m_context);
ScreenWidth = width;
ScreenHeight = height;
Windowed = windowed;*/
ID3D11RenderTargetView* nullViews[] = { nullptr };
m_context->OMSetRenderTargets(0, nullViews, NULL);
DX11_DELETE(m_renderTarget);
DX11_DELETE(m_dumpScreenRenderTarget);
DX11_DELETE(m_shadowMap);
DX11_DELETE(m_gameFont);
DX11_DELETE(m_spriteBatch);
DX11_DELETE(m_primitiveBatch);
m_backBufferTexture->Release();
m_backBufferRTV->Release();
m_depthStencilView->Release();
m_depthStencilTexture->Release();
m_context->Flush();
m_context->ClearState();
//res = m_swapChain->ResizeBuffers(2, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
/*res = m_swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
if (FAILED(res))
return false;*/
IDXGIOutput* output;
res = m_swapChain->GetContainingOutput(&output);
if (FAILED(res))
return false;
DXGI_SWAP_CHAIN_DESC scd;
res = m_swapChain->GetDesc(&scd);
if (FAILED(res))
return false;
UINT numModes = 1024;
DXGI_MODE_DESC modes[1024];
res = output->GetDisplayModeList(scd.BufferDesc.Format, 0, &numModes, modes);
if (FAILED(res))
return false;
DXGI_MODE_DESC* mode = &modes[0];
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numModes; i++)
{
mode = &modes[i];
if (mode->Width == width && mode->Height == height)
break;
}
res = m_swapChain->ResizeTarget(mode);
if (FAILED(res))
return false;
if (!initialiseScreen(width, height, frequency, windowed, WindowsHandle, true))
return false;
2019-04-30 20:39:03 +02:00
ScreenWidth = width;
ScreenHeight = height;
Windowed = windowed;
2019-01-13 21:57:16 +01:00
return true;
}
2019-12-02 09:11:21 +01:00
ID3D11Buffer* Renderer11::createConstantBuffer(int size)
2019-01-13 21:57:16 +01:00
{
ID3D11Buffer* buffer;
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = ceil(size / 16) * 16; // Constant buffer must have a size multiple of 16 bytes
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
HRESULT res = m_device->CreateBuffer(&desc, NULL, &buffer);
if (FAILED(res))
return NULL;
return buffer;
}
2019-12-02 09:11:21 +01:00
int Renderer11::getAnimatedTextureInfo(short textureId)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_numAnimatedTextureSets; i++)
2019-01-13 21:57:16 +01:00
{
RendererAnimatedTextureSet* set = m_animatedTextureSets[i];
2019-12-02 09:11:21 +01:00
for (int j = 0; j < set->NumTextures; j++)
2019-01-13 21:57:16 +01:00
{
if (set->Textures[j]->Id == textureId)
return i;
}
}
return -1;
}
void Renderer11::initialiseHairRemaps()
{
memset(m_normalLaraSkinJointRemap, -1, 15 * 32 * 2);
memset(m_youngLaraSkinJointRemap, -1, 15 * 32 * 2);
// Normal Lara
m_normalLaraSkinJointRemap[1][0] = 0;
m_normalLaraSkinJointRemap[1][1] = 0;
m_normalLaraSkinJointRemap[1][2] = 0;
m_normalLaraSkinJointRemap[1][3] = 0;
m_normalLaraSkinJointRemap[1][4] = 0;
m_normalLaraSkinJointRemap[1][5] = 0;
m_normalLaraSkinJointRemap[2][0] = 1;
m_normalLaraSkinJointRemap[2][1] = 1;
m_normalLaraSkinJointRemap[2][2] = 1;
m_normalLaraSkinJointRemap[2][3] = 1;
m_normalLaraSkinJointRemap[2][4] = 1;
m_normalLaraSkinJointRemap[3][4] = 2;
m_normalLaraSkinJointRemap[3][5] = 2;
m_normalLaraSkinJointRemap[3][6] = 2;
m_normalLaraSkinJointRemap[3][7] = 2;
m_normalLaraSkinJointRemap[4][0] = 0;
m_normalLaraSkinJointRemap[4][1] = 0;
m_normalLaraSkinJointRemap[4][2] = 0;
m_normalLaraSkinJointRemap[4][3] = 0;
m_normalLaraSkinJointRemap[4][4] = 0;
m_normalLaraSkinJointRemap[4][5] = 0;
m_normalLaraSkinJointRemap[5][0] = 4;
m_normalLaraSkinJointRemap[5][1] = 4;
m_normalLaraSkinJointRemap[5][2] = 4;
m_normalLaraSkinJointRemap[5][3] = 4;
m_normalLaraSkinJointRemap[5][4] = 4;
m_normalLaraSkinJointRemap[6][4] = 5;
m_normalLaraSkinJointRemap[6][5] = 5;
m_normalLaraSkinJointRemap[6][6] = 5;
m_normalLaraSkinJointRemap[6][7] = 5;
m_normalLaraSkinJointRemap[7][0] = 0;
m_normalLaraSkinJointRemap[7][1] = 0;
m_normalLaraSkinJointRemap[7][2] = 0;
m_normalLaraSkinJointRemap[7][3] = 0;
m_normalLaraSkinJointRemap[7][4] = 0;
m_normalLaraSkinJointRemap[7][5] = 0;
m_normalLaraSkinJointRemap[8][6] = 7;
m_normalLaraSkinJointRemap[8][7] = 7;
m_normalLaraSkinJointRemap[8][8] = 7;
m_normalLaraSkinJointRemap[8][9] = 7;
m_normalLaraSkinJointRemap[8][10] = 7;
m_normalLaraSkinJointRemap[8][11] = 7;
m_normalLaraSkinJointRemap[9][5] = 8;
m_normalLaraSkinJointRemap[9][6] = 8;
m_normalLaraSkinJointRemap[9][7] = 8;
m_normalLaraSkinJointRemap[9][8] = 8;
m_normalLaraSkinJointRemap[9][9] = 8;
m_normalLaraSkinJointRemap[10][0] = 9;
m_normalLaraSkinJointRemap[10][1] = 9;
m_normalLaraSkinJointRemap[10][2] = 9;
m_normalLaraSkinJointRemap[10][3] = 9;
m_normalLaraSkinJointRemap[10][4] = 9;
m_normalLaraSkinJointRemap[11][6] = 7;
m_normalLaraSkinJointRemap[11][7] = 7;
m_normalLaraSkinJointRemap[11][8] = 7;
m_normalLaraSkinJointRemap[11][9] = 7;
m_normalLaraSkinJointRemap[11][10] = 7;
m_normalLaraSkinJointRemap[11][11] = 7;
m_normalLaraSkinJointRemap[12][5] = 11;
m_normalLaraSkinJointRemap[12][6] = 11;
m_normalLaraSkinJointRemap[12][7] = 11;
m_normalLaraSkinJointRemap[12][8] = 11;
m_normalLaraSkinJointRemap[12][9] = 11;
m_normalLaraSkinJointRemap[13][0] = 12;
m_normalLaraSkinJointRemap[13][1] = 12;
m_normalLaraSkinJointRemap[13][2] = 12;
m_normalLaraSkinJointRemap[13][3] = 12;
m_normalLaraSkinJointRemap[13][4] = 12;
m_normalLaraSkinJointRemap[14][6] = 7;
m_normalLaraSkinJointRemap[14][7] = 7;
m_normalLaraSkinJointRemap[14][8] = 7;
m_normalLaraSkinJointRemap[14][9] = 7;
m_normalLaraSkinJointRemap[14][10] = 7;
m_normalLaraSkinJointRemap[14][11] = 7;
// Young Lara
m_youngLaraSkinJointRemap[1][0] = 0; // Left up leg
m_youngLaraSkinJointRemap[1][1] = 0;
m_youngLaraSkinJointRemap[1][2] = 0;
m_youngLaraSkinJointRemap[1][3] = 0;
m_youngLaraSkinJointRemap[1][4] = 0;
m_youngLaraSkinJointRemap[1][5] = 0;
m_youngLaraSkinJointRemap[2][0] = 1; // Bottom left leg
m_youngLaraSkinJointRemap[2][1] = 1;
m_youngLaraSkinJointRemap[2][2] = 1;
m_youngLaraSkinJointRemap[2][3] = 1;
m_youngLaraSkinJointRemap[2][4] = 1;
m_youngLaraSkinJointRemap[3][0] = 2; // Left foot
m_youngLaraSkinJointRemap[3][1] = 2;
m_youngLaraSkinJointRemap[3][2] = 2;
m_youngLaraSkinJointRemap[3][3] = 2;
m_youngLaraSkinJointRemap[4][6] = 0; // Right upper leg
m_youngLaraSkinJointRemap[4][7] = 0;
m_youngLaraSkinJointRemap[4][8] = 0;
m_youngLaraSkinJointRemap[4][9] = 0;
m_youngLaraSkinJointRemap[4][10] = 0;
m_youngLaraSkinJointRemap[4][11] = 0;
m_youngLaraSkinJointRemap[5][0] = 4; // Right bottom leg
m_youngLaraSkinJointRemap[5][1] = 4;
m_youngLaraSkinJointRemap[5][2] = 4;
m_youngLaraSkinJointRemap[5][3] = 4;
m_youngLaraSkinJointRemap[5][4] = 4;
m_youngLaraSkinJointRemap[6][0] = 5; // Right foot
m_youngLaraSkinJointRemap[6][1] = 5;
m_youngLaraSkinJointRemap[6][2] = 5;
m_youngLaraSkinJointRemap[6][3] = 5;
m_youngLaraSkinJointRemap[7][0] = 0; // Torso
m_youngLaraSkinJointRemap[7][1] = 0;
m_youngLaraSkinJointRemap[7][2] = 0;
m_youngLaraSkinJointRemap[7][3] = 0;
m_youngLaraSkinJointRemap[7][4] = 0;
m_youngLaraSkinJointRemap[7][5] = 0;
m_youngLaraSkinJointRemap[8][0] = 7; // Left upper arm
m_youngLaraSkinJointRemap[8][1] = 7;
m_youngLaraSkinJointRemap[8][2] = 7;
m_youngLaraSkinJointRemap[8][3] = 7;
m_youngLaraSkinJointRemap[8][4] = 7;
m_youngLaraSkinJointRemap[8][5] = 7;
m_youngLaraSkinJointRemap[9][5] = 8; // Left bottom arm
m_youngLaraSkinJointRemap[9][6] = 8;
m_youngLaraSkinJointRemap[9][7] = 8;
m_youngLaraSkinJointRemap[9][8] = 8;
m_youngLaraSkinJointRemap[9][9] = 8;
m_youngLaraSkinJointRemap[10][0] = 9; // Left hand
m_youngLaraSkinJointRemap[10][1] = 9;
m_youngLaraSkinJointRemap[10][2] = 9;
m_youngLaraSkinJointRemap[10][3] = 9;
m_youngLaraSkinJointRemap[10][4] = 9;
m_youngLaraSkinJointRemap[11][0] = 7; // Right upper arm
m_youngLaraSkinJointRemap[11][1] = 7;
m_youngLaraSkinJointRemap[11][2] = 7;
m_youngLaraSkinJointRemap[11][3] = 7;
m_youngLaraSkinJointRemap[11][4] = 7;
m_youngLaraSkinJointRemap[11][5] = 7;
m_youngLaraSkinJointRemap[12][5] = 11; // Right low arm
m_youngLaraSkinJointRemap[12][6] = 11;
m_youngLaraSkinJointRemap[12][7] = 11;
m_youngLaraSkinJointRemap[12][8] = 11;
m_youngLaraSkinJointRemap[12][9] = 11;
m_youngLaraSkinJointRemap[13][0] = 12; // Right arm
m_youngLaraSkinJointRemap[13][1] = 12;
m_youngLaraSkinJointRemap[13][2] = 12;
m_youngLaraSkinJointRemap[13][3] = 12;
m_youngLaraSkinJointRemap[13][4] = 12;
m_youngLaraSkinJointRemap[14][0] = 7; // Head
m_youngLaraSkinJointRemap[14][1] = 7;
m_youngLaraSkinJointRemap[14][2] = 7;
m_youngLaraSkinJointRemap[14][3] = 7;
m_youngLaraSkinJointRemap[14][4] = 7;
m_youngLaraSkinJointRemap[14][5] = 7;
}
void Renderer11::getVisibleRooms(int from, int to, Vector4* viewPort, bool water, int count)
{
2019-01-16 20:54:45 +01:00
// Avoid allocations, 1024 should be fine
RendererRoomNode nodes[1024];
2019-12-02 09:11:21 +01:00
int nextNode = 0;
2019-01-16 20:54:45 +01:00
// Avoid reallocations, 1024 should be fine
RendererRoomNode* stack[1024];
2019-12-02 09:11:21 +01:00
int stackDepth = 0;
2019-01-13 21:57:16 +01:00
2019-01-16 20:54:45 +01:00
RendererRoomNode* node = &nodes[nextNode++];
2019-01-13 21:57:16 +01:00
node->To = to;
node->From = -1;
2019-01-16 20:54:45 +01:00
// Push
stack[stackDepth++] = node;
2019-01-13 21:57:16 +01:00
2019-01-16 20:54:45 +01:00
while (stackDepth > 0)
{
// Pop
node = stack[--stackDepth];
2019-01-13 21:57:16 +01:00
if (m_rooms[node->To]->Visited)
continue;
2019-01-16 20:54:45 +01:00
ROOM_INFO* room = &Rooms[node->To];
Vector3 roomCentre = Vector3(room->x + room->xSize * WALL_SIZE / 2.0f,
2019-12-11 22:25:26 +01:00
(room->minfloor + room->maxceiling) / 2.0f,
2019-01-16 20:54:45 +01:00
room->z + room->ySize * WALL_SIZE / 2.0f);
Vector3 laraPosition = Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z);
m_rooms[node->To]->Distance = (roomCentre - laraPosition).Length();
2019-01-13 21:57:16 +01:00
m_rooms[node->To]->Visited = true;
m_roomsToDraw.Add(m_rooms[node->To]);
2019-01-13 21:57:16 +01:00
collectLightsForRoom(node->To);
2019-01-13 21:57:16 +01:00
collectItems(node->To);
2019-01-16 20:54:45 +01:00
collectStatics(node->To);
2019-01-13 21:57:16 +01:00
collectEffects(node->To);
2019-01-16 20:54:45 +01:00
2019-01-13 21:57:16 +01:00
Vector4 clipPort;
2019-12-02 09:11:21 +01:00
short numDoors = *(room->door);
2019-01-13 21:57:16 +01:00
if (numDoors)
{
2019-12-02 09:11:21 +01:00
short* door = room->door + 1;
2019-01-13 21:57:16 +01:00
for (int i = 0; i < numDoors; i++) {
2019-12-02 09:11:21 +01:00
short adjoiningRoom = *(door);
2019-01-13 21:57:16 +01:00
if (node->From != adjoiningRoom && checkPortal(node->To, door, viewPort, &node->ClipPort))
{
RendererRoomNode* childNode = &nodes[nextNode++];
2019-01-13 21:57:16 +01:00
childNode->From = node->To;
childNode->To = adjoiningRoom;
2019-01-16 20:54:45 +01:00
// Push
stack[stackDepth++] = childNode;
2019-01-13 21:57:16 +01:00
}
door += 16;
}
}
}
}
2019-12-02 09:11:21 +01:00
bool Renderer11::checkPortal(short roomIndex, short* portal, Vector4* viewPort, Vector4* clipPort)
2019-01-13 21:57:16 +01:00
{
2019-12-11 22:25:26 +01:00
//return true;
2019-01-13 21:57:16 +01:00
ROOM_INFO* room = &Rooms[roomIndex];
Vector3 n = Vector3(*(portal + 1), *(portal + 2), *(portal + 3));
Vector3 v = Vector3(Camera.pos.x - (room->x + *(portal + 4)),
Camera.pos.y - (room->y + *(portal + 5)),
Camera.pos.z - (room->z + *(portal + 6)));
if (n.Dot(v) <= 0.0f)
return false;
int zClip = 0;
Vector4 p[4];
clipPort->x = FLT_MAX;
clipPort->y = FLT_MAX;
clipPort->z = FLT_MIN;
clipPort->w = FLT_MIN;
for (int i = 0; i < 4; i++) {
2019-01-16 20:54:45 +01:00
Vector4 tmp = Vector4(*(portal + 4 + 3 * i) + room->x, *(portal + 4 + 3 * i + 1) + room->y,
2019-01-13 21:57:16 +01:00
*(portal + 4 + 3 * i + 2) + room->z, 1.0f);
Vector4::Transform(tmp, ViewProjection, p[i]);
if (p[i].w > 0.0f) {
p[i].x *= (1.0f / p[i].w);
p[i].y *= (1.0f / p[i].w);
p[i].z *= (1.0f / p[i].w);
clipPort->x = min(clipPort->x, p[i].x);
clipPort->y = min(clipPort->y, p[i].y);
clipPort->z = max(clipPort->z, p[i].x);
clipPort->w = max(clipPort->w, p[i].y);
}
else
zClip++;
}
if (zClip == 4)
return false;
if (zClip > 0) {
for (int i = 0; i < 4; i++) {
2019-01-16 20:54:45 +01:00
Vector4 a = p[i];
Vector4 b = p[(i + 1) % 4];
2019-01-13 21:57:16 +01:00
if ((a.w > 0.0f) ^ (b.w > 0.0f)) {
if (a.x < 0.0f && b.x < 0.0f)
clipPort->x = -1.0f;
else
if (a.x > 0.0f && b.x > 0.0f)
clipPort->z = 1.0f;
else {
clipPort->x = -1.0f;
clipPort->z = 1.0f;
}
if (a.y < 0.0f && b.y < 0.0f)
clipPort->y = -1.0f;
else
if (a.y > 0.0f && b.y > 0.0f)
clipPort->w = 1.0f;
else {
clipPort->y = -1.0f;
clipPort->w = 1.0f;
}
}
}
}
if (clipPort->x > viewPort->z || clipPort->y > viewPort->w || clipPort->z < viewPort->x || clipPort->w < viewPort->y)
return false;
clipPort->x = max(clipPort->x, viewPort->x);
clipPort->y = max(clipPort->y, viewPort->y);
clipPort->z = min(clipPort->z, viewPort->z);
clipPort->w = min(clipPort->w, viewPort->w);
return true;
}
void Renderer11::collectRooms()
{
2019-12-02 09:11:21 +01:00
short baseRoomIndex = Camera.pos.roomNumber;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NumberRooms; i++)
{
m_rooms[i]->Visited = false;
m_rooms[i]->LightsToDraw.Clear();
}
2019-01-13 21:57:16 +01:00
Vector4 vp = Vector4(-1.0f, -1.0f, 1.0f, 1.0f);
getVisibleRooms(-1, baseRoomIndex, &vp, false, 0);
}
2019-12-02 09:11:21 +01:00
inline void Renderer11::collectItems(short roomNumber)
2019-01-13 21:57:16 +01:00
{
RendererRoom* room = m_rooms[roomNumber];
if (room == NULL)
return;
ROOM_INFO* r = room->Room;
2019-12-02 09:11:21 +01:00
short itemNum = NO_ITEM;
2019-01-13 21:57:16 +01:00
for (itemNum = r->itemNumber; itemNum != NO_ITEM; itemNum = Items[itemNum].nextItem)
{
//printf("ItemNum: %d, NextItem: %d\n", itemNum, Items[itemNum].nextItem);
2019-01-13 21:57:16 +01:00
ITEM_INFO* item = &Items[itemNum];
if (item->objectNumber == ID_LARA && itemNum == Items[itemNum].nextItem)
break;
if (item->objectNumber == ID_LARA)
continue;
if (item->status == ITEM_INVISIBLE)
2019-01-13 21:57:16 +01:00
continue;
if (m_moveableObjects[item->objectNumber] == NULL)
2019-01-16 20:54:45 +01:00
continue;
RendererItem* newItem = &m_items[itemNum];
newItem->Item = item;
newItem->Id = itemNum;
newItem->NumMeshes = Objects[item->objectNumber].nmeshes;
newItem->World = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(item->pos.yRot),
TR_ANGLE_TO_RAD(item->pos.xRot),
TR_ANGLE_TO_RAD(item->pos.zRot)) *
2019-01-16 20:54:45 +01:00
Matrix::CreateTranslation(item->pos.xPos, item->pos.yPos, item->pos.zPos);
2019-01-13 21:57:16 +01:00
collectLightsForItem(item->roomNumber, newItem);
m_itemsToDraw.Add(newItem);
2019-01-13 21:57:16 +01:00
}
}
2019-12-02 09:11:21 +01:00
inline void Renderer11::collectStatics(short roomNumber)
2019-01-16 20:54:45 +01:00
{
RendererRoom* room = m_rooms[roomNumber];
if (room == NULL)
return;
ROOM_INFO* r = room->Room;
if (r->numMeshes <= 0)
return;
MESH_INFO* mesh = r->mesh;
2019-12-02 09:11:21 +01:00
int numStatics = room->Statics.size();
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numStatics; i++)
2019-01-16 20:54:45 +01:00
{
RendererStatic* newStatic = &room->Statics[i];
newStatic->Mesh = mesh;
newStatic->RoomIndex = roomNumber;
newStatic->World = Matrix::CreateRotationY(TR_ANGLE_TO_RAD(mesh->yRot)) * Matrix::CreateTranslation(mesh->x, mesh->y, mesh->z);
m_staticsToDraw.Add(newStatic);
2019-01-16 20:54:45 +01:00
mesh++;
}
}
2019-12-02 09:11:21 +01:00
inline void Renderer11::collectLightsForEffect(short roomNumber, RendererEffect* effect)
{
effect->Lights.Clear();
RendererRoom* room = m_rooms[roomNumber];
if (room == NULL)
return;
ROOM_INFO * r = room->Room;
if (r->numLights <= 0)
return;
m_tempItemLights.Clear();
Vector3 itemPosition = Vector3(effect->Effect->pos.xPos, effect->Effect->pos.yPos, effect->Effect->pos.zPos);
// Dynamic lights have the priority
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_dynamicLights.Size(); i++)
{
RendererLight* light = m_dynamicLights[i];
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
if (distance > light->Out)
continue;
m_tempItemLights.Add(light);
}
2019-12-02 09:11:21 +01:00
int numLights = room->Lights.size();
m_shadowLight = NULL;
RendererLight* brightestLight = NULL;
float brightest = 0.0f;
2019-12-02 09:11:21 +01:00
for (int j = 0; j < numLights; j++)
{
RendererLight* light = &room->Lights[j];
// Check only lights different from sun
if (light->Type == LIGHT_TYPE_SUN)
{
// Sun is added without checks
}
else if (light->Type == LIGHT_TYPE_POINT || light->Type == LIGHT_TYPE_SHADOW)
{
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
// Collect only lights nearer than 20 sectors
if (distance >= 20 * WALL_SIZE)
continue;
// Check the out radius
if (distance > light->Out)
continue;
// If Lara, try to collect shadow casting light
if (effect->Effect->objectNumber == ID_LARA)
{
float attenuation = 1.0f - distance / light->Out;
float intensity = max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
}
}
else if (light->Type == LIGHT_TYPE_SPOT)
{
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
// Collect only lights nearer than 20 sectors
if (distance >= 20 * WALL_SIZE)
continue;
// Check the range
if (distance > light->Range)
continue;
}
else
{
// Invalid light type
continue;
}
m_tempItemLights.Add(light);
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < min(MAX_LIGHTS_PER_ITEM, m_tempItemLights.Size()); i++)
{
effect->Lights.Add(m_tempItemLights[i]);
}
}
2019-12-02 09:11:21 +01:00
inline void Renderer11::collectLightsForItem(short roomNumber, RendererItem* item)
2019-01-16 20:54:45 +01:00
{
item->Lights.Clear();
2019-01-16 20:54:45 +01:00
RendererRoom* room = m_rooms[roomNumber];
if (room == NULL)
return;
ROOM_INFO* r = room->Room;
if (r->numLights <= 0)
return;
m_tempItemLights.Clear();
Vector3 itemPosition = Vector3(item->Item->pos.xPos, item->Item->pos.yPos, item->Item->pos.zPos);
// Dynamic lights have the priority
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_dynamicLights.Size(); i++)
2019-01-16 20:54:45 +01:00
{
RendererLight* light = m_dynamicLights[i];
2019-01-16 20:54:45 +01:00
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
if (distance > light->Out)
2019-01-16 20:54:45 +01:00
continue;
m_tempItemLights.Add(light);
}
2019-12-02 09:11:21 +01:00
int numLights = room->Lights.size();
m_shadowLight = NULL;
RendererLight* brightestLight = NULL;
float brightest = 0.0f;
2019-12-02 09:11:21 +01:00
for (int j = 0; j < numLights; j++)
{
RendererLight* light = &room->Lights[j];
2019-01-16 20:54:45 +01:00
// Check only lights different from sun
if (light->Type == LIGHT_TYPE_SUN)
2019-01-16 20:54:45 +01:00
{
// Sun is added without checks
}
else if (light->Type == LIGHT_TYPE_POINT || light->Type == LIGHT_TYPE_SHADOW)
{
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
2019-01-16 20:54:45 +01:00
float distance = (itemPosition - lightPosition).Length();
2019-01-16 20:54:45 +01:00
// Collect only lights nearer than 20 sectors
if (distance >= 20 * WALL_SIZE)
2019-01-16 20:54:45 +01:00
continue;
// Check the out radius
if (distance > light->Out)
continue;
// If Lara, try to collect shadow casting light
if (item->Item->objectNumber == ID_LARA)
{
float attenuation = 1.0f - distance / light->Out;
float intensity = max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
}
}
else if (light->Type == LIGHT_TYPE_SPOT)
{
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
// Collect only lights nearer than 20 sectors
if (distance >= 20 * WALL_SIZE)
continue;
// Check the range
if (distance > light->Range)
continue;
// If Lara, try to collect shadow casting light
if (item->Item->objectNumber == ID_LARA)
{
float attenuation = 1.0f - distance / light->Range;
float intensity = max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
}
}
else
{
// Invalid light type
continue;
}
m_tempItemLights.Add(light);
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < min(MAX_LIGHTS_PER_ITEM, m_tempItemLights.Size()); i++)
{
item->Lights.Add(m_tempItemLights[i]);
2019-01-16 20:54:45 +01:00
}
if (item->Item->objectNumber == ID_LARA)
{
m_shadowLight = brightestLight;
}
}
2019-12-02 09:11:21 +01:00
inline void Renderer11::collectLightsForRoom(short roomNumber)
{
RendererRoom* room = m_rooms[roomNumber];
if (room == NULL)
return;
ROOM_INFO* r = room->Room;
if (r->numLights <= 0)
return;
2019-12-02 09:11:21 +01:00
int numLights = room->Lights.size();
// Collect dynamic lights for rooms
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_dynamicLights.Size(); i++)
{
RendererLight* light = m_dynamicLights[i];
float left = r->x + WALL_SIZE;
float bottom = r->z + WALL_SIZE;
float right = r->x + (r->xSize - 1) * WALL_SIZE;
float top = r->z + (r->ySize - 1) * WALL_SIZE;
float closestX = light->Position.x;
if (closestX < left)
closestX = left;
else if (closestX > right)
closestX = right;
float closestZ = light->Position.z;
if (closestZ < bottom)
closestZ = bottom;
else if (closestZ > top)
closestZ = top;
// Calculate the distance between the circle's center and this closest point
float distanceX = light->Position.x - closestX;
float distanceY = light->Position.z - closestZ;
// If the distance is less than the circle's radius, an intersection occurs
float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY);
if (distanceSquared < SQUARE(light->Out))
room->LightsToDraw.Add(light);
}
}
bool Renderer11::sphereBoxIntersection(Vector3 boxMin, Vector3 boxMax, Vector3 sphereCentre, float sphereRadius)
{
//Vector3 closestPointInAabb = Vector3::Min(Vector3::Max(sphereCentre, boxMin), boxMax);
//double distanceSquared = (closestPointInAabb - sphereCentre).LengthSquared();
//return (distanceSquared < (sphereRadius * sphereRadius));
/*float x = max(boxMin.x, min(sphereCentre.x, boxMax.x));
float y = max(boxMin.y, min(sphereCentre.y, boxMax.y));
float z = max(boxMin.z, min(sphereCentre.z, boxMax.z));
float distance = sqrt((x - sphereCentre.x) * (x - sphereCentre.x) +
(y - sphereCentre.y) * (y - sphereCentre.y) +
(z - sphereCentre.z) * (z - sphereCentre.z));
return (distance < sphereRadius);*/
return 0;
2019-01-16 20:54:45 +01:00
}
void Renderer11::prepareLights()
{
// Add dynamic lights
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_dynamicLights.Size(); i++)
m_lightsToDraw.Add(m_dynamicLights[i]);
2019-01-16 20:54:45 +01:00
// Now I have a list full of draw. Let's sort them.
//std::sort(m_lightsToDraw.begin(), m_lightsToDraw.end(), SortLightsFunction);
//m_lightsToDraw.Sort(SortLightsFunction);
2019-01-16 20:54:45 +01:00
// Let's draw first 32 lights
//if (m_lightsToDraw.size() > 32)
// m_lightsToDraw.resize(32);
2019-01-16 20:54:45 +01:00
// Now try to search for a shadow caster, using Lara as reference
RendererRoom* room = m_rooms[LaraItem->roomNumber];
// Search for the brightest light. We do a simple version of the classic calculation done in pixel shader.
RendererLight* brightestLight = NULL;
float brightest = 0.0f;
// Try room lights
if (room->Lights.size() != 0)
{
2019-12-02 09:11:21 +01:00
for (int j = 0; j < room->Lights.size(); j++)
2019-01-16 20:54:45 +01:00
{
RendererLight* light = &room->Lights[j];
Vector4 itemPos = Vector4(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos, 1.0f);
Vector4 lightVector = itemPos - light->Position;
float distance = lightVector.Length();
lightVector.Normalize();
float intensity;
float attenuation;
float angle;
float d;
float attenuationRange;
float attenuationAngle;
switch ((int)light->Type)
2019-01-16 20:54:45 +01:00
{
case LIGHT_TYPES::LIGHT_TYPE_POINT:
if (distance > light->Out || light->Out < 2048.0f)
continue;
attenuation = 1.0f - distance / light->Out;
intensity = max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
break;
case LIGHT_TYPES::LIGHT_TYPE_SPOT:
if (distance > light->Range)
continue;
attenuation = 1.0f - distance / light->Range;
intensity = max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
break;
}
}
}
// If the brightest light is found, then fill the data structure. We ignore for now dynamic lights for shadows.
m_shadowLight = brightestLight;
}
2019-12-02 09:11:21 +01:00
inline void Renderer11::collectEffects(short roomNumber)
2019-01-13 21:57:16 +01:00
{
RendererRoom* room = m_rooms[roomNumber];
if (room == NULL)
return;
ROOM_INFO* r = room->Room;
2019-12-02 09:11:21 +01:00
short fxNum = NO_ITEM;
2019-01-13 21:57:16 +01:00
for (fxNum = r->fxNumber; fxNum != NO_ITEM; fxNum = Effects[fxNum].nextFx)
{
FX_INFO* fx = &Effects[fxNum];
2019-01-13 21:57:16 +01:00
if (fx->objectNumber < 0)
continue;
OBJECT_INFO* obj = &Objects[fx->objectNumber];
2019-01-16 20:54:45 +01:00
RendererEffect* newEffect = &m_effects[fxNum];
newEffect->Effect = fx;
newEffect->Id = fxNum;
newEffect->World = Matrix::CreateTranslation(fx->pos.xPos, fx->pos.yPos, fx->pos.zPos);
newEffect->Mesh = m_meshPointersToMesh[reinterpret_cast<unsigned int>(Meshes[0 (obj->nmeshes ? obj->meshIndex : fx->frameNumber * 2)])];
collectLightsForEffect(fx->roomNumber, newEffect);
2019-01-16 20:54:45 +01:00
m_effectsToDraw.Add(newEffect);
short* mp = Meshes[(obj->nmeshes ? obj->meshIndex : fx->frameNumber)];
short hhh = 0;
2019-01-13 21:57:16 +01:00
}
}
2019-12-02 09:11:21 +01:00
RendererMesh* Renderer11::getRendererMeshFromTrMesh(RendererObject* obj, short* meshPtr, short* refMeshPtr,
short boneIndex, int isJoints, int isHairs)
2019-01-13 21:57:16 +01:00
{
RendererMesh* mesh = new RendererMesh();
2019-12-02 09:11:21 +01:00
short* basePtr = meshPtr;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
short cx = *meshPtr++;
short cy = *meshPtr++;
short cz = *meshPtr++;
short r1 = *meshPtr++;
short r2 = *meshPtr++;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
short numVertices = *meshPtr++;
2019-01-13 21:57:16 +01:00
VECTOR* vertices = (VECTOR*)malloc(sizeof(VECTOR) * numVertices);
2019-12-02 09:11:21 +01:00
for (int v = 0; v < numVertices; v++)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
short x = *meshPtr++;
short y = *meshPtr++;
short z = *meshPtr++;
2019-01-13 21:57:16 +01:00
vertices[v].vx = x;
vertices[v].vy = y;
vertices[v].vz = z;
mesh->Positions.push_back(Vector3(x, y, z));
}
2019-12-02 09:11:21 +01:00
short numNormals = *meshPtr++;
2019-01-13 21:57:16 +01:00
VECTOR* normals = NULL;
2019-12-02 09:11:21 +01:00
short* colors = NULL;
2019-01-13 21:57:16 +01:00
if (numNormals > 0)
{
normals = (VECTOR*)malloc(sizeof(VECTOR) * numNormals);
2019-12-02 09:11:21 +01:00
for (int v = 0; v < numNormals; v++)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
short x = *meshPtr++;
short y = *meshPtr++;
short z = *meshPtr++;
2019-01-13 21:57:16 +01:00
normals[v].vx = x;
normals[v].vy = y;
normals[v].vz = z;
}
}
else
{
2019-12-02 09:11:21 +01:00
short numLights = -numNormals;
colors = (short*)malloc(sizeof(short) * numLights);
for (int v = 0; v < numLights; v++)
{
colors[v] = *meshPtr++;
}
}
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
short numRectangles = *meshPtr++;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
for (int r = 0; r < numRectangles; r++)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
short v1 = *meshPtr++;
short v2 = *meshPtr++;
short v3 = *meshPtr++;
short v4 = *meshPtr++;
short textureId = *meshPtr++;
short effects = *meshPtr++;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
short indices[4] = { v1,v2,v3,v4 };
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
short textureIndex = textureId & 0x7FFF;
2019-01-13 21:57:16 +01:00
bool doubleSided = (textureId & 0x8000) >> 15;
// Get the object texture
OBJECT_TEXTURE* texture = &ObjectTextures[textureIndex];
2019-12-02 09:11:21 +01:00
int tile = texture->tileAndFlag & 0x7FFF;
2019-01-13 21:57:16 +01:00
// Create vertices
RendererBucket* bucket;
2019-12-02 09:11:21 +01:00
int bucketIndex = RENDERER_BUCKET_SOLID;
2019-01-13 21:57:16 +01:00
if (!doubleSided)
{
if (texture->attribute == 2 || (effects & 1))
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
else
2019-01-13 21:57:16 +01:00
bucketIndex = RENDERER_BUCKET_SOLID;
}
else
{
if (texture->attribute == 2 || (effects & 1))
bucketIndex = RENDERER_BUCKET_TRANSPARENT_DS;
else
bucketIndex = RENDERER_BUCKET_SOLID_DS;
}
// ColAddHorizon special handling
if (obj != NULL && obj->Id == ID_HORIZON && g_GameFlow->GetLevel(CurrentLevel)->ColAddHorizon)
2019-01-13 21:57:16 +01:00
{
if (texture->attribute == 2 || (effects & 1))
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
else
bucketIndex = RENDERER_BUCKET_SOLID;
}
bucket = &mesh->Buckets[bucketIndex];
if (obj != NULL) obj->HasDataInBucket[bucketIndex] = true;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
int baseVertices = bucket->NumVertices;
for (int v = 0; v < 4; v++)
2019-01-13 21:57:16 +01:00
{
RendererVertex vertex;
vertex.Position.x = vertices[indices[v]].vx;
vertex.Position.y = vertices[indices[v]].vy;
vertex.Position.z = vertices[indices[v]].vz;
if (numNormals > 0)
{
vertex.Normal.x = normals[indices[v]].vx / 16300.0f;
vertex.Normal.y = normals[indices[v]].vy / 16300.0f;
vertex.Normal.z = normals[indices[v]].vz / 16300.0f;
}
vertex.UV.x = (texture->vertices[v].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.UV.y = (texture->vertices[v].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.Bone = boneIndex;
if (isJoints && boneIndex != 0 && m_laraSkinJointRemap[boneIndex][indices[v]] != -1)
vertex.Bone = m_laraSkinJointRemap[boneIndex][indices[v]];
if (isHairs)
vertex.Bone = indices[v];
if (colors == NULL)
{
vertex.Color = Vector4::One * 0.5f;
}
else
{
2019-12-02 09:11:21 +01:00
short shade = colors[indices[v]];
shade = (255 - shade * 255 / 8191) & 0xFF;
vertex.Color = Vector4(shade / 255.0f, shade / 255.0f, shade / 255.0f, 1.0f);
}
2019-01-13 21:57:16 +01:00
bucket->NumVertices++;
bucket->Vertices.push_back(vertex);
}
bucket->Indices.push_back(baseVertices);
bucket->Indices.push_back(baseVertices + 1);
bucket->Indices.push_back(baseVertices + 3);
bucket->Indices.push_back(baseVertices + 2);
bucket->Indices.push_back(baseVertices + 3);
bucket->Indices.push_back(baseVertices + 1);
bucket->NumIndices += 6;
RendererPolygon newPolygon;
newPolygon.Shape = SHAPE_RECTANGLE;
newPolygon.TextureId = textureId;
2019-01-13 21:57:16 +01:00
newPolygon.Indices[0] = baseVertices;
newPolygon.Indices[1] = baseVertices + 1;
newPolygon.Indices[2] = baseVertices + 2;
newPolygon.Indices[3] = baseVertices + 3;
bucket->Polygons.push_back(newPolygon);
}
2019-12-02 09:11:21 +01:00
short numTriangles = *meshPtr++;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
for (int r = 0; r < numTriangles; r++)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
short v1 = *meshPtr++;
short v2 = *meshPtr++;
short v3 = *meshPtr++;
short textureId = *meshPtr++;
short effects = *meshPtr++;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
short indices[3] = { v1,v2,v3 };
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
short textureIndex = textureId & 0x7FFF;
2019-01-13 21:57:16 +01:00
bool doubleSided = (textureId & 0x8000) >> 15;
// Get the object texture
OBJECT_TEXTURE* texture = &ObjectTextures[textureIndex];
2019-12-02 09:11:21 +01:00
int tile = texture->tileAndFlag & 0x7FFF;
2019-01-13 21:57:16 +01:00
// Create vertices
RendererBucket* bucket;
2019-12-02 09:11:21 +01:00
int bucketIndex = RENDERER_BUCKET_SOLID;
2019-01-13 21:57:16 +01:00
if (!doubleSided)
{
if (texture->attribute == 2 || (effects & 1))
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
else
bucketIndex = RENDERER_BUCKET_SOLID;
}
else
{
if (texture->attribute == 2 || (effects & 1))
bucketIndex = RENDERER_BUCKET_TRANSPARENT_DS;
else
bucketIndex = RENDERER_BUCKET_SOLID_DS;
}
bucket = &mesh->Buckets[bucketIndex];
if (obj != NULL) obj->HasDataInBucket[bucketIndex] = true;
2019-01-13 21:57:16 +01:00
2019-12-02 09:11:21 +01:00
int baseVertices = bucket->NumVertices;
for (int v = 0; v < 3; v++)
2019-01-13 21:57:16 +01:00
{
RendererVertex vertex;
vertex.Position.x = vertices[indices[v]].vx;
vertex.Position.y = vertices[indices[v]].vy;
vertex.Position.z = vertices[indices[v]].vz;
if (numNormals > 0)
{
vertex.Normal.x = normals[indices[v]].vx / 16300.0f;
vertex.Normal.y = normals[indices[v]].vy / 16300.0f;
vertex.Normal.z = normals[indices[v]].vz / 16300.0f;
}
vertex.UV.x = (texture->vertices[v].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.UV.y = (texture->vertices[v].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.Bone = boneIndex;
if (isJoints && boneIndex != 0 && m_laraSkinJointRemap[boneIndex][indices[v]] != -1)
vertex.Bone = m_laraSkinJointRemap[boneIndex][indices[v]];
if (isHairs)
vertex.Bone = indices[v];
if (colors == NULL)
{
vertex.Color = Vector4::One * 0.5f;
}
else
{
2019-12-02 09:11:21 +01:00
short shade = colors[indices[v]];
shade = (255 - shade * 255 / 8191) & 0xFF;
vertex.Color = Vector4(shade / 255.0f, shade / 255.0f, shade / 255.0f, 1.0f);
}
2019-01-13 21:57:16 +01:00
bucket->NumVertices++;
bucket->Vertices.push_back(vertex);
}
bucket->Indices.push_back(baseVertices);
bucket->Indices.push_back(baseVertices + 1);
bucket->Indices.push_back(baseVertices + 2);
bucket->NumIndices += 3;
RendererPolygon newPolygon;
newPolygon.Shape = SHAPE_TRIANGLE;
newPolygon.TextureId = textureId;
2019-01-13 21:57:16 +01:00
newPolygon.Indices[0] = baseVertices;
newPolygon.Indices[1] = baseVertices + 1;
newPolygon.Indices[2] = baseVertices + 2;
bucket->Polygons.push_back(newPolygon);
}
free(vertices);
if (normals != NULL) free(normals);
if (colors != NULL) free(colors);
2019-01-13 21:57:16 +01:00
unsigned int castedMeshPtr = reinterpret_cast<unsigned int>(refMeshPtr);
if (m_meshPointersToMesh.find(castedMeshPtr) == m_meshPointersToMesh.end())
m_meshPointersToMesh.insert(pair<unsigned int, RendererMesh*>(castedMeshPtr, mesh));
m_meshes.push_back(mesh);
2019-01-13 21:57:16 +01:00
return mesh;
}
void Renderer11::buildHierarchyRecursive(RendererObject* obj, RendererBone* node, RendererBone* parentNode)
{
node->GlobalTransform = node->Transform * parentNode->GlobalTransform;
obj->BindPoseTransforms[node->Index] = node->GlobalTransform;
obj->Skeleton->GlobalTranslation = Vector3(0.0f, 0.0f, 0.0f);
node->GlobalTranslation = node->Translation + parentNode->GlobalTranslation;
for (int j = 0; j < node->Children.size(); j++)
{
buildHierarchyRecursive(obj, node->Children[j], node);
}
}
void Renderer11::buildHierarchy(RendererObject* obj)
{
obj->Skeleton->GlobalTransform = obj->Skeleton->Transform;
obj->BindPoseTransforms[obj->Skeleton->Index] = obj->Skeleton->GlobalTransform;
obj->Skeleton->GlobalTranslation = Vector3(0.0f, 0.0f, 0.0f);
for (int j = 0; j < obj->Skeleton->Children.size(); j++)
{
buildHierarchyRecursive(obj, obj->Skeleton->Children[j], obj->Skeleton);
}
}
2019-12-02 09:11:21 +01:00
void Renderer11::fromTrAngle(Matrix* matrix, short* frameptr, int index)
2019-01-13 21:57:16 +01:00
{
2019-12-02 09:11:21 +01:00
short* ptr = &frameptr[0];
2019-01-13 21:57:16 +01:00
ptr += 9;
for (int i = 0; i < index; i++)
{
ptr += ((*ptr & 0xc000) == 0 ? 2 : 1);
}
int rot0 = *ptr++;
int frameMode = (rot0 & 0xc000);
int rot1;
int rotX;
int rotY;
int rotZ;
switch (frameMode)
{
case 0:
rot1 = *ptr++;
rotX = ((rot0 & 0x3ff0) >> 4);
rotY = (((rot1 & 0xfc00) >> 10) | ((rot0 & 0xf) << 6) & 0x3ff);
rotZ = ((rot1) & 0x3ff);
*matrix = Matrix::CreateFromYawPitchRoll(rotY* (360.0f / 1024.0f) * RADIAN,
rotX* (360.0f / 1024.0f) * RADIAN,
rotZ* (360.0f / 1024.0f) * RADIAN);
break;
case 0x4000:
*matrix = Matrix::CreateRotationX((rot0 & 0xfff)* (360.0f / 4096.0f) * RADIAN);
break;
case 0x8000:
*matrix = Matrix::CreateRotationY((rot0 & 0xfff)* (360.0f / 4096.0f) * RADIAN);
break;
case 0xc000:
*matrix = Matrix::CreateRotationZ((rot0 & 0xfff)* (360.0f / 4096.0f) * RADIAN);
break;
}
}
2019-01-16 20:54:45 +01:00
2019-12-02 09:11:21 +01:00
bool Renderer11::updateConstantBuffer(ID3D11Buffer* buffer, void* data, int size)
2019-01-16 20:54:45 +01:00
{
HRESULT res;
D3D11_MAPPED_SUBRESOURCE mappedResource;
// Lock the constant buffer so it can be written to.
res = m_context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(res))
return false;
// Get a pointer to the data in the constant buffer.
char* dataPtr = reinterpret_cast<char*>(mappedResource.pData);
memcpy(dataPtr, data, size);
// Unlock the constant buffer.
m_context->Unmap(buffer, 0);
return true;
}
void Renderer11::updateItemsAnimations()
{
Matrix translation;
Matrix rotation;
2019-12-02 09:11:21 +01:00
int numItems = m_itemsToDraw.Size();
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numItems; i++)
{
RendererItem* itemToDraw = m_itemsToDraw[i];
ITEM_INFO* item = itemToDraw->Item;
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
// Lara has her own routine
if (item->objectNumber == ID_LARA)
continue;
OBJECT_INFO* obj = &Objects[item->objectNumber];
RendererObject* moveableObj = m_moveableObjects[item->objectNumber];
// Update animation matrices
if (obj->animIndex != -1 /*&& item->objectNumber != ID_HARPOON*/)
{
// Apply extra rotations
2019-12-02 09:11:21 +01:00
int lastJoint = 0;
for (int j = 0; j < moveableObj->LinearizedBones.size(); j++)
{
RendererBone* currentBone = moveableObj->LinearizedBones[j];
currentBone->ExtraRotation = Vector3(0.0f, 0.0f, 0.0f);
if (creature)
{
if (currentBone->ExtraRotationFlags & ROT_Y)
{
currentBone->ExtraRotation.y = TR_ANGLE_TO_RAD(creature->jointRotation[lastJoint]);
lastJoint++;
}
if (currentBone->ExtraRotationFlags & ROT_X)
{
currentBone->ExtraRotation.x = TR_ANGLE_TO_RAD(creature->jointRotation[lastJoint]);
lastJoint++;
}
if (currentBone->ExtraRotationFlags & ROT_Z)
{
currentBone->ExtraRotation.z = TR_ANGLE_TO_RAD(creature->jointRotation[lastJoint]);
lastJoint++;
}
}
}
2019-12-02 09:11:21 +01:00
short *framePtr[2];
int rate;
int frac = GetFrame_D2(item, framePtr, &rate);
updateAnimation(itemToDraw, moveableObj, framePtr, frac, rate, 0xFFFFFFFF);
2019-12-02 09:11:21 +01:00
for (int m = 0; m < itemToDraw->NumMeshes; m++)
itemToDraw->AnimationTransforms[m] = itemToDraw->AnimationTransforms[m].Transpose();
}
// Update world matrix
//translation = Matrix::CreateTranslation(item->pos.xPos, item->pos.yPos, item->pos.zPos);
//rotation = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(item->pos.yRot), TR_ANGLE_TO_RAD(item->pos.xRot), TR_ANGLE_TO_RAD(item->pos.zRot));
//itemToDraw->World = rotation * translation;
int test = 0;
}
}
void Renderer11::updateLaraAnimations()
{
Matrix translation;
Matrix rotation;
Matrix lastMatrix;
Matrix hairMatrix;
Matrix identity;
Matrix world;
RendererObject* laraObj = m_moveableObjects[ID_LARA];
// Clear extra rotations
2019-12-02 09:11:21 +01:00
for (int i = 0; i < laraObj->LinearizedBones.size(); i++)
laraObj->LinearizedBones[i]->ExtraRotation = Vector3(0.0f, 0.0f, 0.0f);
// Lara world matrix
translation = Matrix::CreateTranslation(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos);
rotation = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(LaraItem->pos.yRot), TR_ANGLE_TO_RAD(LaraItem->pos.xRot), TR_ANGLE_TO_RAD(LaraItem->pos.zRot));
m_LaraWorldMatrix = rotation * translation;
// Update first Lara's animations
laraObj->LinearizedBones[LM_TORSO]->ExtraRotation = Vector3(TR_ANGLE_TO_RAD(Lara.torsoXrot), TR_ANGLE_TO_RAD(Lara.torsoYrot), TR_ANGLE_TO_RAD(Lara.torsoZrot));
laraObj->LinearizedBones[LM_HEAD]->ExtraRotation = Vector3(TR_ANGLE_TO_RAD(Lara.headXrot), TR_ANGLE_TO_RAD(Lara.headYrot), TR_ANGLE_TO_RAD(Lara.headZrot));
// First calculate matrices for legs, hips, head and torso
int mask = MESH_BITS(LM_HIPS) | MESH_BITS(LM_LTHIGH) | MESH_BITS(LM_LSHIN) | MESH_BITS(LM_LFOOT) | MESH_BITS(LM_RTHIGH) | MESH_BITS(LM_RSHIN) | MESH_BITS(LM_RFOOT) | MESH_BITS(LM_TORSO) | MESH_BITS(LM_HEAD);
2019-12-15 16:19:01 +01:00
short *framePtr[2];
int rate, frac;
frac = GetFrame_D2(LaraItem, framePtr, &rate);
updateAnimation(NULL, laraObj, framePtr, frac, rate, mask);
// Then the arms, based on current weapon status
if (Lara.gunStatus == LG_NO_ARMS || Lara.gunStatus == LG_HANDS_BUSY && Lara.gunType != WEAPON_FLARE)
{
// Both arms
mask = MESH_BITS(LM_LINARM) | MESH_BITS(LM_LOUTARM) | MESH_BITS(LM_LHAND) | MESH_BITS(LM_RINARM) | MESH_BITS(LM_ROUTARM) | MESH_BITS(LM_RHAND);
frac = GetFrame_D2(LaraItem, framePtr, &rate);
updateAnimation(NULL, laraObj, framePtr, frac, rate, mask);
}
else
{
// While handling weapon some extra rotation could be applied to arms
laraObj->LinearizedBones[LM_LINARM]->ExtraRotation += Vector3(TR_ANGLE_TO_RAD(Lara.leftArm.xRot), TR_ANGLE_TO_RAD(0), TR_ANGLE_TO_RAD(-Lara.leftArm.yRot));
laraObj->LinearizedBones[LM_RINARM]->ExtraRotation += Vector3(TR_ANGLE_TO_RAD(Lara.rightArm.xRot), TR_ANGLE_TO_RAD(0), TR_ANGLE_TO_RAD(-Lara.rightArm.yRot));
LARA_ARM* leftArm = &Lara.leftArm;
LARA_ARM* rightArm = &Lara.rightArm;
// HACK: backguns handles differently // TokyoSU: not really a hack since it's the original way to do that.
switch (Lara.gunType)
{
case WEAPON_SHOTGUN:
case WEAPON_HK:
case WEAPON_CROSSBOW:
case WEAPON_GRENADE_LAUNCHER:
case WEAPON_HARPOON_GUN:
short* shotgunFramePtr;
// Left arm
mask = MESH_BITS(LM_LINARM) | MESH_BITS(LM_LOUTARM) | MESH_BITS(LM_LHAND);
shotgunFramePtr = Lara.leftArm.frameBase + (Lara.leftArm.frameNumber) * (Anims[Lara.leftArm.animNumber].interpolation >> 8);
updateAnimation(NULL, laraObj, &shotgunFramePtr, 0, 1, mask);
// Right arm
mask = MESH_BITS(LM_RINARM) | MESH_BITS(LM_ROUTARM) | MESH_BITS(LM_RHAND);
shotgunFramePtr = Lara.rightArm.frameBase + (Lara.rightArm.frameNumber) * (Anims[Lara.rightArm.animNumber].interpolation >> 8);
updateAnimation(NULL, laraObj, &shotgunFramePtr, 0, 1, mask);
break;
case WEAPON_PISTOLS:
case WEAPON_UZI:
case WEAPON_REVOLVER:
default:
{
short* pistolFramePtr;
// Left arm
int upperArmMask = MESH_BITS(LM_LINARM);
mask = MESH_BITS(LM_LOUTARM) | MESH_BITS(LM_LHAND);
pistolFramePtr = Lara.leftArm.frameBase + (Lara.leftArm.frameNumber - Anims[Lara.leftArm.animNumber].frameBase) * (Anims[Lara.leftArm.animNumber].interpolation >> 8);
updateAnimation(NULL, laraObj, &pistolFramePtr, 0, 1, upperArmMask, true);
updateAnimation(NULL, laraObj, &pistolFramePtr, 0, 1, mask);
// Right arm
upperArmMask = MESH_BITS(LM_RINARM);
mask = MESH_BITS(LM_ROUTARM) | MESH_BITS(LM_RHAND);
pistolFramePtr = Lara.rightArm.frameBase + (Lara.rightArm.frameNumber - Anims[Lara.rightArm.animNumber].frameBase) * (Anims[Lara.rightArm.animNumber].interpolation >> 8);
updateAnimation(NULL, laraObj, &pistolFramePtr, 0, 1, upperArmMask, true);
updateAnimation(NULL, laraObj, &pistolFramePtr, 0, 1, mask);
}
break;
case WEAPON_FLARE:
// Left arm
mask = MESH_BITS(LM_LINARM) | MESH_BITS(LM_LOUTARM) | MESH_BITS(LM_LHAND);
frac = getFrame(Lara.leftArm.animNumber, Lara.leftArm.frameNumber, framePtr, &rate);
updateAnimation(NULL, laraObj, framePtr, frac, rate, mask);
// Right arm
mask = MESH_BITS(LM_RINARM) | MESH_BITS(LM_ROUTARM) | MESH_BITS(LM_RHAND);
frac = GetFrame_D2(LaraItem, framePtr, &rate);
updateAnimation(NULL, laraObj, framePtr, frac, rate, mask);
break;
}
}
// At this point, Lara's matrices are ready. Now let's do ponytails...
if (m_moveableObjects[ID_LARA_HAIR] != NULL)
{
RendererObject* hairsObj = m_moveableObjects[ID_LARA_HAIR];
lastMatrix = Matrix::Identity;
identity = Matrix::Identity;
Vector3 parentVertices[6][4];
Matrix headMatrix;
RendererObject* objSkin = m_moveableObjects[ID_LARA_SKIN];
RendererObject* objLara = m_moveableObjects[ID_LARA];
2019-12-15 16:19:01 +01:00
RendererMesh* parentMesh = objSkin->ObjectMeshes[LM_HEAD];
RendererBone* parentBone = objSkin->LinearizedBones[LM_HEAD];
2019-12-15 16:19:01 +01:00
world = objLara->AnimationTransforms[LM_HEAD] * m_LaraWorldMatrix;
2019-12-02 09:11:21 +01:00
int lastVertex = 0;
int lastIndex = 0;
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
2019-12-02 09:11:21 +01:00
for (int p = 0; p < ((level->LaraType == LARA_YOUNG) ? 2 : 1); p++)
{
// We can't use hardware skinning here, however hairs have just a few vertices so
// it's not so bad doing skinning in software
if (level->LaraType == LARA_YOUNG)
{
if (p == 1)
{
parentVertices[0][0] = Vector3::Transform(parentMesh->Positions[68], world);
parentVertices[0][1] = Vector3::Transform(parentMesh->Positions[69], world);
parentVertices[0][2] = Vector3::Transform(parentMesh->Positions[70], world);
parentVertices[0][3] = Vector3::Transform(parentMesh->Positions[71], world);
}
else
{
parentVertices[0][0] = Vector3::Transform(parentMesh->Positions[78], world);
parentVertices[0][1] = Vector3::Transform(parentMesh->Positions[78], world);
parentVertices[0][2] = Vector3::Transform(parentMesh->Positions[77], world);
parentVertices[0][3] = Vector3::Transform(parentMesh->Positions[76], world);
}
}
else
{
parentVertices[0][0] = Vector3::Transform(parentMesh->Positions[37], world);
parentVertices[0][1] = Vector3::Transform(parentMesh->Positions[39], world);
parentVertices[0][2] = Vector3::Transform(parentMesh->Positions[40], world);
parentVertices[0][3] = Vector3::Transform(parentMesh->Positions[38], world);
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < 6; i++)
{
RendererMesh* mesh = hairsObj->ObjectMeshes[i];
RendererBucket* bucket = &mesh->Buckets[RENDERER_BUCKET_SOLID];
translation = Matrix::CreateTranslation(Hairs[7 * p + i].pos.xPos, Hairs[7 * p + i].pos.yPos, Hairs[7 * p + i].pos.zPos);
rotation = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(Hairs[7 * p + i].pos.yRot), TR_ANGLE_TO_RAD(Hairs[7 * p + i].pos.xRot), TR_ANGLE_TO_RAD(Hairs[7 * p + i].pos.zRot));
m_hairsMatrices[6 * p + i] = rotation * translation;
2019-12-02 09:11:21 +01:00
int baseVertex = lastVertex;
2019-12-02 09:11:21 +01:00
for (int j = 0; j < bucket->Vertices.size(); j++)
{
2019-12-02 09:11:21 +01:00
int oldVertexIndex = (int)bucket->Vertices[j].Bone;
if (oldVertexIndex < 4)
{
m_hairVertices[lastVertex].Position.x = parentVertices[i][oldVertexIndex].x;
m_hairVertices[lastVertex].Position.y = parentVertices[i][oldVertexIndex].y;
m_hairVertices[lastVertex].Position.z = parentVertices[i][oldVertexIndex].z;
m_hairVertices[lastVertex].UV.x = bucket->Vertices[j].UV.x;
m_hairVertices[lastVertex].UV.y = bucket->Vertices[j].UV.y;
Vector3 n = Vector3(bucket->Vertices[j].Normal.x, bucket->Vertices[j].Normal.y, bucket->Vertices[j].Normal.z);
n.Normalize();
n = Vector3::TransformNormal(n, m_hairsMatrices[6 * p + i]);
n.Normalize();
m_hairVertices[lastVertex].Normal.x = n.x;
m_hairVertices[lastVertex].Normal.y = n.y;
m_hairVertices[lastVertex].Normal.z = n.z;
m_hairVertices[lastVertex].Color = Vector4::One * 0.5f;
lastVertex++;
}
else
{
Vector3 in = Vector3(bucket->Vertices[j].Position.x, bucket->Vertices[j].Position.y, bucket->Vertices[j].Position.z);
Vector3 out = Vector3::Transform(in, m_hairsMatrices[6 * p + i]);
if (i < 5)
{
parentVertices[i + 1][oldVertexIndex - 4].x = out.x;
parentVertices[i + 1][oldVertexIndex - 4].y = out.y;
parentVertices[i + 1][oldVertexIndex - 4].z = out.z;
}
m_hairVertices[lastVertex].Position.x = out.x;
m_hairVertices[lastVertex].Position.y = out.y;
m_hairVertices[lastVertex].Position.z = out.z;
m_hairVertices[lastVertex].UV.x = bucket->Vertices[j].UV.x;
m_hairVertices[lastVertex].UV.y = bucket->Vertices[j].UV.y;
Vector3 n = Vector3(bucket->Vertices[j].Normal.x, bucket->Vertices[j].Normal.y, bucket->Vertices[j].Normal.z);
n.Normalize();
n = Vector3::TransformNormal(n, m_hairsMatrices[6 * p + i]);
n.Normalize();
m_hairVertices[lastVertex].Normal.x = n.x;
m_hairVertices[lastVertex].Normal.y = n.y;
m_hairVertices[lastVertex].Normal.z = n.z;
m_hairVertices[lastVertex].Color = Vector4::One * 0.5f;
lastVertex++;
}
}
2019-12-02 09:11:21 +01:00
for (int j = 0; j < bucket->Indices.size(); j++)
{
m_hairIndices[lastIndex] = baseVertex + bucket->Indices[j];
lastIndex++;
}
}
}
}
// Transpose matrices for shaders
2019-12-02 09:11:21 +01:00
for (int m = 0; m < 15; m++)
laraObj->AnimationTransforms[m] = laraObj->AnimationTransforms[m].Transpose();
}
2019-12-02 09:11:21 +01:00
int Renderer11::getFrame(short animation, short frame, short** framePtr, int* rate)
{
ITEM_INFO item;
item.animNumber = animation;
item.frameNumber = frame;
return GetFrame_D2(&item, framePtr, rate);
}
void Renderer11::updateEffects()
{
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_effectsToDraw.Size(); i++)
{
RendererEffect* fx = m_effectsToDraw[i];
Matrix translation = Matrix::CreateTranslation(fx->Effect->pos.xPos, fx->Effect->pos.yPos, fx->Effect->pos.zPos);
2019-12-15 16:19:01 +01:00
Matrix rotation = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(fx->Effect->pos.yRot), TR_ANGLE_TO_RAD(fx->Effect->pos.xRot), TR_ANGLE_TO_RAD(fx->Effect->pos.zRot));
m_effectsToDraw[i]->World = rotation * translation;
}
}
void Renderer11::updateAnimation(RendererItem* item, RendererObject* obj, short** frmptr, short frac, short rate, int mask, bool useObjectWorldRotation)
{
RendererBone* bones[32];
2019-12-02 09:11:21 +01:00
int nextBone = 0;
Matrix rotation;
Matrix* transforms = (item == NULL ? obj->AnimationTransforms.data() : &item->AnimationTransforms[0]);
// Push
bones[nextBone++] = obj->Skeleton;
while (nextBone != 0)
{
// Pop the last bone in the stack
RendererBone* bone = bones[--nextBone];
bool calculateMatrix = (mask >> bone->Index) & 1;
if (calculateMatrix)
{
Vector3 p = Vector3((int)*(frmptr[0] + 6), (int)*(frmptr[0] + 7), (int)*(frmptr[0] + 8));
fromTrAngle(&rotation, frmptr[0], bone->Index);
if (frac)
{
Vector3 p2 = Vector3((int)*(frmptr[1] + 6), (int)*(frmptr[1] + 7), (int)*(frmptr[1] + 8));
p = Vector3::Lerp(p, p2, frac / ((float)rate));
Matrix rotation2;
fromTrAngle(&rotation2, frmptr[1], bone->Index);
Quaternion q1, q2, q3;
q1 = Quaternion::CreateFromRotationMatrix(rotation);
q2 = Quaternion::CreateFromRotationMatrix(rotation2);
q3 = Quaternion::Slerp(q1, q2, frac / ((float)rate));
rotation = Matrix::CreateFromQuaternion(q3);
}
Matrix translation;
if (bone == obj->Skeleton)
translation = Matrix::CreateTranslation(p.x, p.y, p.z);
Matrix extraRotation;
extraRotation = Matrix::CreateFromYawPitchRoll(bone->ExtraRotation.y, bone->ExtraRotation.x, bone->ExtraRotation.z);
if (useObjectWorldRotation) {
Quaternion invertedQuat;
transforms[bone->Parent->Index].Invert().Decompose(Vector3(), invertedQuat, Vector3());
rotation = extraRotation * rotation * Matrix::CreateFromQuaternion(invertedQuat);
}
else {
rotation = extraRotation * rotation;
}
if (bone != obj->Skeleton)
transforms[bone->Index] = rotation * bone->Transform;
else
transforms[bone->Index] = rotation * translation;
if (bone != obj->Skeleton)
transforms[bone->Index] = transforms[bone->Index] * transforms[bone->Parent->Index];
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < bone->Children.size(); i++)
{
// Push
bones[nextBone++] = bone->Children[i];
}
}
}
2019-12-02 09:11:21 +01:00
bool Renderer11::printDebugMessage(int x, int y, int alpha, byte r, byte g, byte b, LPCSTR Message)
{
2019-01-16 20:54:45 +01:00
return true;
}
void Renderer11::printDebugMessage(LPCSTR message, ...)
{
char buffer[255];
ZeroMemory(buffer, 255);
va_list args;
va_start(args, message);
_vsprintf_l(buffer, message, NULL, args);
va_end(args);
PrintString(10, m_currentY, buffer, 0xFFFFFFFF, PRINTSTRING_OUTLINE);
m_currentY += 20;
}
void Renderer11::drawBlood()
{
2019-12-02 09:11:21 +01:00
for (int i = 0; i < 32; i++)
{
BLOOD_STRUCT* blood = &Blood[i];
if (blood->on)
{
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + 15],
Vector3(blood->x, blood->y, blood->z),
Vector4(blood->shade * 244/255.0f, blood->shade * 0, blood->shade * 0,1.0f),
TR_ANGLE_TO_RAD(blood->rotAng), 1.0f, blood->size * 8.0f, blood->size * 8.0f,
BLENDMODE_ALPHABLEND);
}
}
}
void Renderer11::drawSparks()
{
2019-12-15 16:19:01 +01:00
for (int i = 0; i < MAX_SPARKS; i++)
{
SPARKS* spark = &Sparks[i];
if (spark->on)
{
if (spark->flags & SP_DEF)
{
FX_INFO* fx = &Effects[spark->fxObj];
AddSpriteBillboard(m_sprites[spark->def],
Vector3(fx->pos.xPos + spark->x,fx->pos.yPos + spark->y, fx->pos.zPos + spark->z),
Vector4(spark->r/255.0f, spark->g / 255.0f, spark->b / 255.0f,1.0f),
TR_ANGLE_TO_RAD(spark->rotAng), spark->scalar, spark->size * 12.0f, spark->size * 12.0f,
BLENDMODE_ALPHABLEND);
}
else
{
Vector3 v = Vector3(spark->xVel, spark->yVel, spark->zVel);
v.Normalize();
AddLine3D(Vector3(spark->x, spark->y, spark->z),Vector3( spark->x + v.x * 24.0f, spark->y + v.y * 24.0f, spark->z + v.z * 24.0f), Vector4(spark->r / 255.0f, spark->g / 255.0f, spark->b / 255.0f,1.0f));
}
}
}
}
void Renderer11::drawFires()
{
2019-12-15 16:19:01 +01:00
for (int k = 0; k < MAX_FIRE_LIST; k++)
{
FIRE_LIST* fire = &Fires[k];
if (fire->on)
{
2019-12-15 16:19:01 +01:00
for (int i = 0; i < MAX_SPARKS_FIRE; i++)
{
FIRE_SPARKS* spark = &FireSparks[i];
if (spark->on)
AddSpriteBillboard(m_sprites[spark->def], Vector3(fire->x + spark->x, fire->y + spark->y, fire->z + spark->z), Vector4(spark->r / 255.0f, spark->g / 255.0f, spark->b / 255.0f,1.0f), TR_ANGLE_TO_RAD(spark->rotAng), spark->scalar, spark->size * 4.0f, spark->size * 4.0f, BLENDMODE_ALPHABLEND);
}
}
}
}
void Renderer11::AddSpriteBillboard(RendererSprite* sprite,Vector3 pos, Vector4 color, float rotation, float scale, float width, float height, BLEND_MODES blendMode)
{
if (m_nextSprite >= MAX_SPRITES)
return;
scale = 1.0f;
width *= scale;
height *= scale;
RendererSpriteToDraw* spr = &m_spritesBuffer[m_nextSprite++];
spr->Type = RENDERER_SPRITE_TYPE::SPRITE_TYPE_BILLBOARD;
spr->Sprite = sprite;
spr->pos = pos;
spr->color = color;
spr->Rotation = rotation;
spr->Scale = scale;
spr->Width = width;
spr->Height = height;
spr->BlendMode = blendMode;
m_spritesToDraw.Add(spr);
}
void Renderer11::drawSmokes()
{
2019-12-02 09:11:21 +01:00
for (int i = 0; i < 32; i++)
{
SMOKE_SPARKS* spark = &SmokeSparks[i];
if (spark->on)
{
AddSpriteBillboard(m_sprites[spark->def],
Vector3(spark->x, spark->y, spark->z),
Vector4(spark->shade / 255.0f, spark->shade / 255.0f, spark->shade / 255.0f,1.0f),
TR_ANGLE_TO_RAD(spark->rotAng), spark->scalar, spark->size * 4.0f, spark->size * 4.0f,
BLENDMODE_ALPHABLEND);
}
}
}
void Renderer11::AddLine3D(Vector3 start, Vector3 end, Vector4 color)
{
if (m_nextLine3D >= MAX_LINES_3D)
return;
2019-02-02 15:40:44 +01:00
RendererLine3D* line = &m_lines3DBuffer[m_nextLine3D++];
line->start = start;
line->end = end;
line->color = color;
m_lines3DToDraw.Add(line);
}
void Renderer11::AddSprite3D(RendererSprite* sprite, Vector3 vtx1,Vector3 vtx2, Vector3 vtx3, Vector3 vtx4, Vector4 color, float rotation, float scale, float width, float height, BLEND_MODES blendMode)
{
if (m_nextSprite >= MAX_SPRITES)
return;
scale = 1.0f;
width *= scale;
height *= scale;
RendererSpriteToDraw* spr = &m_spritesBuffer[m_nextSprite++];
spr->Type = RENDERER_SPRITE_TYPE::SPRITE_TYPE_3D;
spr->Sprite = sprite;
spr->vtx1 = vtx1;
spr->vtx2 = vtx2;
spr->vtx3 = vtx3;
spr->vtx4 = vtx4;
spr->color = color;
spr->Rotation = rotation;
spr->Scale = scale;
spr->Width = width;
spr->Height = height;
spr->BlendMode = blendMode;
m_spritesToDraw.Add(spr);
}
void Renderer11::drawShockwaves()
{
2019-12-15 16:19:01 +01:00
for (int i = 0; i < MAX_SHOCKWAVE; i++)
{
SHOCKWAVE_STRUCT* shockwave = &ShockWaves[i];
if (shockwave->life)
{
byte color = shockwave->life * 8;
// Inner circle
float angle = PI / 32.0f;
float c = cos(angle);
float s = sin(angle);
float x1 = shockwave->x + (shockwave->innerRad * c);
float z1 = shockwave->z + (shockwave->innerRad * s);
float x4 = shockwave->x + (shockwave->outerRad * c);
float z4 = shockwave->z + (shockwave->outerRad * s);
angle -= PI / 8.0f;
2019-12-02 09:11:21 +01:00
for (int j = 0; j < 16; j++)
{
c = cos(angle);
s = sin(angle);
float x2 = shockwave->x + (shockwave->innerRad * c);
float z2 = shockwave->z + (shockwave->innerRad * s);
float x3 = shockwave->x + (shockwave->outerRad * c);
float z3 = shockwave->z + (shockwave->outerRad * s);
angle -= PI / 8.0f;
AddSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_SPLASH],
Vector3(x1, shockwave->y, z1),
Vector3(x2, shockwave->y, z2),
Vector3(x3, shockwave->y, z3),
Vector3(x4, shockwave->y, z4),
Vector4(color / 255.0f, color / 255.0f, color/255.0f,1.0f), 0, 1, 0, 0, BLENDMODE_ALPHABLEND);
x1 = x2;
z1 = z2;
x4 = x3;
z4 = z3;
}
}
}
}
void Renderer11::drawRipples()
{
2019-12-15 16:19:01 +01:00
for (int i = 0; i < MAX_RIPPLES; i++)
{
RIPPLE_STRUCT* ripple = &Ripples[i];
if (ripple->flags & 1)
{
float x1 = ripple->x - ripple->size;
float z1 = ripple->z - ripple->size;
float x2 = ripple->x + ripple->size;
float z2 = ripple->z + ripple->size;
float y = ripple->y;
byte color = (ripple->init ? ripple->init << 1 : ripple->life << 1);
AddSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_RIPPLES], Vector3(x1, y, z2),Vector3(x2, y, z2),Vector3( x2, y, z1),Vector3( x1, y, z1),Vector4( color / 255.0f, color / 255.0f, color/255.0f,1.0f), 0.0f, 1.0f, ripple->size, ripple->size, BLENDMODE_ALPHABLEND);
}
}
}
void Renderer11::drawDrips()
{
2019-12-15 16:19:01 +01:00
for (int i = 0; i < MAX_DRIPS; i++)
{
DRIP_STRUCT* drip = &Drips[i];
if (drip->on)
{
AddLine3D(Vector3(drip->x, drip->y, drip->z),Vector3( drip->x, drip->y + 24.0f, drip->z), Vector4(drip->r/255.0f, drip->g/255.0f, drip->b/255.0f,1.0f));
}
}
}
void Renderer11::drawBubbles()
{
2019-12-15 16:19:01 +01:00
for (int i = 0; i < MAX_BUBBLES; i++)
{
BUBBLE_STRUCT* bubble = &Bubbles[i];
if (bubble->size)
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_BUBBLES], Vector3(bubble->pos.x, bubble->pos.y, bubble->pos.z),Vector4( bubble->shade, bubble->shade, bubble->shade,1.0f), 0.0f, 1.0f, bubble->size * 0.5f, bubble->size * 0.5f, BLENDMODE_ALPHABLEND);
}
}
void Renderer11::drawSplahes()
{
constexpr size_t NUM_POINTS = 12;
2019-12-15 16:19:01 +01:00
for (int i = 0; i < MAX_SPLASH; i++)
{
SPLASH_STRUCT& splash = Splashes[i];
if (splash.isActive)
{
constexpr float alpha = 360 / NUM_POINTS;
byte color = (splash.life >= 32 ? 255 : (byte)((splash.life / 32.0f) * 255));
if (!splash.isRipple) {
if (splash.heightSpeed < 0 && splash.height < 1024) {
float multiplier = splash.height / 1024.0f;
color = (float)color*multiplier;
}
}
float innerRadius = splash.innerRad;
float outerRadius = splash.outerRad;
float xInner;
float zInner;
float xOuter;
float zOuter;
float x2Inner;
float z2Inner;
float x2Outer;
float z2Outer;
float yInner = splash.y;
float yOuter = splash.y - splash.height;
for (int i = 0; i < NUM_POINTS; i++) {
xInner = innerRadius * sin(alpha * i * PI / 180);
zInner = innerRadius * cos(alpha * i * PI / 180);
xOuter = outerRadius * sin(alpha * i * PI / 180);
zOuter = outerRadius * cos(alpha * i * PI / 180);
xInner += splash.x;
zInner += splash.z;
xOuter += splash.x;
zOuter += splash.z;
int j = (i + 1) % NUM_POINTS;
x2Inner = innerRadius * sin(alpha * j * PI / 180);
x2Inner += splash.x;
z2Inner = innerRadius * cos(alpha * j * PI / 180);
z2Inner += splash.z;
x2Outer = outerRadius * sin(alpha * j * PI / 180);
x2Outer += splash.x;
z2Outer = outerRadius * cos(alpha * j * PI / 180);
z2Outer += splash.z;
AddSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + splash.spriteSequenceStart + (int)splash.animationPhase],Vector3( xOuter, yOuter, zOuter), Vector3(x2Outer, yOuter, z2Outer),Vector3( x2Inner, yInner, z2Inner), Vector3(xInner, yInner, zInner),Vector4( color / 255.0f, color / 255.0f, color / 255.0f,1.0f), 0, 1, 0, 0, BLENDMODE_ALPHABLEND);
}
}
}
}
bool Renderer11::drawSprites()
{
m_context->RSSetState(m_states->CullNone());
m_context->OMSetDepthStencilState(m_states->DepthRead(), 0);
m_context->VSSetShader(m_vsSprites, NULL, 0);
m_context->PSSetShader(m_psSprites, NULL, 0);
m_stCameraMatrices.View = View.Transpose();
m_stCameraMatrices.Projection = Projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
m_stMisc.AlphaTest = true;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
for (int b = 0; b < 4; b++)
{
BLEND_MODES currentBlendMode = (BLEND_MODES)b;
2019-12-02 09:11:21 +01:00
int numSpritesToDraw = m_spritesToDraw.Size();
int lastSprite = 0;
m_primitiveBatch->Begin();
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numSpritesToDraw; i++)
{
RendererSpriteToDraw* spr = m_spritesToDraw[i];
if (spr->BlendMode != currentBlendMode)
continue;
switch (currentBlendMode) {
case BLENDMODE_ALPHABLEND:
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
break;
case BLENDMODE_ALPHATEST:
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
break;
case BLENDMODE_OPAQUE:
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
break;
case BLENDMODE_SUBTRACTIVE:
m_context->OMSetBlendState(m_subtractiveBlendState, NULL, 0xFFFFFFFF);
break;
}
if (spr->Type == RENDERER_SPRITE_TYPE::SPRITE_TYPE_BILLBOARD)
{
float halfWidth = spr->Width / 2.0f;
float halfHeight = spr->Height / 2.0f;
Matrix billboardMatrix;
createBillboardMatrix(&billboardMatrix, &spr->pos, &Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z), spr->Rotation);
Vector3 p0 = Vector3(-halfWidth, -halfHeight, 0);
Vector3 p1 = Vector3(halfWidth, -halfHeight, 0);
Vector3 p2 = Vector3(halfWidth, halfHeight, 0);
Vector3 p3 = Vector3(-halfWidth, halfHeight, 0);
Vector3 p0t = Vector3::Transform(p0, billboardMatrix);
Vector3 p1t = Vector3::Transform(p1, billboardMatrix);
Vector3 p2t = Vector3::Transform(p2, billboardMatrix);
Vector3 p3t = Vector3::Transform(p3, billboardMatrix);
RendererVertex v0;
v0.Position.x = p0t.x;
v0.Position.y = p0t.y;
v0.Position.z = p0t.z;
v0.UV.x = spr->Sprite->UV[0].x;
v0.UV.y = spr->Sprite->UV[0].y;
v0.Color = spr->color;
RendererVertex v1;
v1.Position.x = p1t.x;
v1.Position.y = p1t.y;
v1.Position.z = p1t.z;
v1.UV.x = spr->Sprite->UV[1].x;
v1.UV.y = spr->Sprite->UV[1].y;
v1.Color = spr->color;
RendererVertex v2;
v2.Position.x = p2t.x;
v2.Position.y = p2t.y;
v2.Position.z = p2t.z;
v2.UV.x = spr->Sprite->UV[2].x;
v2.UV.y = spr->Sprite->UV[2].y;
v2.Color = spr->color;
RendererVertex v3;
v3.Position.x = p3t.x;
v3.Position.y = p3t.y;
v3.Position.z = p3t.z;
v3.UV.x = spr->Sprite->UV[3].x;
v3.UV.y = spr->Sprite->UV[3].y;
v3.Color = spr->color;
m_primitiveBatch->DrawQuad(v0, v1, v2, v3);
}
else if (spr->Type == RENDERER_SPRITE_TYPE::SPRITE_TYPE_3D)
{
Vector3 p0t = spr->vtx1;
Vector3 p1t = spr->vtx2;
Vector3 p2t = spr->vtx3;
Vector3 p3t = spr->vtx4;
RendererVertex v0;
v0.Position.x = p0t.x;
v0.Position.y = p0t.y;
v0.Position.z = p0t.z;
v0.UV.x = spr->Sprite->UV[0].x;
v0.UV.y = spr->Sprite->UV[0].y;
v0.Color = spr->color;
RendererVertex v1;
v1.Position.x = p1t.x;
v1.Position.y = p1t.y;
v1.Position.z = p1t.z;
v1.UV.x = spr->Sprite->UV[1].x;
v1.UV.y = spr->Sprite->UV[1].y;
v1.Color = spr->color;
RendererVertex v2;
v2.Position.x = p2t.x;
v2.Position.y = p2t.y;
v2.Position.z = p2t.z;
v2.UV.x = spr->Sprite->UV[2].x;
v2.UV.y = spr->Sprite->UV[2].y;
v2.Color = spr->color;
RendererVertex v3;
v3.Position.x = p3t.x;
v3.Position.y = p3t.y;
v3.Position.z = p3t.z;
v3.UV.x = spr->Sprite->UV[3].x;
v3.UV.y = spr->Sprite->UV[3].y;
v3.Color = spr->color;
m_primitiveBatch->DrawQuad(v0, v1, v2, v3);
}
}
m_primitiveBatch->End();
}
m_context->RSSetState(m_states->CullCounterClockwise());
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
return true;
}
void Renderer11::createBillboardMatrix(Matrix* out, Vector3* particlePos, Vector3* cameraPos, float rotation)
{
Vector3 look = *particlePos;
look = look - *cameraPos;
look.Normalize();
Vector3 cameraUp = Vector3(0.0f, -1.0f, 0.0f);
Vector3 right;
right = cameraUp.Cross(look);
right.Normalize();
// Rotate right vector
Matrix rightTransform = Matrix::CreateFromAxisAngle(look, rotation);
right = Vector3::Transform(right, rightTransform);
Vector3 up;
up = look.Cross(right);
up.Normalize();
*out = Matrix::Identity;
out->_11 = right.x;
out->_12 = right.y;
out->_13 = right.z;
out->_21 = up.x;
out->_22 = up.y;
out->_23 = up.z;
out->_31 = look.x;
out->_32 = look.y;
out->_33 = look.z;
out->_41 = particlePos->x;
out->_42 = particlePos->y;
out->_43 = particlePos->z;
}
void Renderer11::updateAnimatedTextures()
{
// Update room's animated textures
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NumberRooms; i++)
{
RendererRoom* room = m_rooms[i];
if (room == NULL)
continue;
2019-12-02 09:11:21 +01:00
for (int bucketIndex = 0; bucketIndex < NUM_BUCKETS; bucketIndex++)
{
RendererBucket* bucket = &room->AnimatedBuckets[bucketIndex];
if (bucket->Vertices.size() == 0)
continue;
2019-12-02 09:11:21 +01:00
for (int p = 0; p < bucket->Polygons.size(); p++)
{
RendererPolygon* polygon = &bucket->Polygons[p];
RendererAnimatedTextureSet* set = m_animatedTextureSets[polygon->AnimatedSet];
2019-12-02 09:11:21 +01:00
int textureIndex = -1;
for (int j = 0; j < set->NumTextures; j++)
{
if (set->Textures[j]->Id == polygon->TextureId)
{
textureIndex = j;
break;
}
}
if (textureIndex == -1)
continue;
if (textureIndex == set->NumTextures - 1)
textureIndex = 0;
else
textureIndex++;
polygon->TextureId = set->Textures[textureIndex]->Id;
2019-12-02 09:11:21 +01:00
for (int v = 0; v < (polygon->Shape == SHAPE_RECTANGLE ? 4 : 3); v++)
{
bucket->Vertices[polygon->Indices[v]].UV.x = set->Textures[textureIndex]->UV[v].x;
bucket->Vertices[polygon->Indices[v]].UV.y = set->Textures[textureIndex]->UV[v].y;
}
}
}
}
// Update waterfalls textures
2019-12-02 09:11:21 +01:00
for (int i = ID_WATERFALL1; i <= ID_WATERFALLSS2; i++)
{
OBJECT_INFO* obj = &Objects[i];
if (obj->loaded)
{
RendererObject* waterfall = m_moveableObjects[i];
2019-12-02 09:11:21 +01:00
for (int m = 0; m < waterfall->ObjectMeshes.size(); m++)
{
RendererMesh* mesh = waterfall->ObjectMeshes[m];
RendererBucket* bucket = &mesh->Buckets[RENDERER_BUCKET_TRANSPARENT_DS];
2019-12-02 09:11:21 +01:00
for (int v = 0; v < bucket->Vertices.size(); v++)
{
RendererVertex* vertex = &bucket->Vertices[v];
int y = vertex->UV.y * TEXTURE_ATLAS_SIZE + 64;
y %= 128;
vertex->UV.y = (float)y / TEXTURE_ATLAS_SIZE;
}
}
}
}
}
bool Renderer11::drawLines3D()
{
m_context->RSSetState(m_states->CullNone());
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
m_context->OMSetDepthStencilState(m_states->DepthRead(), 0);
m_context->VSSetShader(m_vsSolid, NULL, 0);
m_context->PSSetShader(m_psSolid, NULL, 0);
m_stCameraMatrices.View = View.Transpose();
m_stCameraMatrices.Projection = Projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
m_context->IASetInputLayout(m_inputLayout);
m_primitiveBatch->Begin();
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_lines3DToDraw.Size(); i++)
{
2019-02-02 15:40:44 +01:00
RendererLine3D* line = m_lines3DToDraw[i];
RendererVertex v1;
v1.Position = line->start;
v1.Color = line->color;
RendererVertex v2;
v2.Position = line->end;
v2.Color = line->color;
m_primitiveBatch->DrawLine(v1, v2);
}
m_primitiveBatch->End();
m_context->RSSetState(m_states->CullCounterClockwise());
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
return true;
}
bool Renderer11::doRain()
{
if (m_firstWeather)
{
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_RAIN_DROPS; i++)
{
m_rain[i].Reset = true;
m_rain[i].Draw = true;
}
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_RAIN_DROPS; i++)
{
RendererWeatherParticle* drop = &m_rain[i];
if (drop->Reset)
{
drop->Draw = true;
drop->X = LaraItem->pos.xPos + rand() % WEATHER_RADIUS - WEATHER_RADIUS / 2.0f;
drop->Y = LaraItem->pos.yPos - (m_firstWeather ? rand() % WEATHER_HEIGHT : WEATHER_HEIGHT);
drop->Z = LaraItem->pos.zPos + rand() % WEATHER_RADIUS - WEATHER_RADIUS / 2.0f;
// Check if in inside room
2019-12-02 09:11:21 +01:00
short roomNumber = Camera.pos.roomNumber;
FLOOR_INFO* floor = GetFloor(drop->X, drop->Y, drop->Z, &roomNumber);
ROOM_INFO* room = &Rooms[roomNumber];
if (!(room->flags & ENV_FLAG_OUTSIDE))
{
drop->Reset = true;
continue;
}
drop->Size = RAIN_SIZE + (rand() % 64);
drop->AngleH = (rand() % RAIN_MAX_ANGLE_H) * RADIAN;
drop->AngleV = (rand() % RAIN_MAX_ANGLE_V) * RADIAN;
drop->Reset = false;
}
float x1 = drop->X;
float y1 = drop->Y;
float z1 = drop->Z;
float radius = drop->Size * sin(drop->AngleV);
float dx = sin(drop->AngleH) * radius;
float dy = drop->Size * cos(drop->AngleV);
float dz = cos(drop->AngleH) * radius;
drop->X += dx;
drop->Y += RAIN_DELTA_Y;
drop->Z += dz;
if (drop->Draw)
AddLine3D(Vector3(x1, y1, z1),Vector3( drop->X, drop->Y, drop->Z), Vector4(RAIN_COLOR, RAIN_COLOR, RAIN_COLOR,1.0f));
// If rain drop has hit the ground, then reset it and add a little drip
2019-12-02 09:11:21 +01:00
short roomNumber = Camera.pos.roomNumber;
FLOOR_INFO* floor = GetFloor(drop->X, drop->Y, drop->Z, &roomNumber);
ROOM_INFO* room = &Rooms[roomNumber];
if (drop->Y >= room->y + room->minfloor)
{
drop->Reset = true;
AddWaterSparks(drop->X, room->y + room->minfloor, drop->Z, 1);
}
}
m_firstWeather = false;
return true;
2019-02-02 15:40:44 +01:00
}
bool Renderer11::doSnow()
{
if (m_firstWeather)
{
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_SNOW_PARTICLES; i++)
2019-02-02 15:40:44 +01:00
m_snow[i].Reset = true;
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_SNOW_PARTICLES; i++)
2019-02-02 15:40:44 +01:00
{
RendererWeatherParticle* snow = &m_snow[i];
if (snow->Reset)
{
snow->X = LaraItem->pos.xPos + rand() % WEATHER_RADIUS - WEATHER_RADIUS / 2.0f;
snow->Y = LaraItem->pos.yPos - (m_firstWeather ? rand() % WEATHER_HEIGHT : WEATHER_HEIGHT) + (rand() % 512);
snow->Z = LaraItem->pos.zPos + rand() % WEATHER_RADIUS - WEATHER_RADIUS / 2.0f;
// Check if in inside room
2019-12-02 09:11:21 +01:00
short roomNumber = Camera.pos.roomNumber;
2019-02-02 15:40:44 +01:00
FLOOR_INFO* floor = GetFloor(snow->X, snow->Y, snow->Z, &roomNumber);
ROOM_INFO* room = &Rooms[roomNumber];
if (!(room->flags & ENV_FLAG_OUTSIDE))
continue;
snow->Size = SNOW_DELTA_Y + (rand() % 64);
snow->AngleH = (rand() % SNOW_MAX_ANGLE_H) * RADIAN;
snow->AngleV = (rand() % SNOW_MAX_ANGLE_V) * RADIAN;
snow->Reset = false;
}
float radius = snow->Size * sin(snow->AngleV);
float dx = sin(snow->AngleH) * radius;
float dz = cos(snow->AngleH) * radius;
snow->X += dx;
snow->Y += SNOW_DELTA_Y;
snow->Z += dz;
if (snow->X <= 0 || snow->Z <= 0 || snow->X >= 100 * 1024.0f || snow->Z >= 100 * 1024.0f)
{
snow->Reset = true;
continue;
}
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], Vector3(snow->X, snow->Y, snow->Z), Vector4(1, 1, 1,1),
2019-02-02 15:40:44 +01:00
0.0f, 1.0f, SNOW_SIZE, SNOW_SIZE,
BLENDMODE_ALPHABLEND);
2019-12-02 09:11:21 +01:00
short roomNumber = Camera.pos.roomNumber;
2019-02-02 15:40:44 +01:00
FLOOR_INFO* floor = GetFloor(snow->X, snow->Y, snow->Z, &roomNumber);
ROOM_INFO* room = &Rooms[roomNumber];
if (snow->Y >= room->y + room->minfloor)
snow->Reset = true;
}
m_firstWeather = false;
return true;
}
bool Renderer11::drawDebris(bool transparent)
2019-02-02 15:40:44 +01:00
{
UINT cPasses = 1;
// First collect debrises
vector<RendererVertex> vertices;
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_DEBRIS; i++)
2019-02-02 15:40:44 +01:00
{
DEBRIS_STRUCT* debris = &Debris[i];
if (debris->on)
2019-02-02 15:40:44 +01:00
{
Matrix translation = Matrix::CreateTranslation(debris->x, debris->y, debris->z);
Matrix rotation = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(debris->yRot), TR_ANGLE_TO_RAD(debris->xRot), 0);
2019-02-02 15:40:44 +01:00
Matrix world = rotation * translation;
2019-12-02 09:11:21 +01:00
OBJECT_TEXTURE* texture = &ObjectTextures[(int)(debris->textInfo) & 0x7FFF];
int tile = texture->tileAndFlag & 0x7FFF;
2019-02-02 15:40:44 +01:00
2019-03-18 22:50:41 +01:00
// Draw only debris of the current bucket
if (texture->attribute == 0 && transparent ||
texture->attribute == 1 && transparent ||
texture->attribute == 2 && !transparent)
2019-02-02 15:40:44 +01:00
continue;
RendererVertex vertex;
// Prepare the triangle
Vector3 p = Vector3(debris->xyzOffsets1[0], debris->xyzOffsets1[1], debris->xyzOffsets1[2]);
2019-03-18 22:50:41 +01:00
p = Vector3::Transform(p, world);
vertex.Position.x = p.x;
vertex.Position.y = p.y;
vertex.Position.z = p.z;
vertex.UV.x = (texture->vertices[0].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.UV.y = (texture->vertices[0].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.Color.x = debris->pad[2] / 255.0f;
vertex.Color.y = debris->pad[3] / 255.0f;
vertex.Color.z = debris->pad[4] / 255.0f;
2019-02-02 15:40:44 +01:00
vertices.push_back(vertex);
p = Vector3(debris->xyzOffsets2[0], debris->xyzOffsets2[1], debris->xyzOffsets2[2]);
2019-03-18 22:50:41 +01:00
p = Vector3::Transform(p, world);
vertex.Position.x = p.x;
vertex.Position.y = p.y;
vertex.Position.z = p.z;
vertex.UV.x = (texture->vertices[1].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.UV.y = (texture->vertices[1].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.Color.x = debris->pad[6] / 255.0f;
vertex.Color.y = debris->pad[7] / 255.0f;
vertex.Color.z = debris->pad[8] / 255.0f;
2019-02-02 15:40:44 +01:00
vertices.push_back(vertex);
p = Vector3(debris->xyzOffsets3[0], debris->xyzOffsets3[1], debris->xyzOffsets3[2]);
2019-03-18 22:50:41 +01:00
p = Vector3::Transform(p, world);
vertex.Position.x = p.x;
vertex.Position.y = p.y;
vertex.Position.z = p.z;
vertex.UV.x = (texture->vertices[2].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.UV.y = (texture->vertices[2].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
vertex.Color.x = debris->pad[10] / 255.0f;
vertex.Color.y = debris->pad[11] / 255.0f;
vertex.Color.z = debris->pad[12] / 255.0f;
2019-03-18 22:50:41 +01:00
vertices.push_back(vertex);
2019-02-02 15:40:44 +01:00
}
}
// Check if no debris have to be drawn
2019-03-18 22:50:41 +01:00
if (vertices.size() == 0)
2019-02-02 15:40:44 +01:00
return true;
2019-03-18 22:50:41 +01:00
m_primitiveBatch->Begin();
2019-02-02 15:40:44 +01:00
2019-03-18 22:50:41 +01:00
// Set shaders
m_context->VSSetShader(m_vsStatics, NULL, 0);
m_context->PSSetShader(m_psStatics, NULL, 0);
2019-02-02 15:40:44 +01:00
2019-03-18 22:50:41 +01:00
// Set texture
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
2019-02-02 15:40:44 +01:00
2019-03-18 22:50:41 +01:00
// Set camera matrices
m_stCameraMatrices.View = View.Transpose();
m_stCameraMatrices.Projection = Projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
2019-02-02 15:40:44 +01:00
2019-03-18 22:50:41 +01:00
m_stMisc.AlphaTest = !transparent;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
2019-02-02 15:40:44 +01:00
2019-03-18 22:50:41 +01:00
m_stStatic.World = Matrix::Identity;
m_stStatic.Color = Vector4::One;
updateConstantBuffer(m_cbStatic, &m_stStatic, sizeof(CStaticBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbStatic);
2019-02-02 15:40:44 +01:00
2019-03-18 22:50:41 +01:00
// Draw vertices
m_primitiveBatch->Draw(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST, vertices.data(), vertices.size());
m_numDrawCalls++;
2019-02-02 15:40:44 +01:00
2019-03-18 22:50:41 +01:00
m_primitiveBatch->End();
2019-02-02 15:40:44 +01:00
return true;
}
bool Renderer11::drawBats()
{
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
2019-02-02 15:40:44 +01:00
if (Objects[ID_BATS].loaded)
{
OBJECT_INFO* obj = &Objects[ID_BATS];
RendererObject* moveableObj = m_moveableObjects[ID_BATS];
2019-12-02 09:11:21 +01:00
short* meshPtr = Meshes[Objects[ID_BATS].meshIndex + 2 * (-GlobalCounter & 3)];
RendererMesh* mesh = m_meshPointersToMesh[reinterpret_cast<unsigned int>(meshPtr)];
2019-12-02 09:11:21 +01:00
for (int m = 0; m < 32; m++)
2019-02-02 15:40:44 +01:00
memcpy(&m_stItem.BonesMatrices[m], &Matrix::Identity, sizeof(Matrix));
2019-12-02 09:11:21 +01:00
for (int b = 0; b < 2; b++)
2019-02-02 15:40:44 +01:00
{
RendererBucket* bucket = &mesh->Buckets[b];
if (bucket->NumVertices == 0)
continue;
for (int i = 0; i < NUM_BATS; i++)
2019-02-02 15:40:44 +01:00
{
BAT_STRUCT* bat = &Bats[i];
if (bat->on)
{
Matrix translation = Matrix::CreateTranslation(bat->pos.xPos, bat->pos.yPos, bat->pos.zPos);
Matrix rotation = Matrix::CreateFromYawPitchRoll(bat->pos.yRot, bat->pos.xRot, bat->pos.zRot);
Matrix world = rotation * translation;
m_stItem.World = world.Transpose();
2019-02-02 15:40:44 +01:00
m_stItem.Position = Vector4(bat->pos.xPos, bat->pos.yPos, bat->pos.zPos, 1.0f);
m_stItem.AmbientLight = m_rooms[bat->roomNumber]->AmbientLight;
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
2019-02-02 15:40:44 +01:00
}
}
}
}
2019-02-02 15:40:44 +01:00
return true;
}
bool Renderer11::drawRats()
{
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
2019-02-02 15:40:44 +01:00
if (Objects[ID_RATS].loaded)
{
OBJECT_INFO* obj = &Objects[ID_BATS];
RendererObject* moveableObj = m_moveableObjects[ID_BATS];
2019-02-02 15:40:44 +01:00
2019-12-02 09:11:21 +01:00
for (int m = 0; m < 32; m++)
memcpy(&m_stItem.BonesMatrices[m], &Matrix::Identity, sizeof(Matrix));
2019-02-02 15:40:44 +01:00
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_RATS; i += 4)
2019-02-02 15:40:44 +01:00
{
RAT_STRUCT* rat = &Rats[i];
if (rat->on)
{
2019-12-02 09:11:21 +01:00
short* meshPtr = Meshes[Objects[ID_BATS].meshIndex + (((i + Wibble) >> 2) & 0xE)];
RendererMesh* mesh = m_meshPointersToMesh[reinterpret_cast<unsigned int>(meshPtr)];
Matrix translation = Matrix::CreateTranslation(rat->pos.xPos, rat->pos.yPos, rat->pos.zPos);
Matrix rotation = Matrix::CreateFromYawPitchRoll(rat->pos.yRot, rat->pos.xRot, rat->pos.zRot);
Matrix world = rotation * translation;
2019-02-02 15:40:44 +01:00
m_stItem.World = world.Transpose();
m_stItem.Position = Vector4(rat->pos.xPos, rat->pos.yPos, rat->pos.zPos, 1.0f);
m_stItem.AmbientLight = m_rooms[rat->roomNumber]->AmbientLight;
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
2019-02-02 15:40:44 +01:00
2019-12-02 09:11:21 +01:00
for (int b = 0; b < 2; b++)
2019-02-02 15:40:44 +01:00
{
RendererBucket* bucket = &mesh->Buckets[b];
2019-02-02 15:40:44 +01:00
if (bucket->NumVertices == 0)
continue;
2019-02-02 15:40:44 +01:00
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
2019-02-02 15:40:44 +01:00
}
}
}
}
2019-02-02 15:40:44 +01:00
return true;
}
bool Renderer11::drawSpiders()
{
/*XMMATRIX world;
UINT cPasses = 1;
if (Objects[ID_SPIDER].loaded)
{
OBJECT_INFO* obj = &Objects[ID_SPIDER];
RendererObject* moveableObj = m_moveableObjects[ID_SPIDER].get();
2019-12-02 09:11:21 +01:00
short* meshPtr = Meshes[Objects[ID_SPIDER].meshIndex + ((Wibble >> 2) & 2)];
2019-02-02 15:40:44 +01:00
RendererMesh* mesh = m_meshPointersToMesh[meshPtr];
RendererBucket* bucket = mesh->GetBucket(bucketIndex);
if (bucket->NumVertices == 0)
return true;
setGpuStateForBucket(bucketIndex);
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
m_device->SetIndices(bucket->GetIndexBuffer());
LPD3DXEFFECT effect;
if (pass == RENDERER_PASS_SHADOW_MAP)
effect = m_shaderDepth->GetEffect();
else if (pass == RENDERER_PASS_RECONSTRUCT_DEPTH)
effect = m_shaderReconstructZBuffer->GetEffect();
else if (pass == RENDERER_PASS_GBUFFER)
effect = m_shaderFillGBuffer->GetEffect();
else
effect = m_shaderTransparent->GetEffect();
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), false);
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPE_MOVEABLE);
if (bucketIndex == RENDERER_BUCKET_SOLID || bucketIndex == RENDERER_BUCKET_SOLID_DS)
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLENDMODE_OPAQUE);
else
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLENDMODE_ALPHATEST);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_SPIDERS; i++)
2019-02-02 15:40:44 +01:00
{
SPIDER_STRUCT* spider = &Spiders[i];
if (spider->on)
{
XMMATRIXTranslation(&m_tempTranslation, spider->pos.xPos, spider->pos.yPos, spider->pos.zPos);
XMMATRIXRotationYawPitchRoll(&m_tempRotation, spider->pos.yRot, spider->pos.xRot, spider->pos.zRot);
XMMATRIXMultiply(&m_tempWorld, &m_tempRotation, &m_tempTranslation);
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &m_tempWorld);
effect->SetVector(effect->GetParameterByName(NULL, "AmbientLight"), &m_rooms[spider->roomNumber]->AmbientLight);
for (int iPass = 0; iPass < cPasses; iPass++)
{
effect->BeginPass(iPass);
effect->CommitChanges();
drawPrimitives(D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
effect->EndPass();
}
}
}
}*/
return true;
}
2019-12-02 09:11:21 +01:00
int Renderer11::drawInventoryScene()
2019-02-02 15:40:44 +01:00
{
char stringBuffer[255];
bool drawLogo = true;
RECT guiRect;
Vector4 guiColor = Vector4(0.0f, 0.0f, 0.25f, 0.5f);
bool drawGuiRect = false;
2019-02-02 15:40:44 +01:00
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = ScreenWidth;
rect.bottom = ScreenHeight;
m_lines2DToDraw.Clear();
m_strings.clear();
m_nextLine2D = 0;
2019-02-02 15:40:44 +01:00
// Set basic render states
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
m_context->RSSetState(m_states->CullCounterClockwise());
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
// Bind and clear render target
m_context->ClearRenderTargetView(m_renderTarget->RenderTargetView, Colors::Black);
m_context->ClearDepthStencilView(m_renderTarget->DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
m_context->OMSetRenderTargets(1, &m_renderTarget->RenderTargetView, m_renderTarget->DepthStencilView);
2019-02-02 15:40:44 +01:00
m_context->RSSetViewports(1, &m_viewport);
// Clear the Z-Buffer after drawing the background
if (g_Inventory->GetType() == INV_TYPE_TITLE)
2019-02-02 15:40:44 +01:00
{
if (g_GameFlow->TitleType == TITLE_BACKGROUND)
drawFullScreenQuad(m_titleScreen->ShaderResourceView, Vector3(m_fadeFactor, m_fadeFactor, m_fadeFactor), false);
else
drawFullScreenQuad(m_dumpScreenRenderTarget->ShaderResourceView, Vector3(1.0f, 1.0f, 1.0f), false);
2019-02-02 15:40:44 +01:00
}
else
{
drawFullScreenQuad(m_dumpScreenRenderTarget->ShaderResourceView, Vector3(0.2f, 0.2f, 0.2f), false);
}
m_context->ClearDepthStencilView(m_renderTarget->DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
2019-02-02 15:40:44 +01:00
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
// Set vertex buffer
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
2019-02-02 15:40:44 +01:00
// Set shaders
m_context->VSSetShader(m_vsInventory, NULL, 0);
m_context->PSSetShader(m_psInventory, NULL, 0);
// Set texture
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
InventoryRing* activeRing = g_Inventory->GetRing(g_Inventory->GetActiveRing());
2019-12-02 09:11:21 +01:00
int lastRing = 0;
float cameraX = INV_CAMERA_DISTANCE * cos(g_Inventory->GetCameraTilt() * RADIAN);
float cameraY = g_Inventory->GetCameraY() - INV_CAMERA_DISTANCE * sin(g_Inventory->GetCameraTilt() * RADIAN);
float cameraZ = 0.0f;
m_stCameraMatrices.View = Matrix::CreateLookAt(Vector3(cameraX, cameraY, cameraZ),
Vector3(0.0f, g_Inventory->GetCameraY() - 512.0f, 0.0f), Vector3(0.0f, -1.0f, 0.0f)).Transpose();
m_stCameraMatrices.Projection = Matrix::CreatePerspectiveFieldOfView(80.0f * RADIAN,
g_Renderer->ScreenWidth / (float)g_Renderer->ScreenHeight, 1.0f, 200000.0f).Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
2019-12-02 09:11:21 +01:00
for (int k = 0; k < NUM_INVENTORY_RINGS; k++)
2019-02-02 15:40:44 +01:00
{
InventoryRing* ring = g_Inventory->GetRing(k);
if (ring->draw == false || ring->numObjects == 0)
2019-02-02 15:40:44 +01:00
continue;
2019-12-02 09:11:21 +01:00
short numObjects = ring->numObjects;
2019-02-02 15:40:44 +01:00
float deltaAngle = 360.0f / numObjects;
2019-12-02 09:11:21 +01:00
int objectIndex = 0;
2019-02-02 15:40:44 +01:00
objectIndex = ring->currentObject;
// Yellow title
if (ring->focusState == INV_FOCUS_STATE_NONE && g_Inventory->GetType() != INV_TYPE_TITLE)
PrintString(400, 20, g_GameFlow->GetString(activeRing->titleStringIndex), PRINTSTRING_COLOR_YELLOW, PRINTSTRING_CENTER);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numObjects; i++)
2019-02-02 15:40:44 +01:00
{
2019-12-02 09:11:21 +01:00
short inventoryObject = ring->objects[objectIndex].inventoryObject;
short objectNumber = g_Inventory->GetInventoryObject(ring->objects[objectIndex].inventoryObject)->objectNumber;
//if (ring->focusState != INV_FOCUS_STATE_NONE && (k != g_Inventory->GetActiveRing() || inventoryObject != ring->objects[i].inventoryObject))
// continue;
2019-02-02 15:40:44 +01:00
// Calculate the inventory object position and rotation
float currentAngle = 0.0f;
2019-12-02 09:11:21 +01:00
short steps = -objectIndex + ring->currentObject;
2019-02-02 15:40:44 +01:00
if (steps < 0) steps += numObjects;
currentAngle = steps * deltaAngle;
currentAngle += ring->rotation;
2019-02-02 15:40:44 +01:00
if (ring->focusState == INV_FOCUS_STATE_NONE && k == g_Inventory->GetActiveRing())
{
if (objectIndex == ring->currentObject)
ring->objects[objectIndex].rotation += 45 * 360 / 30;
else if (ring->objects[objectIndex].rotation != 0)
ring->objects[objectIndex].rotation += 45 * 360 / 30;
}
else if (ring->focusState != INV_FOCUS_STATE_POPUP && ring->focusState != INV_FOCUS_STATE_POPOVER)
g_Inventory->GetRing(k)->objects[objectIndex].rotation = 0;
if (ring->objects[objectIndex].rotation > 65536.0f)
ring->objects[objectIndex].rotation = 0;
2019-12-02 09:11:21 +01:00
int x = ring->distance * cos(currentAngle * RADIAN);
int y = g_Inventory->GetRing(k)->y;
int z = ring->distance * sin(currentAngle * RADIAN);
2019-02-02 15:40:44 +01:00
// Prepare the object transform
Matrix scale = Matrix::CreateScale(ring->objects[objectIndex].scale, ring->objects[objectIndex].scale, ring->objects[objectIndex].scale);
Matrix translation = Matrix::CreateTranslation(x, y, z);
Matrix rotation = Matrix::CreateRotationY(TR_ANGLE_TO_RAD(ring->objects[objectIndex].rotation + 16384 + g_Inventory->GetInventoryObject(inventoryObject)->rotY));
2019-02-02 15:40:44 +01:00
Matrix transform = (scale * rotation) * translation;
2019-02-02 15:40:44 +01:00
OBJECT_INFO* obj = &Objects[objectNumber];
RendererObject* moveableObj = m_moveableObjects[objectNumber];
if (moveableObj == NULL)
continue;
2019-02-02 15:40:44 +01:00
// Build the object animation matrices
if (ring->focusState == INV_FOCUS_STATE_FOCUSED && obj->animIndex != -1 &&
objectIndex == ring->currentObject && k == g_Inventory->GetActiveRing())
{
2019-12-02 09:11:21 +01:00
short* framePtr[2];
int rate = 0;
2019-02-02 15:40:44 +01:00
getFrame(obj->animIndex, ring->frameIndex, framePtr, &rate);
updateAnimation(NULL, moveableObj, framePtr, 0, 1, 0xFFFFFFFF);
}
else
{
if (obj->animIndex != -1)
updateAnimation(NULL, moveableObj, &Anims[obj->animIndex].framePtr, 0, 1, 0xFFFFFFFF);
}
2019-12-02 09:11:21 +01:00
for (int n = 0; n < moveableObj->ObjectMeshes.size(); n++)
2019-02-02 15:40:44 +01:00
{
RendererMesh* mesh = moveableObj->ObjectMeshes[n];
2019-04-26 21:09:58 +02:00
// HACK: revolver and crossbow + lasersight
if (moveableObj->Id == ID_REVOLVER_ITEM && !g_LaraExtra.Weapons[WEAPON_REVOLVER].HasLasersight && n > 0)
break;
if (moveableObj->Id == ID_CROSSBOW_ITEM && !g_LaraExtra.Weapons[WEAPON_CROSSBOW].HasLasersight && n > 0)
break;
2019-02-02 15:40:44 +01:00
// Finish the world matrix
if (obj->animIndex != -1)
m_stItem.World = (moveableObj->AnimationTransforms[n] * transform).Transpose();
2019-02-02 15:40:44 +01:00
else
m_stItem.World = (moveableObj->BindPoseTransforms[n].Transpose() * transform).Transpose();
2019-02-02 15:40:44 +01:00
m_stItem.AmbientLight = Vector4(0.5f, 0.5f, 0.5f, 1.0f);
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
m_context->PSSetConstantBuffers(1, 1, &m_cbItem);
2019-12-02 09:11:21 +01:00
for (int m = 0; m < NUM_BUCKETS; m++)
2019-02-02 15:40:44 +01:00
{
RendererBucket* bucket = &mesh->Buckets[m];
if (bucket->NumVertices == 0)
continue;
if (m < 2)
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
else
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
m_stMisc.AlphaTest = (m < 2);
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
2019-02-02 15:40:44 +01:00
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
}
}
2019-12-02 09:11:21 +01:00
short inventoryItem = ring->objects[objectIndex].inventoryObject;
2019-02-02 15:40:44 +01:00
// Draw special stuff if needed
if (objectIndex == ring->currentObject && k == g_Inventory->GetActiveRing())
{
if (g_Inventory->GetActiveRing() == INV_RING_OPTIONS)
{
/* **************** PASSAPORT ************* */
if (inventoryItem == INV_OBJECT_PASSPORT && ring->focusState == INV_FOCUS_STATE_FOCUSED)
2019-02-02 15:40:44 +01:00
{
/* **************** LOAD AND SAVE MENU ************* */
2019-02-02 15:40:44 +01:00
if (ring->passportAction == INV_WHAT_PASSPORT_LOAD_GAME || ring->passportAction == INV_WHAT_PASSPORT_SAVE_GAME)
{
y = 44;
2019-02-02 15:40:44 +01:00
2019-12-02 09:11:21 +01:00
for (int n = 0; n < MAX_SAVEGAMES; n++)
2019-02-02 15:40:44 +01:00
{
if (!g_NewSavegameInfos[n].Present)
PrintString(400, y, g_GameFlow->GetString(45), D3DCOLOR_ARGB(255, 255, 255, 255),
2019-02-02 15:40:44 +01:00
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == n ? PRINTSTRING_BLINK : 0));
else
{
sprintf(stringBuffer, "%05d", g_NewSavegameInfos[n].Count);
PrintString(200, y, stringBuffer, D3DCOLOR_ARGB(255, 255, 255, 255), PRINTSTRING_OUTLINE |
2019-02-02 15:40:44 +01:00
(ring->selectedIndex == n ? PRINTSTRING_BLINK | PRINTSTRING_DONT_UPDATE_BLINK : 0));
PrintString(250, y, (char*)g_NewSavegameInfos[n].LevelName.c_str(), D3DCOLOR_ARGB(255, 255, 255, 255), PRINTSTRING_OUTLINE |
2019-02-02 15:40:44 +01:00
(ring->selectedIndex == n ? PRINTSTRING_BLINK | PRINTSTRING_DONT_UPDATE_BLINK : 0));
sprintf(stringBuffer, g_GameFlow->GetString(44), g_NewSavegameInfos[n].Days, g_NewSavegameInfos[n].Hours, g_NewSavegameInfos[n].Minutes, g_NewSavegameInfos[n].Seconds);
PrintString(475, y, stringBuffer, D3DCOLOR_ARGB(255, 255, 255, 255),
2019-02-02 15:40:44 +01:00
PRINTSTRING_OUTLINE | (ring->selectedIndex == n ? PRINTSTRING_BLINK : 0));
}
y += 24;
2019-02-02 15:40:44 +01:00
}
drawLogo = false;
drawGuiRect = true;
guiRect.left = 180;
guiRect.right = 440;
guiRect.top = 24;
guiRect.bottom = y + 20 - 24;
//drawColoredQuad(180, 24, 440, y + 20 - 24, Vector4(0.0f, 0.0f, 0.25f, 0.5f));
2019-02-02 15:40:44 +01:00
}
/* **************** SELECT LEVEL ************* */
2019-02-02 15:40:44 +01:00
else if (ring->passportAction == INV_WHAT_PASSPORT_SELECT_LEVEL)
{
drawLogo = false;
drawGuiRect = true;
guiRect.left = 200;
guiRect.right = 400;
guiRect.top = 24;
guiRect.bottom = 24 * (g_GameFlow->GetNumLevels() - 1) + 40;
//drawColoredQuad(200, 24, 400, 24 * (g_GameFlow->GetNumLevels() - 1) + 40, Vector4(0.0f, 0.0f, 0.25f, 0.5f));
2019-12-02 09:11:21 +01:00
short lastY = 50;
2019-02-02 15:40:44 +01:00
2019-12-02 09:11:21 +01:00
for (int n = 1; n < g_GameFlow->GetNumLevels(); n++)
2019-02-02 15:40:44 +01:00
{
GameScriptLevel* levelScript = g_GameFlow->GetLevel(n);
PrintString(400, lastY, g_GameFlow->GetString(levelScript->NameStringIndex), D3DCOLOR_ARGB(255, 255, 255, 255),
2019-02-02 15:40:44 +01:00
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == n - 1 ? PRINTSTRING_BLINK : 0));
lastY += 24;
}
}
char* string = (char*)"";
switch (ring->passportAction)
{
case INV_WHAT_PASSPORT_NEW_GAME:
string = g_GameFlow->GetString(STRING_NEW_GAME);
2019-02-02 15:40:44 +01:00
break;
case INV_WHAT_PASSPORT_SELECT_LEVEL:
string = g_GameFlow->GetString(STRING_SELECT_LEVEL);
2019-02-02 15:40:44 +01:00
break;
case INV_WHAT_PASSPORT_LOAD_GAME:
string = g_GameFlow->GetString(STRING_LOAD_GAME);
2019-02-02 15:40:44 +01:00
break;
case INV_WHAT_PASSPORT_SAVE_GAME:
string = g_GameFlow->GetString(STRING_SAVE_GAME);
2019-02-02 15:40:44 +01:00
break;
case INV_WHAT_PASSPORT_EXIT_GAME:
string = g_GameFlow->GetString(STRING_EXIT_GAME);
2019-02-02 15:40:44 +01:00
break;
case INV_WHAT_PASSPORT_EXIT_TO_TITLE:
string = g_GameFlow->GetString(STRING_EXIT_TO_TITLE);
2019-02-02 15:40:44 +01:00
break;
}
PrintString(400, 550, string, PRINTSTRING_COLOR_ORANGE, PRINTSTRING_CENTER | PRINTSTRING_OUTLINE);
}
/* **************** GRAPHICS SETTINGS ************* */
2019-02-02 15:40:44 +01:00
else if (inventoryItem == INV_OBJECT_SUNGLASSES && ring->focusState == INV_FOCUS_STATE_FOCUSED)
{
// Draw settings menu
RendererVideoAdapter* adapter = &m_adapters[g_Configuration.Adapter];
2019-12-02 09:11:21 +01:00
int y = 200;
2019-02-02 15:40:44 +01:00
PrintString(400, y, g_GameFlow->GetString(STRING_DISPLAY),
PRINTSTRING_COLOR_YELLOW, PRINTSTRING_OUTLINE | PRINTSTRING_CENTER);
y += 25;
2019-02-02 15:40:44 +01:00
// Screen resolution
PrintString(200, y, g_GameFlow->GetString(STRING_SCREEN_RESOLUTION),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 0 ? PRINTSTRING_BLINK : 0));
RendererDisplayMode* mode = &adapter->DisplayModes[ring->SelectedVideoMode];
char buffer[255];
ZeroMemory(buffer, 255);
sprintf(buffer, "%d x %d (%d Hz)", mode->Width, mode->Height, mode->RefreshRate);
PrintString(400, y, buffer, PRINTSTRING_COLOR_WHITE,
2019-02-02 15:40:44 +01:00
PRINTSTRING_OUTLINE | (ring->selectedIndex == 0 ? PRINTSTRING_BLINK : 0));
y += 25;
// Windowed mode
PrintString(200, y, g_GameFlow->GetString(STRING_WINDOWED),
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 1 ? PRINTSTRING_BLINK : 0));
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.Windowed ? STRING_ENABLED : STRING_DISABLED),
PRINTSTRING_COLOR_WHITE,
PRINTSTRING_OUTLINE | (ring->selectedIndex == 1 ? PRINTSTRING_BLINK : 0));
y += 25;
2019-02-02 15:40:44 +01:00
// Enable dynamic shadows
PrintString(200, y, g_GameFlow->GetString(STRING_SHADOWS),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 2 ? PRINTSTRING_BLINK : 0));
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.EnableShadows ? STRING_ENABLED : STRING_DISABLED),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_WHITE,
PRINTSTRING_OUTLINE | (ring->selectedIndex == 2 ? PRINTSTRING_BLINK : 0));
2019-02-02 15:40:44 +01:00
y += 25;
2019-02-02 15:40:44 +01:00
// Enable caustics
PrintString(200, y, g_GameFlow->GetString(STRING_CAUSTICS),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 3 ? PRINTSTRING_BLINK : 0));
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.EnableCaustics ? STRING_ENABLED : STRING_DISABLED),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_WHITE,
PRINTSTRING_OUTLINE | (ring->selectedIndex == 3 ? PRINTSTRING_BLINK : 0));
2019-02-02 15:40:44 +01:00
y += 25;
2019-02-02 15:40:44 +01:00
// Enable volumetric fog
PrintString(200, y, g_GameFlow->GetString(STRING_VOLUMETRIC_FOG),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 4 ? PRINTSTRING_BLINK : 0));
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.EnableVolumetricFog ? STRING_ENABLED : STRING_DISABLED),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_WHITE,
PRINTSTRING_OUTLINE | (ring->selectedIndex == 4 ? PRINTSTRING_BLINK : 0));
2019-02-02 15:40:44 +01:00
y += 25;
2019-02-02 15:40:44 +01:00
// Apply and cancel
PrintString(400, y, g_GameFlow->GetString(STRING_APPLY),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == 5 ? PRINTSTRING_BLINK : 0));
y += 25;
PrintString(400, y, g_GameFlow->GetString(STRING_CANCEL),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == 6 ? PRINTSTRING_BLINK : 0));
y += 25;
drawLogo = false;
drawGuiRect = true;
guiRect.left = 180;
guiRect.right = 440;
guiRect.top = 180;
guiRect.bottom = y + 20 - 180;
//drawColoredQuad(180, 180, 440, y + 20 - 180, Vector4(0.0f, 0.0f, 0.25f, 0.5f));
2019-02-02 15:40:44 +01:00
}
/* **************** AUDIO SETTINGS ************* */
2019-02-02 15:40:44 +01:00
else if (inventoryItem == INV_OBJECT_HEADPHONES && ring->focusState == INV_FOCUS_STATE_FOCUSED)
{
// Draw sound menu
y = 200;
PrintString(400, y, g_GameFlow->GetString(STRING_SOUND),
PRINTSTRING_COLOR_YELLOW, PRINTSTRING_OUTLINE | PRINTSTRING_CENTER);
y += 25;
2019-02-02 15:40:44 +01:00
// Enable sound
PrintString(200, y, g_GameFlow->GetString(STRING_ENABLE_SOUND),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 0 ? PRINTSTRING_BLINK : 0));
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.EnableSound ? STRING_ENABLED : STRING_DISABLED),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_WHITE,
PRINTSTRING_OUTLINE | (ring->selectedIndex == 0 ? PRINTSTRING_BLINK : 0));
y += 25;
2019-02-02 15:40:44 +01:00
// Enable sound special effects
PrintString(200, y, g_GameFlow->GetString(STRING_SPECIAL_SOUND_FX),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 1 ? PRINTSTRING_BLINK : 0));
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.EnableAudioSpecialEffects ? STRING_ENABLED : STRING_DISABLED),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_WHITE,
PRINTSTRING_OUTLINE | (ring->selectedIndex == 1 ? PRINTSTRING_BLINK : 0));
y += 25;
2019-02-02 15:40:44 +01:00
// Music volume
PrintString(200, y, g_GameFlow->GetString(STRING_MUSIC_VOLUME),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_OUTLINE | (ring->selectedIndex == 2 ? PRINTSTRING_BLINK : 0));
DrawBar(400, y + 4, 150, 18, ring->Configuration.MusicVolume, 0x0000FF, 0x0000FF);
y += 25;
2019-02-02 15:40:44 +01:00
// Sound FX volume
PrintString(200, y, g_GameFlow->GetString(STRING_SFX_VOLUME),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_OUTLINE | (ring->selectedIndex == 3 ? PRINTSTRING_BLINK : 0));
DrawBar(400, y + 4, 150, 18, ring->Configuration.SfxVolume, 0x0000FF, 0x0000FF);
y += 25;
2019-02-02 15:40:44 +01:00
// Apply and cancel
PrintString(400, y, g_GameFlow->GetString(STRING_APPLY),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == 4 ? PRINTSTRING_BLINK : 0));
y += 25;
PrintString(400, y, g_GameFlow->GetString(STRING_CANCEL),
2019-02-02 15:40:44 +01:00
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == 5 ? PRINTSTRING_BLINK : 0));
y += 25;
drawLogo = false;
drawGuiRect = true;
guiRect.left = 180;
guiRect.right = 440;
guiRect.top = 180;
guiRect.bottom = y + 20 - 180;
//drawColoredQuad(180, 180, 440, y + 20 - 180, Vector4(0.0f, 0.0f, 0.25f, 0.5f));
2019-02-02 15:40:44 +01:00
}
/* **************** CONTROLS SETTINGS ************* */
else if (inventoryItem == INV_OBJECT_KEYS && ring->focusState == INV_FOCUS_STATE_FOCUSED)
{
// Draw sound menu
2019-05-11 09:26:39 +02:00
y = 40;
PrintString(400, y, g_GameFlow->GetString(STRING_CONTROLS),
PRINTSTRING_COLOR_YELLOW, PRINTSTRING_OUTLINE | PRINTSTRING_CENTER);
y += 25;
2019-12-02 09:11:21 +01:00
for (int k = 0; k < 18; k++)
{
PrintString(200, y, g_GameFlow->GetString(STRING_CONTROLS_MOVE_FORWARD + k),
PRINTSTRING_COLOR_WHITE,
PRINTSTRING_OUTLINE | (ring->selectedIndex == k ? PRINTSTRING_BLINK : 0) |
(ring->waitingForKey ? PRINTSTRING_DONT_UPDATE_BLINK : 0));
if (ring->waitingForKey && k == ring->selectedIndex)
{
PrintString(400, y, g_GameFlow->GetString(STRING_WAITING_FOR_KEY),
PRINTSTRING_COLOR_YELLOW,
PRINTSTRING_OUTLINE | PRINTSTRING_BLINK);
}
else
{
2019-12-15 16:19:01 +01:00
PrintString(400, y, (char*)g_KeyNames[KeyboardLayout1[k]],
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_OUTLINE);
}
y += 25;
}
// Apply and cancel
PrintString(400, y, g_GameFlow->GetString(STRING_APPLY),
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == NUM_CONTROLS + 0 ? PRINTSTRING_BLINK : 0));
y += 25;
PrintString(400, y, g_GameFlow->GetString(STRING_CANCEL),
PRINTSTRING_COLOR_ORANGE,
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == NUM_CONTROLS + 1 ? PRINTSTRING_BLINK : 0));
y += 25;
2019-05-11 09:26:39 +02:00
drawLogo = false;
drawGuiRect = true;
guiRect.left = 180;
guiRect.right = 440;
guiRect.top = 20;
guiRect.bottom = y + 20 - 20;
//drawColoredQuad(180, 20, 440, y + 20 - 20, Vector4(0.0f, 0.0f, 0.25f, 0.5f));
}
2019-02-02 15:40:44 +01:00
else
{
// Draw the description below the object
char* string = g_GameFlow->GetString(g_Inventory->GetInventoryObject(inventoryItem)->objectName); // (char*)g_NewStrings[g_Inventory->GetInventoryObject(inventoryItem)->objectName].c_str(); // &AllStrings[AllStringsOffsets[g_Inventory->GetInventoryObject(inventoryItem)->objectName]];
PrintString(400, 550, string, PRINTSTRING_COLOR_ORANGE, PRINTSTRING_CENTER | PRINTSTRING_OUTLINE);
}
}
else
{
2019-12-02 09:11:21 +01:00
short inventoryItem = g_Inventory->GetRing(k)->objects[objectIndex].inventoryObject;
2019-02-02 15:40:44 +01:00
char* string = g_GameFlow->GetString(g_Inventory->GetInventoryObject(inventoryItem)->objectName); // &AllStrings[AllStringsOffsets[InventoryObjectsList[inventoryItem].objectName]];
if (g_Inventory->IsCurrentObjectWeapon() && ring->focusState == INV_FOCUS_STATE_FOCUSED)
{
y = 100;
2019-12-02 09:11:21 +01:00
for (int a = 0; a < ring->numActions; a++)
{
2019-12-02 09:11:21 +01:00
int stringIndex = 0;
if (ring->actions[a] == INV_ACTION_USE) stringIndex = STRING_USE;
if (ring->actions[a] == INV_ACTION_COMBINE) stringIndex = STRING_COMBINE;
if (ring->actions[a] == INV_ACTION_SEPARE) stringIndex = STRING_SEPARE;
if (ring->actions[a] == INV_ACTION_SELECT_AMMO) stringIndex = STRING_CHOOSE_AMMO;
// Apply and cancel
PrintString(400, y, g_GameFlow->GetString(stringIndex),
PRINTSTRING_COLOR_WHITE,
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == a ? PRINTSTRING_BLINK : 0));
y += 25;
}
drawLogo = false;
drawGuiRect = true;
guiRect.left = 300;
guiRect.right = 200;
guiRect.top = 80;
guiRect.bottom = y + 20 - 80;
//drawColoredQuad(300, 80, 200, y + 20 - 80, Vector4(0.0f, 0.0f, 0.25f, 0.5f));
}
2019-12-02 09:11:21 +01:00
int quantity = -1;
2019-02-02 15:40:44 +01:00
switch (objectNumber)
{
case ID_BIGMEDI_ITEM:
quantity = Lara.numLargeMedipack;
break;
case ID_SMALLMEDI_ITEM:
quantity = Lara.numSmallMedipack;
break;
case ID_FLARE_INV_ITEM:
quantity = Lara.numFlares;
break;
case ID_SHOTGUN_AMMO1_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_SHOTGUN].Ammo[0];
2019-02-02 15:40:44 +01:00
if (quantity != -1)
quantity /= 6;
break;
case ID_SHOTGUN_AMMO2_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_SHOTGUN].Ammo[1];
2019-02-02 15:40:44 +01:00
if (quantity != -1)
quantity /= 6;
break;
case ID_HK_AMMO_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_HK].Ammo[0];
2019-02-02 15:40:44 +01:00
break;
case ID_CROSSBOW_AMMO1_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_CROSSBOW].Ammo[0];
2019-02-02 15:40:44 +01:00
break;
case ID_CROSSBOW_AMMO2_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_CROSSBOW].Ammo[1];
break;
case ID_CROSSBOW_AMMO3_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_CROSSBOW].Ammo[2];
2019-02-02 15:40:44 +01:00
break;
case ID_REVOLVER_AMMO_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_REVOLVER].Ammo[0];
2019-02-02 15:40:44 +01:00
break;
case ID_UZI_AMMO_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_UZI].Ammo[0];
break;
case ID_PISTOLS_AMMO_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_PISTOLS].Ammo[0];
break;
case ID_GRENADE_AMMO1_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_GRENADE_LAUNCHER].Ammo[0];
break;
case ID_GRENADE_AMMO2_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_GRENADE_LAUNCHER].Ammo[1];
break;
case ID_GRENADE_AMMO3_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_GRENADE_LAUNCHER].Ammo[2];
break;
case ID_HARPOON_AMMO_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_HARPOON_GUN].Ammo[0];
break;
case ID_ROCKET_LAUNCHER_AMMO_ITEM:
quantity = g_LaraExtra.Weapons[WEAPON_ROCKET_LAUNCHER].Ammo[0];
2019-02-02 15:40:44 +01:00
break;
case ID_PICKUP_ITEM4:
quantity = Savegame.Level.Secrets;
break;
default:
if (objectNumber >= ID_PUZZLE_ITEM1 && objectNumber <= ID_PUZZLE_ITEM8)
quantity = Lara.puzzleItems[objectNumber - ID_PUZZLE_ITEM1];
else if (objectNumber >= ID_PUZZLE_ITEM1_COMBO1 && objectNumber <= ID_PUZZLE_ITEM8_COMBO2)
quantity = (Lara.puzzleItemsCombo >> (objectNumber - ID_PUZZLE_ITEM1_COMBO1)) & 1;
else if (objectNumber >= ID_KEY_ITEM1 && objectNumber <= ID_KEY_ITEM8)
quantity = (Lara.keyItems >> (objectNumber - ID_KEY_ITEM1)) & 1;
else if (objectNumber >= ID_KEY_ITEM1_COMBO1 && objectNumber <= ID_KEY_ITEM8_COMBO2)
quantity = (Lara.keyItemsCombo >> (objectNumber - ID_KEY_ITEM1_COMBO1)) & 1;
else if (objectNumber >= ID_PICKUP_ITEM1 && objectNumber <= ID_PICKUP_ITEM3)
quantity = (Lara.pickupItems >> (objectNumber - ID_PICKUP_ITEM1)) & 1;
else if (objectNumber >= ID_PICKUP_ITEM1_COMBO1 && objectNumber <= ID_PICKUP_ITEM3_COMBO2)
quantity = (Lara.pickupItemsCombo >> (objectNumber - ID_PICKUP_ITEM1_COMBO1)) & 1;
else if (objectNumber == ID_EXAMINE1)
quantity = Lara.examine1;
else if (objectNumber == ID_EXAMINE2)
quantity = Lara.examine2;
else if (objectNumber == ID_EXAMINE3)
quantity = Lara.examine3;
}
if (quantity < 1)
PrintString(400, 550, string, D3DCOLOR_ARGB(255, 216, 117, 49), PRINTSTRING_CENTER);
else
{
sprintf(stringBuffer, "%d x %s", quantity, string);
PrintString(400, 550, stringBuffer, D3DCOLOR_ARGB(255, 216, 117, 49), PRINTSTRING_CENTER);
}
}
}
objectIndex++;
if (objectIndex == numObjects) objectIndex = 0;
}
lastRing++;
}
if (drawGuiRect)
{
// Draw blu box
drawColoredQuad(guiRect.left, guiRect.top, guiRect.right, guiRect.bottom, guiColor);
}
drawLines2D();
2019-02-02 15:40:44 +01:00
drawAllStrings();
if (g_Inventory->GetType() == INV_TYPE_TITLE && g_GameFlow->TitleType == TITLE_FLYBY && drawLogo)
{
// Draw main logo
float factorX = ScreenWidth / 800.0f;
float factorY = ScreenHeight / 600.0f;
RECT rect;
rect.left = 250 * factorX;
rect.right = 550 * factorX;
rect.top = 50 * factorY;
rect.bottom = 200 * factorY;
m_spriteBatch->Begin(SpriteSortMode_BackToFront, m_states->Additive());
m_spriteBatch->Draw(m_logo->ShaderResourceView, rect, Vector4::One);
m_spriteBatch->End();
}
2019-02-02 15:40:44 +01:00
return 0;
}
2019-12-02 09:11:21 +01:00
bool Renderer11::drawColoredQuad(int x, int y, int w, int h, Vector4 color)
{
float factorW = ScreenWidth / 800.0f;
float factorH = ScreenHeight / 600.0f;
RECT rect;
rect.top = y * factorH;
rect.left = x * factorW;
rect.bottom = (y + h) * factorH;
rect.right = (x + w) * factorW;
m_spriteBatch->Begin(SpriteSortMode_BackToFront, m_states->AlphaBlend(), NULL, m_states->DepthRead());
m_spriteBatch->Draw(m_whiteTexture->ShaderResourceView, rect, color);
m_spriteBatch->End();
int shiftW = 4 * factorW;
int shiftH = 4 * factorH;
AddLine2D(rect.left + shiftW, rect.top + shiftH, rect.right - shiftW, rect.top + shiftH, 128, 128, 128, 128);
AddLine2D(rect.right - shiftW, rect.top + shiftH, rect.right - shiftW, rect.bottom - shiftH, 128, 128, 128, 128);
AddLine2D(rect.left + shiftW, rect.bottom - shiftH, rect.right - shiftW, rect.bottom - shiftH, 128, 128, 128, 128);
AddLine2D(rect.left + shiftW, rect.top + shiftH, rect.left + shiftW, rect.bottom - shiftH, 128, 128, 128, 128);
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
return true;
}
2019-03-20 00:05:00 +01:00
bool Renderer11::drawFullScreenQuad(ID3D11ShaderResourceView* texture, Vector3 color, bool cinematicBars)
{
RendererVertex vertices[4];
2019-03-20 00:05:00 +01:00
if (!cinematicBars)
{
vertices[0].Position.x = -1.0f;
vertices[0].Position.y = 1.0f;
vertices[0].Position.z = 0.0f;
vertices[0].UV.x = 0.0f;
vertices[0].UV.y = 0.0f;
vertices[0].Color = Vector4(color.x, color.y, color.z, 1.0f);
vertices[1].Position.x = 1.0f;
vertices[1].Position.y = 1.0f;
vertices[1].Position.z = 0.0f;
vertices[1].UV.x = 1.0f;
vertices[1].UV.y = 0.0f;
vertices[1].Color = Vector4(color.x, color.y, color.z, 1.0f);
vertices[2].Position.x = 1.0f;
vertices[2].Position.y = -1.0f;
vertices[2].Position.z = 0.0f;
vertices[2].UV.x = 1.0f;
vertices[2].UV.y = 1.0f;
vertices[2].Color = Vector4(color.x, color.y, color.z, 1.0f);
vertices[3].Position.x = -1.0f;
vertices[3].Position.y = -1.0f;
vertices[3].Position.z = 0.0f;
vertices[3].UV.x = 0.0f;
vertices[3].UV.y = 1.0f;
vertices[3].Color = Vector4(color.x, color.y, color.z, 1.0f);
}
else
{
float cinematicFactor = 0.12f;
vertices[0].Position.x = -1.0f;
vertices[0].Position.y = 1.0f - cinematicFactor * 2;
vertices[0].Position.z = 0.0f;
vertices[0].UV.x = 0.0f;
vertices[0].UV.y = cinematicFactor;
vertices[0].Color = Vector4(color.x, color.y, color.z, 1.0f);
vertices[1].Position.x = 1.0f;
vertices[1].Position.y = 1.0f - cinematicFactor * 2;
vertices[1].Position.z = 0.0f;
vertices[1].UV.x = 1.0f;
vertices[1].UV.y = cinematicFactor;
vertices[1].Color = Vector4(color.x, color.y, color.z, 1.0f);
vertices[2].Position.x = 1.0f;
vertices[2].Position.y = -(1.0f - cinematicFactor * 2);
vertices[2].Position.z = 0.0f;
vertices[2].UV.x = 1.0f;
vertices[2].UV.y = 1.0f - cinematicFactor;
vertices[2].Color = Vector4(color.x, color.y, color.z, 1.0f);
vertices[3].Position.x = -1.0f;
vertices[3].Position.y = -(1.0f - cinematicFactor * 2);
vertices[3].Position.z = 0.0f;
vertices[3].UV.x = 0.0f;
vertices[3].UV.y = 1.0f - cinematicFactor;
vertices[3].Color = Vector4(color.x, color.y, color.z, 1.0f);
}
m_context->VSSetShader(m_vsFullScreenQuad, NULL, 0);
m_context->PSSetShader(m_psFullScreenQuad, NULL, 0);
m_context->PSSetShaderResources(0, 1, &texture);
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_primitiveBatch->Begin();
m_primitiveBatch->DrawQuad(vertices[0], vertices[1], vertices[2], vertices[3]);
m_primitiveBatch->End();
return true;
}
bool Renderer11::drawRopes()
{
2019-12-02 09:11:21 +01:00
for (int n = 0; n < NumRopes; n++)
{
ROPE_STRUCT* rope = &Ropes[n];
if (rope->active)
{
// Original algorithm:
// 1) Transform segment coordinates from 3D to 2D + depth
// 2) Get dx, dy and the segment length
// 3) Get sine and cosine from dx / length and dy / length
// 4) Calculate a scale factor
// 5) Get the coordinates of the 4 corners of each sprite iteratively
// 6) Last step only for us, unproject back to 3D coordinates
// Tranform rope points
Vector3 projected[24];
Matrix world = Matrix::Identity;
2019-12-02 09:11:21 +01:00
for (int i = 0; i < 24; i++)
{
Vector3 absolutePosition = Vector3(rope->position.x + rope->segment[i].x / 65536.0f,
rope->position.y + rope->segment[i].y / 65536.0f,
rope->position.z + rope->segment[i].z / 65536.0f);
projected[i] = m_viewportToolkit->Project(absolutePosition, Projection, View, world);
}
// Now each rope point is transformed in screen X, Y and Z depth
// Let's calculate dx, dy corrections and scaling
float dx = projected[1].x - projected[0].x;
float dy = projected[1].y - projected[0].y;
float length = sqrt(dx * dx + dy * dy);
float s = 0;
float c = 0;
if (length != 0)
{
s = -dy / length;
c = dx / length;
}
float w = 6.0f;
if (projected[0].z)
{
w = 6.0f * PhdPerspective / projected[0].z / 65536.0f;
if (w < 3)
w = 3;
}
float sdx = s * w;
float sdy = c * w;
float x1 = projected[0].x - sdx;
float y1 = projected[0].y - sdy;
float x2 = projected[0].x + sdx;
float y2 = projected[0].y + sdy;
float depth = projected[0].z;
2019-12-02 09:11:21 +01:00
for (int j = 0; j < 24; j++)
{
Vector3 p1 = m_viewportToolkit->Unproject(Vector3(x1, y1, depth), Projection, View, world);
Vector3 p2 = m_viewportToolkit->Unproject(Vector3(x2, y2, depth), Projection, View, world);
dx = projected[j].x - projected[j - 1].x;
dy = projected[j].y - projected[j - 1].y;
length = sqrt(dx * dx + dy * dy);
s = 0;
c = 0;
if (length != 0)
{
s = -dy / length;
c = dx / length;
}
w = 6.0f;
if (projected[j].z)
{
w = 6.0f * PhdPerspective / projected[j].z / 65536.0f;
if (w < 3)
w = 3;
}
float sdx = s * w;
float sdy = c * w;
float x3 = projected[j].x - sdx;
float y3 = projected[j].y - sdy;
float x4 = projected[j].x + sdx;
float y4 = projected[j].y + sdy;
depth = projected[j].z;
Vector3 p3 = m_viewportToolkit->Unproject(Vector3(x3, y3, depth), Projection, View, world);
Vector3 p4 = m_viewportToolkit->Unproject(Vector3(x4, y4, depth), Projection, View, world);
AddSprite3D(m_sprites[20],
Vector3(p1.x, p1.y, p1.z),
Vector3(p2.x, p2.y, p2.z),
Vector3(p3.x, p3.y, p3.z),
Vector3(p4.x, p4.y, p4.z),
Vector4(0.5f, 0.5f, 0.5f,1.0f), 0, 1, 0, 0, BLENDMODE_OPAQUE);
x1 = x4;
y1 = y4;
x2 = x3;
y2 = y3;
}
}
}
return true;
}
bool Renderer11::drawLines2D()
{
m_context->RSSetState(m_states->CullNone());
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->OMSetDepthStencilState(m_states->DepthRead(), 0);
m_context->VSSetShader(m_vsSolid, NULL, 0);
m_context->PSSetShader(m_psSolid, NULL, 0);
Matrix world = Matrix::CreateOrthographicOffCenter(0, ScreenWidth, ScreenHeight, 0, m_viewport.MinDepth, m_viewport.MaxDepth);
m_stCameraMatrices.View = Matrix::Identity;
m_stCameraMatrices.Projection = Matrix::Identity;
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
m_context->IASetInputLayout(m_inputLayout);
m_primitiveBatch->Begin();
2019-12-02 09:11:21 +01:00
for (int i = 0; i < m_lines2DToDraw.Size(); i++)
{
RendererLine2D* line = m_lines2DToDraw[i];
RendererVertex v1;
v1.Position.x = line->Vertices[0].x;
v1.Position.y = line->Vertices[0].y;
v1.Position.z = 1.0f;
v1.Color.x = line->Color.x / 255.0f;
v1.Color.y = line->Color.y / 255.0f;
v1.Color.z = line->Color.z / 255.0f;
v1.Color.w = line->Color.w / 255.0f;
RendererVertex v2;
v2.Position.x = line->Vertices[1].x;
v2.Position.y = line->Vertices[1].y;
v2.Position.z = 1.0f;
v2.Color.x = line->Color.x / 255.0f;
v2.Color.y = line->Color.y / 255.0f;
v2.Color.z = line->Color.z / 255.0f;
v2.Color.w = line->Color.w / 255.0f;
v1.Position = Vector3::Transform(v1.Position, world);
v2.Position = Vector3::Transform(v2.Position, world);
v1.Position.z = 0.5f;
v2.Position.z = 0.5f;
m_primitiveBatch->DrawLine(v1, v2);
}
m_primitiveBatch->End();
m_context->RSSetState(m_states->CullCounterClockwise());
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
return true;
}
bool Renderer11::drawOverlays()
{
if (!BinocularRange && !SpotcamOverlay)
return true;
m_context->OMSetBlendState(m_states->AlphaBlend(), NULL, 0xFFFFFFFF);
2019-03-20 00:05:00 +01:00
drawFullScreenQuad(m_binocularsTexture->ShaderResourceView, Vector3::One, false);
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
return true;
}
bool Renderer11::DrawBar(int x, int y, int w, int h, int percent, int color1, int color2)
{
byte r1 = (color1 >> 16) & 0xFF;
byte g1 = (color1 >> 8) & 0xFF;
byte b1 = (color1 >> 0) & 0xFF;
byte r2 = (color2 >> 16) & 0xFF;
byte g2 = (color2 >> 8) & 0xFF;
byte b2 = (color2 >> 0) & 0xFF;
float factorX = ScreenWidth / 800.0f;
float factorY = ScreenHeight / 600.0f;
2019-12-02 09:11:21 +01:00
int realX = x * factorX;
int realY = y * factorY;
int realW = w * factorX;
int realH = h * factorY;
2019-12-02 09:11:21 +01:00
int realPercent = percent / 100.0f * realW;
2019-12-02 09:11:21 +01:00
for (int i = 0; i < realH; i++)
AddLine2D(realX, realY + i, realX + realW, realY + i, 0, 0, 0, 255);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < realH; i++)
AddLine2D(realX, realY + i, realX + realPercent, realY + i, r1, g1, b1, 255);
AddLine2D(realX, realY, realX + realW, realY, 255, 255, 255, 255);
AddLine2D(realX, realY + realH, realX + realW, realY + realH, 255, 255, 255, 255);
AddLine2D(realX, realY, realX, realY + realH, 255, 255, 255, 255);
AddLine2D(realX + realW, realY, realX + realW, realY + realH + 1, 255, 255, 255, 255);
return true;
}
void Renderer11::drawFootprints()
{
for (auto i = footprints.begin(); i != footprints.end();i++) {
FOOTPRINT_STRUCT& footprint = *i;
if (footprint.active) {
float y = footprint.pos.yPos;
Matrix rot = Matrix::CreateRotationY(TR_ANGLE_TO_RAD(footprint.pos.yRot) + PI);
Vector3 p1 = Vector3(-64, 0, -64);
Vector3 p2 = Vector3(64, 0, -64);
Vector3 p3 = Vector3(64, 0, 64);
Vector3 p4 = Vector3(-64, 0, 64);
p1 = XMVector3Transform(p1, rot);
p2 = XMVector3Transform(p2, rot);
p3 = XMVector3Transform(p3, rot);
p4 = XMVector3Transform(p4, rot);
p1 += Vector3(footprint.pos.xPos, footprint.pos.yPos, footprint.pos.zPos);
p2 += Vector3(footprint.pos.xPos, footprint.pos.yPos, footprint.pos.zPos);
p3 += Vector3(footprint.pos.xPos, footprint.pos.yPos, footprint.pos.zPos);
p4 += Vector3(footprint.pos.xPos, footprint.pos.yPos, footprint.pos.zPos);
2020-01-07 16:19:54 +01:00
AddSprite3D(m_sprites[Objects[ID_MISC_SPRITES].meshIndex+1], p1,p2,p3,p4, Vector4(footprint.opacity / 255.0f, footprint.opacity / 255.0f, footprint.opacity / 255.0f, footprint.opacity / 255.0f),
0, 1, 1, 1, BLENDMODE_SUBTRACTIVE);
}
}
}
void Renderer11::AddLine2D(int x1, int y1, int x2, int y2, byte r, byte g, byte b, byte a)
{
RendererLine2D* line = &m_lines2DBuffer[m_nextLine2D++];
line->Vertices[0] = Vector2(x1, y1);
line->Vertices[1] = Vector2(x2, y2);
line->Color = Vector4(r, g, b, a);
m_lines2DToDraw.Add(line);
2019-03-17 23:45:00 +01:00
}
bool Renderer11::drawGunFlashes()
{
if (!Lara.rightArm.flash_gun && !Lara.leftArm.flash_gun)
return true;
Matrix world;
Matrix translation;
Matrix rotation;
RendererObject* laraObj = m_moveableObjects[ID_LARA];
RendererObject* laraSkin = m_moveableObjects[ID_LARA_SKIN];
OBJECT_INFO* obj = &Objects[0];
RendererRoom* room = m_rooms[LaraItem->roomNumber];
RendererItem* item = &m_items[Lara.itemNumber];
m_stItem.AmbientLight = room->AmbientLight;
memcpy(m_stItem.BonesMatrices, &Matrix::Identity, sizeof(Matrix));
m_stLights.NumLights = item->Lights.Size();
2019-12-02 09:11:21 +01:00
for (int j = 0; j < item->Lights.Size(); j++)
2019-03-17 23:45:00 +01:00
memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight));
updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer));
m_context->PSSetConstantBuffers(2, 1, &m_cbLights);
m_stMisc.AlphaTest = true;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
2019-12-02 09:11:21 +01:00
short length = 0;
short zOffset = 0;
short rotationX = 0;
2019-03-17 23:45:00 +01:00
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
m_context->OMSetDepthStencilState(m_states->DepthNone(), 0);
if (Lara.weaponItem != WEAPON_FLARE && Lara.weaponItem != WEAPON_SHOTGUN && Lara.weaponItem != WEAPON_CROSSBOW)
{
2019-12-15 16:19:01 +01:00
switch (Lara.weaponItem)
2019-03-17 23:45:00 +01:00
{
2019-12-15 16:19:01 +01:00
case WEAPON_REVOLVER:
2019-03-17 23:45:00 +01:00
length = 192;
zOffset = 68;
rotationX = -14560;
2019-12-15 16:19:01 +01:00
break;
case WEAPON_UZI:
2019-03-17 23:45:00 +01:00
length = 190;
zOffset = 50;
2019-12-15 16:19:01 +01:00
break;
case WEAPON_HK:
2019-03-17 23:45:00 +01:00
length = 300;
zOffset = 92;
rotationX = -14560;
2019-12-15 16:19:01 +01:00
break;
default:
2019-12-15 16:19:01 +01:00
case WEAPON_PISTOLS:
2019-03-17 23:45:00 +01:00
length = 180;
zOffset = 40;
rotationX = -16830;
2019-12-15 16:19:01 +01:00
break;
2019-03-17 23:45:00 +01:00
}
OBJECT_INFO* flashObj = &Objects[ID_GUN_FLASH];
RendererObject* flashMoveable = m_moveableObjects[ID_GUN_FLASH];
RendererMesh* flashMesh = flashMoveable->ObjectMeshes[0];
2019-12-02 09:11:21 +01:00
for (int b = 0; b < NUM_BUCKETS; b++)
2019-03-17 23:45:00 +01:00
{
RendererBucket* flashBucket = &flashMesh->Buckets[b];
if (flashBucket->NumVertices != 0)
{
Matrix offset = Matrix::CreateTranslation(0, length, zOffset);
Matrix rotation2 = Matrix::CreateRotationX(TR_ANGLE_TO_RAD(rotationX));
if (Lara.leftArm.flash_gun)
{
2019-12-15 16:19:01 +01:00
world = laraObj->AnimationTransforms[LM_LHAND].Transpose() * m_LaraWorldMatrix;
2019-03-17 23:45:00 +01:00
world = offset * world;
world = rotation2 * world;
m_stItem.World = world.Transpose();
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
m_context->DrawIndexed(flashBucket->NumIndices, flashBucket->StartIndex, 0);
m_numDrawCalls++;
}
if (Lara.rightArm.flash_gun)
{
2019-12-15 16:19:01 +01:00
world = laraObj->AnimationTransforms[LM_RHAND].Transpose() * m_LaraWorldMatrix;
2019-03-17 23:45:00 +01:00
world = offset * world;
world = rotation2 * world;
m_stItem.World = world.Transpose();
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
m_context->DrawIndexed(flashBucket->NumIndices, flashBucket->StartIndex, 0);
m_numDrawCalls++;
}
}
}
}
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
return true;
}
bool Renderer11::drawGunShells()
{
RendererRoom* room = m_rooms[LaraItem->roomNumber];
RendererItem* item = &m_items[Lara.itemNumber];
m_stItem.AmbientLight = room->AmbientLight;
memcpy(m_stItem.BonesMatrices, &Matrix::Identity, sizeof(Matrix));
m_stLights.NumLights = item->Lights.Size();
2019-12-02 09:11:21 +01:00
for (int j = 0; j < item->Lights.Size(); j++)
2019-03-17 23:45:00 +01:00
memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight));
updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer));
m_context->PSSetConstantBuffers(2, 1, &m_cbLights);
m_stMisc.AlphaTest = true;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < 24; i++)
2019-03-17 23:45:00 +01:00
{
GUNSHELL_STRUCT* gunshell = &Gunshells[i];
2019-03-17 23:45:00 +01:00
if (gunshell->counter > 0)
{
OBJECT_INFO* obj = &Objects[gunshell->objectNumber];
RendererObject* moveableObj = m_moveableObjects[gunshell->objectNumber];
Matrix translation = Matrix::CreateTranslation(gunshell->pos.xPos, gunshell->pos.yPos, gunshell->pos.zPos);
2019-12-15 16:19:01 +01:00
Matrix rotation = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(gunshell->pos.yRot), TR_ANGLE_TO_RAD(gunshell->pos.xRot), TR_ANGLE_TO_RAD(gunshell->pos.zRot));
2019-03-17 23:45:00 +01:00
Matrix world = rotation * translation;
m_stItem.World = world.Transpose();
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
RendererMesh* mesh = moveableObj->ObjectMeshes[0];
2019-12-02 09:11:21 +01:00
for (int b = 0; b < NUM_BUCKETS; b++)
2019-03-17 23:45:00 +01:00
{
RendererBucket* bucket = &mesh->Buckets[b];
if (bucket->NumVertices == 0)
continue;
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
}
}
return true;
2019-03-18 23:30:41 +01:00
}
void Renderer11::drawUnderwaterDust()
{
if (m_firstUnderwaterDustParticles)
{
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_UNDERWATER_DUST_PARTICLES; i++)
2019-03-18 23:30:41 +01:00
m_underwaterDustParticles[i].Reset = true;
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_UNDERWATER_DUST_PARTICLES; i++)
2019-03-18 23:30:41 +01:00
{
RendererUnderwaterDustParticle* dust = &m_underwaterDustParticles[i];
if (dust->Reset)
{
dust->X = LaraItem->pos.xPos + rand() % UNDERWATER_DUST_PARTICLES_RADIUS - UNDERWATER_DUST_PARTICLES_RADIUS / 2.0f;
dust->Y = LaraItem->pos.yPos + rand() % UNDERWATER_DUST_PARTICLES_RADIUS - UNDERWATER_DUST_PARTICLES_RADIUS / 2.0f;
dust->Z = LaraItem->pos.zPos + rand() % UNDERWATER_DUST_PARTICLES_RADIUS - UNDERWATER_DUST_PARTICLES_RADIUS / 2.0f;
// Check if water room
2019-12-02 09:11:21 +01:00
short roomNumber = Camera.pos.roomNumber;
2019-03-18 23:30:41 +01:00
FLOOR_INFO* floor = GetFloor(dust->X, dust->Y, dust->Z, &roomNumber);
if (!isRoomUnderwater(roomNumber))
continue;
if (!isInRoom(dust->X, dust->Y, dust->Z, roomNumber))
{
dust->Reset = true;
continue;
}
dust->Life = 0;
dust->Reset = false;
}
dust->Life++;
byte color = (dust->Life > 16 ? 32 - dust->Life : dust->Life) * 4;
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], Vector3(dust->X, dust->Y, dust->Z),Vector4( color/255.0f, color/255.0f, color/255.0f,1.0f), 0.0f, 1.0f, 12, 12, BLENDMODE_ALPHABLEND);
2019-03-18 23:30:41 +01:00
if (dust->Life >= 32)
dust->Reset = true;
}
m_firstUnderwaterDustParticles = false;
return;
}
2019-12-02 09:11:21 +01:00
bool Renderer11::isRoomUnderwater(short roomNumber)
2019-03-18 23:30:41 +01:00
{
2019-12-15 16:19:01 +01:00
return (m_rooms[roomNumber]->Room->flags & ENV_FLAG_WATER);
2019-03-18 23:30:41 +01:00
}
2019-12-02 09:11:21 +01:00
bool Renderer11::isInRoom(int x, int y, int z, short roomNumber)
2019-03-18 23:30:41 +01:00
{
RendererRoom* room = m_rooms[roomNumber];
ROOM_INFO* r = room->Room;
return (x >= r->x && x <= r->x + r->xSize * 1024.0f &&
2019-12-15 16:19:01 +01:00
y >= r->maxceiling && y <= r->minfloor &&
z >= r->z && z <= r->z + r->ySize * 1024.0f);
2019-03-18 23:30:41 +01:00
}
vector<RendererVideoAdapter>* Renderer11::GetAdapters()
{
return &m_adapters;
}
2019-12-02 09:11:21 +01:00
int Renderer11::DrawPickup(short objectNum)
{
drawObjectOn2DPosition(700 + PickupX, 450, objectNum, 0, m_pickupRotation, 0); // TODO: + PickupY
m_pickupRotation += 45 * 360 / 30;
return 0;
}
2019-12-02 09:11:21 +01:00
bool Renderer11::drawObjectOn2DPosition(short x, short y, short objectNum, short rotX, short rotY, short rotZ)
{
Matrix translation;
Matrix rotation;
Matrix world;
Matrix view;
Matrix projection;
Matrix scale;
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
x *= (ScreenWidth / 800.0f);
y *= (ScreenHeight / 600.0f);
view = Matrix::CreateLookAt(Vector3(0.0f, 0.0f, 2048.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, -1.0f, 0.0f));
projection = Matrix::CreateOrthographic(ScreenWidth, ScreenHeight, -1024.0f, 1024.0f);
OBJECT_INFO* obj = &Objects[objectNum];
RendererObject* moveableObj = m_moveableObjects[objectNum];
if (obj->animIndex != -1)
{
updateAnimation(NULL, moveableObj, &Anims[obj->animIndex].framePtr, 0, 0, 0xFFFFFFFF);
}
Vector3 pos = m_viewportToolkit->Unproject(Vector3(x, y, 1), projection, view, Matrix::Identity);
// Clear just the Z-buffer so we can start drawing on top of the scene
m_context->ClearDepthStencilView(m_currentRenderTarget->DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
// Set vertex buffer
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
// Set shaders
m_context->VSSetShader(m_vsInventory, NULL, 0);
m_context->PSSetShader(m_psInventory, NULL, 0);
// Set texture
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
// Set matrices
m_stCameraMatrices.View = view.Transpose();
m_stCameraMatrices.Projection = projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
2019-12-02 09:11:21 +01:00
for (int n = 0; n < moveableObj->ObjectMeshes.size(); n++)
{
RendererMesh* mesh = moveableObj->ObjectMeshes[n];
// Finish the world matrix
translation = Matrix::CreateTranslation(pos.x, pos.y, pos.z + 1024.0f);
rotation = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(rotY), TR_ANGLE_TO_RAD(rotX), TR_ANGLE_TO_RAD(rotZ));
scale = Matrix::CreateScale(0.5f);
world = scale * rotation;
world = world * translation;
if (obj->animIndex != -1)
m_stItem.World = (moveableObj->AnimationTransforms[n] * world).Transpose();
else
m_stItem.World = (moveableObj->BindPoseTransforms[n].Transpose() * world).Transpose();
m_stItem.AmbientLight = Vector4(0.5f, 0.5f, 0.5f, 1.0f);
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
m_context->PSSetConstantBuffers(1, 1, &m_cbItem);
2019-12-02 09:11:21 +01:00
for (int m = 0; m < NUM_BUCKETS; m++)
{
RendererBucket* bucket = &mesh->Buckets[m];
if (bucket->NumVertices == 0)
continue;
if (m < 2)
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
else
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
m_stMisc.AlphaTest = (m < 2);
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
}
}
return true;
}
bool Renderer11::drawShadowMap()
{
m_shadowLight = NULL;
RendererLight* brightestLight = NULL;
float brightest = 0.0f;
Vector3 itemPosition = Vector3(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos);
2019-12-02 09:11:21 +01:00
for (int k = 0; k < m_roomsToDraw.Size(); k++)
{
RendererRoom* room = m_roomsToDraw[k];
2019-12-02 09:11:21 +01:00
int numLights = room->Lights.size();
2019-12-02 09:11:21 +01:00
for (int j = 0; j < numLights; j++)
{
RendererLight* light = &room->Lights[j];
// Check only lights different from sun
if (light->Type == LIGHT_TYPE_SUN)
{
// Sun is added without checks
}
2020-01-03 06:48:15 +01:00
else if (light->Type == LIGHT_TYPE_POINT)
{
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
// Collect only lights nearer than 20 sectors
if (distance >= 20 * WALL_SIZE)
continue;
// Check the out radius
if (distance > light->Out)
continue;
float attenuation = 1.0f - distance / light->Out;
float intensity = max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
}
else if (light->Type == LIGHT_TYPE_SPOT)
{
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
// Collect only lights nearer than 20 sectors
if (distance >= 20 * WALL_SIZE)
continue;
// Check the range
if (distance > light->Range)
continue;
// If Lara, try to collect shadow casting light
float attenuation = 1.0f - distance / light->Range;
float intensity = max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
}
else
{
// Invalid light type
continue;
}
}
}
m_shadowLight = brightestLight;
if (m_shadowLight == NULL)
return true;
// Reset GPU state
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->RSSetState(m_states->CullCounterClockwise());
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
// Bind and clear render target
m_context->ClearRenderTargetView(m_shadowMap->RenderTargetView, Colors::White);
m_context->ClearDepthStencilView(m_shadowMap->DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
m_context->OMSetRenderTargets(1, &m_shadowMap->RenderTargetView, m_shadowMap->DepthStencilView);
m_context->RSSetViewports(1, &m_shadowMapViewport);
//drawLara(false, true);
Vector3 lightPos = Vector3(m_shadowLight->Position.x, m_shadowLight->Position.y, m_shadowLight->Position.z);
Vector3 itemPos = Vector3(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos);
if (lightPos == itemPos)
return true;
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
// Set shaders
m_context->VSSetShader(m_vsShadowMap, NULL, 0);
m_context->PSSetShader(m_psShadowMap, NULL, 0);
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetInputLayout(m_inputLayout);
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
// Set texture
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
m_context->PSSetSamplers(0, 1, &sampler);
2020-01-03 10:49:15 +01:00
// Set camera matrices
Matrix view = Matrix::CreateLookAt(lightPos,
itemPos,
Vector3(0.0f, -1.0f, 0.0f));
2020-01-03 20:40:52 +01:00
Matrix projection = Matrix::CreatePerspectiveFieldOfView(90.0f * RADIAN, 1.0f, 64.0f,
(m_shadowLight->Type == LIGHT_TYPE_POINT ? m_shadowLight->Out : m_shadowLight->Range) * 1.2f);
m_stCameraMatrices.View = view.Transpose();
m_stCameraMatrices.Projection = projection.Transpose();
updateConstantBuffer(m_cbCameraMatrices, &m_stCameraMatrices, sizeof(CCameraMatrixBuffer));
m_context->VSSetConstantBuffers(0, 1, &m_cbCameraMatrices);
2020-01-03 06:48:15 +01:00
m_stShadowMap.LightViewProjection = (view * projection).Transpose();
m_stMisc.AlphaTest = true;
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
RendererObject* laraObj = m_moveableObjects[ID_LARA];
RendererObject* laraSkin = m_moveableObjects[ID_LARA_SKIN];
RendererRoom* room = m_rooms[LaraItem->roomNumber];
m_stItem.World = m_LaraWorldMatrix.Transpose();
m_stItem.Position = Vector4(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos, 1.0f);
m_stItem.AmbientLight = room->AmbientLight;
memcpy(m_stItem.BonesMatrices, laraObj->AnimationTransforms.data(), sizeof(Matrix) * 32);
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
m_context->VSSetConstantBuffers(1, 1, &m_cbItem);
m_context->PSSetConstantBuffers(1, 1, &m_cbItem);
2019-12-02 09:11:21 +01:00
for (int k = 0; k < laraSkin->ObjectMeshes.size(); k++)
{
RendererMesh* mesh = m_meshPointersToMesh[reinterpret_cast<unsigned int>(Lara.meshPtrs[k])];
2019-12-02 09:11:21 +01:00
for (int j = 0; j < 2; j++)
{
RendererBucket* bucket = &mesh->Buckets[j];
if (bucket->Vertices.size() == 0)
continue;
if (j == RENDERER_BUCKET_SOLID_DS || j == RENDERER_BUCKET_TRANSPARENT_DS)
m_context->RSSetState(m_states->CullNone());
else
m_context->RSSetState(m_states->CullCounterClockwise());
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
}
if (m_moveableObjects[ID_LARA_SKIN_JOINTS] != NULL)
{
RendererObject* laraSkinJoints = m_moveableObjects[ID_LARA_SKIN_JOINTS];
2019-12-02 09:11:21 +01:00
for (int k = 0; k < laraSkinJoints->ObjectMeshes.size(); k++)
{
RendererMesh* mesh = laraSkinJoints->ObjectMeshes[k];
2019-12-02 09:11:21 +01:00
for (int j = 0; j < 2; j++)
{
RendererBucket* bucket = &mesh->Buckets[j];
if (bucket->Vertices.size() == 0)
continue;
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
}
}
2019-12-02 09:11:21 +01:00
for (int k = 0; k < laraSkin->ObjectMeshes.size(); k++)
{
RendererMesh* mesh = laraSkin->ObjectMeshes[k];
2019-12-02 09:11:21 +01:00
for (int j = 0; j < NUM_BUCKETS; j++)
{
RendererBucket* bucket = &mesh->Buckets[j];
if (bucket->Vertices.size() == 0)
continue;
// Draw vertices
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
m_numDrawCalls++;
}
}
// Hairs are pre-transformed
Matrix matrices[8] = { Matrix::Identity, Matrix::Identity, Matrix::Identity, Matrix::Identity,
Matrix::Identity, Matrix::Identity, Matrix::Identity, Matrix::Identity };
memcpy(m_stItem.BonesMatrices, matrices, sizeof(Matrix) * 8);
m_stItem.World = Matrix::Identity;
updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer));
if (m_moveableObjects[ID_LARA_HAIR] != NULL)
2020-01-03 06:48:15 +01:00
{
m_primitiveBatch->Begin();
m_primitiveBatch->DrawIndexed(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
2019-12-02 09:11:21 +01:00
(const unsigned short*)m_hairIndices.data(), m_numHairIndices,
m_hairVertices.data(), m_numHairVertices);
m_primitiveBatch->End();
}
2019-05-09 13:50:55 +02:00
return true;
}
bool Renderer11::DoTitleImage()
{
Texture2D* texture = Texture2D::LoadFromFile(m_device, (char*)g_GameFlow->Intro);
2019-05-09 13:50:55 +02:00
if (!texture)
return false;
float currentFade = 0;
while (currentFade <= 1.0f)
{
drawFullScreenImage(texture->ShaderResourceView, currentFade);
SyncRenderer();
currentFade += FADE_FACTOR;
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < 30 * 1.5f; i++)
2019-05-09 13:50:55 +02:00
{
drawFullScreenImage(texture->ShaderResourceView, 1.0f);
SyncRenderer();
}
currentFade = 1.0f;
while (currentFade >= 0.0f)
{
drawFullScreenImage(texture->ShaderResourceView, currentFade);
SyncRenderer();
currentFade -= FADE_FACTOR;
}
delete texture;
return true;
}