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"
|
2019-05-08 21:11:18 +02:00
|
|
|
#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"
|
2019-02-02 08:23:54 +01:00
|
|
|
#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"
|
2019-11-14 20:15:29 +01:00
|
|
|
#include "..\Game\healt.h"
|
2019-12-22 00:20:10 +01:00
|
|
|
#include "../Game/tomb4fx.h"
|
2019-01-13 21:57:16 +01:00
|
|
|
|
|
|
|
#include <D3Dcompiler.h>
|
2019-01-21 22:23:32 +01:00
|
|
|
#include <chrono>
|
2019-01-13 21:57:16 +01:00
|
|
|
#include <stack>
|
2019-12-15 19:07:38 +01:00
|
|
|
#include "../Game/misc.h"
|
2019-01-13 21:57:16 +01:00
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
using ns = chrono::nanoseconds;
|
|
|
|
using get_time = chrono::steady_clock;
|
|
|
|
|
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)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
return (a->Distance - b->Distance);
|
|
|
|
}
|
|
|
|
|
2019-01-13 21:57:16 +01:00
|
|
|
Renderer11::Renderer11()
|
|
|
|
{
|
|
|
|
initialiseHairRemaps();
|
2019-02-03 09:40:00 +01:00
|
|
|
|
|
|
|
m_blinkColorDirection = 1;
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Renderer11::~Renderer11()
|
|
|
|
{
|
2019-06-10 21:42:42 +02:00
|
|
|
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);
|
|
|
|
|
2019-03-15 23:03:54 +01:00
|
|
|
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++)
|
2019-03-15 23:03:54 +01:00
|
|
|
DX11_DELETE(m_caustics[i]);
|
|
|
|
|
|
|
|
DX11_DELETE(m_titleScreen);
|
|
|
|
DX11_DELETE(m_binocularsTexture);
|
2019-03-30 08:17:04 +01:00
|
|
|
DX11_DELETE(m_whiteTexture);
|
2019-06-10 21:42:42 +02:00
|
|
|
DX11_DELETE(m_logo);
|
2019-03-15 23:03:54 +01:00
|
|
|
|
|
|
|
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);
|
2019-05-10 20:38:48 +02:00
|
|
|
DX11_RELEASE(m_cbCameraMatrices);
|
|
|
|
DX11_RELEASE(m_cbItem);
|
|
|
|
DX11_RELEASE(m_cbStatic);
|
|
|
|
DX11_RELEASE(m_cbLights);
|
|
|
|
DX11_RELEASE(m_cbMisc);
|
2019-03-15 23:03:54 +01:00
|
|
|
|
|
|
|
DX11_DELETE(m_renderTarget);
|
|
|
|
DX11_DELETE(m_dumpScreenRenderTarget);
|
2019-05-10 20:38:48 +02:00
|
|
|
DX11_DELETE(m_shadowMap);
|
2019-03-15 23:03:54 +01:00
|
|
|
|
2019-06-10 21:42:42 +02:00
|
|
|
DX11_RELEASE(m_swapChain);
|
|
|
|
DX11_RELEASE(m_context);
|
|
|
|
DX11_RELEASE(m_device);
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::FreeRendererData()
|
|
|
|
{
|
2019-03-24 10:08:54 +01:00
|
|
|
m_meshPointersToMesh.clear();
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < ID_NUMBER_OBJECTS; i++)
|
2019-03-15 23:03:54 +01:00
|
|
|
DX11_DELETE(m_moveableObjects[i]);
|
|
|
|
free(m_moveableObjects);
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < g_NumSprites; i++)
|
2019-03-24 10:08:54 +01:00
|
|
|
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++)
|
2019-03-15 23:03:54 +01:00
|
|
|
DX11_DELETE(m_spriteSequences[i]);
|
|
|
|
free(m_spriteSequences);
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < NUM_STATICS; i++)
|
2019-03-15 23:03:54 +01:00
|
|
|
DX11_DELETE(m_staticObjects[i]);
|
|
|
|
free(m_staticObjects);
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < NUM_ROOMS; i++)
|
2019-03-15 23:03:54 +01:00
|
|
|
DX11_DELETE(m_rooms[i]);
|
|
|
|
free(m_rooms);
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < m_numAnimatedTextureSets; i++)
|
2019-03-15 23:03:54 +01:00
|
|
|
DX11_DELETE(m_animatedTextureSets[i]);
|
|
|
|
free(m_animatedTextureSets);
|
|
|
|
|
2019-01-13 21:57:16 +01:00
|
|
|
DX11_DELETE(m_textureAtlas);
|
2019-03-15 23:03:54 +01:00
|
|
|
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()
|
|
|
|
{
|
2019-12-11 07:40:47 +01:00
|
|
|
D3D_FEATURE_LEVEL levels[1] = { D3D_FEATURE_LEVEL_10_0 };
|
2019-02-10 09:15:02 +01:00
|
|
|
D3D_FEATURE_LEVEL featureLevel;
|
2019-12-14 22:41:38 +01:00
|
|
|
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
|
2019-02-10 09:15:02 +01:00
|
|
|
|
|
|
|
if (FAILED(res))
|
|
|
|
return false;
|
|
|
|
|
2019-01-13 21:57:16 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Renderer11::EnumerateVideoModes()
|
|
|
|
{
|
2019-02-10 09:15:02 +01:00
|
|
|
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);
|
2019-02-10 09:15:02 +01:00
|
|
|
|
|
|
|
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))
|
2019-03-24 10:08:54 +01:00
|
|
|
{
|
|
|
|
delete displayModes;
|
2019-02-10 09:15:02 +01:00
|
|
|
return false;
|
2019-03-24 10:08:54 +01:00
|
|
|
}
|
2019-02-10 09:15:02 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = 0; j < numModes; j++)
|
2019-02-10 09:15:02 +01:00
|
|
|
{
|
|
|
|
DXGI_MODE_DESC* mode = &displayModes[j];
|
|
|
|
|
|
|
|
RendererDisplayMode newMode;
|
|
|
|
|
2019-05-10 20:38:48 +02:00
|
|
|
// discard lower resolutions
|
|
|
|
if (mode->Width < 1024 || mode->Height < 768)
|
|
|
|
continue;
|
|
|
|
|
2019-02-10 09:15:02 +01:00
|
|
|
newMode.Width = mode->Width;
|
|
|
|
newMode.Height = mode->Height;
|
|
|
|
newMode.RefreshRate = mode->RefreshRate.Numerator / mode->RefreshRate.Denominator;
|
|
|
|
|
2019-05-10 20:38:48 +02:00
|
|
|
bool found = false;
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int k = 0; k < adapter.DisplayModes.size(); k++)
|
2019-05-10 20:38:48 +02:00
|
|
|
{
|
|
|
|
RendererDisplayMode* currentMode = &adapter.DisplayModes[k];
|
|
|
|
if (currentMode->Width == newMode.Width && currentMode->Height == newMode.Height &&
|
|
|
|
currentMode->RefreshRate == newMode.RefreshRate)
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
continue;
|
|
|
|
|
2019-02-10 09:15:02 +01:00
|
|
|
adapter.DisplayModes.push_back(newMode);
|
|
|
|
|
|
|
|
printf("\t\t %d x %d %d Hz\n", newMode.Width, newMode.Height, newMode.RefreshRate);
|
|
|
|
}
|
|
|
|
|
2019-03-24 10:08:54 +01:00
|
|
|
m_adapters.push_back(adapter);
|
|
|
|
|
|
|
|
delete displayModes;
|
2019-02-10 09:15:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2019-05-02 21:19:24 +02:00
|
|
|
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;
|
2019-05-03 20:58:36 +02:00
|
|
|
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
|
|
|
|
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_STRETCHED;
|
2019-05-02 21:19:24 +02:00
|
|
|
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-05-03 20:58:36 +02:00
|
|
|
|
2019-01-13 21:57:16 +01:00
|
|
|
IDXGIDevice* dxgiDevice = NULL;
|
2019-05-02 21:19:24 +02:00
|
|
|
res = m_device->QueryInterface(__uuidof(IDXGIDevice), (void**)& dxgiDevice);
|
2019-01-13 21:57:16 +01:00
|
|
|
if (FAILED(res))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
IDXGIAdapter* dxgiAdapter = NULL;
|
2019-05-02 21:19:24 +02:00
|
|
|
res = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)& dxgiAdapter);
|
2019-01-13 21:57:16 +01:00
|
|
|
if (FAILED(res))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
IDXGIFactory* dxgiFactory = NULL;
|
2019-05-02 21:19:24 +02:00
|
|
|
res = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)& dxgiFactory);
|
2019-01-13 21:57:16 +01:00
|
|
|
if (FAILED(res))
|
|
|
|
return false;
|
|
|
|
|
2019-05-02 21:19:24 +02:00
|
|
|
if (reset)
|
2019-05-03 20:58:36 +02:00
|
|
|
{
|
|
|
|
// Always return to windowed mode otherwise crash will happen
|
|
|
|
m_swapChain->SetFullscreenState(false, NULL);
|
2019-05-02 21:19:24 +02:00
|
|
|
m_swapChain->Release();
|
2019-05-03 20:58:36 +02:00
|
|
|
}
|
2019-05-02 21:19:24 +02:00
|
|
|
|
2019-01-13 21:57:16 +01:00
|
|
|
m_swapChain = NULL;
|
|
|
|
res = dxgiFactory->CreateSwapChain(m_device, &sd, &m_swapChain);
|
|
|
|
if (FAILED(res))
|
|
|
|
return false;
|
|
|
|
|
2019-05-02 21:19:24 +02:00
|
|
|
dxgiFactory->MakeWindowAssociation(handle, 0);
|
2019-05-03 20:58:36 +02:00
|
|
|
res = m_swapChain->SetFullscreenState(!windowed, NULL);
|
2019-05-02 21:19:24 +02:00
|
|
|
|
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;
|
2019-05-02 21:19:24 +02:00
|
|
|
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");
|
2019-01-23 07:31:56 +01:00
|
|
|
m_primitiveBatch = new PrimitiveBatch<RendererVertex>(m_context);
|
2019-01-13 21:57:16 +01:00
|
|
|
|
2019-05-02 21:19:24 +02: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);
|
|
|
|
|
|
|
|
// 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,
|
2019-05-03 20:58:36 +02:00
|
|
|
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);
|
2019-05-02 21:19:24 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND handle)
|
2019-05-02 21:19:24 +02:00
|
|
|
{
|
|
|
|
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
|
2019-12-14 22:41:38 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
m_titleScreen = Texture2D::LoadFromFile(m_device, (char*)g_GameFlow->GetLevel(0)->Background.c_str());
|
2019-03-15 23:03:54 +01:00
|
|
|
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;
|
|
|
|
|
2019-03-30 08:17:04 +01:00
|
|
|
m_whiteTexture = Texture2D::LoadFromFile(m_device, "WhiteSprite.png");
|
|
|
|
if (m_whiteTexture == NULL)
|
|
|
|
return false;
|
|
|
|
|
2019-06-01 09:32:42 +02:00
|
|
|
m_logo = Texture2D::LoadFromFile(m_device, "Logo.png");
|
|
|
|
if (m_logo == NULL)
|
|
|
|
return false;
|
|
|
|
|
2019-01-13 21:57:16 +01:00
|
|
|
// Load shaders
|
2019-02-01 17:31:49 +01:00
|
|
|
ID3D10Blob* blob;
|
2019-01-13 21:57:16 +01:00
|
|
|
|
2019-02-01 17:31:49 +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;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
// 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},
|
|
|
|
};
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_psRooms = compilePixelShader("Shaders\\DX11_Rooms.fx", "PS", "ps_4_0", &blob);
|
|
|
|
if (m_psRooms == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_vsItems = compileVertexShader("Shaders\\DX11_Items.fx", "VS", "vs_4_0", &blob);
|
|
|
|
if (m_vsItems == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_psItems = compilePixelShader("Shaders\\DX11_Items.fx", "PS", "ps_4_0", &blob);
|
|
|
|
if (m_psItems == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_vsStatics = compileVertexShader("Shaders\\DX11_Statics.fx", "VS", "vs_4_0", &blob);
|
|
|
|
if (m_vsStatics == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_psStatics = compilePixelShader("Shaders\\DX11_Statics.fx", "PS", "ps_4_0", &blob);
|
|
|
|
if (m_psStatics == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_vsHairs = compileVertexShader("Shaders\\DX11_Hairs.fx", "VS", "vs_4_0", &blob);
|
|
|
|
if (m_vsHairs == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_psHairs = compilePixelShader("Shaders\\DX11_Hairs.fx", "PS", "ps_4_0", &blob);
|
|
|
|
if (m_psHairs == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_vsSky = compileVertexShader("Shaders\\DX11_Sky.fx", "VS", "vs_4_0", &blob);
|
|
|
|
if (m_vsSky == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_psSky = compilePixelShader("Shaders\\DX11_Sky.fx", "PS", "ps_4_0", &blob);
|
|
|
|
if (m_psSky == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_vsSprites = compileVertexShader("Shaders\\DX11_Sprites.fx", "VS", "vs_4_0", &blob);
|
|
|
|
if (m_vsSprites == NULL)
|
2019-01-28 21:51:51 +01:00
|
|
|
return false;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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;
|
|
|
|
|
2019-02-02 08:23:54 +01:00
|
|
|
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;
|
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
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;
|
|
|
|
|
2019-04-26 15:10:32 +02:00
|
|
|
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
|
2019-01-28 21:51:51 +01:00
|
|
|
m_cbCameraMatrices = createConstantBuffer(sizeof(CCameraMatrixBuffer));
|
|
|
|
m_cbItem = createConstantBuffer(sizeof(CItemBuffer));
|
|
|
|
m_cbStatic = createConstantBuffer(sizeof(CStaticBuffer));
|
2019-02-09 09:35:20 +01:00
|
|
|
m_cbLights = createConstantBuffer(sizeof(CLightBuffer));
|
|
|
|
m_cbMisc = createConstantBuffer(sizeof(CMiscBuffer));
|
2019-04-26 15:10:32 +02:00
|
|
|
m_cbShadowMap = createConstantBuffer(sizeof(CShadowLightBuffer));
|
2019-01-28 21:51:51 +01:00
|
|
|
|
2019-03-18 23:30:41 +01:00
|
|
|
m_currentCausticsFrame = 0;
|
2019-03-20 23:43:52 +01:00
|
|
|
m_firstWeather = true;
|
2019-03-18 23:30:41 +01:00
|
|
|
|
2019-03-24 10:08:54 +01:00
|
|
|
// Preallocate lists
|
2019-11-25 13:18:24 +01:00
|
|
|
m_roomsToDraw.Reserve(NUM_ROOMS);
|
2019-03-24 10:08:54 +01:00
|
|
|
m_itemsToDraw.Reserve(NUM_ITEMS);
|
|
|
|
m_effectsToDraw.Reserve(NUM_ITEMS);
|
2019-11-25 13:18:24 +01:00
|
|
|
m_lightsToDraw.Reserve(MAX_LIGHTS_DRAW);
|
|
|
|
m_dynamicLights.Reserve(MAX_DYNAMIC_LIGHTS);
|
|
|
|
m_staticsToDraw.Reserve(MAX_DRAW_STATICS);
|
2019-03-24 10:08:54 +01:00
|
|
|
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);
|
2019-03-26 23:29:56 +01:00
|
|
|
m_pickupRotation = 0;
|
2019-03-24 10:08:54 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < NUM_ITEMS; i++)
|
2019-03-24 10:08:54 +01:00
|
|
|
{
|
|
|
|
m_items[i].Lights.Reserve(MAX_LIGHTS_PER_ITEM);
|
2019-09-22 21:14:43 +02:00
|
|
|
m_effects[i].Lights.Reserve(MAX_LIGHTS_PER_ITEM);
|
2019-03-24 10:08:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
m_textureAtlas = NULL;
|
|
|
|
m_skyTexture = NULL;
|
|
|
|
|
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);
|
2019-03-15 23:03:54 +01:00
|
|
|
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;
|
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
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;
|
2019-05-31 21:45:13 +02:00
|
|
|
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);
|
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
m_stCameraMatrices.View = View;
|
|
|
|
m_stCameraMatrices.Projection = Projection;
|
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
bool Renderer11::drawAmbientCubeMap(short roomNumber)
|
2019-01-28 21:51:51 +01:00
|
|
|
{
|
|
|
|
return true;
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
2019-01-16 20:54:45 +01:00
|
|
|
void Renderer11::clearSceneItems()
|
|
|
|
{
|
2019-01-21 22:23:32 +01:00
|
|
|
m_roomsToDraw.Clear();
|
|
|
|
m_itemsToDraw.Clear();
|
|
|
|
m_effectsToDraw.Clear();
|
|
|
|
m_lightsToDraw.Clear();
|
|
|
|
m_staticsToDraw.Clear();
|
2019-02-01 17:31:49 +01:00
|
|
|
m_spritesToDraw.Clear();
|
|
|
|
m_lines3DToDraw.Clear();
|
2019-03-16 20:55:27 +01:00
|
|
|
m_lines2DToDraw.Clear();
|
2019-01-16 20:54:45 +01:00
|
|
|
}
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
bool Renderer11::drawHorizonAndSky()
|
2019-01-13 21:57:16 +01:00
|
|
|
{
|
2019-02-01 17:31:49 +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);
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
if (!level->Horizon)
|
|
|
|
return true;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
if (BinocularRange)
|
2019-05-31 21:45:13 +02:00
|
|
|
AlterFOV(14560 - BinocularRange);
|
2019-01-16 20:54:45 +01:00
|
|
|
|
2019-02-01 17:31:49 +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;
|
|
|
|
}
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
color = Vector4((SkyStormColor[0]) / 255.0f, SkyStormColor[1] / 255.0f, SkyStormColor[2] / 255.0f, 1.0f);
|
|
|
|
}
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
ID3D11SamplerState* sampler;
|
|
|
|
UINT stride = sizeof(RendererVertex);
|
|
|
|
UINT offset = 0;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
// Draw the sky
|
|
|
|
Matrix rotation = Matrix::CreateRotationX(PI);
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
RendererVertex vertices[4];
|
|
|
|
float size = 9728.0f;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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;
|
2019-03-29 00:27:16 +01:00
|
|
|
vertices[0].Color.x = 1.0f;
|
|
|
|
vertices[0].Color.y = 1.0f;
|
|
|
|
vertices[0].Color.z = 1.0f;
|
|
|
|
vertices[0].Color.w = 1.0f;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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;
|
2019-03-29 00:27:16 +01:00
|
|
|
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
|
|
|
|
2019-02-01 17:31:49 +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;
|
2019-03-29 00:27:16 +01:00
|
|
|
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
|
|
|
|
2019-02-01 17:31:49 +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;
|
2019-03-29 00:27:16 +01:00
|
|
|
vertices[3].Color.x = 1.0f;
|
|
|
|
vertices[3].Color.y = 1.0f;
|
|
|
|
vertices[3].Color.z = 1.0f;
|
|
|
|
vertices[3].Color.w = 1.0f;
|
2019-02-01 17:31:49 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
m_stMisc.AlphaTest = true;
|
|
|
|
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
|
|
|
|
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
2019-01-28 21:51:51 +01:00
|
|
|
|
|
|
|
// 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
|
|
|
|
2019-01-28 21:51:51 +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
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
RendererObject* moveableObj = m_moveableObjects[ID_HORIZON];
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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;
|
2019-03-20 23:43:52 +01:00
|
|
|
updateConstantBuffer(m_cbStatic, &m_stStatic, sizeof(CStaticBuffer));
|
2019-02-01 17:31:49 +01:00
|
|
|
m_context->VSSetConstantBuffers(1, 1, &m_cbStatic);
|
|
|
|
m_context->PSSetConstantBuffers(1, 1, &m_cbStatic);
|
2019-01-28 21:51:51 +01:00
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
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++)
|
2019-01-28 21:51:51 +01:00
|
|
|
{
|
|
|
|
RendererMesh* mesh = moveableObj->ObjectMeshes[k];
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = 0; j < NUM_BUCKETS; j++)
|
2019-01-28 21:51:51 +01:00
|
|
|
{
|
|
|
|
RendererBucket* bucket = &mesh->Buckets[j];
|
|
|
|
|
|
|
|
if (bucket->Vertices.size() == 0)
|
|
|
|
continue;
|
|
|
|
|
2019-03-29 00:27: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());
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
// Draw vertices
|
|
|
|
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
|
|
|
|
m_numDrawCalls++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
// Clear just the Z-buffer so we can start drawing on top of the horizon
|
2019-03-20 23:43:52 +01:00
|
|
|
m_context->ClearDepthStencilView(m_currentRenderTarget->DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
|
2019-01-13 21:57:16 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
bool Renderer11::drawRooms(bool transparent, bool animated)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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-02-02 07:59:44 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
// Set shaders
|
|
|
|
m_context->VSSetShader(m_vsRooms, NULL, 0);
|
|
|
|
m_context->PSSetShader(m_psRooms, NULL, 0);
|
|
|
|
|
|
|
|
// Set texture
|
|
|
|
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
|
2019-02-09 09:35:20 +01:00
|
|
|
ID3D11SamplerState* sampler = m_states->AnisotropicWrap();
|
2019-04-26 15:10:32 +02:00
|
|
|
ID3D11SamplerState* shadowSampler = m_states->PointClamp();
|
2019-01-28 21:51:51 +01:00
|
|
|
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);
|
2019-04-26 15:10:32 +02:00
|
|
|
m_context->PSSetSamplers(1, 1, &shadowSampler);
|
|
|
|
m_context->PSSetShaderResources(2, 1, &m_shadowMap->ShaderResourceView);
|
|
|
|
|
2019-01-28 21:51:51 +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-04-26 15:10:32 +02:00
|
|
|
|
|
|
|
// Set shadow map data
|
|
|
|
if (m_shadowLight != NULL)
|
|
|
|
{
|
|
|
|
memcpy(&m_stShadowMap.Light, m_shadowLight, sizeof(ShaderLight));
|
|
|
|
m_stShadowMap.CastShadows = true;
|
|
|
|
//m_stShadowMap.ViewProjectionInverse = ViewProjection.Invert().Transpose();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
if (animated)
|
|
|
|
m_primitiveBatch->Begin();
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < m_roomsToDraw.Size(); i++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-01-16 20:54:45 +01:00
|
|
|
RendererRoom* room = m_roomsToDraw[i];
|
2019-03-18 23:30:41 +01:00
|
|
|
|
2019-02-09 09:35:20 +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++)
|
2019-02-09 09:35:20 +01:00
|
|
|
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-02-01 17:31:49 +01:00
|
|
|
|
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);
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = firstBucket; j < lastBucket; j++)
|
2019-01-13 21:57:16 +01:00
|
|
|
{
|
2019-02-09 09:35:20 +01:00
|
|
|
RendererBucket* bucket;
|
2019-02-02 07:59:44 +01:00
|
|
|
if (!animated)
|
2019-02-09 09:35:20 +01:00
|
|
|
bucket = &room->Buckets[j];
|
|
|
|
else
|
|
|
|
bucket = &room->AnimatedBuckets[j];
|
2019-01-13 21:57:16 +01:00
|
|
|
|
2019-02-09 09:35:20 +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
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
if (!animated)
|
|
|
|
{
|
2019-02-02 07:59:44 +01:00
|
|
|
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++)
|
2019-02-02 07:59:44 +01:00
|
|
|
{
|
|
|
|
RendererPolygon* poly = &bucket->Polygons[k];
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
if (animated)
|
|
|
|
m_primitiveBatch->End();
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
bool Renderer11::drawStatics(bool transparent)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
|
|
|
//return true;
|
2019-02-01 17:31:49 +01:00
|
|
|
UINT stride = sizeof(RendererVertex);
|
|
|
|
UINT offset = 0;
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
int firstBucket = (transparent ? 2 : 0);
|
|
|
|
int lastBucket = (transparent ? 4 : 2);
|
2019-02-02 07:59:44 +01:00
|
|
|
|
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);
|
2019-02-01 17:31:49 +01:00
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
// Set shaders
|
|
|
|
m_context->VSSetShader(m_vsStatics, NULL, 0);
|
|
|
|
m_context->PSSetShader(m_psStatics, NULL, 0);
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
// Set texture
|
|
|
|
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
|
2019-02-01 17:31:49 +01:00
|
|
|
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
|
2019-01-28 21:51:51 +01:00
|
|
|
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-02-01 17:31:49 +01:00
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
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_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;
|
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
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
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
m_stStatic.World = (Matrix::CreateRotationY(TR_ANGLE_TO_RAD(msh->yRot)) * Matrix::CreateTranslation(msh->x, msh->y, msh->z)).Transpose();
|
2019-02-01 17:31:49 +01:00
|
|
|
m_stStatic.Color = Vector4(((msh->shade >> 10) & 0xFF) / 255.0f, ((msh->shade >> 5) & 0xFF) / 255.0f, ((msh->shade >> 0) & 0xFF) / 255.0f, 1.0f);
|
2019-01-28 21:51:51 +01:00
|
|
|
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++)
|
2019-02-09 09:35:20 +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());
|
|
|
|
|
|
|
|
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);
|
2019-02-09 09:35:20 +01:00
|
|
|
|
|
|
|
RendererRoom* room = m_rooms[item->Item->roomNumber];
|
2019-11-09 09:55:56 +01:00
|
|
|
if (room == NULL)
|
|
|
|
return true;
|
2019-02-09 09:35:20 +01:00
|
|
|
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++)
|
2019-02-09 09:35:20 +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 = !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++)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2019-02-09 09:35:20 +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);
|
2019-01-28 21:51:51 +01:00
|
|
|
m_numDrawCalls++;
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-10 09:15:02 +01:00
|
|
|
bool Renderer11::drawWaterfalls()
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
|
|
|
UINT stride = sizeof(RendererVertex);
|
|
|
|
UINT offset = 0;
|
|
|
|
|
2019-02-10 09:15:02 +01:00
|
|
|
// 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++)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
2019-02-10 09:15:02 +01:00
|
|
|
RendererItem* item = m_itemsToDraw[i];
|
|
|
|
RendererRoom* room = m_rooms[item->Item->roomNumber];
|
|
|
|
RendererObject* moveableObj = m_moveableObjects[item->Item->objectNumber];
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
short objectNumber = item->Item->objectNumber;
|
2019-02-10 09:15:02 +01:00
|
|
|
if (objectNumber >= ID_WATERFALL1 && objectNumber <= ID_WATERFALLSS2)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
2019-02-10 09:15:02 +01:00
|
|
|
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++)
|
2019-02-10 09:15:02 +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 = false;
|
|
|
|
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
|
|
|
|
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-02-10 09:15:02 +01:00
|
|
|
m_primitiveBatch->Begin();
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int k = 0; k < moveableObj->ObjectMeshes.size(); k++)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
2019-02-10 09:15:02 +01:00
|
|
|
RendererMesh* mesh = moveableObj->ObjectMeshes[k];
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int b = 0; b < NUM_BUCKETS; b++)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
2019-02-10 09:15:02 +01:00
|
|
|
RendererBucket* bucket = &mesh->Buckets[b];
|
|
|
|
|
|
|
|
if (bucket->Vertices.size() == 0)
|
|
|
|
continue;
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int p = 0; p < bucket->Polygons.size(); p++)
|
2019-02-10 09:15:02 +01:00
|
|
|
{
|
|
|
|
RendererPolygon* poly = &bucket->Polygons[p];
|
|
|
|
|
|
|
|
OBJECT_TEXTURE* texture = &ObjectTextures[poly->TextureId];
|
2019-12-02 09:11:21 +01:00
|
|
|
int tile = texture->tileAndFlag & 0x7FFF;
|
2019-02-10 09:15:02 +01:00
|
|
|
|
|
|
|
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]]);
|
|
|
|
}
|
|
|
|
}
|
2019-02-09 09:35:20 +01:00
|
|
|
}
|
|
|
|
}
|
2019-02-10 09:15:02 +01:00
|
|
|
|
|
|
|
m_primitiveBatch->End();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
continue;
|
2019-02-09 09:35:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
bool Renderer11::drawItems(bool transparent, bool animated)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-02-03 11:58:15 +01:00
|
|
|
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-02-02 07:59:44 +01:00
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
m_context->IASetVertexBuffers(0, 1, &m_moveablesVertexBuffer->Buffer, &stride, &offset);
|
2019-02-03 11:58:15 +01:00
|
|
|
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
|
|
m_context->IASetInputLayout(m_inputLayout);
|
2019-02-09 09:35:20 +01:00
|
|
|
m_context->IASetIndexBuffer(m_moveablesIndexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0);
|
2019-02-03 11:58:15 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < m_itemsToDraw.Size(); i++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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;
|
2019-02-02 07:59:44 +01:00
|
|
|
if (moveableObj->DoNotDraw)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
2019-02-02 07:59:44 +01:00
|
|
|
continue;
|
2019-02-09 09:35:20 +01:00
|
|
|
}
|
|
|
|
else if (objectNumber >= ID_WATERFALL1 && objectNumber <= ID_WATERFALLSS2)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-02-09 09:35:20 +01:00
|
|
|
// We'll draw waterfalls later
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
drawAnimatingItem(item, transparent, animated);
|
|
|
|
}
|
|
|
|
}
|
2019-02-01 17:31:49 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-22 21:14:43 +02:00
|
|
|
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);
|
2019-09-22 21:14:43 +02:00
|
|
|
|
|
|
|
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++)
|
2019-09-22 21:14:43 +02:00
|
|
|
{
|
|
|
|
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);
|
2019-09-22 21:14:43 +02:00
|
|
|
|
|
|
|
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++)
|
2019-09-22 21:14:43 +02:00
|
|
|
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++)
|
2019-09-22 21:14:43 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-04-26 15:10:32 +02:00
|
|
|
bool Renderer11::drawLara(bool transparent, bool shadowMap)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-03-17 11:21:11 +01:00
|
|
|
// Don't draw Lara if binoculars or sniper
|
2019-05-31 21:45:13 +02:00
|
|
|
if (BinocularRange || SpotcamOverlay || SpotcamDontDrawLara || CurrentLevel == 0)
|
2019-03-17 11:21:11 +01:00
|
|
|
return true;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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-02-02 07:59:44 +01:00
|
|
|
|
2019-01-23 07:31:56 +01:00
|
|
|
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-09 09:35:20 +01:00
|
|
|
RendererItem* item = &m_items[Lara.itemNumber];
|
2019-12-11 18:07:27 +01:00
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
// Set shaders
|
2019-04-26 15:10:32 +02:00
|
|
|
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);
|
|
|
|
}
|
2019-02-01 17:31:49 +01:00
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
// Set texture
|
|
|
|
m_context->PSSetShaderResources(0, 1, &m_textureAtlas->ShaderResourceView);
|
2019-02-01 17:31:49 +01:00
|
|
|
ID3D11SamplerState* sampler = m_states->AnisotropicClamp();
|
2019-01-28 21:51:51 +01:00
|
|
|
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-02-01 17:31:49 +01:00
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
m_stMisc.AlphaTest = !transparent;
|
|
|
|
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
|
|
|
|
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
|
|
|
|
|
2019-01-23 07:31:56 +01:00
|
|
|
RendererObject* laraObj = m_moveableObjects[ID_LARA];
|
|
|
|
RendererObject* laraSkin = m_moveableObjects[ID_LARA_SKIN];
|
2019-01-28 21:51:51 +01:00
|
|
|
RendererRoom* room = m_rooms[LaraItem->roomNumber];
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
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-01-23 07:31:56 +01:00
|
|
|
|
2019-04-26 15:10:32 +02:00
|
|
|
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++)
|
2019-04-26 15:10:32 +02: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);
|
|
|
|
}
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int k = 0; k < laraSkin->ObjectMeshes.size(); k++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-03-24 10:08:54 +01:00
|
|
|
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++)
|
2019-01-23 07:31:56 +01:00
|
|
|
{
|
|
|
|
RendererBucket* bucket = &mesh->Buckets[j];
|
2019-12-11 18:07:27 +01:00
|
|
|
|
2019-01-23 07:31:56 +01:00
|
|
|
if (bucket->Vertices.size() == 0)
|
|
|
|
continue;
|
|
|
|
|
2019-03-17 11:21:11 +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-23 07:31:56 +01:00
|
|
|
// Draw vertices
|
|
|
|
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
|
2019-01-28 21:51:51 +01:00
|
|
|
m_numDrawCalls++;
|
2019-01-23 07:31:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_moveableObjects[ID_LARA_SKIN_JOINTS] != NULL)
|
|
|
|
{
|
|
|
|
RendererObject* laraSkinJoints = m_moveableObjects[ID_LARA_SKIN_JOINTS];
|
2019-02-01 17:31:49 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int k = 0; k < laraSkinJoints->ObjectMeshes.size(); k++)
|
2019-01-23 07:31:56 +01:00
|
|
|
{
|
|
|
|
RendererMesh* mesh = laraSkinJoints->ObjectMeshes[k];
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = firstBucket; j < lastBucket; j++)
|
2019-01-23 07:31:56 +01:00
|
|
|
{
|
|
|
|
RendererBucket* bucket = &mesh->Buckets[j];
|
|
|
|
|
|
|
|
if (bucket->Vertices.size() == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Draw vertices
|
|
|
|
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
|
2019-01-28 21:51:51 +01:00
|
|
|
m_numDrawCalls++;
|
2019-01-23 07:31:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
if (!transparent)
|
2019-01-23 07:31:56 +01:00
|
|
|
{
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int k = 0; k < laraSkin->ObjectMeshes.size(); k++)
|
2019-01-23 07:31:56 +01:00
|
|
|
{
|
2019-02-02 07:59:44 +01:00
|
|
|
RendererMesh* mesh = laraSkin->ObjectMeshes[k];
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = 0; j < NUM_BUCKETS; j++)
|
2019-02-02 07:59:44 +01:00
|
|
|
{
|
|
|
|
RendererBucket* bucket = &mesh->Buckets[j];
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
if (bucket->Vertices.size() == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Draw vertices
|
|
|
|
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
|
|
|
|
m_numDrawCalls++;
|
|
|
|
}
|
2019-01-23 07:31:56 +01:00
|
|
|
}
|
2019-02-03 11:58:15 +01:00
|
|
|
|
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));
|
2019-02-03 11:58:15 +01:00
|
|
|
|
|
|
|
if (m_moveableObjects[ID_HAIR] != NULL)
|
|
|
|
{
|
|
|
|
m_primitiveBatch->Begin();
|
2019-12-11 18:07:27 +01:00
|
|
|
m_primitiveBatch->DrawIndexed(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, (const uint16_t*)m_hairIndices.data(), m_numHairIndices, m_hairVertices.data(), m_numHairVertices);
|
2019-02-03 11:58:15 +01:00
|
|
|
m_primitiveBatch->End();
|
2019-03-17 19:28:25 +01:00
|
|
|
}
|
2019-01-23 07:31:56 +01:00
|
|
|
}
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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;
|
2019-03-16 20:55:27 +01:00
|
|
|
m_nextLine2D = 0;
|
|
|
|
|
2019-03-18 23:30:41 +01:00
|
|
|
m_currentCausticsFrame++;
|
|
|
|
m_currentCausticsFrame %= 32;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
m_strings.clear();
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
ViewProjection = View * Projection;
|
2019-02-09 09:35:20 +01:00
|
|
|
m_stLights.CameraPosition = Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z);
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
// Prepare the scene to draw
|
|
|
|
auto time1 = chrono::high_resolution_clock::now();
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
clearSceneItems();
|
|
|
|
collectRooms();
|
|
|
|
updateLaraAnimations();
|
|
|
|
updateItemsAnimations();
|
|
|
|
updateEffects();
|
2019-02-09 09:35:20 +01:00
|
|
|
|
|
|
|
m_items[Lara.itemNumber].Item = LaraItem;
|
|
|
|
collectLightsForItem(LaraItem->roomNumber, &m_items[Lara.itemNumber]);
|
|
|
|
|
|
|
|
// Update animated textures every 2 frames
|
|
|
|
if (GnFrameCounter % 2 == 0)
|
2019-02-02 07:59:44 +01:00
|
|
|
updateAnimatedTextures();
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
auto time2 = chrono::high_resolution_clock::now();
|
|
|
|
m_timeUpdate = (chrono::duration_cast<ns>(time2 - time1)).count() / 1000000;
|
2019-02-09 09:35:20 +01:00
|
|
|
time1 = time2;
|
2019-02-01 17:31:49 +01:00
|
|
|
|
2019-04-26 15:10:32 +02:00
|
|
|
// Draw shadow map
|
|
|
|
if (g_Configuration.EnableShadows)
|
|
|
|
drawShadowMap();
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
// Reset GPU state
|
|
|
|
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
|
|
|
|
m_context->RSSetState(m_states->CullCounterClockwise());
|
|
|
|
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
|
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
// Bind and clear render target
|
2019-03-20 23:43:52 +01:00
|
|
|
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);
|
2019-02-01 17:31:49 +01:00
|
|
|
|
|
|
|
m_context->RSSetViewports(1, &m_viewport);
|
|
|
|
|
|
|
|
drawHorizonAndSky();
|
2019-02-02 07:59:44 +01:00
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
// Opaque geometry
|
2019-02-02 07:59:44 +01:00
|
|
|
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
|
|
|
|
|
|
|
|
drawRooms(false, false);
|
|
|
|
drawRooms(false, true);
|
|
|
|
drawStatics(false);
|
2019-04-26 15:10:32 +02:00
|
|
|
drawLara(false, false);
|
2019-02-02 07:59:44 +01:00
|
|
|
drawItems(false, false);
|
|
|
|
drawItems(false, true);
|
2019-09-22 21:14:43 +02:00
|
|
|
drawEffects(false);
|
2019-03-17 23:45:00 +01:00
|
|
|
drawGunFlashes();
|
|
|
|
drawGunShells();
|
2019-03-18 22:57:32 +01:00
|
|
|
drawDebris(false);
|
2019-03-20 23:43:52 +01:00
|
|
|
drawBats();
|
|
|
|
drawRats();
|
|
|
|
drawSpiders();
|
2019-03-18 22:57:32 +01:00
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
// Transparent geometry
|
2019-02-02 07:59:44 +01:00
|
|
|
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
|
|
|
|
m_context->OMSetDepthStencilState(m_states->DepthRead(), 0);
|
|
|
|
|
|
|
|
drawRooms(true, false);
|
|
|
|
drawRooms(true, true);
|
|
|
|
drawStatics(true);
|
2019-04-26 15:10:32 +02:00
|
|
|
drawLara(true, false);
|
2019-02-02 07:59:44 +01:00
|
|
|
drawItems(true, false);
|
|
|
|
drawItems(true, true);
|
2019-09-22 21:14:43 +02:00
|
|
|
drawEffects(true);
|
2019-02-10 09:15:02 +01:00
|
|
|
drawWaterfalls();
|
2019-03-18 22:50:41 +01:00
|
|
|
drawDebris(true);
|
2019-02-02 07:59:44 +01:00
|
|
|
|
|
|
|
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
|
|
|
|
m_context->OMSetDepthStencilState(m_states->DepthDefault(), 0);
|
2019-02-01 17:31:49 +01:00
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
// Do special effects and weather
|
2019-02-01 17:31:49 +01:00
|
|
|
drawFires();
|
|
|
|
drawSmokes();
|
|
|
|
drawBlood();
|
|
|
|
drawSparks();
|
|
|
|
drawBubbles();
|
|
|
|
drawDrips();
|
|
|
|
drawRipples();
|
|
|
|
drawUnderwaterDust();
|
|
|
|
drawSplahes();
|
|
|
|
drawShockwaves();
|
|
|
|
|
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;
|
|
|
|
}
|
2019-02-02 08:23:54 +01:00
|
|
|
|
2019-03-16 20:55:27 +01:00
|
|
|
drawRopes();
|
2019-02-01 17:31:49 +01:00
|
|
|
drawSprites();
|
2019-02-02 08:23:54 +01:00
|
|
|
drawLines3D();
|
2019-02-01 17:31:49 +01:00
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
time2 = chrono::high_resolution_clock::now();
|
|
|
|
m_timeFrame = (chrono::duration_cast<ns>(time2 - time1)).count() / 1000000;
|
2019-02-01 17:31:49 +01:00
|
|
|
time1 = time2;
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-03-16 20:55:27 +01:00
|
|
|
// Bars
|
|
|
|
DrawDashBar();
|
|
|
|
UpdateHealtBar(0);
|
|
|
|
UpdateAirBar(0);
|
2019-03-26 23:29:56 +01:00
|
|
|
DrawAllPickups();
|
2019-03-16 20:55:27 +01:00
|
|
|
|
|
|
|
drawLines2D();
|
|
|
|
|
2019-06-01 09:32:42 +02:00
|
|
|
if (CurrentLevel != 0)
|
|
|
|
{
|
|
|
|
// Draw binoculars or lasersight
|
|
|
|
drawOverlays();
|
|
|
|
|
|
|
|
m_currentY = 60;
|
2019-12-14 22:41:38 +01:00
|
|
|
#ifdef _DEBUG
|
|
|
|
ROOM_INFO* r = &Rooms[LaraItem->roomNumber];
|
2019-06-01 09:32:42 +02:00
|
|
|
|
|
|
|
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);
|
2019-12-19 15:13:13 -03:00
|
|
|
printDebugMessage("Lara.rot: %d %d %d", LaraItem->pos.xRot, LaraItem->pos.yRot, LaraItem->pos.zRot);
|
2019-06-18 21:21:11 +02:00
|
|
|
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);
|
2019-06-01 09:32:42 +02:00
|
|
|
printDebugMessage("Room: %d %d %d %d", r->x, r->z, r->x + r->xSize * WALL_SIZE, r->z + r->ySize * WALL_SIZE);
|
2019-12-20 23:02:35 -03:00
|
|
|
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);
|
2019-12-14 22:41:38 +01:00
|
|
|
#endif
|
2019-06-01 09:32:42 +02:00
|
|
|
}
|
2019-02-02 07:59:44 +01:00
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
drawAllStrings();
|
|
|
|
|
2019-06-01 09:32:42 +02:00
|
|
|
/*m_spriteBatch->Begin();
|
2019-04-26 15:10:32 +02:00
|
|
|
RECT rect; rect.top = rect.left = 0; rect.right = rect.bottom = 300;
|
|
|
|
m_spriteBatch->Draw(m_shadowMap->ShaderResourceView, rect, Colors::White);
|
2019-06-01 09:32:42 +02:00
|
|
|
m_spriteBatch->End();*/
|
2019-04-26 15:10:32 +02:00
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
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
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
if (CurrentLevel == 0 && g_GameFlow->TitleType == TITLE_FLYBY)
|
|
|
|
drawScene(true);
|
2019-03-15 23:03:54 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
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()
|
2019-03-15 23:03:54 +01:00
|
|
|
{
|
|
|
|
// 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);
|
2019-03-15 23:03:54 +01:00
|
|
|
|
|
|
|
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)
|
2019-03-29 00:27:16 +01:00
|
|
|
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
|
2019-03-29 00:27:16 +01:00
|
|
|
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()
|
|
|
|
{
|
2019-11-11 16:17:45 +01:00
|
|
|
m_moveableObjects = (RendererObject**)malloc(sizeof(RendererObject*) * ID_NUMBER_OBJECTS);
|
|
|
|
ZeroMemory(m_moveableObjects, sizeof(RendererObject*) * ID_NUMBER_OBJECTS);
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-11-11 16:17:45 +01:00
|
|
|
m_spriteSequences = (RendererSpriteSequence**)malloc(sizeof(RendererSpriteSequence*) * ID_NUMBER_OBJECTS);
|
|
|
|
ZeroMemory(m_spriteSequences, sizeof(RendererSpriteSequence*) * ID_NUMBER_OBJECTS);
|
2019-02-01 17:31:49 +01:00
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
m_staticObjects = (RendererObject**)malloc(sizeof(RendererObject*) * NUM_STATICS);
|
|
|
|
ZeroMemory(m_staticObjects, sizeof(RendererObject*) * NUM_STATICS);
|
|
|
|
|
2019-03-15 23:03:54 +01:00
|
|
|
m_rooms = (RendererRoom**)malloc(sizeof(RendererRoom*) * NUM_ROOMS);
|
|
|
|
ZeroMemory(m_rooms, sizeof(RendererRoom*) * NUM_ROOMS);
|
2019-02-02 07:59:44 +01:00
|
|
|
|
2019-03-24 10:08:54 +01:00
|
|
|
m_meshes.clear();
|
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
// Step 0: prepare animated textures
|
2019-12-02 09:11:21 +01:00
|
|
|
short numSets = *AnimatedTextureRanges;
|
|
|
|
short* animatedPtr = AnimatedTextureRanges;
|
2019-02-02 07:59:44 +01:00
|
|
|
animatedPtr++;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-03-15 23:03:54 +01:00
|
|
|
m_animatedTextureSets = (RendererAnimatedTextureSet**)malloc(sizeof(RendererAnimatedTextureSet*) * NUM_ANIMATED_SETS);
|
2019-02-02 07:59:44 +01:00
|
|
|
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++;
|
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-02-02 07:59:44 +01:00
|
|
|
set->Textures[j] = newTexture;
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
2019-02-02 07:59:44 +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
|
|
|
|
2019-04-30 12:56:27 +02:00
|
|
|
if (g_GameFlow->GetLevel(CurrentLevel)->LaraType == LARA_YOUNG)
|
2019-01-13 21:57:16 +01:00
|
|
|
{
|
2019-01-23 07:31:56 +01:00
|
|
|
memcpy(m_laraSkinJointRemap, m_youngLaraSkinJointRemap, 15 * 32 * 2);
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-01-23 07:31:56 +01:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-24 10:08:54 +01:00
|
|
|
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;
|
2019-02-01 17:31:49 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2019-03-15 23:03:54 +01:00
|
|
|
//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;
|
2019-02-09 09:35:20 +01:00
|
|
|
r->AmbientLight = Vector4(room->ambient.b / 255.0f, room->ambient.g / 255.0f, room->ambient.r / 255.0f, 1.0f);
|
2019-02-01 17:31:49 +01:00
|
|
|
r->LightsToDraw.Reserve(32);
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
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
|
|
|
{
|
2019-01-23 07:31:56 +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-02-03 11:58:15 +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)
|
|
|
|
{
|
2019-02-03 11:58:15 +01:00
|
|
|
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;
|
2019-02-09 09:35:20 +01:00
|
|
|
light.Intensity = 1.0f;
|
2019-01-16 20:54:45 +01:00
|
|
|
|
|
|
|
r->Lights.push_back(light);
|
|
|
|
}
|
|
|
|
else if (oldLight->LightType == LIGHT_TYPE_POINT)
|
|
|
|
{
|
2019-02-03 11:58:15 +01:00
|
|
|
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-02-09 09:35:20 +01:00
|
|
|
}
|
2019-01-16 20:54:45 +01:00
|
|
|
else if (oldLight->LightType == LIGHT_TYPE_SHADOW)
|
|
|
|
{
|
2019-02-03 11:58:15 +01:00
|
|
|
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;
|
2019-02-09 09:35:20 +01:00
|
|
|
light.Intensity = 1.0f;
|
2019-01-16 20:54:45 +01:00
|
|
|
|
|
|
|
r->Lights.push_back(light);
|
|
|
|
}
|
|
|
|
else if (oldLight->LightType == LIGHT_TYPE_SPOT)
|
|
|
|
{
|
2019-02-03 11:58:15 +01:00
|
|
|
light.Position = Vector3(oldLight->x, oldLight->y, oldLight->z);
|
|
|
|
light.Color = Vector3(oldLight->r, oldLight->g, oldLight->b);
|
2019-02-01 17:31:49 +01:00
|
|
|
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;
|
2019-02-10 09:15:02 +01:00
|
|
|
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);
|
2019-02-09 09:35:20 +01:00
|
|
|
}
|
2019-02-10 09:15:02 +01:00
|
|
|
|
|
|
|
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_HAIR);
|
|
|
|
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_HAIR)
|
|
|
|
{
|
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);
|
|
|
|
}
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
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);
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-22 21:14:43 +02:00
|
|
|
// 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-09-22 21:14:43 +02:00
|
|
|
{
|
2019-12-02 09:11:21 +01:00
|
|
|
unsigned int mp = reinterpret_cast<unsigned int>(Meshes[i * 2]);
|
2019-09-22 21:14:43 +02:00
|
|
|
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];
|
2019-09-22 21:14:43 +02:00
|
|
|
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());
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
// Step 5: prepare sprites
|
2019-03-24 10:08:54 +01:00
|
|
|
m_sprites = (RendererSprite**)malloc(sizeof(RendererSprite*) * g_NumSprites);
|
|
|
|
ZeroMemory(m_sprites, sizeof(RendererSprite*) * g_NumSprites);
|
2019-02-01 17:31:49 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < g_NumSprites; i++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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;
|
2019-02-01 17:31:49 +01:00
|
|
|
|
|
|
|
RendererSpriteSequence* sequence = new RendererSpriteSequence(MoveablesIds[i], numSprites);
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = baseSprite; j < baseSprite + numSprites; j++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-10 09:15:02 +01:00
|
|
|
{
|
2019-02-09 09:35:20 +01:00
|
|
|
if (Objects[ID_WATERFALL1 + i].loaded)
|
|
|
|
{
|
2019-02-10 09:15:02 +01:00
|
|
|
// Get the first textured bucket
|
|
|
|
RendererBucket* bucket = NULL;
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = 0; j < NUM_BUCKETS; j++)
|
2019-02-10 09:15:02 +01:00
|
|
|
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];
|
2019-02-09 09:35:20 +01:00
|
|
|
WaterfallTextures[i] = texture;
|
|
|
|
WaterfallY[i] = texture->vertices[0].y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-13 21:57:16 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-14 22:41:38 +01:00
|
|
|
ID3D11VertexShader* Renderer11::compileVertexShader(const char* fileName, const char* function, const char* model, ID3D10Blob** bytecode)
|
2019-01-13 21:57:16 +01:00
|
|
|
{
|
|
|
|
HRESULT res;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
*bytecode = NULL;
|
2019-01-13 21:57:16 +01:00
|
|
|
ID3DBlob* errors = NULL;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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))
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
printf("Compilation failed: %s\n", errors->GetBufferPointer());
|
2019-01-13 21:57:16 +01:00
|
|
|
return NULL;
|
2019-02-01 17:31:49 +01:00
|
|
|
}
|
2019-01-13 21:57:16 +01:00
|
|
|
|
|
|
|
ID3D11VertexShader* shader = NULL;
|
2019-02-01 17:31:49 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-12-14 22:41:38 +01:00
|
|
|
ID3D11PixelShader* Renderer11::compilePixelShader(const char* fileName, const char* function, const char* model, ID3D10Blob** bytecode)
|
2019-01-13 21:57:16 +01:00
|
|
|
{
|
|
|
|
HRESULT res;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
*bytecode = NULL;
|
2019-01-13 21:57:16 +01:00
|
|
|
ID3DBlob* errors = NULL;
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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))
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
printf("Compilation failed: %s\n", errors->GetBufferPointer());
|
2019-01-13 21:57:16 +01:00
|
|
|
return NULL;
|
2019-02-01 17:31:49 +01:00
|
|
|
}
|
2019-01-13 21:57:16 +01:00
|
|
|
|
|
|
|
ID3D11PixelShader* shader = NULL;
|
2019-02-01 17:31:49 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-12-14 22:41:38 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-12-14 22:41:38 +01:00
|
|
|
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::DrawDashBar()
|
|
|
|
{
|
2019-03-16 20:55:27 +01:00
|
|
|
if (DashTimer < 120)
|
2019-12-02 09:11:21 +01:00
|
|
|
drawBar(630, 32, 150, 12, 100 * (unsigned short)DashTimer / 120, 0xA0A000, 0xA000);
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
void Renderer11::DrawHealthBar(int percentual)
|
2019-01-13 21:57:16 +01:00
|
|
|
{
|
2019-12-29 19:10:53 +01:00
|
|
|
int color2;
|
2019-03-16 20:55:27 +01:00
|
|
|
if (Lara.poisoned || Lara.gassed)
|
|
|
|
color2 = 0xA0A000;
|
2019-12-29 19:10:53 +01:00
|
|
|
else
|
|
|
|
color2 = 0xA00000;
|
2019-03-16 20:55:27 +01:00
|
|
|
drawBar(20, 32, 150, 12, percentual, 0xA00000, color2);
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
void Renderer11::DrawAirBar(int percentual)
|
2019-01-13 21:57:16 +01:00
|
|
|
{
|
2019-12-29 19:10:53 +01:00
|
|
|
/* Draw the air bar only if lara is not one a swamp room */
|
|
|
|
if (!(Rooms[LaraItem->roomNumber].flags & ENV_FLAG_SWAMP))
|
|
|
|
drawBar(20, 10, 150, 12, percentual, 0x0000A0, 0x0050A0);
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::ClearDynamicLights()
|
|
|
|
{
|
2019-02-01 17:31:49 +01:00
|
|
|
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++];
|
|
|
|
|
2019-12-15 19:07:38 +01:00
|
|
|
dynamicLight->Position = Vector3(float(x), float(y), float(z));
|
2019-02-03 11:58:15 +01:00
|
|
|
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;
|
2019-02-03 11:58:15 +01:00
|
|
|
dynamicLight->Dynamic = 1;
|
2019-01-16 21:21:14 +01:00
|
|
|
dynamicLight->Intensity = 2.0f;
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
m_dynamicLights.Add(dynamicLight);
|
2019-12-22 00:20:10 +01:00
|
|
|
//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()
|
|
|
|
{
|
2019-03-15 23:03:54 +01:00
|
|
|
m_fadeStatus = RENDERER_FADE_STATUS::FADE_IN;
|
|
|
|
m_fadeFactor = 0.0f;
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::FadeOut()
|
|
|
|
{
|
2019-03-15 23:03:54 +01:00
|
|
|
m_fadeStatus = RENDERER_FADE_STATUS::FADE_OUT;
|
|
|
|
m_fadeFactor = 1.0f;
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::DrawLoadingScreen(char* fileName)
|
|
|
|
{
|
2019-03-29 00:27:16 +01:00
|
|
|
return;
|
|
|
|
|
2019-03-15 23:03:54 +01:00
|
|
|
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);
|
2019-03-15 23:03:54 +01:00
|
|
|
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)
|
|
|
|
{
|
2019-03-15 23:03:54 +01:00
|
|
|
m_progress = value;
|
2019-01-13 21:57:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Renderer11::IsFading()
|
|
|
|
{
|
2019-03-15 23:03:54 +01:00
|
|
|
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;
|
|
|
|
|
2019-05-02 21:19:24 +02:00
|
|
|
/*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;
|
|
|
|
}
|
|
|
|
|
2019-05-02 21:19:24 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-05-02 21:19:24 +02:00
|
|
|
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++)
|
2019-05-02 21:19:24 +02:00
|
|
|
{
|
|
|
|
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;
|
2019-01-21 22:23:32 +01:00
|
|
|
m_roomsToDraw.Add(m_rooms[node->To]);
|
2019-01-13 21:57:16 +01:00
|
|
|
|
2019-02-03 11:58:15 +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))
|
|
|
|
{
|
2019-01-21 22:23:32 +01:00
|
|
|
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++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-01-21 22:23:32 +01:00
|
|
|
m_rooms[i]->Visited = false;
|
2019-02-01 17:31:49 +01:00
|
|
|
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)
|
|
|
|
{
|
2019-09-22 21:14:43 +02:00
|
|
|
//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;
|
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
if (item->status == ITEM_INVISIBLE)
|
2019-01-13 21:57:16 +01:00
|
|
|
continue;
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
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;
|
2019-01-21 22:23:32 +01:00
|
|
|
newItem->NumMeshes = Objects[item->objectNumber].nmeshes;
|
2019-01-16 20:54:45 +01:00
|
|
|
newItem->World = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(item->pos.yPos),
|
|
|
|
TR_ANGLE_TO_RAD(item->pos.xPos),
|
|
|
|
TR_ANGLE_TO_RAD(item->pos.zPos)) *
|
|
|
|
Matrix::CreateTranslation(item->pos.xPos, item->pos.yPos, item->pos.zPos);
|
2019-01-13 21:57:16 +01:00
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
collectLightsForItem(item->roomNumber, newItem);
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
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-01-21 22:23:32 +01:00
|
|
|
|
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);
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
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)
|
2019-09-22 21:14:43 +02:00
|
|
|
{
|
|
|
|
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++)
|
2019-09-22 21:14:43 +02:00
|
|
|
{
|
|
|
|
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();
|
2019-09-22 21:14:43 +02:00
|
|
|
|
|
|
|
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++)
|
2019-09-22 21:14:43 +02:00
|
|
|
{
|
|
|
|
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++)
|
2019-09-22 21:14:43 +02:00
|
|
|
{
|
|
|
|
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
|
|
|
{
|
2019-02-03 11:58:15 +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;
|
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
m_tempItemLights.Clear();
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
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
|
|
|
{
|
2019-02-03 11:58:15 +01:00
|
|
|
RendererLight* light = m_dynamicLights[i];
|
2019-01-16 20:54:45 +01:00
|
|
|
|
2019-02-03 11:58:15 +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;
|
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
m_tempItemLights.Add(light);
|
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
int numLights = room->Lights.size();
|
2019-02-03 11:58:15 +01:00
|
|
|
|
2019-04-26 15:10:32 +02:00
|
|
|
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++)
|
2019-02-03 11:58:15 +01:00
|
|
|
{
|
|
|
|
RendererLight* light = &room->Lights[j];
|
|
|
|
|
2019-01-16 20:54:45 +01:00
|
|
|
// Check only lights different from sun
|
2019-02-03 11:58:15 +01:00
|
|
|
if (light->Type == LIGHT_TYPE_SUN)
|
2019-01-16 20:54:45 +01:00
|
|
|
{
|
2019-02-03 11:58:15 +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
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
float distance = (itemPosition - lightPosition).Length();
|
2019-01-16 20:54:45 +01:00
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
// Collect only lights nearer than 20 sectors
|
|
|
|
if (distance >= 20 * WALL_SIZE)
|
2019-01-16 20:54:45 +01:00
|
|
|
continue;
|
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
// Check the out radius
|
|
|
|
if (distance > light->Out)
|
|
|
|
continue;
|
2019-04-26 15:10:32 +02:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2019-02-09 09:35:20 +01:00
|
|
|
}
|
2019-02-03 11:58:15 +01:00
|
|
|
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;
|
2019-04-26 15:10:32 +02:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2019-02-03 11:58:15 +01:00
|
|
|
}
|
|
|
|
else
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
2019-02-03 11:58:15 +01:00
|
|
|
// Invalid light type
|
|
|
|
continue;
|
|
|
|
}
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
m_tempItemLights.Add(light);
|
|
|
|
}
|
2019-02-09 09:35:20 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < min(MAX_LIGHTS_PER_ITEM, m_tempItemLights.Size()); i++)
|
2019-02-03 11:58:15 +01:00
|
|
|
{
|
2019-02-09 09:35:20 +01:00
|
|
|
item->Lights.Add(m_tempItemLights[i]);
|
2019-01-16 20:54:45 +01:00
|
|
|
}
|
2019-04-26 15:10:32 +02:00
|
|
|
|
|
|
|
if (item->Item->objectNumber == ID_LARA)
|
|
|
|
{
|
|
|
|
m_shadowLight = brightestLight;
|
|
|
|
}
|
2019-02-03 11:58:15 +01:00
|
|
|
}
|
2019-02-01 17:31:49 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
inline void Renderer11::collectLightsForRoom(short roomNumber)
|
2019-02-03 11:58:15 +01:00
|
|
|
{
|
|
|
|
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();
|
2019-02-03 11:58:15 +01:00
|
|
|
|
|
|
|
// Collect dynamic lights for rooms
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < m_dynamicLights.Size(); i++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
RendererLight* light = m_dynamicLights[i];
|
2019-02-02 07:59:44 +01:00
|
|
|
|
|
|
|
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))
|
2019-02-01 17:31:49 +01:00
|
|
|
room->LightsToDraw.Add(light);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Renderer11::sphereBoxIntersection(Vector3 boxMin, Vector3 boxMax, Vector3 sphereCentre, float sphereRadius)
|
|
|
|
{
|
2019-02-02 07:59:44 +01:00
|
|
|
//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++)
|
2019-01-21 22:23:32 +01:00
|
|
|
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.
|
2019-01-21 22:23:32 +01:00
|
|
|
//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
|
2019-01-21 22:23:32 +01:00
|
|
|
//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;
|
|
|
|
|
2019-02-03 11:58:15 +01:00
|
|
|
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-09-22 21:14:43 +02:00
|
|
|
|
2019-01-13 21:57:16 +01:00
|
|
|
if (fx->objectNumber < 0)
|
|
|
|
continue;
|
|
|
|
|
2019-09-22 21:14:43 +02:00
|
|
|
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);
|
2019-09-22 21:14:43 +02:00
|
|
|
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
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
m_effectsToDraw.Add(newEffect);
|
2019-09-22 21:14:43 +02:00
|
|
|
|
|
|
|
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-01-28 21:51:51 +01:00
|
|
|
{
|
2019-12-02 09:11:21 +01:00
|
|
|
short numLights = -numNormals;
|
|
|
|
colors = (short*)malloc(sizeof(short) * numLights);
|
|
|
|
for (int v = 0; v < numLights; v++)
|
2019-01-28 21:51:51 +01:00
|
|
|
{
|
|
|
|
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;
|
2019-02-09 09:35:20 +01:00
|
|
|
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
|
2019-09-22 21:14:43 +02:00
|
|
|
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];
|
2019-09-22 21:14:43 +02:00
|
|
|
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];
|
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
if (colors == NULL)
|
|
|
|
{
|
|
|
|
vertex.Color = Vector4::One * 0.5f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-02 09:11:21 +01:00
|
|
|
short shade = colors[indices[v]];
|
2019-01-28 21:51:51 +01:00
|
|
|
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;
|
2019-02-09 09:35:20 +01:00
|
|
|
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];
|
2019-09-22 21:14:43 +02:00
|
|
|
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];
|
|
|
|
|
2019-01-28 21:51:51 +01:00
|
|
|
if (colors == NULL)
|
|
|
|
{
|
|
|
|
vertex.Color = Vector4::One * 0.5f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-02 09:11:21 +01:00
|
|
|
short shade = colors[indices[v]];
|
2019-01-28 21:51:51 +01:00
|
|
|
shade = (255 - shade * 255 / 8191) & 0xFF;
|
|
|
|
vertex.Color = Vector4(shade / 255.0f, shade / 255.0f, shade / 255.0f, 1.0f);
|
|
|
|
}
|
2019-01-23 07:31:56 +01:00
|
|
|
|
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;
|
2019-02-09 09:35:20 +01:00
|
|
|
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);
|
2019-01-28 21:51:51 +01:00
|
|
|
if (colors != NULL) free(colors);
|
2019-01-13 21:57:16 +01:00
|
|
|
|
2019-03-24 10:08:54 +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);
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::updateItemsAnimations()
|
|
|
|
{
|
|
|
|
Matrix translation;
|
|
|
|
Matrix rotation;
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
int numItems = m_itemsToDraw.Size();
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < numItems; i++)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
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);
|
2019-01-21 22:23:32 +01:00
|
|
|
|
|
|
|
updateAnimation(itemToDraw, moveableObj, framePtr, frac, rate, 0xFFFFFFFF);
|
2019-01-23 07:31:56 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int m = 0; m < itemToDraw->NumMeshes; m++)
|
2019-01-23 07:31:56 +01:00
|
|
|
itemToDraw->AnimationTransforms[m] = itemToDraw->AnimationTransforms[m].Transpose();
|
2019-01-21 22:23:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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++)
|
2019-01-21 22:23:32 +01:00
|
|
|
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);
|
2019-12-15 19:07:38 +01:00
|
|
|
rotation = Matrix::CreateFromYawPitchRoll(TR_ANGLE_TO_RAD(LaraItem->pos.yRot), TR_ANGLE_TO_RAD(LaraItem->pos.xRot), TR_ANGLE_TO_RAD(LaraItem->pos.zRot));
|
2019-01-23 07:31:56 +01:00
|
|
|
|
|
|
|
m_LaraWorldMatrix = rotation * translation;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
|
|
|
// Update first Lara's animations
|
2019-12-15 19:07:38 +01:00
|
|
|
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));
|
2019-01-21 22:23:32 +01:00
|
|
|
|
|
|
|
// First calculate matrices for legs, hips, head and torso
|
2019-12-15 19:07:38 +01:00
|
|
|
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];
|
2019-12-15 19:07:38 +01:00
|
|
|
int rate, frac;
|
|
|
|
|
|
|
|
frac = GetFrame_D2(LaraItem, framePtr, &rate);
|
2019-01-21 22:23:32 +01:00
|
|
|
updateAnimation(NULL, laraObj, framePtr, frac, rate, mask);
|
|
|
|
|
|
|
|
// Then the arms, based on current weapon status
|
2019-12-15 19:07:38 +01:00
|
|
|
if (Lara.gunStatus == LG_NO_ARMS || Lara.gunStatus == LG_HANDS_BUSY && Lara.gunType != WEAPON_FLARE)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
// Both arms
|
2019-12-15 19:07:38 +01:00
|
|
|
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);
|
2019-01-21 22:23:32 +01:00
|
|
|
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
|
2019-12-15 19:07:38 +01:00
|
|
|
laraObj->LinearizedBones[LM_LINARM]->ExtraRotation += Vector3(TR_ANGLE_TO_RAD(Lara.leftArm.xRot), TR_ANGLE_TO_RAD(Lara.leftArm.yRot), TR_ANGLE_TO_RAD(Lara.leftArm.zRot));
|
|
|
|
laraObj->LinearizedBones[LM_RINARM]->ExtraRotation += Vector3(TR_ANGLE_TO_RAD(Lara.rightArm.xRot), TR_ANGLE_TO_RAD(Lara.rightArm.yRot), TR_ANGLE_TO_RAD(Lara.rightArm.zRot));
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-12-27 10:50:59 +01:00
|
|
|
LARA_ARM* leftArm = &Lara.leftArm;
|
|
|
|
LARA_ARM* rightArm = &Lara.rightArm;
|
|
|
|
|
2019-12-15 19:07:38 +01:00
|
|
|
// HACK: backguns handles differently // TokyoSU: not really a hack since it's the original way to do that.
|
|
|
|
switch (Lara.gunType)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
2019-12-15 19:07:38 +01:00
|
|
|
case WEAPON_SHOTGUN:
|
|
|
|
case WEAPON_HK:
|
|
|
|
case WEAPON_CROSSBOW:
|
|
|
|
case WEAPON_GRENADE_LAUNCHER:
|
|
|
|
case WEAPON_HARPOON_GUN:
|
|
|
|
short* shotgunFramePtr;
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
// Left arm
|
2019-12-15 19:07:38 +01:00
|
|
|
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
|
|
|
|
mask = MESH_BITS(LM_LINARM) | MESH_BITS(LM_LOUTARM) | MESH_BITS(LM_LHAND);
|
2019-12-27 10:50:59 +01:00
|
|
|
pistolFramePtr = Lara.leftArm.frameBase + (Lara.leftArm.frameNumber - Anims[Lara.leftArm.animNumber].frameBase) * (Anims[Lara.leftArm.animNumber].interpolation >> 8);
|
2019-12-15 19:07:38 +01:00
|
|
|
updateAnimation(NULL, laraObj, &pistolFramePtr, 0, 1, mask);
|
|
|
|
|
|
|
|
// Right arm
|
|
|
|
mask = MESH_BITS(LM_RINARM) | MESH_BITS(LM_ROUTARM) | MESH_BITS(LM_RHAND);
|
2019-12-27 10:50:59 +01:00
|
|
|
pistolFramePtr = Lara.rightArm.frameBase + (Lara.rightArm.frameNumber- Anims[Lara.rightArm.animNumber].frameBase) * (Anims[Lara.rightArm.animNumber].interpolation >> 8);
|
2019-12-15 19:07:38 +01:00
|
|
|
updateAnimation(NULL, laraObj, &pistolFramePtr, 0, 1, mask);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WEAPON_FLARE:
|
2019-01-21 22:23:32 +01:00
|
|
|
// Left arm
|
2019-12-15 19:07:38 +01:00
|
|
|
mask = MESH_BITS(LM_LINARM) | MESH_BITS(LM_LOUTARM) | MESH_BITS(LM_LHAND);
|
2019-01-21 22:23:32 +01:00
|
|
|
frac = getFrame(Lara.leftArm.animNumber, Lara.leftArm.frameNumber, framePtr, &rate);
|
|
|
|
updateAnimation(NULL, laraObj, framePtr, frac, rate, mask);
|
|
|
|
|
|
|
|
// Right arm
|
2019-12-15 19:07:38 +01:00
|
|
|
mask = MESH_BITS(LM_RINARM) | MESH_BITS(LM_ROUTARM) | MESH_BITS(LM_RHAND);
|
2019-01-21 22:23:32 +01:00
|
|
|
frac = GetFrame_D2(LaraItem, framePtr, &rate);
|
|
|
|
updateAnimation(NULL, laraObj, framePtr, frac, rate, mask);
|
2019-12-15 19:07:38 +01:00
|
|
|
break;
|
2019-01-21 22:23:32 +01:00
|
|
|
}
|
2019-12-15 19:07:38 +01:00
|
|
|
}
|
2019-01-21 22:23:32 +01:00
|
|
|
|
|
|
|
// At this point, Lara's matrices are ready. Now let's do ponytails...
|
|
|
|
if (m_moveableObjects[ID_HAIR] != NULL)
|
|
|
|
{
|
|
|
|
RendererObject* hairsObj = m_moveableObjects[ID_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-01-21 22:23:32 +01:00
|
|
|
|
2019-12-15 16:19:01 +01:00
|
|
|
world = objLara->AnimationTransforms[LM_HEAD] * m_LaraWorldMatrix;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
int lastVertex = 0;
|
|
|
|
int lastIndex = 0;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
|
|
|
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++)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
// We can't use hardware skinning here, however hairs have just a few vertices so
|
|
|
|
// it's not so bad doing skinning in software
|
2019-04-30 12:56:27 +02:00
|
|
|
if (level->LaraType == LARA_YOUNG)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
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);
|
2019-12-15 19:07:38 +01:00
|
|
|
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));
|
2019-01-21 22:23:32 +01:00
|
|
|
m_hairsMatrices[6 * p + i] = rotation * translation;
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
int baseVertex = lastVertex;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = 0; j < bucket->Vertices.size(); j++)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
2019-12-02 09:11:21 +01:00
|
|
|
int oldVertexIndex = (int)bucket->Vertices[j].Bone;
|
2019-01-21 22:23:32 +01:00
|
|
|
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;
|
|
|
|
|
2019-01-23 07:31:56 +01:00
|
|
|
m_hairVertices[lastVertex].Color = Vector4::One * 0.5f;
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
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;
|
|
|
|
|
2019-01-23 07:31:56 +01:00
|
|
|
m_hairVertices[lastVertex].Color = Vector4::One * 0.5f;
|
|
|
|
|
2019-01-21 22:23:32 +01:00
|
|
|
lastVertex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = 0; j < bucket->Indices.size(); j++)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
m_hairIndices[lastIndex] = baseVertex + bucket->Indices[j];
|
|
|
|
lastIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-23 07:31:56 +01:00
|
|
|
|
|
|
|
// Transpose matrices for shaders
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int m = 0; m < 15; m++)
|
2019-01-23 07:31:56 +01:00
|
|
|
laraObj->AnimationTransforms[m] = laraObj->AnimationTransforms[m].Transpose();
|
2019-01-21 22:23:32 +01:00
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
int Renderer11::getFrame(short animation, short frame, short** framePtr, int* rate)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
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));
|
2019-01-21 22:23:32 +01:00
|
|
|
m_effectsToDraw[i]->World = rotation * translation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
void Renderer11::updateAnimation(RendererItem* item, RendererObject* obj, short** frmptr, short frac, short rate, int mask)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
RendererBone* bones[32];
|
2019-12-02 09:11:21 +01:00
|
|
|
int nextBone = 0;
|
2019-01-21 22:23:32 +01:00
|
|
|
|
|
|
|
Matrix rotation;
|
|
|
|
|
2019-01-23 07:31:56 +01:00
|
|
|
Matrix* transforms = (item == NULL ? obj->AnimationTransforms.data() : &item->AnimationTransforms[0]);
|
2019-01-21 22:23:32 +01:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
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++)
|
2019-01-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
// 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-21 22:23:32 +01:00
|
|
|
{
|
|
|
|
|
2019-01-16 20:54:45 +01:00
|
|
|
return true;
|
2019-02-01 17:31:49 +01:00
|
|
|
}
|
|
|
|
|
2019-12-14 22:41:38 +01:00
|
|
|
void Renderer11::printDebugMessage(LPCSTR message, ...)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
char buffer[255];
|
|
|
|
ZeroMemory(buffer, 255);
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start(args, message);
|
2019-02-02 07:59:44 +01:00
|
|
|
_vsprintf_l(buffer, message, NULL, args);
|
2019-02-01 17:31:49 +01:00
|
|
|
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++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
BLOOD_STRUCT* blood = &Blood[i];
|
2019-12-22 07:56:44 +01:00
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
if (blood->on)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
addSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + 15],
|
|
|
|
blood->x, blood->y, blood->z,
|
2019-12-22 00:20:10 +01:00
|
|
|
blood->shade * 244, blood->shade * 0, blood->shade * 0,
|
|
|
|
TR_ANGLE_TO_RAD(blood->rotAng), 1.0f, blood->size * 8.0f, blood->size * 8.0f,
|
2019-02-01 17:31:49 +01:00
|
|
|
BLENDMODE_ALPHABLEND);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::drawSparks()
|
|
|
|
{
|
2019-12-15 16:19:01 +01:00
|
|
|
for (int i = 0; i < MAX_SPARKS; i++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
SPARKS* spark = &Sparks[i];
|
|
|
|
if (spark->on)
|
|
|
|
{
|
|
|
|
if (spark->flags & SP_DEF)
|
|
|
|
{
|
2019-09-22 21:14:43 +02:00
|
|
|
FX_INFO* fx = &Effects[spark->fxObj];
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
addSpriteBillboard(m_sprites[spark->def],
|
2019-09-22 21:14:43 +02:00
|
|
|
fx->pos.xPos + spark->x,fx->pos.yPos + spark->y, fx->pos.zPos + spark->z,
|
2019-02-01 17:31:49 +01:00
|
|
|
spark->r, spark->g, spark->b,
|
|
|
|
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(spark->x, spark->y, spark->z, spark->x + v.x * 24.0f, spark->y + v.y * 24.0f, spark->z + v.z * 24.0f, spark->r, spark->g, spark->b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::drawFires()
|
|
|
|
{
|
2019-12-15 16:19:01 +01:00
|
|
|
for (int k = 0; k < MAX_FIRE_LIST; k++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
FIRE_SPARKS* spark = &FireSparks[i];
|
|
|
|
if (spark->on)
|
2019-12-15 16:19:01 +01:00
|
|
|
addSpriteBillboard(m_sprites[spark->def], fire->x + spark->x, fire->y + spark->y, fire->z + spark->z, spark->r, spark->g, spark->b, TR_ANGLE_TO_RAD(spark->rotAng), spark->scalar, spark->size * 4.0f, spark->size * 4.0f, BLENDMODE_ALPHABLEND);
|
2019-02-01 17:31:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::addSpriteBillboard(RendererSprite* sprite, float x, float y, float z, byte r, byte g, byte b, 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->X = x;
|
|
|
|
spr->Y = y;
|
|
|
|
spr->Z = z;
|
|
|
|
spr->R = r;
|
|
|
|
spr->G = g;
|
|
|
|
spr->B = b;
|
|
|
|
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++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
SMOKE_SPARKS* spark = &SmokeSparks[i];
|
2019-12-22 07:56:44 +01:00
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
if (spark->on)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-12-22 00:20:10 +01:00
|
|
|
addSpriteBillboard(m_sprites[spark->def],
|
2019-02-01 17:31:49 +01:00
|
|
|
spark->x, spark->y, spark->z,
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->shade, spark->shade, spark->shade,
|
|
|
|
TR_ANGLE_TO_RAD(spark->rotAng), spark->scalar, spark->size * 4.0f, spark->size * 4.0f,
|
2019-02-01 17:31:49 +01:00
|
|
|
BLENDMODE_ALPHABLEND);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
void Renderer11::addLine3D(int x1, int y1, int z1, int x2, int y2, int z2, byte r, byte g, byte b)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
if (m_nextLine3D >= MAX_LINES_3D)
|
|
|
|
return;
|
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
RendererLine3D* line = &m_lines3DBuffer[m_nextLine3D++];
|
2019-02-01 17:31:49 +01:00
|
|
|
|
|
|
|
line->X1 = x1;
|
|
|
|
line->Y1 = y1;
|
|
|
|
line->Z1 = z1;
|
|
|
|
line->X2 = x2;
|
|
|
|
line->Y2 = y2;
|
|
|
|
line->Z2 = z2;
|
|
|
|
line->R = r;
|
|
|
|
line->G = g;
|
|
|
|
line->B = b;
|
|
|
|
|
|
|
|
m_lines3DToDraw.Add(line);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::addSprite3D(RendererSprite* sprite, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, byte r, byte g, byte b, 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->X1 = x1;
|
|
|
|
spr->Y1 = y1;
|
|
|
|
spr->Z1 = z1;
|
|
|
|
spr->X2 = x2;
|
|
|
|
spr->Y2 = y2;
|
|
|
|
spr->Z2 = z2;
|
|
|
|
spr->X3 = x3;
|
|
|
|
spr->Y3 = y3;
|
|
|
|
spr->Z3 = z3;
|
|
|
|
spr->X4 = x4;
|
|
|
|
spr->Y4 = y4;
|
|
|
|
spr->Z4 = z4;
|
|
|
|
spr->R = r;
|
|
|
|
spr->G = g;
|
|
|
|
spr->B = b;
|
|
|
|
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++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2019-12-15 16:19:01 +01:00
|
|
|
addSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_SPLASH],
|
2019-02-01 17:31:49 +01:00
|
|
|
x1, shockwave->y, z1,
|
|
|
|
x2, shockwave->y, z2,
|
|
|
|
x3, shockwave->y, z3,
|
|
|
|
x4, shockwave->y, z4,
|
|
|
|
color, color, color, 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++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2019-12-15 16:19:01 +01:00
|
|
|
addSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_RIPPLES], x1, y, z2, x2, y, z2, x2, y, z1, x1, y, z1, color, color, color, 0.0f, 1.0f, ripple->size, ripple->size, BLENDMODE_ALPHABLEND);
|
2019-02-01 17:31:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::drawDrips()
|
|
|
|
{
|
2019-12-15 16:19:01 +01:00
|
|
|
for (int i = 0; i < MAX_DRIPS; i++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
DRIP_STRUCT* drip = &Drips[i];
|
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
if (drip->on)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-12-22 00:20:10 +01:00
|
|
|
addLine3D(drip->x, drip->y, drip->z, drip->x, drip->y + 24.0f, drip->z, drip->r, drip->g, drip->b);
|
2019-02-01 17:31:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::drawBubbles()
|
|
|
|
{
|
2019-12-15 16:19:01 +01:00
|
|
|
for (int i = 0; i < MAX_BUBBLES; i++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
BUBBLE_STRUCT* bubble = &Bubbles[i];
|
|
|
|
if (bubble->size)
|
2019-12-15 16:19:01 +01:00
|
|
|
addSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_BUBBLES], bubble->pos.x, bubble->pos.y, bubble->pos.z, bubble->shade * 255, bubble->shade * 255, bubble->shade * 255, 0.0f, 1.0f, bubble->size * 0.5f, bubble->size * 0.5f, BLENDMODE_ALPHABLEND);
|
2019-02-01 17:31:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::drawSplahes()
|
|
|
|
{
|
2019-12-29 12:23:36 +01:00
|
|
|
constexpr size_t NUM_POINTS = 12;
|
2019-12-15 16:19:01 +01:00
|
|
|
for (int i = 0; i < MAX_SPLASH; i++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-12-29 12:23:36 +01:00
|
|
|
SPLASH_STRUCT& splash = Splashes[i];
|
|
|
|
if (splash.isActive)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
2019-12-29 12:23:36 +01:00
|
|
|
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;
|
|
|
|
}
|
2019-02-01 17:31:49 +01:00
|
|
|
}
|
2019-12-29 12:23:36 +01:00
|
|
|
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], xOuter, yOuter, zOuter, x2Outer, yOuter, z2Outer, x2Inner, yInner, z2Inner, xInner, yInner, zInner, color, color, color, 0, 1, 0, 0, BLENDMODE_ALPHABLEND);
|
2019-02-01 17:31:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
m_stMisc.AlphaTest = true;
|
|
|
|
updateConstantBuffer(m_cbMisc, &m_stMisc, sizeof(CMiscBuffer));
|
|
|
|
m_context->PSSetConstantBuffers(3, 1, &m_cbMisc);
|
|
|
|
|
2019-02-01 17:31:49 +01:00
|
|
|
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);
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int b = 0; b < 3; b++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
BLEND_MODES currentBlendMode = (BLEND_MODES)b;
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
int numSpritesToDraw = m_spritesToDraw.Size();
|
|
|
|
int lastSprite = 0;
|
2019-02-01 17:31:49 +01:00
|
|
|
|
|
|
|
m_primitiveBatch->Begin();
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < numSpritesToDraw; i++)
|
2019-02-01 17:31:49 +01:00
|
|
|
{
|
|
|
|
RendererSpriteToDraw* spr = m_spritesToDraw[i];
|
|
|
|
|
|
|
|
if (spr->BlendMode != currentBlendMode)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (currentBlendMode == BLENDMODE_OPAQUE)
|
|
|
|
{
|
|
|
|
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spr->Type == RENDERER_SPRITE_TYPE::SPRITE_TYPE_BILLBOARD)
|
|
|
|
{
|
|
|
|
float halfWidth = spr->Width / 2.0f;
|
|
|
|
float halfHeight = spr->Height / 2.0f;
|
|
|
|
|
|
|
|
Matrix billboardMatrix;
|
2019-12-15 19:07:38 +01:00
|
|
|
createBillboardMatrix(&billboardMatrix, &Vector3(spr->X, spr->Y, spr->Z), &Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z), spr->Rotation);
|
2019-02-01 17:31:49 +01:00
|
|
|
|
|
|
|
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.x = spr->R / 255.0f;
|
|
|
|
v0.Color.y = spr->G / 255.0f;
|
|
|
|
v0.Color.z = spr->B / 255.0f;
|
|
|
|
v0.Color.w = 1.0f;
|
|
|
|
|
|
|
|
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.x = spr->R / 255.0f;
|
|
|
|
v1.Color.y = spr->G / 255.0f;
|
|
|
|
v1.Color.z = spr->B / 255.0f;
|
|
|
|
v1.Color.w = 1.0f;
|
|
|
|
|
|
|
|
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.x = spr->R / 255.0f;
|
|
|
|
v2.Color.y = spr->G / 255.0f;
|
|
|
|
v2.Color.z = spr->B / 255.0f;
|
|
|
|
v2.Color.w = 1.0f;
|
|
|
|
|
|
|
|
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.x = spr->R / 255.0f;
|
|
|
|
v3.Color.y = spr->G / 255.0f;
|
|
|
|
v3.Color.z = spr->B / 255.0f;
|
|
|
|
v3.Color.w = 1.0f;
|
|
|
|
|
|
|
|
m_primitiveBatch->DrawQuad(v0, v1, v2, v3);
|
|
|
|
}
|
|
|
|
else if (spr->Type == RENDERER_SPRITE_TYPE::SPRITE_TYPE_3D)
|
|
|
|
{
|
|
|
|
Vector3 p0t = Vector3(spr->X1, spr->Y1, spr->Z1);
|
|
|
|
Vector3 p1t = Vector3(spr->X2, spr->Y2, spr->Z2);
|
|
|
|
Vector3 p2t = Vector3(spr->X3, spr->Y3, spr->Z3);
|
|
|
|
Vector3 p3t = Vector3(spr->X4, spr->Y4, spr->Z4);
|
|
|
|
|
|
|
|
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.x = spr->R / 255.0f;
|
|
|
|
v0.Color.y = spr->G / 255.0f;
|
|
|
|
v0.Color.z = spr->B / 255.0f;
|
|
|
|
v0.Color.w = 1.0f;
|
|
|
|
|
|
|
|
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.x = spr->R / 255.0f;
|
|
|
|
v1.Color.y = spr->G / 255.0f;
|
|
|
|
v1.Color.z = spr->B / 255.0f;
|
|
|
|
v1.Color.w = 1.0f;
|
|
|
|
|
|
|
|
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.x = spr->R / 255.0f;
|
|
|
|
v2.Color.y = spr->G / 255.0f;
|
|
|
|
v2.Color.z = spr->B / 255.0f;
|
|
|
|
v2.Color.w = 1.0f;
|
|
|
|
|
|
|
|
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.x = spr->R / 255.0f;
|
|
|
|
v3.Color.y = spr->G / 255.0f;
|
|
|
|
v3.Color.z = spr->B / 255.0f;
|
|
|
|
v3.Color.w = 1.0f;
|
|
|
|
|
|
|
|
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;
|
2019-02-02 07:59:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer11::updateAnimatedTextures()
|
|
|
|
{
|
2019-02-09 09:35:20 +01:00
|
|
|
// Update room's animated textures
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < NumberRooms; i++)
|
2019-02-02 07:59:44 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-02 07:59:44 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-02 07:59:44 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-02 07:59:44 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-02 07:59:44 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-09 09:35:20 +01:00
|
|
|
|
|
|
|
// Update waterfalls textures
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = ID_WATERFALL1; i <= ID_WATERFALLSS2; i++)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-02-09 09:35:20 +01:00
|
|
|
{
|
|
|
|
RendererVertex* vertex = &bucket->Vertices[v];
|
|
|
|
int y = vertex->UV.y * TEXTURE_ATLAS_SIZE + 64;
|
|
|
|
y %= 128;
|
|
|
|
vertex->UV.y = (float)y / TEXTURE_ATLAS_SIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-02 08:23:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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 08:23:54 +01:00
|
|
|
{
|
2019-02-02 15:40:44 +01:00
|
|
|
RendererLine3D* line = m_lines3DToDraw[i];
|
2019-02-02 08:23:54 +01:00
|
|
|
|
|
|
|
RendererVertex v1;
|
|
|
|
v1.Position.x = line->X1;
|
|
|
|
v1.Position.y = line->Y1;
|
|
|
|
v1.Position.z = line->Z1;
|
|
|
|
v1.Color.x = line->R / 255.0f;
|
|
|
|
v1.Color.y = line->G / 255.0f;
|
|
|
|
v1.Color.z = line->B / 255.0f;
|
|
|
|
v1.Color.w = 1.0f;
|
|
|
|
|
|
|
|
RendererVertex v2;
|
|
|
|
v2.Position.x = line->X2;
|
|
|
|
v2.Position.y = line->Y2;
|
|
|
|
v2.Position.z = line->Z2;
|
|
|
|
v2.Color.x = line->R / 255.0f;
|
|
|
|
v2.Color.y = line->G / 255.0f;
|
|
|
|
v2.Color.z = line->B / 255.0f;
|
|
|
|
v2.Color.w = 1.0f;
|
|
|
|
|
|
|
|
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++)
|
2019-03-29 00:27:16 +01:00
|
|
|
{
|
2019-02-02 08:23:54 +01:00
|
|
|
m_rain[i].Reset = true;
|
2019-03-29 00:27:16 +01:00
|
|
|
m_rain[i].Draw = true;
|
|
|
|
}
|
2019-02-02 08:23:54 +01:00
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < NUM_RAIN_DROPS; i++)
|
2019-02-02 08:23:54 +01:00
|
|
|
{
|
|
|
|
RendererWeatherParticle* drop = &m_rain[i];
|
|
|
|
|
|
|
|
if (drop->Reset)
|
|
|
|
{
|
2019-03-29 00:27:16 +01:00
|
|
|
drop->Draw = true;
|
|
|
|
|
2019-02-02 08:23:54 +01:00
|
|
|
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;
|
2019-02-02 08:23:54 +01:00
|
|
|
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;
|
|
|
|
|
2019-03-29 00:27:16 +01:00
|
|
|
if (drop->Draw)
|
|
|
|
addLine3D(x1, y1, z1, drop->X, drop->Y, drop->Z, (byte)(RAIN_COLOR * 255.0f), (byte)(RAIN_COLOR * 255.0f), (byte)(RAIN_COLOR * 255.0f));
|
2019-02-02 08:23:54 +01:00
|
|
|
|
|
|
|
// 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;
|
2019-02-02 08:23:54 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-12-15 19:07:38 +01:00
|
|
|
addSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], snow->X, snow->Y, snow->Z, 255, 255, 255,
|
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;
|
|
|
|
}
|
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
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];
|
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
if (debris->on)
|
2019-02-02 15:40:44 +01:00
|
|
|
{
|
|
|
|
Matrix translation = Matrix::CreateTranslation(debris->x, debris->y, debris->z);
|
2019-12-22 00:20:10 +01:00
|
|
|
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
|
2019-12-15 19:07:38 +01:00
|
|
|
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
|
2019-12-22 00:20:10 +01:00
|
|
|
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;
|
2019-12-22 00:20:10 +01:00
|
|
|
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);
|
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
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;
|
2019-12-22 00:20:10 +01:00
|
|
|
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);
|
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
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;
|
2019-12-22 00:20:10 +01:00
|
|
|
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()
|
|
|
|
{
|
2019-03-20 23:43:52 +01:00
|
|
|
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)];
|
2019-03-24 10:08:54 +01:00
|
|
|
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;
|
|
|
|
|
2019-12-15 19:07:38 +01:00
|
|
|
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;
|
|
|
|
|
2019-03-20 23:43:52 +01:00
|
|
|
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));
|
|
|
|
|
2019-03-20 23:43:52 +01:00
|
|
|
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
|
|
|
|
m_numDrawCalls++;
|
2019-02-02 15:40:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-20 23:43:52 +01:00
|
|
|
}
|
2019-02-02 15:40:44 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Renderer11::drawRats()
|
|
|
|
{
|
2019-03-20 23:43:52 +01:00
|
|
|
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)
|
|
|
|
{
|
2019-03-20 23:43:52 +01:00
|
|
|
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++)
|
2019-03-20 23:43:52 +01:00
|
|
|
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)];
|
2019-03-24 10:08:54 +01:00
|
|
|
RendererMesh* mesh = m_meshPointersToMesh[reinterpret_cast<unsigned int>(meshPtr)];
|
|
|
|
|
2019-03-20 23:43:52 +01:00
|
|
|
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
|
|
|
|
2019-03-20 23:43:52 +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
|
|
|
{
|
2019-03-20 23:43:52 +01:00
|
|
|
RendererBucket* bucket = &mesh->Buckets[b];
|
2019-02-02 15:40:44 +01:00
|
|
|
|
2019-03-20 23:43:52 +01:00
|
|
|
if (bucket->NumVertices == 0)
|
|
|
|
continue;
|
2019-02-02 15:40:44 +01:00
|
|
|
|
2019-03-20 23:43:52 +01:00
|
|
|
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
|
|
|
|
m_numDrawCalls++;
|
2019-02-02 15:40:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-20 23:43:52 +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];
|
|
|
|
|
2019-06-01 09:32:42 +02:00
|
|
|
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;
|
|
|
|
|
2019-04-26 15:10:32 +02:00
|
|
|
m_lines2DToDraw.Clear();
|
2019-02-03 09:40:00 +01:00
|
|
|
m_strings.clear();
|
|
|
|
|
2019-04-26 15:10:32 +02:00
|
|
|
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);
|
|
|
|
|
2019-03-15 23:03:54 +01:00
|
|
|
// 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);
|
|
|
|
|
2019-03-15 23:03:54 +01:00
|
|
|
// Clear the Z-Buffer after drawing the background
|
|
|
|
if (g_Inventory->GetType() == INV_TYPE_TITLE)
|
2019-02-02 15:40:44 +01:00
|
|
|
{
|
2019-05-31 21:45:13 +02: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
|
|
|
|
{
|
2019-04-26 15:10:32 +02:00
|
|
|
drawFullScreenQuad(m_dumpScreenRenderTarget->ShaderResourceView, Vector3(0.2f, 0.2f, 0.2f), false);
|
2019-03-15 23:03:54 +01:00
|
|
|
}
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-03-15 23:03:54 +01:00
|
|
|
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-03-15 23:03:54 +01:00
|
|
|
|
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);
|
|
|
|
|
2019-04-27 10:24:44 +02:00
|
|
|
InventoryRing* activeRing = g_Inventory->GetRing(g_Inventory->GetActiveRing());
|
2019-12-02 09:11:21 +01:00
|
|
|
int lastRing = 0;
|
2019-04-27 10:24:44 +02:00
|
|
|
|
|
|
|
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),
|
2019-06-01 09:32:42 +02:00
|
|
|
Vector3(0.0f, g_Inventory->GetCameraY() - 512.0f, 0.0f), Vector3(0.0f, -1.0f, 0.0f)).Transpose();
|
2019-04-27 10:24:44 +02:00
|
|
|
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);
|
2019-04-26 15:10:32 +02:00
|
|
|
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;
|
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
// Yellow title
|
2019-05-31 21:45:13 +02:00
|
|
|
if (ring->focusState == INV_FOCUS_STATE_NONE && g_Inventory->GetType() != INV_TYPE_TITLE)
|
2019-04-27 18:22:30 +02:00
|
|
|
PrintString(400, 20, g_GameFlow->GetString(activeRing->titleStringIndex), PRINTSTRING_COLOR_YELLOW, PRINTSTRING_CENTER);
|
2019-04-26 15:10:32 +02:00
|
|
|
|
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;
|
2019-05-31 21:45:13 +02:00
|
|
|
|
|
|
|
//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
|
2019-05-31 21:45:13 +02:00
|
|
|
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;
|
2019-04-27 10:24:44 +02:00
|
|
|
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-05-06 23:48:35 +02:00
|
|
|
|
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);
|
2019-04-30 12:56:27 +02:00
|
|
|
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-03-15 23:03:54 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
OBJECT_INFO* obj = &Objects[objectNumber];
|
|
|
|
RendererObject* moveableObj = m_moveableObjects[objectNumber];
|
2019-12-27 08:25:27 +01:00
|
|
|
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)
|
2019-02-03 09:40:00 +01:00
|
|
|
m_stItem.World = (moveableObj->AnimationTransforms[n] * transform).Transpose();
|
2019-02-02 15:40:44 +01:00
|
|
|
else
|
2019-02-03 09:40:00 +01:00
|
|
|
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);
|
|
|
|
|
2019-02-09 09:35:20 +01:00
|
|
|
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)
|
|
|
|
{
|
2019-03-30 08:17:04 +01:00
|
|
|
/* **************** PASSAPORT ************* */
|
2019-12-13 13:52:47 +01:00
|
|
|
if (inventoryItem == INV_OBJECT_PASSPORT && ring->focusState == INV_FOCUS_STATE_FOCUSED)
|
2019-02-02 15:40:44 +01:00
|
|
|
{
|
2019-03-30 08:17:04 +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)
|
|
|
|
{
|
2019-03-30 08:17:04 +01:00
|
|
|
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
|
|
|
{
|
2019-03-26 23:29:56 +01:00
|
|
|
if (!g_NewSavegameInfos[n].Present)
|
2019-03-30 08:17:04 +01:00
|
|
|
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);
|
2019-03-30 08:17:04 +01:00
|
|
|
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));
|
|
|
|
|
2019-03-30 08:17:04 +01:00
|
|
|
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);
|
2019-03-30 08:17:04 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2019-03-30 08:17:04 +01:00
|
|
|
y += 24;
|
2019-02-02 15:40:44 +01:00
|
|
|
}
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-06-01 09:32:42 +02: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
|
|
|
}
|
2019-03-30 08:17:04 +01:00
|
|
|
/* **************** SELECT LEVEL ************* */
|
2019-02-02 15:40:44 +01:00
|
|
|
else if (ring->passportAction == INV_WHAT_PASSPORT_SELECT_LEVEL)
|
|
|
|
{
|
2019-06-01 09:32:42 +02:00
|
|
|
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-03-30 08:17:04 +01:00
|
|
|
|
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);
|
2019-03-26 23:29:56 +01:00
|
|
|
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:
|
2019-05-08 21:11:18 +02:00
|
|
|
string = g_GameFlow->GetString(STRING_NEW_GAME);
|
2019-02-02 15:40:44 +01:00
|
|
|
break;
|
|
|
|
case INV_WHAT_PASSPORT_SELECT_LEVEL:
|
2019-05-08 21:11:18 +02:00
|
|
|
string = g_GameFlow->GetString(STRING_SELECT_LEVEL);
|
2019-02-02 15:40:44 +01:00
|
|
|
break;
|
|
|
|
case INV_WHAT_PASSPORT_LOAD_GAME:
|
2019-05-08 21:11:18 +02:00
|
|
|
string = g_GameFlow->GetString(STRING_LOAD_GAME);
|
2019-02-02 15:40:44 +01:00
|
|
|
break;
|
|
|
|
case INV_WHAT_PASSPORT_SAVE_GAME:
|
2019-05-08 21:11:18 +02:00
|
|
|
string = g_GameFlow->GetString(STRING_SAVE_GAME);
|
2019-02-02 15:40:44 +01:00
|
|
|
break;
|
|
|
|
case INV_WHAT_PASSPORT_EXIT_GAME:
|
2019-05-08 21:11:18 +02:00
|
|
|
string = g_GameFlow->GetString(STRING_EXIT_GAME);
|
2019-02-02 15:40:44 +01:00
|
|
|
break;
|
|
|
|
case INV_WHAT_PASSPORT_EXIT_TO_TITLE:
|
2019-05-08 21:11:18 +02:00
|
|
|
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);
|
|
|
|
}
|
2019-03-30 08:17:04 +01:00
|
|
|
/* **************** 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
|
2019-03-20 23:43:52 +01:00
|
|
|
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
|
|
|
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(STRING_DISPLAY),
|
2019-03-30 08:17:04 +01:00
|
|
|
PRINTSTRING_COLOR_YELLOW, PRINTSTRING_OUTLINE | PRINTSTRING_CENTER);
|
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
// Screen resolution
|
2019-05-08 21:11:18 +02:00
|
|
|
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);
|
|
|
|
|
2019-03-20 23:43:52 +01:00
|
|
|
PrintString(400, y, buffer, PRINTSTRING_COLOR_WHITE,
|
2019-02-02 15:40:44 +01:00
|
|
|
PRINTSTRING_OUTLINE | (ring->selectedIndex == 0 ? PRINTSTRING_BLINK : 0));
|
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-20 23:43:52 +01:00
|
|
|
|
2019-05-02 21:19:24 +02:00
|
|
|
// Windowed mode
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(200, y, g_GameFlow->GetString(STRING_WINDOWED),
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_COLOR_ORANGE,
|
|
|
|
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 1 ? PRINTSTRING_BLINK : 0));
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.Windowed ? STRING_ENABLED : STRING_DISABLED),
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_COLOR_WHITE,
|
|
|
|
PRINTSTRING_OUTLINE | (ring->selectedIndex == 1 ? PRINTSTRING_BLINK : 0));
|
|
|
|
|
|
|
|
y += 25;
|
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
// Enable dynamic shadows
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(200, y, g_GameFlow->GetString(STRING_SHADOWS),
|
2019-02-02 15:40:44 +01:00
|
|
|
PRINTSTRING_COLOR_ORANGE,
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 2 ? PRINTSTRING_BLINK : 0));
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.EnableShadows ? STRING_ENABLED : STRING_DISABLED),
|
2019-02-02 15:40:44 +01:00
|
|
|
PRINTSTRING_COLOR_WHITE,
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_OUTLINE | (ring->selectedIndex == 2 ? PRINTSTRING_BLINK : 0));
|
2019-02-02 15:40:44 +01:00
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-20 23:43:52 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
// Enable caustics
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(200, y, g_GameFlow->GetString(STRING_CAUSTICS),
|
2019-02-02 15:40:44 +01:00
|
|
|
PRINTSTRING_COLOR_ORANGE,
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 3 ? PRINTSTRING_BLINK : 0));
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.EnableCaustics ? STRING_ENABLED : STRING_DISABLED),
|
2019-02-02 15:40:44 +01:00
|
|
|
PRINTSTRING_COLOR_WHITE,
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_OUTLINE | (ring->selectedIndex == 3 ? PRINTSTRING_BLINK : 0));
|
2019-02-02 15:40:44 +01:00
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-20 23:43:52 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
// Enable volumetric fog
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(200, y, g_GameFlow->GetString(STRING_VOLUMETRIC_FOG),
|
2019-02-02 15:40:44 +01:00
|
|
|
PRINTSTRING_COLOR_ORANGE,
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_DONT_UPDATE_BLINK | PRINTSTRING_OUTLINE | (ring->selectedIndex == 4 ? PRINTSTRING_BLINK : 0));
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(ring->Configuration.EnableVolumetricFog ? STRING_ENABLED : STRING_DISABLED),
|
2019-02-02 15:40:44 +01:00
|
|
|
PRINTSTRING_COLOR_WHITE,
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_OUTLINE | (ring->selectedIndex == 4 ? PRINTSTRING_BLINK : 0));
|
2019-02-02 15:40:44 +01:00
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-20 23:43:52 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
// Apply and cancel
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(STRING_APPLY),
|
2019-02-02 15:40:44 +01:00
|
|
|
PRINTSTRING_COLOR_ORANGE,
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == 5 ? PRINTSTRING_BLINK : 0));
|
2019-03-20 23:43:52 +01:00
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-20 23:43:52 +01:00
|
|
|
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(STRING_CANCEL),
|
2019-02-02 15:40:44 +01:00
|
|
|
PRINTSTRING_COLOR_ORANGE,
|
2019-05-02 21:19:24 +02:00
|
|
|
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == 6 ? PRINTSTRING_BLINK : 0));
|
2019-03-20 23:43:52 +01:00
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-06-01 09:32:42 +02:00
|
|
|
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
|
|
|
}
|
2019-03-30 08:17:04 +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
|
2019-03-15 23:03:54 +01:00
|
|
|
|
2019-03-30 08:17:04 +01:00
|
|
|
y = 200;
|
|
|
|
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(STRING_SOUND),
|
2019-03-30 08:17:04 +01:00
|
|
|
PRINTSTRING_COLOR_YELLOW, PRINTSTRING_OUTLINE | PRINTSTRING_CENTER);
|
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
// Enable sound
|
2019-05-08 21:11:18 +02:00
|
|
|
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));
|
2019-05-08 21:11:18 +02:00
|
|
|
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));
|
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
// Enable sound special effects
|
2019-05-08 21:11:18 +02:00
|
|
|
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));
|
2019-05-08 21:11:18 +02:00
|
|
|
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));
|
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
// Music volume
|
2019-05-08 21:11:18 +02:00
|
|
|
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));
|
2019-06-01 09:32:42 +02:00
|
|
|
drawBar(400, y + 4, 150, 18, ring->Configuration.MusicVolume, 0x0000FF, 0x0000FF);
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-02-02 15:40:44 +01:00
|
|
|
|
|
|
|
// Sound FX volume
|
2019-05-08 21:11:18 +02:00
|
|
|
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));
|
2019-06-01 09:32:42 +02:00
|
|
|
drawBar(400, y + 4, 150, 18, ring->Configuration.SfxVolume, 0x0000FF, 0x0000FF);
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-02-02 15:40:44 +01:00
|
|
|
|
|
|
|
// Apply and cancel
|
2019-05-08 21:11:18 +02:00
|
|
|
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));
|
2019-04-28 16:48:29 +02:00
|
|
|
|
|
|
|
y += 25;
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-05-08 21:11:18 +02:00
|
|
|
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));
|
2019-04-28 16:48:29 +02:00
|
|
|
|
|
|
|
y += 25;
|
2019-03-30 08:17:04 +01:00
|
|
|
|
2019-06-01 09:32:42 +02:00
|
|
|
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
|
|
|
}
|
2019-04-28 16:48:29 +02:00
|
|
|
/* **************** CONTROLS SETTINGS ************* */
|
2019-04-27 18:22:30 +02:00
|
|
|
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;
|
2019-04-27 18:22:30 +02:00
|
|
|
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(STRING_CONTROLS),
|
2019-04-27 18:22:30 +02:00
|
|
|
PRINTSTRING_COLOR_YELLOW, PRINTSTRING_OUTLINE | PRINTSTRING_CENTER);
|
|
|
|
|
|
|
|
y += 25;
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int k = 0; k < 18; k++)
|
2019-04-27 18:22:30 +02:00
|
|
|
{
|
|
|
|
PrintString(200, y, g_GameFlow->GetString(STRING_CONTROLS_MOVE_FORWARD + k),
|
2019-04-28 16:48:29 +02:00
|
|
|
PRINTSTRING_COLOR_WHITE,
|
|
|
|
PRINTSTRING_OUTLINE | (ring->selectedIndex == k ? PRINTSTRING_BLINK : 0) |
|
|
|
|
(ring->waitingForKey ? PRINTSTRING_DONT_UPDATE_BLINK : 0));
|
|
|
|
|
|
|
|
if (ring->waitingForKey && k == ring->selectedIndex)
|
|
|
|
{
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(STRING_WAITING_FOR_KEY),
|
2019-04-28 16:48:29 +02:00
|
|
|
PRINTSTRING_COLOR_YELLOW,
|
|
|
|
PRINTSTRING_OUTLINE | PRINTSTRING_BLINK);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-15 16:19:01 +01:00
|
|
|
PrintString(400, y, (char*)g_KeyNames[KeyboardLayout1[k]],
|
2019-04-28 16:48:29 +02:00
|
|
|
PRINTSTRING_COLOR_ORANGE,
|
2019-04-27 18:22:30 +02:00
|
|
|
PRINTSTRING_OUTLINE);
|
2019-04-28 16:48:29 +02:00
|
|
|
}
|
2019-04-27 18:22:30 +02:00
|
|
|
|
|
|
|
y += 25;
|
|
|
|
}
|
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
// Apply and cancel
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(STRING_APPLY),
|
2019-04-28 16:48:29 +02:00
|
|
|
PRINTSTRING_COLOR_ORANGE,
|
|
|
|
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == NUM_CONTROLS + 0 ? PRINTSTRING_BLINK : 0));
|
|
|
|
|
|
|
|
y += 25;
|
|
|
|
|
2019-05-08 21:11:18 +02:00
|
|
|
PrintString(400, y, g_GameFlow->GetString(STRING_CANCEL),
|
2019-04-28 16:48:29 +02:00
|
|
|
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
|
|
|
|
2019-06-01 09:32:42 +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-04-27 18:22:30 +02:00
|
|
|
}
|
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]];
|
|
|
|
|
2019-04-26 15:10:32 +02:00
|
|
|
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-04-26 15:10:32 +02:00
|
|
|
{
|
2019-12-02 09:11:21 +01:00
|
|
|
int stringIndex = 0;
|
2019-05-08 21:11:18 +02:00
|
|
|
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;
|
2019-04-26 15:10:32 +02:00
|
|
|
|
|
|
|
// Apply and cancel
|
|
|
|
PrintString(400, y, g_GameFlow->GetString(stringIndex),
|
|
|
|
PRINTSTRING_COLOR_WHITE,
|
|
|
|
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == a ? PRINTSTRING_BLINK : 0));
|
|
|
|
|
2019-04-28 16:48:29 +02:00
|
|
|
y += 25;
|
2019-04-26 15:10:32 +02:00
|
|
|
}
|
|
|
|
|
2019-06-01 09:32:42 +02:00
|
|
|
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-04-26 15:10:32 +02:00
|
|
|
}
|
|
|
|
|
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:
|
2019-04-26 15:10:32 +02:00
|
|
|
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:
|
2019-04-26 15:10:32 +02:00
|
|
|
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:
|
2019-04-26 15:10:32 +02:00
|
|
|
quantity = g_LaraExtra.Weapons[WEAPON_HK].Ammo[0];
|
2019-02-02 15:40:44 +01:00
|
|
|
break;
|
|
|
|
case ID_CROSSBOW_AMMO1_ITEM:
|
2019-04-26 15:10:32 +02:00
|
|
|
quantity = g_LaraExtra.Weapons[WEAPON_CROSSBOW].Ammo[0];
|
2019-02-02 15:40:44 +01:00
|
|
|
break;
|
|
|
|
case ID_CROSSBOW_AMMO2_ITEM:
|
2019-04-26 15:10:32 +02:00
|
|
|
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:
|
2019-04-26 15:10:32 +02:00
|
|
|
quantity = g_LaraExtra.Weapons[WEAPON_REVOLVER].Ammo[0];
|
2019-02-02 15:40:44 +01:00
|
|
|
break;
|
|
|
|
case ID_UZI_AMMO_ITEM:
|
2019-04-26 15:10:32 +02:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
|
2019-06-01 09:32:42 +02:00
|
|
|
if (drawGuiRect)
|
|
|
|
{
|
|
|
|
// Draw blu box
|
|
|
|
drawColoredQuad(guiRect.left, guiRect.top, guiRect.right, guiRect.bottom, guiColor);
|
|
|
|
}
|
|
|
|
|
2019-03-26 23:29:56 +01:00
|
|
|
drawLines2D();
|
2019-02-02 15:40:44 +01:00
|
|
|
drawAllStrings();
|
2019-06-01 09:32:42 +02:00
|
|
|
|
|
|
|
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-03-30 08:17:04 +01:00
|
|
|
|
2019-02-02 15:40:44 +01:00
|
|
|
return 0;
|
2019-02-03 11:58:15 +01:00
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
bool Renderer11::drawColoredQuad(int x, int y, int w, int h, Vector4 color)
|
2019-03-30 08:17:04 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2019-06-01 09:32:42 +02:00
|
|
|
m_spriteBatch->Begin(SpriteSortMode_BackToFront, m_states->AlphaBlend(), NULL, m_states->DepthRead());
|
2019-03-30 08:17:04 +01:00
|
|
|
m_spriteBatch->Draw(m_whiteTexture->ShaderResourceView, rect, color);
|
|
|
|
m_spriteBatch->End();
|
|
|
|
|
|
|
|
int shiftW = 4 * factorW;
|
|
|
|
int shiftH = 4 * factorH;
|
|
|
|
|
|
|
|
insertLine2D(rect.left + shiftW, rect.top + shiftH, rect.right - shiftW, rect.top + shiftH, 128, 128, 128, 128);
|
|
|
|
insertLine2D(rect.right - shiftW, rect.top + shiftH, rect.right - shiftW, rect.bottom - shiftH, 128, 128, 128, 128);
|
|
|
|
insertLine2D(rect.left + shiftW, rect.bottom - shiftH, rect.right - shiftW, rect.bottom - shiftH, 128, 128, 128, 128);
|
|
|
|
insertLine2D(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)
|
2019-02-03 11:58:15 +01:00
|
|
|
{
|
|
|
|
RendererVertex vertices[4];
|
2019-03-17 11:21:11 +01:00
|
|
|
|
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);
|
|
|
|
}
|
2019-02-03 11:58:15 +01:00
|
|
|
|
|
|
|
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;
|
2019-03-16 20:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Renderer11::drawRopes()
|
|
|
|
{
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int n = 0; n < NumRopes; n++)
|
2019-03-16 20:55:27 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-03-16 20:55:27 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2019-03-29 00:27:16 +01:00
|
|
|
projected[i] = m_viewportToolkit->Project(absolutePosition, Projection, View, world);
|
2019-03-16 20:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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++)
|
2019-03-16 20:55:27 +01:00
|
|
|
{
|
2019-03-29 00:27:16 +01:00
|
|
|
Vector3 p1 = m_viewportToolkit->Unproject(Vector3(x1, y1, depth), Projection, View, world);
|
|
|
|
Vector3 p2 = m_viewportToolkit->Unproject(Vector3(x2, y2, depth), Projection, View, world);
|
2019-03-16 20:55:27 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2019-03-29 00:27:16 +01:00
|
|
|
Vector3 p3 = m_viewportToolkit->Unproject(Vector3(x3, y3, depth), Projection, View, world);
|
|
|
|
Vector3 p4 = m_viewportToolkit->Unproject(Vector3(x4, y4, depth), Projection, View, world);
|
2019-03-16 20:55:27 +01:00
|
|
|
|
|
|
|
addSprite3D(m_sprites[20],
|
|
|
|
p1.x, p1.y, p1.z,
|
|
|
|
p2.x, p2.y, p2.z,
|
|
|
|
p3.x, p3.y, p3.z,
|
|
|
|
p4.x, p4.y, p4.z,
|
|
|
|
128, 128, 128, 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());
|
2019-03-17 08:52:28 +01:00
|
|
|
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
|
2019-03-16 20:55:27 +01:00
|
|
|
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++)
|
2019-03-16 20:55:27 +01:00
|
|
|
{
|
|
|
|
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;
|
2019-03-30 08:17:04 +01:00
|
|
|
v1.Color.w = line->Color.w / 255.0f;
|
2019-03-16 20:55:27 +01:00
|
|
|
|
|
|
|
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;
|
2019-03-30 08:17:04 +01:00
|
|
|
v2.Color.w = line->Color.w / 255.0f;
|
2019-03-16 20:55:27 +01:00
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
2019-03-17 11:21:11 +01:00
|
|
|
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);
|
2019-03-17 11:21:11 +01:00
|
|
|
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
|
|
|
|
|
2019-03-16 20:55:27 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
bool Renderer11::drawBar(int x, int y, int w, int h, int percent, int color1, int color2)
|
2019-03-16 20:55:27 +01:00
|
|
|
{
|
|
|
|
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-03-16 20:55:27 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
int realPercent = percent / 100.0f * realW;
|
2019-03-16 20:55:27 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < realH; i++)
|
2019-03-30 08:17:04 +01:00
|
|
|
insertLine2D(realX, realY + i, realX + realW, realY + i, 0, 0, 0, 255);
|
2019-03-16 20:55:27 +01:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int i = 0; i < realH; i++)
|
2019-03-30 08:17:04 +01:00
|
|
|
insertLine2D(realX, realY + i, realX + realPercent, realY + i, r1, g1, b1, 255);
|
2019-03-16 20:55:27 +01:00
|
|
|
|
2019-03-30 08:17:04 +01:00
|
|
|
insertLine2D(realX, realY, realX + realW, realY, 255, 255, 255, 255);
|
|
|
|
insertLine2D(realX, realY + realH, realX + realW, realY + realH, 255, 255, 255, 255);
|
|
|
|
insertLine2D(realX, realY, realX, realY + realH, 255, 255, 255, 255);
|
|
|
|
insertLine2D(realX + realW, realY, realX + realW, realY + realH + 1, 255, 255, 255, 255);
|
2019-03-16 20:55:27 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
void Renderer11::insertLine2D(int x1, int y1, int x2, int y2, byte r, byte g, byte b, byte a)
|
2019-03-16 20:55:27 +01:00
|
|
|
{
|
|
|
|
RendererLine2D* line = &m_lines2DBuffer[m_nextLine2D++];
|
|
|
|
|
|
|
|
line->Vertices[0] = Vector2(x1, y1);
|
|
|
|
line->Vertices[1] = Vector2(x2, y2);
|
2019-03-30 08:17:04 +01:00
|
|
|
line->Color = Vector4(r, g, b, a);
|
2019-03-16 20:55:27 +01:00
|
|
|
|
|
|
|
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;
|
2019-12-15 19:07:38 +01:00
|
|
|
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
|
|
|
{
|
2019-12-22 00:20:10 +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;
|
|
|
|
|
2019-12-29 12:23:36 +01:00
|
|
|
addSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], dust->X, dust->Y, dust->Z, color, color, color, 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
|
|
|
}
|
2019-03-20 23:43:52 +01:00
|
|
|
|
|
|
|
vector<RendererVideoAdapter>* Renderer11::GetAdapters()
|
|
|
|
{
|
|
|
|
return &m_adapters;
|
2019-03-26 23:29:56 +01:00
|
|
|
}
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
int Renderer11::DrawPickup(short objectNum)
|
2019-03-26 23:29:56 +01:00
|
|
|
{
|
2019-12-15 19:07:38 +01:00
|
|
|
drawObjectOn2DPosition(700 + PickupX, 450, objectNum, 0, m_pickupRotation, 0); // TODO: + PickupY
|
2019-03-26 23:29:56 +01:00
|
|
|
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)
|
2019-03-26 23:29:56 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-03-29 00:27:16 +01:00
|
|
|
Vector3 pos = m_viewportToolkit->Unproject(Vector3(x, y, 1), projection, view, Matrix::Identity);
|
2019-03-26 23:29:56 +01:00
|
|
|
|
|
|
|
// 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++)
|
2019-03-26 23:29:56 +01:00
|
|
|
{
|
|
|
|
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++)
|
2019-03-26 23:29:56 +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);
|
|
|
|
|
|
|
|
m_context->DrawIndexed(bucket->NumIndices, bucket->StartIndex, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-26 15:10:32 +02:00
|
|
|
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++)
|
2019-04-26 15:10:32 +02:00
|
|
|
{
|
|
|
|
RendererRoom* room = m_roomsToDraw[k];
|
2019-12-02 09:11:21 +01:00
|
|
|
int numLights = room->Lights.size();
|
2019-04-26 15:10:32 +02:00
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = 0; j < numLights; j++)
|
2019-04-26 15:10:32 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
// Set camera matrices
|
|
|
|
Matrix view = Matrix::CreateLookAt(lightPos,
|
|
|
|
itemPos,
|
|
|
|
Vector3(0.0f, -1.0f, 0.0f));
|
2019-12-15 16:19:01 +01:00
|
|
|
Matrix projection = Matrix::CreatePerspectiveFieldOfView(90.0f * RADIAN, 1.0f, 1.0f,
|
2019-04-26 15:10:32 +02:00
|
|
|
m_shadowLight->Out * 1.5f);
|
|
|
|
|
|
|
|
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_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++)
|
2019-04-26 15:10:32 +02:00
|
|
|
{
|
|
|
|
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++)
|
2019-04-26 15:10:32 +02:00
|
|
|
{
|
|
|
|
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++)
|
2019-04-26 15:10:32 +02:00
|
|
|
{
|
|
|
|
RendererMesh* mesh = laraSkinJoints->ObjectMeshes[k];
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = 0; j < 2; j++)
|
2019-04-26 15:10:32 +02:00
|
|
|
{
|
|
|
|
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++)
|
2019-04-26 15:10:32 +02:00
|
|
|
{
|
|
|
|
RendererMesh* mesh = laraSkin->ObjectMeshes[k];
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
for (int j = 0; j < NUM_BUCKETS; j++)
|
2019-04-26 15:10:32 +02:00
|
|
|
{
|
|
|
|
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_HAIR] != NULL)
|
|
|
|
{
|
|
|
|
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,
|
2019-04-26 15:10:32 +02:00
|
|
|
m_hairVertices.data(), m_numHairVertices);
|
|
|
|
m_primitiveBatch->End();
|
|
|
|
}
|
|
|
|
|
2019-05-09 13:50:55 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Renderer11::DoTitleImage()
|
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
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;
|
|
|
|
|
2019-03-26 23:29:56 +01:00
|
|
|
return true;
|
2019-03-20 23:43:52 +01:00
|
|
|
}
|