mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-02 09:47:58 +03:00
6040 lines
No EOL
196 KiB
C++
6040 lines
No EOL
196 KiB
C++
#include "Renderer.h"
|
|
|
|
#include "Structs.h"
|
|
#include "Enums.h"
|
|
#include "RendererBucket.h"
|
|
#include "RendererMesh.h"
|
|
#include "RendererObject.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stack>
|
|
#include <chrono>
|
|
#include <thread>
|
|
|
|
#include <d3d9.h>
|
|
#include <d3dx9.h>
|
|
#include <DxErr.h>
|
|
|
|
#include "..\Global\global.h"
|
|
|
|
#include "..\Specific\input.h"
|
|
#include "..\Specific\winmain.h"
|
|
#include "..\Specific\roomload.h"
|
|
#include "..\Specific\game.h"
|
|
|
|
#include "..\Game\draw.h"
|
|
#include "..\Game\healt.h"
|
|
#include "..\Game\pickup.h"
|
|
#include "..\Game\inventory.h"
|
|
#include "..\Game\gameflow.h"
|
|
#include "..\Game\lara.h"
|
|
#include "..\Game\effect2.h"
|
|
|
|
using ns = chrono::nanoseconds;
|
|
using get_time = chrono::steady_clock;
|
|
|
|
Renderer::Renderer()
|
|
{
|
|
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;
|
|
|
|
m_quadVertices[0].x = -1;
|
|
m_quadVertices[0].y = 1;
|
|
m_quadVertices[0].z = 1;
|
|
m_quadVertices[0].u = 0;
|
|
m_quadVertices[0].v = 0;
|
|
|
|
m_quadVertices[1].x = 1;
|
|
m_quadVertices[1].y = 1;
|
|
m_quadVertices[1].z = 1;
|
|
m_quadVertices[1].u = 1;
|
|
m_quadVertices[1].v = 0;
|
|
|
|
m_quadVertices[2].x = -1;
|
|
m_quadVertices[2].y = -1;
|
|
m_quadVertices[2].z = 1;
|
|
m_quadVertices[2].u = 0;
|
|
m_quadVertices[2].v = 1;
|
|
|
|
m_quadVertices[3].x = 1;
|
|
m_quadVertices[3].y = -1;
|
|
m_quadVertices[3].z = 1;
|
|
m_quadVertices[3].u = 1;
|
|
m_quadVertices[3].v = 1;
|
|
|
|
m_quadIndices[0] = 0;
|
|
m_quadIndices[1] = 3;
|
|
m_quadIndices[2] = 2;
|
|
m_quadIndices[3] = 0;
|
|
m_quadIndices[4] = 1;
|
|
m_quadIndices[5] = 3;
|
|
|
|
for (__int32 i = 0; i < 1000; i++)
|
|
{
|
|
float x = rand() % 16000 + 2048;
|
|
float y = rand() % 2048 + 256;
|
|
float z = rand() % 16000 + 2048;
|
|
|
|
float r = (rand() % 255) / 255.0f;
|
|
float g = (rand() % 255) / 255.0f;
|
|
float b = (rand() % 255) / 255.0f;
|
|
|
|
RendererLight* light = new RendererLight();
|
|
light->Position = D3DXVECTOR4(x, y, z, 1);
|
|
light->Color = D3DXVECTOR4(r, g, b, 1);
|
|
light->Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
|
|
light->Out = 1024.0f;
|
|
|
|
m_testLights.push_back(light);
|
|
}
|
|
}
|
|
|
|
Renderer::~Renderer()
|
|
{
|
|
DX_RELEASE(m_d3D);
|
|
DX_RELEASE(m_device);
|
|
DX_RELEASE(m_textureAtlas);
|
|
DX_RELEASE(m_fontAndMiscTexture);
|
|
DX_RELEASE(m_debugFont);
|
|
DX_RELEASE(m_gameFont);
|
|
DX_RELEASE(m_skyTexture);
|
|
|
|
delete m_lightBuffer;
|
|
delete m_normalBuffer;
|
|
delete m_vertexLightBuffer;
|
|
delete m_colorBuffer;
|
|
delete m_outputBuffer;
|
|
delete m_shaderClearGBuffer;
|
|
delete m_shaderFillGBuffer;
|
|
delete m_shaderLight;
|
|
delete m_shaderCombine;
|
|
delete m_sphereMesh;
|
|
delete m_shadowMap;
|
|
delete m_renderTarget;
|
|
}
|
|
|
|
bool Renderer::Initialise(__int32 w, __int32 h, bool windowed, HWND handle)
|
|
{
|
|
HRESULT res;
|
|
|
|
DB_Log(2, "Renderer::Initialise - DLL");
|
|
printf("Initialising DX\n");
|
|
|
|
m_d3D = Direct3DCreate9(D3D_SDK_VERSION);
|
|
if (m_d3D == NULL)
|
|
return false;
|
|
|
|
D3DPRESENT_PARAMETERS d3dpp;
|
|
|
|
ScreenWidth = w;
|
|
ScreenHeight = h;
|
|
Windowed = windowed;
|
|
|
|
ZeroMemory(&d3dpp, sizeof(d3dpp));
|
|
d3dpp.Windowed = windowed;
|
|
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
d3dpp.hDeviceWindow = handle;
|
|
d3dpp.BackBufferWidth = w;
|
|
d3dpp.BackBufferHeight = h;
|
|
d3dpp.EnableAutoDepthStencil = TRUE;
|
|
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
|
|
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
|
|
|
|
res = m_d3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, handle, D3DCREATE_HARDWARE_VERTEXPROCESSING,
|
|
&d3dpp, &m_device);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
// Load the white sprite
|
|
D3DXCreateTextureFromFileEx(m_device, "load.bmp", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0,
|
|
D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &m_titleScreen);
|
|
|
|
// Create effects
|
|
m_mainShader = new MainShader(m_device);
|
|
if (m_mainShader->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_depthShader = new DepthShader(m_device);
|
|
if (m_depthShader->GetEffect() == NULL)
|
|
return false;
|
|
|
|
// Initialise the vertex declaration
|
|
D3DVERTEXELEMENT9 roomVertexElements[] =
|
|
{
|
|
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
|
{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
|
|
{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
|
{ 0, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
|
|
{ 0, 48, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 },
|
|
D3DDECL_END()
|
|
};
|
|
|
|
m_vertexDeclaration = NULL;
|
|
res = m_device->CreateVertexDeclaration(roomVertexElements, &m_vertexDeclaration);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
// Initialise fonts
|
|
res = D3DXCreateFont(m_device, 13, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &m_debugFont);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
res = D3DXCreateFont(m_device, 28, 0, FW_NORMAL, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Ondine"), &m_gameFont);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
// Initialise the sprite object
|
|
res = D3DXCreateSprite(m_device, &m_sprite);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
// Initialise line objects
|
|
m_lines = (RendererLine2D*)malloc(MAX_LINES_2D * sizeof(RendererLine2D));
|
|
m_line = NULL;
|
|
res = D3DXCreateLine(m_device, &m_line);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
// Initialise the main render target for scene dump
|
|
m_renderTarget = new RenderTarget2D(m_device, ScreenWidth, ScreenHeight, D3DFORMAT::D3DFMT_A8R8G8B8);
|
|
if (m_renderTarget->GetTexture() == NULL)
|
|
return false;
|
|
|
|
// Initialise the shadow map
|
|
m_shadowMap = new RenderTarget2D(m_device, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, D3DFORMAT::D3DFMT_R32F);
|
|
if (m_shadowMap->GetTexture() == NULL)
|
|
return false;
|
|
|
|
m_shadowMapCube = new RenderTargetCube(m_device, SHADOW_MAP_SIZE, D3DFORMAT::D3DFMT_R32F);
|
|
if (m_shadowMap->GetTexture() == NULL)
|
|
return false;
|
|
|
|
// Initialise stuff for the new light pre-pass renderer
|
|
m_depthBuffer = new RenderTarget2D(m_device, ScreenWidth, ScreenHeight, D3DFORMAT::D3DFMT_R32F);
|
|
m_normalBuffer = new RenderTarget2D(m_device, ScreenWidth, ScreenHeight, D3DFORMAT::D3DFMT_A8R8G8B8);
|
|
m_colorBuffer = new RenderTarget2D(m_device, ScreenWidth, ScreenHeight, D3DFORMAT::D3DFMT_A8R8G8B8);
|
|
m_outputBuffer = new RenderTarget2D(m_device, ScreenWidth, ScreenHeight, D3DFORMAT::D3DFMT_A8R8G8B8);
|
|
m_lightBuffer = new RenderTarget2D(m_device, ScreenWidth, ScreenHeight, D3DFORMAT::D3DFMT_A8R8G8B8);
|
|
m_vertexLightBuffer = new RenderTarget2D(m_device, ScreenWidth, ScreenHeight, D3DFORMAT::D3DFMT_A8R8G8B8);
|
|
m_shadowBuffer = new RenderTarget2D(m_device, ScreenWidth, ScreenHeight, D3DFORMAT::D3DFMT_A8R8G8B8);
|
|
m_postprocessBuffer = new RenderTarget2D(m_device, ScreenWidth, ScreenHeight, D3DFORMAT::D3DFMT_A8R8G8B8);
|
|
|
|
m_shaderClearGBuffer = new Shader(m_device, (char*)"ClearGBuffer.fx");
|
|
m_shaderClearGBuffer->Compile();
|
|
if (m_shaderClearGBuffer->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_shaderFillGBuffer = new Shader(m_device, (char*)"FillGBuffer.fx");
|
|
m_shaderFillGBuffer->Compile();
|
|
if (m_shaderFillGBuffer->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_shaderLight = new Shader(m_device, (char*)"Light.fx");
|
|
m_shaderLight->Compile();
|
|
if (m_shaderLight->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_shaderCombine = new Shader(m_device, (char*)"CombineFinal.fx");
|
|
m_shaderCombine->Compile();
|
|
if (m_shaderCombine->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_shaderBasic = new Shader(m_device, (char*)"Basic.fx");
|
|
m_shaderBasic->Compile();
|
|
if (m_shaderBasic->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_shaderRain = new Shader(m_device, (char*)"Rain.fx");
|
|
m_shaderRain->Compile();
|
|
if (m_shaderRain->GetEffect() == NULL)
|
|
return false;
|
|
|
|
/*m_shaderFXAA = new Shader(m_device, (char*)"FXAA.fx");
|
|
m_shaderFXAA->Compile();
|
|
if (m_shaderFXAA->GetEffect() == NULL)
|
|
return false;*/
|
|
|
|
m_shaderReconstructZBuffer = new Shader(m_device, (char*)"ReconstructZBuffer.fx");
|
|
m_shaderReconstructZBuffer->Compile();
|
|
if (m_shaderReconstructZBuffer->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_shaderSprites = new Shader(m_device, (char*)"Sprites.fx");
|
|
m_shaderSprites->Compile();
|
|
if (m_shaderSprites->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_shaderRain = new Shader(m_device, (char*)"Rain.fx");
|
|
m_shaderRain->Compile();
|
|
if (m_shaderRain->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_shaderTransparent = new Shader(m_device, (char*)"Transparent.fx");
|
|
m_shaderTransparent->Compile();
|
|
if (m_shaderTransparent->GetEffect() == NULL)
|
|
return false;
|
|
|
|
m_sphereMesh = new RendererSphere(m_device, 1280.0f, 6);
|
|
m_quad = new RendererQuad(m_device, 1024.0f);
|
|
m_skyQuad = new RendererQuad(m_device, 9728.0f);
|
|
|
|
m_halfPixelX = 0.5f / (float)ScreenWidth;
|
|
m_halfPixelY = 0.5f / (float)ScreenHeight;
|
|
|
|
D3DXCreateTextureFromFileEx(m_device, "SSAO.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0,
|
|
D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &m_randomTexture);
|
|
|
|
char* causticsNames[NUM_CAUSTICS_TEXTURES] = { "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" };
|
|
|
|
for (__int32 i = 0; i < NUM_CAUSTICS_TEXTURES; i++)
|
|
{
|
|
D3DXCreateTextureFromFileEx(m_device, causticsNames[i], D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0,
|
|
D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &m_caustics[i]);
|
|
}
|
|
|
|
res = m_device->CreateVertexBuffer(NUM_SPRITES_PER_BUCKET * 4 * sizeof(RendererVertex), D3DUSAGE_WRITEONLY,
|
|
0, D3DPOOL_MANAGED, &m_spritesVertexBuffer, NULL);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
res = m_device->CreateIndexBuffer(NUM_SPRITES_PER_BUCKET * 6 * 4, D3DUSAGE_WRITEONLY, D3DFMT_INDEX32, D3DPOOL_MANAGED,
|
|
&m_spritesIndexBuffer, NULL);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
res = m_device->CreateVertexBuffer(NUM_LINES_PER_BUCKET * 2 * sizeof(RendererVertex), D3DUSAGE_WRITEONLY,
|
|
0, D3DPOOL_MANAGED, &m_linesVertexBuffer, NULL);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
printf("DX initialised\n");
|
|
|
|
// Initialise last non-DX stuff
|
|
m_fadeTimer = 0;
|
|
m_pickupRotation = 0;
|
|
//m_itemsObjectMatrices = NULL;
|
|
m_dynamicLights.reserve(1024);
|
|
m_lights.reserve(1024);
|
|
m_itemsToDraw.reserve(1024);
|
|
m_spritesToDraw.reserve(NUM_SPRITES_PER_BUCKET * 4);
|
|
m_lines3DToDraw.reserve(NUM_LINES_PER_BUCKET * 4);
|
|
m_lines3DVertices.reserve(NUM_LINES_PER_BUCKET * 2);
|
|
m_firstWeather = true;
|
|
|
|
ResetBlink();
|
|
|
|
return true;
|
|
}
|
|
|
|
void Renderer::ResetBlink()
|
|
{
|
|
m_blinkColorDirection = -1;
|
|
m_blinkColorValue = 255;
|
|
}
|
|
|
|
void Renderer::PrintString(__int32 x, __int32 y, char* string, D3DCOLOR color, __int32 flags)
|
|
{
|
|
__int32 realX = x;
|
|
__int32 realY = y;
|
|
float factor = ScreenWidth / 800.0f;
|
|
|
|
RECT rect = { 0, 0, 0, 0 };
|
|
|
|
m_gameFont->DrawTextA(NULL, string, strlen(string), &rect, DT_CALCRECT, color);
|
|
|
|
if (flags & PRINTSTRING_CENTER)
|
|
{
|
|
__int32 width = rect.right - rect.left;
|
|
rect.left = x - width / 2;
|
|
rect.right = x + width / 2;
|
|
rect.top += y;
|
|
rect.bottom += y;
|
|
}
|
|
else
|
|
{
|
|
rect.left = x;
|
|
rect.right += x;
|
|
rect.top = y;
|
|
rect.bottom += y;
|
|
}
|
|
|
|
rect.left *= factor;
|
|
rect.right *= factor;
|
|
rect.top *= factor;
|
|
rect.bottom *= factor;
|
|
|
|
if (flags & PRINTSTRING_BLINK)
|
|
{
|
|
color = D3DCOLOR_ARGB(255, 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flags & PRINTSTRING_OUTLINE)
|
|
{
|
|
__int16 outline = 1;
|
|
rect.left += outline;
|
|
rect.top += outline;
|
|
rect.right += outline;
|
|
rect.bottom += outline;
|
|
|
|
m_gameFont->DrawTextA(NULL, string, -1, &rect, 0, D3DCOLOR_ARGB(255, 0, 0, 0));
|
|
|
|
rect.left -= outline;
|
|
rect.top -= outline;
|
|
rect.right -= outline;
|
|
rect.bottom -= outline;
|
|
}
|
|
|
|
m_gameFont->DrawTextA(NULL, string, -1, &rect, 0, color);
|
|
}
|
|
|
|
bool Renderer::PrintDebugMessage(__int32 x, __int32 y, __int32 alpha, byte r, byte g, byte b, LPCSTR Message)
|
|
{
|
|
D3DCOLOR fontColor = D3DCOLOR_ARGB(alpha, r, g, b);
|
|
RECT rct;
|
|
rct.left = x;
|
|
rct.right = 700;
|
|
rct.top = y;
|
|
rct.bottom = rct.top + 16;
|
|
m_debugFont->DrawTextA(NULL, Message, -1, &rct, 0, fontColor);
|
|
|
|
return true;
|
|
}
|
|
|
|
RendererMesh* Renderer::GetRendererMeshFromTrMesh(RendererObject* obj, __int16* meshPtr, __int16* refMeshPtr,
|
|
__int16 boneIndex, __int32 isJoints, __int32 isHairs)
|
|
{
|
|
RendererMesh* mesh = new RendererMesh(m_device);
|
|
|
|
__int16* basePtr = meshPtr;
|
|
|
|
__int16 cx = *meshPtr++;
|
|
__int16 cy = *meshPtr++;
|
|
__int16 cz = *meshPtr++;
|
|
__int16 r1 = *meshPtr++;
|
|
__int16 r2 = *meshPtr++;
|
|
|
|
__int16 numVertices = *meshPtr++;
|
|
|
|
VECTOR* vertices = (VECTOR*)malloc(sizeof(VECTOR) * numVertices);
|
|
for (__int32 v = 0; v < numVertices; v++)
|
|
{
|
|
__int16 x = *meshPtr++;
|
|
__int16 y = *meshPtr++;
|
|
__int16 z = *meshPtr++;
|
|
|
|
vertices[v].vx = x;
|
|
vertices[v].vy = y;
|
|
vertices[v].vz = z;
|
|
|
|
mesh->Positions.push_back(D3DXVECTOR3(x, y, z));
|
|
}
|
|
|
|
__int16 numNormals = *meshPtr++;
|
|
VECTOR* normals = NULL;
|
|
if (numNormals > 0)
|
|
{
|
|
normals = (VECTOR*)malloc(sizeof(VECTOR) * numNormals);
|
|
for (__int32 v = 0; v < numNormals; v++)
|
|
{
|
|
__int16 x = *meshPtr++;
|
|
__int16 y = *meshPtr++;
|
|
__int16 z = *meshPtr++;
|
|
|
|
normals[v].vx = x;
|
|
normals[v].vy = y;
|
|
normals[v].vz = z;
|
|
}
|
|
}
|
|
else
|
|
meshPtr += (-numNormals);
|
|
|
|
__int16 numRectangles = *meshPtr++;
|
|
|
|
for (__int32 r = 0; r < numRectangles; r++)
|
|
{
|
|
__int16 v1 = *meshPtr++;
|
|
__int16 v2 = *meshPtr++;
|
|
__int16 v3 = *meshPtr++;
|
|
__int16 v4 = *meshPtr++;
|
|
__int16 textureId = *meshPtr++;
|
|
__int16 effects = *meshPtr++;
|
|
|
|
__int16 indices[4] = { v1,v2,v3,v4 };
|
|
|
|
__int16 textureIndex = textureId & 0x7FFF;
|
|
bool doubleSided = (textureId & 0x8000) >> 15;
|
|
|
|
// Get the object texture
|
|
OBJECT_TEXTURE* texture = &ObjectTextures[textureIndex];
|
|
__int32 tile = texture->tileAndFlag & 0x7FFF;
|
|
|
|
// Create vertices
|
|
RendererBucket* bucket;
|
|
__int32 bucketIndex = RENDERER_BUCKET_SOLID;
|
|
if (!doubleSided)
|
|
{
|
|
if (texture->attribute == 2 || (effects & 1))
|
|
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
|
|
else if (texture->attribute == 0)
|
|
bucketIndex = RENDERER_BUCKET_SOLID;
|
|
else
|
|
bucketIndex = RENDERER_BUCKET_ALPHA_TEST;
|
|
}
|
|
else
|
|
{
|
|
if (texture->attribute == 2 || (effects & 1))
|
|
bucketIndex = RENDERER_BUCKET_TRANSPARENT_DS;
|
|
else if (texture->attribute == 0)
|
|
bucketIndex = RENDERER_BUCKET_SOLID_DS;
|
|
else
|
|
bucketIndex = RENDERER_BUCKET_ALPHA_TEST_DS;
|
|
}
|
|
|
|
// ColAddHorizon special handling
|
|
if (obj->GetId() == ID_HORIZON && (gfLevelFlags & 0x200))
|
|
{
|
|
if (texture->attribute == 2 || (effects & 1))
|
|
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
|
|
else
|
|
bucketIndex = RENDERER_BUCKET_SOLID;
|
|
}
|
|
|
|
bucket = mesh->GetBucket(bucketIndex);
|
|
obj->HasDataInBucket[bucketIndex] = true;
|
|
|
|
__int32 baseVertices = bucket->NumVertices;
|
|
for (__int32 v = 0; v < 4; v++)
|
|
{
|
|
RendererVertex vertex;
|
|
|
|
vertex.x = vertices[indices[v]].vx;
|
|
vertex.y = vertices[indices[v]].vy;
|
|
vertex.z = vertices[indices[v]].vz;
|
|
|
|
if (numNormals > 0)
|
|
{
|
|
vertex.nx = normals[indices[v]].vx;
|
|
vertex.ny = normals[indices[v]].vy;
|
|
vertex.nz = normals[indices[v]].vz;
|
|
}
|
|
|
|
vertex.u = (texture->vertices[v].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
|
|
vertex.v = (texture->vertices[v].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
|
|
|
|
vertex.boneAndFlags = boneIndex;
|
|
if (isJoints && boneIndex != 0 && m_laraSkinJointRemap[boneIndex][indices[v]] != -1)
|
|
vertex.boneAndFlags = m_laraSkinJointRemap[boneIndex][indices[v]];
|
|
if (isHairs)
|
|
vertex.boneAndFlags = indices[v];
|
|
/*if (isHairs && boneIndex == 0 && indices[v] < 4)
|
|
vertex.bone = 6;
|
|
if (isHairs && boneIndex != 0 && indices[v] < 4)
|
|
vertex.bone = boneIndex - 1;*/
|
|
|
|
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.Indices[0] = baseVertices;
|
|
newPolygon.Indices[1] = baseVertices + 1;
|
|
newPolygon.Indices[2] = baseVertices + 2;
|
|
newPolygon.Indices[3] = baseVertices + 3;
|
|
bucket->Polygons.push_back(newPolygon);
|
|
}
|
|
|
|
__int16 numTriangles = *meshPtr++;
|
|
|
|
for (__int32 r = 0; r < numTriangles; r++)
|
|
{
|
|
__int16 v1 = *meshPtr++;
|
|
__int16 v2 = *meshPtr++;
|
|
__int16 v3 = *meshPtr++;
|
|
__int16 textureId = *meshPtr++;
|
|
__int16 effects = *meshPtr++;
|
|
|
|
__int16 indices[3] = { v1,v2,v3 };
|
|
|
|
__int16 textureIndex = textureId & 0x7FFF;
|
|
bool doubleSided = (textureId & 0x8000) >> 15;
|
|
|
|
// Get the object texture
|
|
OBJECT_TEXTURE* texture = &ObjectTextures[textureIndex];
|
|
__int32 tile = texture->tileAndFlag & 0x7FFF;
|
|
|
|
// Create vertices
|
|
RendererBucket* bucket;
|
|
__int32 bucketIndex = RENDERER_BUCKET_SOLID;
|
|
if (!doubleSided)
|
|
{
|
|
if (texture->attribute == 2 || (effects & 1))
|
|
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
|
|
else if (texture->attribute == 0)
|
|
bucketIndex = RENDERER_BUCKET_SOLID;
|
|
else
|
|
bucketIndex = RENDERER_BUCKET_ALPHA_TEST;
|
|
}
|
|
else
|
|
{
|
|
if (texture->attribute == 2 || (effects & 1))
|
|
bucketIndex = RENDERER_BUCKET_TRANSPARENT_DS;
|
|
else if (texture->attribute == 0)
|
|
bucketIndex = RENDERER_BUCKET_SOLID_DS;
|
|
else
|
|
bucketIndex = RENDERER_BUCKET_ALPHA_TEST_DS;
|
|
}
|
|
bucket = mesh->GetBucket(bucketIndex);
|
|
obj->HasDataInBucket[bucketIndex] = true;
|
|
|
|
__int32 baseVertices = bucket->NumVertices;
|
|
for (__int32 v = 0; v < 3; v++)
|
|
{
|
|
RendererVertex vertex;
|
|
|
|
vertex.x = vertices[indices[v]].vx;
|
|
vertex.y = vertices[indices[v]].vy;
|
|
vertex.z = vertices[indices[v]].vz;
|
|
|
|
if (numNormals > 0)
|
|
{
|
|
vertex.nx = normals[indices[v]].vx;
|
|
vertex.ny = normals[indices[v]].vy;
|
|
vertex.nz = normals[indices[v]].vz;
|
|
}
|
|
|
|
vertex.u = (texture->vertices[v].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
|
|
vertex.v = (texture->vertices[v].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
|
|
|
|
vertex.boneAndFlags = boneIndex;
|
|
if (isJoints && boneIndex != 0 && m_laraSkinJointRemap[boneIndex][indices[v]] != -1)
|
|
vertex.boneAndFlags = m_laraSkinJointRemap[boneIndex][indices[v]];
|
|
if (isHairs)
|
|
vertex.boneAndFlags = indices[v];
|
|
/*if (isHairs && boneIndex == 0 && indices[v] < 4)
|
|
vertex.bone = 6;
|
|
if (isHairs && boneIndex != 0 && indices[v] < 4)
|
|
vertex.bone = boneIndex - 1;*/
|
|
|
|
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.Indices[0] = baseVertices;
|
|
newPolygon.Indices[1] = baseVertices + 1;
|
|
newPolygon.Indices[2] = baseVertices + 2;
|
|
bucket->Polygons.push_back(newPolygon);
|
|
}
|
|
|
|
free(vertices);
|
|
if (normals != NULL) free(normals);
|
|
|
|
if (MeshPointersToMesh.find(refMeshPtr) == MeshPointersToMesh.end())
|
|
MeshPointersToMesh.insert(pair<__int16*, RendererMesh*>(refMeshPtr, mesh));
|
|
|
|
return mesh;
|
|
}
|
|
|
|
bool Renderer::PrepareDataForTheRenderer()
|
|
{
|
|
// Step -1 XD: prepare animated textures
|
|
__int16 numSets = *AnimatedTextureRanges;
|
|
__int16* animatedPtr = AnimatedTextureRanges;
|
|
animatedPtr++;
|
|
|
|
for (__int32 i = 0; i < numSets; i++)
|
|
{
|
|
RendererAnimatedTextureSet* set = new RendererAnimatedTextureSet();
|
|
__int16 numTextures = *animatedPtr + 1;
|
|
animatedPtr++;
|
|
|
|
for (__int32 j = 0; j < numTextures; j++)
|
|
{
|
|
__int16 textureId = *animatedPtr;
|
|
animatedPtr++;
|
|
|
|
OBJECT_TEXTURE* texture = &ObjectTextures[textureId];
|
|
__int32 tile = texture->tileAndFlag & 0x7FFF;
|
|
|
|
RendererAnimatedTexture* newTexture = new RendererAnimatedTexture();
|
|
newTexture->Id = textureId;
|
|
|
|
for (__int32 k = 0; k < 4; k++)
|
|
{
|
|
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] = D3DXVECTOR2(x, y);
|
|
}
|
|
|
|
set->Textures.push_back(newTexture);
|
|
}
|
|
|
|
m_animatedTextureSets.push_back(set);
|
|
}
|
|
|
|
// Step 0: free all previus resources
|
|
for (map<__int32, RendererRoom*>::iterator it = m_rooms.begin(); it != m_rooms.end(); ++it)
|
|
delete (it->second);
|
|
m_rooms.clear();
|
|
|
|
for (map<__int32, RendererObject*>::iterator it = m_moveableObjects.begin(); it != m_moveableObjects.end(); ++it)
|
|
delete (it->second);
|
|
m_moveableObjects.clear();
|
|
|
|
for (map<__int32, RendererObject*>::iterator it = m_staticObjects.begin(); it != m_staticObjects.end(); ++it)
|
|
delete (it->second);
|
|
m_staticObjects.clear();
|
|
|
|
// Step 1: create the texture atlas
|
|
byte* buffer = (byte*)malloc(TEXTURE_ATLAS_SIZE * TEXTURE_ATLAS_SIZE * 4);
|
|
__int32 blockX = 0;
|
|
__int32 blockY = 0;
|
|
|
|
ZeroMemory(buffer, TEXTURE_ATLAS_SIZE * TEXTURE_ATLAS_SIZE * 4);
|
|
|
|
__int32 typ = LaraDrawType;
|
|
if (gfLevelFlags & 1)
|
|
{
|
|
memcpy(m_laraSkinJointRemap, m_youngLaraSkinJointRemap, 15 * 32 * 2);
|
|
}
|
|
else
|
|
{
|
|
memcpy(m_laraSkinJointRemap, m_normalLaraSkinJointRemap, 15 * 32 * 2);
|
|
}
|
|
|
|
for (int p = 0; p < NumTexturePages; p++)
|
|
{
|
|
for (int y = 0; y < 256; y++)
|
|
{
|
|
for (int x = 0; x < 256; x++)
|
|
{
|
|
__int32 pixelIndex = blockY * TEXTURE_PAGE_SIZE * NUM_TEXTURE_PAGES_PER_ROW + y * 256 * NUM_TEXTURE_PAGES_PER_ROW * 4 + blockX * 256 * 4 + x * 4;
|
|
__int32 oldPixelIndex = p * TEXTURE_PAGE_SIZE + y * 256 * 4 + x * 4;
|
|
|
|
byte r = Texture32[oldPixelIndex];
|
|
byte g = Texture32[oldPixelIndex + 1];
|
|
byte b = Texture32[oldPixelIndex + 2];
|
|
byte a = Texture32[oldPixelIndex + 3];
|
|
|
|
//if (r == 0 && g == 0 && b == 0)
|
|
// a = 0;
|
|
|
|
buffer[pixelIndex] = r;
|
|
buffer[pixelIndex + 1] = g;
|
|
buffer[pixelIndex + 2] = b;
|
|
buffer[pixelIndex + 3] = a;
|
|
}
|
|
}
|
|
|
|
blockX++;
|
|
if (blockX == NUM_TEXTURE_PAGES_PER_ROW)
|
|
{
|
|
blockX = 0;
|
|
blockY++;
|
|
}
|
|
}
|
|
|
|
// Release the eventually old texture
|
|
if (m_textureAtlas != NULL)
|
|
m_textureAtlas->Release();
|
|
|
|
// Create the new texture atlas
|
|
D3DXCreateTexture(m_device, TEXTURE_ATLAS_SIZE, TEXTURE_ATLAS_SIZE, 0, D3DX_DEFAULT,
|
|
D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_textureAtlas);
|
|
|
|
// Lock the texture pixels and copy them from the buffer
|
|
D3DLOCKED_RECT rect;
|
|
m_textureAtlas->LockRect(0, &rect, NULL, NULL);
|
|
unsigned char* dest = static_cast<unsigned char*>(rect.pBits);
|
|
memcpy(dest, buffer, TEXTURE_ATLAS_SIZE * TEXTURE_ATLAS_SIZE * 4);
|
|
m_textureAtlas->UnlockRect(0);
|
|
|
|
D3DXSaveTextureToFile("E:\\Atlas.png", D3DXIMAGE_FILEFORMAT::D3DXIFF_PNG, m_textureAtlas, NULL);
|
|
|
|
// Release the temp buffer
|
|
free(buffer);
|
|
|
|
// Release the eventually old texture
|
|
if (m_fontAndMiscTexture != NULL)
|
|
m_fontAndMiscTexture->Release();
|
|
|
|
if (m_skyTexture != NULL)
|
|
m_skyTexture->Release();
|
|
|
|
// Create the new texture atlas
|
|
D3DXCreateTexture(m_device, 256, 768, 0, D3DX_DEFAULT, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_fontAndMiscTexture);
|
|
|
|
// Lock the texture pixels and copy them from the buffer
|
|
m_fontAndMiscTexture->LockRect(0, &rect, NULL, NULL);
|
|
dest = static_cast<unsigned char*>(rect.pBits);
|
|
memcpy(dest, MiscTextures, 256 * 768 * 4);
|
|
m_fontAndMiscTexture->UnlockRect(0);
|
|
//D3DXSaveTextureToFile("E:\\Misc.png", D3DXIMAGE_FILEFORMAT::D3DXIFF_PNG, m_fontAndMiscTexture, NULL);
|
|
|
|
D3DXCreateTexture(m_device, 256, 256, 0, D3DX_DEFAULT, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_skyTexture);
|
|
|
|
m_skyTexture->LockRect(0, &rect, NULL, NULL);
|
|
dest = static_cast<unsigned char*>(rect.pBits);
|
|
memcpy(dest, MiscTextures + 256 * 512 * 4, 256 * 256 * 4);
|
|
m_fontAndMiscTexture->UnlockRect(0);
|
|
|
|
// Step 2: prepare rooms
|
|
for (__int32 i = 0; i < NumberRooms; i++)
|
|
{
|
|
ROOM_INFO* room = &Rooms[i];
|
|
RendererObject* roomObject = new RendererObject(m_device, -1, 1);
|
|
RendererMesh* mesh = new RendererMesh(m_device);
|
|
RendererRoom* r = new RendererRoom();
|
|
r->Room = room;
|
|
r->RoomObject = roomObject;
|
|
r->AmbientLight = D3DXVECTOR4(room->ambient.r / 255.0f, room->ambient.g / 255.0f, room->ambient.b / 255.0f, 1.0f);
|
|
|
|
m_rooms.insert(pair<__int32, RendererRoom*>(i, r));
|
|
|
|
if (room->NumVertices == 0)
|
|
continue;
|
|
|
|
__int32 lastRectangle = 0;
|
|
__int32 lastTriangle = 0;
|
|
|
|
tr5_room_layer* layers = (tr5_room_layer*)room->LayerOffset;
|
|
|
|
for (__int32 l = 0; l < room->NumLayers; l++)
|
|
{
|
|
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 r = 0; r < layer->NumLayerRectangles; r++)
|
|
{
|
|
tr4_mesh_face4* poly = (tr4_mesh_face4*)polygons;
|
|
|
|
// Get the real texture index and if double sided
|
|
__int16 textureIndex = poly->Texture & 0x3FFF;
|
|
bool doubleSided = (poly->Texture & 0x8000) >> 15;
|
|
|
|
// Get the object texture
|
|
OBJECT_TEXTURE* texture = &ObjectTextures[textureIndex];
|
|
__int32 tile = texture->tileAndFlag & 0x7FFF;
|
|
|
|
// Create vertices
|
|
RendererBucket* bucket;
|
|
|
|
__int32 animatedSetIndex = getAnimatedTextureInfo(textureIndex);
|
|
__int32 bucketIndex = RENDERER_BUCKET_SOLID;
|
|
|
|
if (!doubleSided)
|
|
{
|
|
if (texture->attribute == 2)
|
|
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
|
|
else if (texture->attribute == 0)
|
|
bucketIndex = RENDERER_BUCKET_SOLID;
|
|
else
|
|
bucketIndex = RENDERER_BUCKET_ALPHA_TEST;
|
|
}
|
|
else
|
|
{
|
|
if (texture->attribute == 2)
|
|
bucketIndex = RENDERER_BUCKET_TRANSPARENT_DS;
|
|
else if (texture->attribute == 0)
|
|
bucketIndex = RENDERER_BUCKET_SOLID_DS;
|
|
else
|
|
bucketIndex = RENDERER_BUCKET_ALPHA_TEST_DS;
|
|
}
|
|
|
|
if (animatedSetIndex == -1)
|
|
{
|
|
bucket = mesh->GetBucket(bucketIndex);
|
|
roomObject->HasDataInBucket[bucketIndex] = true;
|
|
}
|
|
else
|
|
{
|
|
bucket = mesh->GetAnimatedBucket(bucketIndex);
|
|
roomObject->HasDataInAnimatedBucket[bucketIndex] = true;
|
|
}
|
|
|
|
// Calculate face normal
|
|
D3DXVECTOR3 p0 = D3DXVECTOR3(vertices[poly->Vertices[0]].Vertex.x,
|
|
vertices[poly->Vertices[0]].Vertex.y,
|
|
vertices[poly->Vertices[0]].Vertex.z);
|
|
D3DXVECTOR3 p1 = D3DXVECTOR3(vertices[poly->Vertices[1]].Vertex.x,
|
|
vertices[poly->Vertices[1]].Vertex.y,
|
|
vertices[poly->Vertices[1]].Vertex.z);
|
|
D3DXVECTOR3 p2 = D3DXVECTOR3(vertices[poly->Vertices[2]].Vertex.x,
|
|
vertices[poly->Vertices[2]].Vertex.y,
|
|
vertices[poly->Vertices[2]].Vertex.z);
|
|
D3DXVECTOR3 e1 = p1 - p0;
|
|
D3DXVECTOR3 e2 = p1 - p2;
|
|
D3DXVECTOR3 normal;
|
|
D3DXVec3Cross(&normal, &e1, &e2);
|
|
D3DXVec3Normalize(&normal, &normal);
|
|
|
|
__int32 baseVertices = bucket->NumVertices;
|
|
for (__int32 v = 0; v < 4; v++)
|
|
{
|
|
RendererVertex vertex; // = new RendererVertex();
|
|
|
|
vertex.x = vertices[poly->Vertices[v]].Vertex.x;
|
|
vertex.y = vertices[poly->Vertices[v]].Vertex.y;
|
|
vertex.z = vertices[poly->Vertices[v]].Vertex.z;
|
|
|
|
vertex.nx = vertices[poly->Vertices[v]].Normal.x;
|
|
vertex.ny = vertices[poly->Vertices[v]].Normal.y;
|
|
vertex.nz = vertices[poly->Vertices[v]].Normal.z;
|
|
|
|
vertex.u = (texture->vertices[v].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
|
|
vertex.v = (texture->vertices[v].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
|
|
|
|
vertex.r = ((vertices[poly->Vertices[v]].Colour >> 16) & 0xFF) / 255.0f;
|
|
vertex.g = ((vertices[poly->Vertices[v]].Colour >> 8) & 0xFF) / 255.0f;
|
|
vertex.b = ((vertices[poly->Vertices[v]].Colour >> 0) & 0xFF) / 255.0f;
|
|
vertex.a = 1.0f;
|
|
|
|
bucket->NumVertices++;
|
|
bucket->Vertices.push_back(vertex);
|
|
roomObject->NumVertices++;
|
|
}
|
|
|
|
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 r = 0; r < layer->NumLayerTriangles; r++)
|
|
{
|
|
tr4_mesh_face3* poly = (tr4_mesh_face3*)polygons;
|
|
|
|
// Get the real texture index and if double sided
|
|
__int16 textureIndex = poly->Texture & 0x3FFF;
|
|
bool doubleSided = (poly->Texture & 0x8000) >> 15;
|
|
|
|
// Get the object texture
|
|
OBJECT_TEXTURE* texture = &ObjectTextures[textureIndex];
|
|
__int32 tile = texture->tileAndFlag & 0x7FFF;
|
|
|
|
// Create vertices
|
|
RendererBucket* bucket;
|
|
|
|
__int32 animatedSetIndex = getAnimatedTextureInfo(textureIndex);
|
|
__int32 bucketIndex = RENDERER_BUCKET_SOLID;
|
|
|
|
if (!doubleSided)
|
|
{
|
|
if (texture->attribute == 2)
|
|
bucketIndex = RENDERER_BUCKET_TRANSPARENT;
|
|
else if (texture->attribute == 0)
|
|
bucketIndex = RENDERER_BUCKET_SOLID;
|
|
else
|
|
bucketIndex = RENDERER_BUCKET_ALPHA_TEST;
|
|
}
|
|
else
|
|
{
|
|
if (texture->attribute == 2)
|
|
bucketIndex = RENDERER_BUCKET_TRANSPARENT_DS;
|
|
else if (texture->attribute == 0)
|
|
bucketIndex = RENDERER_BUCKET_SOLID_DS;
|
|
else
|
|
bucketIndex = RENDERER_BUCKET_ALPHA_TEST_DS;
|
|
}
|
|
|
|
if (animatedSetIndex == -1)
|
|
{
|
|
bucket = mesh->GetBucket(bucketIndex);
|
|
roomObject->HasDataInBucket[bucketIndex] = true;
|
|
}
|
|
else
|
|
{
|
|
bucket = mesh->GetAnimatedBucket(bucketIndex);
|
|
roomObject->HasDataInAnimatedBucket[bucketIndex] = true;
|
|
}
|
|
|
|
// Calculate face normal
|
|
D3DXVECTOR3 p0 = D3DXVECTOR3(vertices[poly->Vertices[0]].Vertex.x,
|
|
vertices[poly->Vertices[0]].Vertex.y,
|
|
vertices[poly->Vertices[0]].Vertex.z);
|
|
D3DXVECTOR3 p1 = D3DXVECTOR3(vertices[poly->Vertices[1]].Vertex.x,
|
|
vertices[poly->Vertices[1]].Vertex.y,
|
|
vertices[poly->Vertices[1]].Vertex.z);
|
|
D3DXVECTOR3 p2 = D3DXVECTOR3(vertices[poly->Vertices[2]].Vertex.x,
|
|
vertices[poly->Vertices[2]].Vertex.y,
|
|
vertices[poly->Vertices[2]].Vertex.z);
|
|
D3DXVECTOR3 e1 = p1 - p0;
|
|
D3DXVECTOR3 e2 = p1 - p2;
|
|
D3DXVECTOR3 normal;
|
|
D3DXVec3Cross(&normal, &e1, &e2);
|
|
D3DXVec3Normalize(&normal, &normal);
|
|
|
|
__int32 baseVertices = bucket->NumVertices;
|
|
for (__int32 v = 0; v < 3; v++)
|
|
{
|
|
RendererVertex vertex; // = new RendererVertex();
|
|
|
|
vertex.x = vertices[poly->Vertices[v]].Vertex.x;
|
|
vertex.y = vertices[poly->Vertices[v]].Vertex.y;
|
|
vertex.z = vertices[poly->Vertices[v]].Vertex.z;
|
|
|
|
vertex.nx = vertices[poly->Vertices[v]].Normal.x;
|
|
vertex.ny = vertices[poly->Vertices[v]].Normal.y;
|
|
vertex.nz = vertices[poly->Vertices[v]].Normal.z;
|
|
|
|
vertex.u = (texture->vertices[v].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE;
|
|
vertex.v = (texture->vertices[v].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE;
|
|
|
|
vertex.r = ((vertices[poly->Vertices[v]].Colour >> 16) & 0xFF) / 255.0f;
|
|
vertex.g = ((vertices[poly->Vertices[v]].Colour >> 8) & 0xFF) / 255.0f;
|
|
vertex.b = ((vertices[poly->Vertices[v]].Colour >> 0) & 0xFF) / 255.0f;
|
|
vertex.a = 1.0f;
|
|
|
|
bucket->NumVertices++;
|
|
bucket->Vertices.push_back(vertex);
|
|
roomObject->NumVertices++;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (room->numLights != 0)
|
|
{
|
|
tr5_room_light* oldLight = room->light;
|
|
|
|
for (__int32 l = 0; l < room->numLights; l++)
|
|
{
|
|
// DEBUG: only point lights
|
|
|
|
RendererLight* light = new RendererLight();
|
|
/*if (oldLight->LightType == LIGHT_TYPES::LIGHT_TYPE_SUN)
|
|
{
|
|
light->Color = D3DXVECTOR4(oldLight->r, oldLight->g, oldLight->b, 1.0f);
|
|
light->Direction = D3DXVECTOR4(oldLight->dx, oldLight->dy, oldLight->dz, 1.0f);
|
|
light->Type = LIGHT_TYPES::LIGHT_TYPE_SUN;
|
|
}
|
|
else*/ if (oldLight->LightType == LIGHT_TYPES::LIGHT_TYPE_POINT)
|
|
{
|
|
light->Position = D3DXVECTOR4(oldLight->x, oldLight->y, oldLight->z, 1.0f);
|
|
light->Color = D3DXVECTOR4(oldLight->r, oldLight->g, oldLight->b, 1.0f);
|
|
light->Direction = D3DXVECTOR4(oldLight->dx, oldLight->dy, oldLight->dz, 1.0f);
|
|
light->Intensity = 1.0f;
|
|
light->In = oldLight->In;
|
|
light->Out = oldLight->Out;
|
|
light->Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
|
|
}
|
|
/*else if (oldLight->LightType == LIGHT_TYPES::LIGHT_TYPE_SHADOW)
|
|
{
|
|
light->Position = D3DXVECTOR4(oldLight->x, oldLight->y, oldLight->z, 1.0f);
|
|
light->Color = D3DXVECTOR4(oldLight->r, oldLight->g, oldLight->b, 1.0f);
|
|
light->Direction = D3DXVECTOR4(oldLight->dx, oldLight->dy, oldLight->dz, 1.0f);
|
|
light->In = oldLight->In;
|
|
light->Out = oldLight->Out;
|
|
light->Type = LIGHT_TYPES::LIGHT_TYPE_SHADOW;
|
|
}*/
|
|
else if (oldLight->LightType == LIGHT_TYPES::LIGHT_TYPE_SPOT)
|
|
{
|
|
light->Position = D3DXVECTOR4(oldLight->x, oldLight->y, oldLight->z, 1.0f);
|
|
light->Color = D3DXVECTOR4(oldLight->r, oldLight->g, oldLight->b, 1.0f);
|
|
light->Direction = D3DXVECTOR4(oldLight->dx, oldLight->dy, oldLight->dz, 1.0f);
|
|
light->Intensity = 1.0f;
|
|
light->In = oldLight->In;
|
|
light->Out = oldLight->Range; //oldLight->Out;
|
|
light->Range = oldLight->Range;
|
|
light->Type = LIGHT_TYPES::LIGHT_TYPE_POINT; // LIGHT_TYPES::LIGHT_TYPE_SPOT;
|
|
}
|
|
|
|
r->Lights.push_back(light);
|
|
}
|
|
}
|
|
|
|
for (__int32 i = 0; i < NUM_BUCKETS; i++)
|
|
mesh->GetBucket((RENDERER_BUCKETS)i)->UpdateBuffers();
|
|
|
|
roomObject->ObjectMeshes.push_back(mesh);
|
|
}
|
|
|
|
m_numHairVertices = 0;
|
|
m_numHairIndices = 0;
|
|
|
|
// Step 3: prepare moveables
|
|
for (__int32 i = 0; i < MoveablesIds.size(); i++)
|
|
{
|
|
__int32 objNum = MoveablesIds[i];
|
|
OBJECT_INFO* obj = &Objects[objNum];
|
|
|
|
if (obj->nmeshes > 0)
|
|
{
|
|
RendererObject* moveable = new RendererObject(m_device, MoveablesIds[i], obj->nmeshes);
|
|
|
|
// 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)
|
|
{
|
|
moveable->DoNotDraw = true;
|
|
}
|
|
else
|
|
{
|
|
moveable->DoNotDraw = false;
|
|
}
|
|
|
|
for (__int32 j = 0; j < obj->nmeshes; j++)
|
|
{
|
|
// HACK: mesh pointer 0 is the placeholder for Lara's body parts and is right hand with pistols
|
|
// We need to override the box index because the engine will take mesh 0 while drawing pistols anim,
|
|
// and vertices have bone index 0 and not 10
|
|
__int32 meshPtrIndex = RawMeshPointers[obj->meshIndex / 2 + j] / 2;
|
|
__int32 boneIndex = (meshPtrIndex == 0 ? HAND_R : j);
|
|
|
|
__int16* meshPtr = &RawMeshData[meshPtrIndex];
|
|
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);
|
|
}
|
|
|
|
__int32* bone = &MeshTrees[obj->boneIndex];
|
|
|
|
stack<RendererBone*> stack;
|
|
|
|
for (int j = 0; j < obj->nmeshes; j++)
|
|
moveable->LinearizedBones.push_back(new RendererBone(j));
|
|
|
|
RendererBone* currentBone = moveable->LinearizedBones[0];
|
|
RendererBone* stackBone = moveable->LinearizedBones[0];
|
|
|
|
for (int mi = 0; mi < obj->nmeshes - 1; mi++)
|
|
{
|
|
int j = mi + 1;
|
|
|
|
__int32 opcode = *(bone++);
|
|
int linkX = *(bone++);
|
|
int linkY = *(bone++);
|
|
int linkZ = *(bone++);
|
|
|
|
switch (opcode)
|
|
{
|
|
case 0:
|
|
moveable->LinearizedBones[j]->Parent = currentBone;
|
|
moveable->LinearizedBones[j]->Translation = D3DXVECTOR3(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 = D3DXVECTOR3(linkX, linkY, linkZ);
|
|
currentBone->Children.push_back(moveable->LinearizedBones[j]);
|
|
currentBone = moveable->LinearizedBones[j];
|
|
|
|
break;
|
|
case 2:
|
|
stack.push(currentBone);
|
|
|
|
moveable->LinearizedBones[j]->Translation = D3DXVECTOR3(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 = D3DXVECTOR3(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++)
|
|
D3DXMatrixTranslation(&moveable->LinearizedBones[n]->Transform,
|
|
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];
|
|
|
|
for (__int32 j = 1; j < obj->nmeshes; j++)
|
|
{
|
|
RendererMesh* jointMesh = moveable->ObjectMeshes[j];
|
|
RendererBone* jointBone = moveable->LinearizedBones[j];
|
|
|
|
for (__int32 b1 = 0; b1 < NUM_BUCKETS; b1++)
|
|
{
|
|
RendererBucket* jointBucket = jointMesh->GetBucket((RENDERER_BUCKETS)b1);
|
|
for (__int32 v1 = 0; v1 < jointBucket->Vertices.size(); v1++)
|
|
{
|
|
RendererVertex* jointVertex = &jointBucket->Vertices[v1];
|
|
if (jointVertex->boneAndFlags != j)
|
|
{
|
|
RendererMesh* skinMesh = objSkin->ObjectMeshes[jointVertex->boneAndFlags];
|
|
RendererBone* skinBone = objSkin->LinearizedBones[jointVertex->boneAndFlags];
|
|
|
|
for (__int32 b2 = 0; b2 < NUM_BUCKETS; b2++)
|
|
{
|
|
RendererBucket* skinBucket = skinMesh->GetBucket((RENDERER_BUCKETS)b2);
|
|
for (__int32 v2 = 0; v2 < skinBucket->Vertices.size(); v2++)
|
|
{
|
|
RendererVertex* skinVertex = &skinBucket->Vertices[v2];
|
|
|
|
__int32 x1 = jointBucket->Vertices[v1].x + jointBone->GlobalTranslation.x;
|
|
__int32 y1 = jointBucket->Vertices[v1].y + jointBone->GlobalTranslation.y;
|
|
__int32 z1 = jointBucket->Vertices[v1].z + jointBone->GlobalTranslation.z;
|
|
|
|
__int32 x2 = skinBucket->Vertices[v2].x + skinBone->GlobalTranslation.x;
|
|
__int32 y2 = skinBucket->Vertices[v2].y + skinBone->GlobalTranslation.y;
|
|
__int32 z2 = skinBucket->Vertices[v2].z + skinBone->GlobalTranslation.z;
|
|
|
|
if (abs(x1 - x2) < 2 && abs(y1 - y2) < 2 && abs(z1 - z2) < 2)
|
|
{
|
|
jointVertex->x = skinVertex->x;
|
|
jointVertex->y = skinVertex->y;
|
|
jointVertex->z = skinVertex->z;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Rebuild the LARA_SKIN object
|
|
for (__int32 j = 0; j < objSkin->ObjectMeshes.size(); j++)
|
|
{
|
|
RendererMesh* mesh = objSkin->ObjectMeshes[j];
|
|
for (__int32 n = 0; n < NUM_BUCKETS; n++)
|
|
mesh->GetBucket((RENDERER_BUCKETS)n)->UpdateBuffers();
|
|
}
|
|
}
|
|
|
|
if (MoveablesIds[i] == ID_HAIR)
|
|
{
|
|
for (__int32 j = 0; j < moveable->ObjectMeshes.size(); j++)
|
|
{
|
|
RendererMesh* mesh = moveable->ObjectMeshes[j];
|
|
for (__int32 n = 0; n < NUM_BUCKETS; n++)
|
|
{
|
|
m_numHairVertices += mesh->GetBucket((RENDERER_BUCKETS)n)->NumVertices;
|
|
m_numHairIndices += mesh->GetBucket((RENDERER_BUCKETS)n)->NumIndices;
|
|
}
|
|
}
|
|
|
|
m_hairVertices = (RendererVertex*)malloc(m_numHairVertices * 2 * sizeof(RendererVertex));
|
|
m_hairIndices = (__int32*)malloc(m_numHairIndices * 2 * 4);
|
|
}
|
|
|
|
// Initialise buffers
|
|
for (__int32 j = 0; j < obj->nmeshes; j++)
|
|
{
|
|
RendererMesh* mesh = moveable->ObjectMeshes[j];
|
|
for (__int32 n = 0; n < NUM_BUCKETS; n++)
|
|
mesh->GetBucket((RENDERER_BUCKETS)n)->UpdateBuffers();
|
|
}
|
|
|
|
m_moveableObjects.insert(pair<__int32, RendererObject*>(MoveablesIds[i], moveable));
|
|
}
|
|
}
|
|
|
|
// Step 4: prepare static meshes
|
|
for (__int32 i = 0; i < StaticObjectsIds.size(); i++)
|
|
{
|
|
STATIC_INFO* obj = &StaticObjects[StaticObjectsIds[i]];
|
|
RendererObject* staticObject = new RendererObject(m_device, StaticObjectsIds[i], 1);
|
|
|
|
__int16* meshPtr = &RawMeshData[RawMeshPointers[obj->meshNumber / 2] / 2];
|
|
RendererMesh* mesh = GetRendererMeshFromTrMesh(staticObject, meshPtr, Meshes[obj->meshNumber], 0, false, false);
|
|
|
|
for (__int32 i = 0; i < NUM_BUCKETS; i++)
|
|
mesh->GetBucket((RENDERER_BUCKETS)i)->UpdateBuffers();
|
|
|
|
staticObject->ObjectMeshes.push_back(mesh);
|
|
|
|
m_staticObjects.insert(pair<__int32, RendererObject*>(StaticObjectsIds[i], staticObject));
|
|
}
|
|
|
|
// Step 5: prepare sprites
|
|
for (__int32 i = 0; i < 41; i++)
|
|
{
|
|
SPRITE* oldSprite = &Sprites[i];
|
|
RendererSprite* sprite = new RendererSprite();
|
|
|
|
sprite->Width = (oldSprite->right - oldSprite->left)*256.0f;
|
|
sprite->Height = (oldSprite->bottom - oldSprite->top)*256.0f;
|
|
|
|
float left = (oldSprite->left * 256.0f /*+ 0.5f*/ + GET_ATLAS_PAGE_X(oldSprite->tile - 1));
|
|
float top = (oldSprite->top * 256.0f /*+ 0.5f*/ + GET_ATLAS_PAGE_Y(oldSprite->tile - 1));
|
|
float right = (oldSprite->right * 256.0f /*+ 0.5f*/ + GET_ATLAS_PAGE_X(oldSprite->tile - 1));
|
|
float bottom = (oldSprite->bottom * 256.0f /*+ 0.5f*/ + GET_ATLAS_PAGE_Y(oldSprite->tile - 1));
|
|
|
|
sprite->UV[0] = D3DXVECTOR2(left / (float)TEXTURE_ATLAS_SIZE, top / (float)TEXTURE_ATLAS_SIZE);
|
|
sprite->UV[1] = D3DXVECTOR2(right / (float)TEXTURE_ATLAS_SIZE, top / (float)TEXTURE_ATLAS_SIZE);
|
|
sprite->UV[2] = D3DXVECTOR2(right / (float)TEXTURE_ATLAS_SIZE, bottom / (float)TEXTURE_ATLAS_SIZE);
|
|
sprite->UV[3] = D3DXVECTOR2(left / (float)TEXTURE_ATLAS_SIZE, bottom / (float)TEXTURE_ATLAS_SIZE);
|
|
|
|
m_sprites.insert(pair<__int32, RendererSprite*>(i, sprite));
|
|
}
|
|
|
|
for (__int32 i = 0; i < MoveablesIds.size(); i++)
|
|
{
|
|
OBJECT_INFO* obj = &Objects[MoveablesIds[i]];
|
|
|
|
if (obj->nmeshes < 0)
|
|
{
|
|
__int16 numSprites = abs(obj->nmeshes);
|
|
__int16 baseSprite = obj->meshIndex;
|
|
|
|
RendererSpriteSequence* sequence = new RendererSpriteSequence(MoveablesIds[i]);
|
|
|
|
for (__int32 j = baseSprite; j < baseSprite + numSprites; j++)
|
|
{
|
|
RendererSprite* sprite = m_sprites[j];
|
|
sequence->SpritesList.push_back(sprite);
|
|
}
|
|
|
|
m_spriteSequences.insert(pair<__int32, RendererSpriteSequence*>(MoveablesIds[i], sequence));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Renderer::BuildHierarchyRecursive(RendererObject* obj, RendererBone* node, RendererBone* parentNode)
|
|
{
|
|
D3DXMatrixMultiply(&node->GlobalTransform, &node->Transform, &parentNode->GlobalTransform);
|
|
obj->BindPoseTransforms[node->Index] = node->GlobalTransform;
|
|
obj->Skeleton->GlobalTranslation = D3DXVECTOR3(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 Renderer::BuildHierarchy(RendererObject* obj)
|
|
{
|
|
obj->Skeleton->GlobalTransform = obj->Skeleton->Transform;
|
|
obj->BindPoseTransforms[obj->Skeleton->Index] = obj->Skeleton->GlobalTransform;
|
|
obj->Skeleton->GlobalTranslation = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
|
|
|
|
for (int j = 0; j < obj->Skeleton->Children.size(); j++)
|
|
{
|
|
BuildHierarchyRecursive(obj, obj->Skeleton->Children[j], obj->Skeleton);
|
|
}
|
|
}
|
|
|
|
void Renderer::FromTrAngle(D3DXMATRIX* matrix, __int16* frameptr, __int32 index)
|
|
{
|
|
__int16* ptr = &frameptr[0];
|
|
|
|
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);
|
|
|
|
D3DXMatrixRotationYawPitchRoll(matrix, rotY* (360.0f / 1024.0f) * RADIAN,
|
|
rotX* (360.0f / 1024.0f) * RADIAN,
|
|
rotZ* (360.0f / 1024.0f) * RADIAN);
|
|
break;
|
|
|
|
case 0x4000:
|
|
D3DXMatrixRotationX(matrix, (rot0 & 0xfff)* (360.0f / 4096.0f) * RADIAN);
|
|
break;
|
|
|
|
case 0x8000:
|
|
D3DXMatrixRotationY(matrix, (rot0 & 0xfff)* (360.0f / 4096.0f) * RADIAN);
|
|
break;
|
|
|
|
case 0xc000:
|
|
D3DXMatrixRotationZ(matrix, (rot0 & 0xfff)* (360.0f / 4096.0f) * RADIAN);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Renderer::BuildAnimationPoseRecursive(RendererObject* obj, __int16** frmptr, D3DXMATRIX* parentTransform,
|
|
__int16 frac, __int16 rate, RendererBone* bone, __int32 mask)
|
|
{
|
|
bool calculateMatrix = (mask >> bone->Index) & 1;
|
|
|
|
D3DXMATRIX rotation;
|
|
if (calculateMatrix)
|
|
{
|
|
FromTrAngle(&rotation, frmptr[0], bone->Index);
|
|
|
|
if (frac)
|
|
{
|
|
D3DXMATRIX rotation2;
|
|
FromTrAngle(&rotation2, frmptr[1], bone->Index);
|
|
|
|
D3DXQUATERNION q1, q2, q3;
|
|
|
|
D3DXQuaternionRotationMatrix(&q1, &rotation);
|
|
D3DXQuaternionRotationMatrix(&q2, &rotation2);
|
|
|
|
D3DXQuaternionSlerp(&q3, &q1, &q2, frac / ((float)rate));
|
|
|
|
D3DXMatrixRotationQuaternion(&rotation, &q3);
|
|
}
|
|
|
|
D3DXMATRIX extraRotation;
|
|
D3DXMatrixRotationYawPitchRoll(&extraRotation, bone->ExtraRotation.y, bone->ExtraRotation.x, bone->ExtraRotation.z);
|
|
|
|
D3DXMatrixMultiply(&obj->AnimationTransforms[bone->Index], &extraRotation, &bone->Transform);
|
|
D3DXMatrixMultiply(&obj->AnimationTransforms[bone->Index], &rotation, &obj->AnimationTransforms[bone->Index]);
|
|
D3DXMatrixMultiply(&obj->AnimationTransforms[bone->Index], &obj->AnimationTransforms[bone->Index], parentTransform);
|
|
}
|
|
|
|
for (int j = 0; j < bone->Children.size(); j++)
|
|
{
|
|
BuildAnimationPoseRecursive(obj, frmptr, &obj->AnimationTransforms[bone->Index], frac, rate,
|
|
bone->Children[j], mask);
|
|
}
|
|
}
|
|
|
|
void Renderer::BuildAnimationPose(RendererObject* obj, __int16** frmptr, __int16 frac, __int16 rate, __int32 mask)
|
|
{
|
|
D3DXVECTOR3 p = D3DXVECTOR3((int)*(frmptr[0] + 6), (int)*(frmptr[0] + 7), (int)*(frmptr[0] + 8));
|
|
|
|
bool calculateMatrix = (mask >> obj->Skeleton->Index) & 1;
|
|
|
|
D3DXMATRIX rotation;
|
|
if (calculateMatrix)
|
|
{
|
|
FromTrAngle(&rotation, frmptr[0], obj->Skeleton->Index);
|
|
|
|
if (frac)
|
|
{
|
|
D3DXVECTOR3 p2 = D3DXVECTOR3((int)*(frmptr[1] + 6), (int)*(frmptr[1] + 7), (int)*(frmptr[1] + 8));
|
|
D3DXVec3Lerp(&p, &p, &p2, frac / ((float)rate));
|
|
|
|
D3DXMATRIX rotation2;
|
|
FromTrAngle(&rotation2, frmptr[1], obj->Skeleton->Index);
|
|
|
|
D3DXQUATERNION q1, q2, q3;
|
|
|
|
D3DXQuaternionRotationMatrix(&q1, &rotation);
|
|
D3DXQuaternionRotationMatrix(&q2, &rotation2);
|
|
|
|
D3DXQuaternionSlerp(&q3, &q1, &q2, frac / ((float)rate));
|
|
|
|
D3DXMatrixRotationQuaternion(&rotation, &q3);
|
|
}
|
|
|
|
D3DXMATRIX translation;
|
|
D3DXMatrixTranslation(&translation, p.x, p.y, p.z);
|
|
|
|
D3DXMATRIX extraRotation;
|
|
D3DXMatrixRotationYawPitchRoll(&extraRotation, obj->Skeleton->ExtraRotation.y, obj->Skeleton->ExtraRotation.x, obj->Skeleton->ExtraRotation.z);
|
|
|
|
D3DXMatrixMultiply(&obj->AnimationTransforms[obj->Skeleton->Index], &extraRotation, &translation);
|
|
D3DXMatrixMultiply(&obj->AnimationTransforms[obj->Skeleton->Index], &rotation, &obj->AnimationTransforms[obj->Skeleton->Index]);
|
|
}
|
|
|
|
for (int j = 0; j < obj->Skeleton->Children.size(); j++)
|
|
{
|
|
BuildAnimationPoseRecursive(obj, frmptr, &obj->AnimationTransforms[obj->Skeleton->Index], frac, rate,
|
|
obj->Skeleton->Children[j], mask);
|
|
}
|
|
}
|
|
|
|
void Renderer::GetVisibleRooms(int from, int to, D3DXVECTOR4* viewPort, bool water, int count)
|
|
{
|
|
if (count > 8) {
|
|
return;
|
|
}
|
|
|
|
ROOM_INFO* room = &Rooms[to];
|
|
|
|
if (!m_rooms[to]->Visited) {
|
|
m_rooms[to]->Visited = true;
|
|
m_roomsToDraw.push_back(to);
|
|
}
|
|
|
|
D3DXVECTOR4 clipPort;
|
|
__int16 numDoors = *(room->door);
|
|
if (numDoors)
|
|
{
|
|
__int16* door = room->door + 1;
|
|
for (int i = 0; i < numDoors; i++) {
|
|
__int16 adjoiningRoom = *(door);
|
|
|
|
if (from != adjoiningRoom && CheckPortal(to, door, viewPort, &clipPort))
|
|
GetVisibleRooms(to, adjoiningRoom, &clipPort, water, count + 1);
|
|
|
|
door += 16;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Renderer::CheckPortal(__int16 roomIndex, __int16* portal, D3DXVECTOR4* viewPort, D3DXVECTOR4* clipPort)
|
|
{
|
|
ROOM_INFO* room = &Rooms[roomIndex];
|
|
|
|
D3DXVECTOR3 n = D3DXVECTOR3(*(portal + 1), *(portal + 2), *(portal + 3));
|
|
D3DXVECTOR3 v = D3DXVECTOR3(Camera.pos.x - (room->x + *(portal + 4)),
|
|
Camera.pos.y - (room->y + *(portal + 5)),
|
|
Camera.pos.z - (room->z + *(portal + 6)));
|
|
|
|
if (D3DXVec3Dot(&n, &v) <= 0.0f)
|
|
return false;
|
|
|
|
int zClip = 0;
|
|
D3DXVECTOR4 p[4];
|
|
|
|
clipPort->x = FLT_MAX;
|
|
clipPort->y = FLT_MAX;
|
|
clipPort->z = FLT_MIN;
|
|
clipPort->w = FLT_MIN;
|
|
|
|
D3DXMATRIX viewProj;
|
|
D3DXMatrixMultiply(&viewProj, &ViewMatrix, &ProjectionMatrix);
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
D3DXVECTOR4 tmp = D3DXVECTOR4(*(portal + 4 + 3 * i) + room->x, *(portal + 4 + 3 * i+1) + room->y,
|
|
*(portal + 4 + 3 * i+2) + room->z, 1.0f);
|
|
D3DXVec4Transform(&p[i], &tmp, &viewProj);
|
|
|
|
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++) {
|
|
D3DXVECTOR4 a = p[i];
|
|
D3DXVECTOR4 b = p[(i + 1) % 4];
|
|
|
|
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 Renderer::CollectRooms()
|
|
{
|
|
__int16 baseRoomIndex = Camera.pos.roomNumber;
|
|
|
|
for (__int32 i = 0; i < NumberRooms; i++)
|
|
if (m_rooms[i] != NULL)
|
|
m_rooms[i]->Visited = false;
|
|
|
|
m_roomsToDraw.clear();
|
|
GetVisibleRooms(-1, baseRoomIndex, &D3DXVECTOR4(-1.0f, -1.0f, 1.0f, 1.0f), false, 0);
|
|
}
|
|
|
|
void Renderer::CollectItems()
|
|
{
|
|
for (vector<RendererItemToDraw*>::iterator it = m_itemsToDraw.begin(); it != m_itemsToDraw.end(); ++it)
|
|
delete (*it);
|
|
m_itemsToDraw.clear();
|
|
|
|
RendererItemToDraw* newItem = new RendererItemToDraw(Lara.itemNumber, LaraItem);
|
|
m_itemsToDraw.push_back(newItem);
|
|
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
ROOM_INFO* r = room->Room;
|
|
|
|
__int16 itemNum = NO_ITEM;
|
|
for (itemNum = r->itemNumber; itemNum != NO_ITEM; itemNum = Items[itemNum].nextItem)
|
|
{
|
|
ITEM_INFO* item = &Items[itemNum];
|
|
if (item->objectNumber == ID_LARA)
|
|
continue;
|
|
|
|
newItem = new RendererItemToDraw(itemNum, item);
|
|
m_itemsToDraw.push_back(newItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Renderer::CollectLights()
|
|
{
|
|
/*if (m_itemsLightInfo == NULL)
|
|
m_itemsLightInfo = (RendererLightInfo*)malloc(NumItems * sizeof(RendererLightInfo));
|
|
|
|
// Reset shadow map
|
|
m_litItems.clear();
|
|
m_enableShadows = false;
|
|
|
|
for (__int32 i = 0; i < NumItems; i++)
|
|
m_itemsLightInfo[i].Active = false;
|
|
|
|
// Take the brightest/nearest light only for drawn items
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
// NB: first item is always Lara
|
|
//__int32 itemIndex = m_itemsToDraw[i];
|
|
RendererItemToDraw* itemToDraw = m_itemsToDraw[i];
|
|
ITEM_INFO* item = itemToDraw->Item;
|
|
RendererRoom* room = m_rooms[item->roomNumber];
|
|
|
|
// Search for the brightest light. We do a simple version of the classic calculation done in pixel shader.
|
|
if (room->Lights.size() != 0)
|
|
{
|
|
m_itemsLightInfo[itemIndex].Active = false;
|
|
|
|
RendererLight* brightestLight = NULL;
|
|
float brightest = 0.0f;
|
|
|
|
for (__int32 j = 0; j < room->Lights.size(); j++)
|
|
{
|
|
RendererLight* light = room->Lights[j];
|
|
|
|
D3DXVECTOR4 itemPos = D3DXVECTOR4(item->pos.xPos, item->pos.yPos, item->pos.zPos, 1.0f);
|
|
D3DXVECTOR4 lightVector = itemPos - light->Position;
|
|
|
|
float distance = D3DXVec4Length(&lightVector);
|
|
D3DXVec4Normalize(&lightVector, &lightVector);
|
|
|
|
float intensity;
|
|
float attenuation;
|
|
float angle;
|
|
float d;
|
|
float attenuationRange;
|
|
float attenuationAngle;
|
|
|
|
switch (light->Type)
|
|
{
|
|
case LIGHT_TYPES::LIGHT_TYPE_POINT:
|
|
if (distance > light->Out)
|
|
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;
|
|
/*case LIGHTTYPE_SPOT:
|
|
if (distance > light->Range)
|
|
continue;
|
|
|
|
d = D3DXVec3Dot(&lightDir, &lightVector);
|
|
angle = acosf(d);
|
|
|
|
if (angle > light->RadOut)
|
|
continue;
|
|
|
|
attenuationRange = 1.0f - distance / light->Range;
|
|
attenuationAngle = 1.0f - angle / light->RadOut;
|
|
intensity = max(0.0f, attenuationRange * attenuationAngle * (light->r + light->g + light->b) / 3.0f);
|
|
|
|
if (intensity >= brightest)
|
|
{
|
|
brightest = intensity;
|
|
brightestLight = light;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
light++;
|
|
}
|
|
|
|
// Try also dynamic lights
|
|
for (__int32 j = 0; j < m_dynamicLights.size(); j++)
|
|
{
|
|
RendererLight* dynamicLight = m_dynamicLights[j];
|
|
|
|
D3DXVECTOR4 itemPos = D3DXVECTOR4(item->pos.xPos, item->pos.yPos, item->pos.zPos, 1.0f);
|
|
D3DXVECTOR4 lightVector = itemPos - dynamicLight->Position;
|
|
|
|
float distance = D3DXVec4Length(&lightVector);
|
|
D3DXVec4Normalize(&lightVector, &lightVector);
|
|
|
|
float intensity;
|
|
float attenuation;
|
|
float angle;
|
|
float d;
|
|
float attenuationRange;
|
|
float attenuationAngle;
|
|
|
|
switch (dynamicLight->Type)
|
|
{
|
|
case LIGHT_TYPES::LIGHT_TYPE_POINT:
|
|
if (distance > dynamicLight->Out)
|
|
continue;
|
|
|
|
attenuation = 1.0f - distance / dynamicLight->Out;
|
|
intensity = max(0.0f, attenuation * (dynamicLight->Color.x + dynamicLight->Color.y + dynamicLight->Color.z) / 3.0f);
|
|
|
|
if (intensity >= brightest)
|
|
{
|
|
brightest = intensity;
|
|
brightestLight = dynamicLight;
|
|
}
|
|
|
|
break;
|
|
|
|
case LIGHT_TYPES::LIGHT_TYPE_SPOT:
|
|
if (distance > dynamicLight->Range)
|
|
continue;
|
|
|
|
attenuation = 1.0f - distance / dynamicLight->Range;
|
|
intensity = max(0.0f, attenuation * (dynamicLight->Color.x + dynamicLight->Color.y + dynamicLight->Color.z) / 3.0f);
|
|
|
|
if (intensity >= brightest)
|
|
{
|
|
brightest = intensity;
|
|
brightestLight = dynamicLight;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If the brightest light is found, then fill the data structure
|
|
if (brightestLight != NULL)
|
|
{
|
|
m_itemsLightInfo[itemIndex].Active = true;
|
|
m_itemsLightInfo[itemIndex].AmbientLight = room->AmbientLight;
|
|
m_itemsLightInfo[itemIndex].Light = brightestLight;
|
|
|
|
// Add the light to shadow maps caster, if possible
|
|
if (m_shadowLight == NULL)
|
|
{
|
|
m_shadowLight = brightestLight;
|
|
}
|
|
|
|
if (m_shadowLight == brightestLight)
|
|
{
|
|
m_litItems.push_back(i);
|
|
break;
|
|
}
|
|
}
|
|
}*
|
|
}*/
|
|
}
|
|
|
|
void Renderer::PrepareShadowMaps()
|
|
{
|
|
UINT cPasses = 1;
|
|
D3DXMATRIX world;
|
|
|
|
// We don't need
|
|
RENDERER_BUCKETS buckets[4] = {
|
|
RENDERER_BUCKETS::RENDERER_BUCKET_SOLID,
|
|
RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS,
|
|
RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST,
|
|
RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS
|
|
};
|
|
|
|
if (m_shadowLight == NULL)
|
|
return;
|
|
|
|
D3DXVECTOR3 lightPos = D3DXVECTOR3(m_shadowLight->Position.x, m_shadowLight->Position.y, m_shadowLight->Position.z);
|
|
|
|
m_depthShader->GetEffect()->Begin(&cPasses, 0);
|
|
m_depthShader->SetTexture(m_textureAtlas);
|
|
|
|
D3DXMatrixPerspectiveFovRH(&m_lightProjection, 90.0f * RADIAN, 1.0f, 1.0f, m_shadowLight->Out * 1.5f);
|
|
m_depthShader->SetProjection(&m_lightProjection);
|
|
|
|
/*for (__int32 f = 0; f < 6; f++)
|
|
{
|
|
D3DXVECTOR3 direction = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
|
|
switch (f)
|
|
{
|
|
case D3DCUBEMAP_FACES::D3DCUBEMAP_FACE_POSITIVE_X:
|
|
direction = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
|
|
break;
|
|
case D3DCUBEMAP_FACES::D3DCUBEMAP_FACE_NEGATIVE_X:
|
|
direction = D3DXVECTOR3(-1.0f, 0.0f, 0.0f);
|
|
break;
|
|
case D3DCUBEMAP_FACES::D3DCUBEMAP_FACE_POSITIVE_Y:
|
|
direction = D3DXVECTOR3(0.0f, -1.0f, 0.0f);
|
|
break;
|
|
case D3DCUBEMAP_FACES::D3DCUBEMAP_FACE_NEGATIVE_Y:
|
|
direction = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
|
|
break;
|
|
case D3DCUBEMAP_FACES::D3DCUBEMAP_FACE_POSITIVE_Z:
|
|
direction = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
|
|
break;
|
|
case D3DCUBEMAP_FACES::D3DCUBEMAP_FACE_NEGATIVE_Z:
|
|
direction = D3DXVECTOR3(0.0f, 0.0f, -1.0f);
|
|
break;
|
|
}
|
|
|
|
D3DXMatrixLookAtRH(&m_lightView,
|
|
&lightPos,
|
|
&direction,
|
|
&D3DXVECTOR3(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos),
|
|
&D3DXVECTOR3(0.0f, -1.0f, 0.0f));
|
|
*/
|
|
|
|
D3DXMatrixLookAtRH(&m_lightView,
|
|
&lightPos,
|
|
&D3DXVECTOR3(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos),
|
|
&D3DXVECTOR3(0.0f, -1.0f, 0.0f));
|
|
|
|
m_depthShader->SetView(&m_lightView);
|
|
|
|
// Bind the shadow map
|
|
//m_shadowMapCube->Bind((D3DCUBEMAP_FACES)f);
|
|
m_shadowMap->Bind();
|
|
|
|
// Begin the scene
|
|
m_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xFFFFFFFF, 1.0f, 0);
|
|
m_device->BeginScene();
|
|
|
|
//Draw Lara
|
|
for (__int32 k = 0; k < 4; k++)
|
|
{
|
|
DrawLaraLPP((RENDERER_BUCKETS)k, RENDERER_PASSES::RENDERER_PASS_SHADOW_MAP);
|
|
}
|
|
|
|
// Draw visible items
|
|
for (__int32 j = 0; j < m_itemsToDraw.size(); j++)
|
|
{
|
|
RendererItemToDraw* itemToDraw = m_itemsToDraw[j];
|
|
ITEM_INFO* item = itemToDraw->Item;
|
|
|
|
D3DXVECTOR3 itemPos = D3DXVECTOR3(item->pos.xPos, item->pos.yPos, item->pos.zPos);
|
|
D3DXVECTOR3 lightVector = (itemPos - lightPos);
|
|
float distance = D3DXVec3Length(&lightVector);
|
|
|
|
if (distance > m_shadowLight->Out*1.5f)
|
|
continue;
|
|
|
|
for (__int32 k = 0; k < 4; k++)
|
|
{
|
|
DrawItemLPP(m_itemsToDraw[j], (RENDERER_BUCKETS)k, RENDERER_PASSES::RENDERER_PASS_SHADOW_MAP);
|
|
}
|
|
}
|
|
|
|
m_device->EndScene();
|
|
m_shadowMap->Unbind();
|
|
|
|
//m_shadowMapCube->Unbind();
|
|
//}
|
|
|
|
m_depthShader->GetEffect()->End();
|
|
}
|
|
|
|
bool Renderer::DrawPrimitives(D3DPRIMITIVETYPE primitiveType, UINT baseVertexIndex, UINT minVertexIndex, UINT numVertices, UINT baseIndex, UINT primitiveCount)
|
|
{
|
|
m_numVertices += numVertices;
|
|
m_numTriangles += primitiveCount;
|
|
m_numDrawCalls++;
|
|
|
|
HRESULT res = m_device->DrawIndexedPrimitive(primitiveType, baseVertexIndex, minVertexIndex, numVertices, baseIndex, primitiveCount);
|
|
return (res == S_OK);
|
|
}
|
|
|
|
bool Renderer::DrawRoom(__int32 roomIndex, RENDERER_BUCKETS bucketIndex, RENDERER_PASSES pass)
|
|
{
|
|
/*D3DXMATRIX world;
|
|
UINT cPasses = 1;
|
|
|
|
// If nothing to render then exit
|
|
RendererRoom* room = m_rooms[roomIndex];
|
|
RendererObject* obj = room->RoomObject;
|
|
if (obj == NULL)
|
|
return true;
|
|
if (obj->ObjectMeshes.size() == 0)
|
|
return true;
|
|
|
|
RendererMesh* mesh = obj->ObjectMeshes[0];
|
|
ROOM_INFO* r = room->Room;
|
|
RendererBucket* bucket;
|
|
|
|
// Draw room geometry first
|
|
bucket = mesh->GetBucket(bucketIndex);
|
|
if (bucket->NumVertices == 0)
|
|
return true;
|
|
|
|
// Bind buffers
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
// Set shader parameters
|
|
LPD3DXEFFECT effect;
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_DEPTH)
|
|
{
|
|
effect = m_depthShader->GetEffect();
|
|
}
|
|
else
|
|
{
|
|
effect = m_mainShader->GetEffect();
|
|
|
|
if (m_shadowLight != NULL && LaraItem->roomNumber == roomIndex)
|
|
{
|
|
m_mainShader->SetEnableShadows(true);
|
|
m_mainShader->SetShadowMap(m_shadowMap->GetTexture());
|
|
m_mainShader->SetLightView(&m_lightView);
|
|
m_mainShader->SetLightProjection(&m_lightProjection);
|
|
|
|
RendererLightInfo* light = &m_itemsLightInfo[m_itemsToDraw[0]];
|
|
m_mainShader->SetLightActive(light->Active);
|
|
if (light->Active)
|
|
{
|
|
m_mainShader->SetLightPosition(&light->Light->Position);
|
|
m_mainShader->SetLightDirection(&light->Light->Direction);
|
|
m_mainShader->SetLightColor(&light->Light->Color);
|
|
m_mainShader->SetLightIn(light->Light->In);
|
|
m_mainShader->SetLightOut(light->Light->Out);
|
|
m_mainShader->SetLightRange(light->Light->Range);
|
|
m_mainShader->SetLightType(light->Light->Type);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_mainShader->SetEnableShadows(false);
|
|
m_mainShader->SetShadowMap(NULL);
|
|
m_mainShader->SetLightActive(false);
|
|
}
|
|
|
|
m_mainShader->SetAmbientLight(&room->AmbientLight);
|
|
m_mainShader->SetModelType(MODEL_TYPES::MODEL_TYPE_ROOM);
|
|
}
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
D3DXMatrixTranslation(&world, r->x, r->y, r->z);
|
|
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_DEPTH)
|
|
m_depthShader->SetWorld(&world);
|
|
else
|
|
m_mainShader->SetWorld(&world);
|
|
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}*/
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::DrawStatic(__int32 roomIndex, __int32 staticIndex, RENDERER_BUCKETS bucketIndex, RENDERER_PASSES pass)
|
|
{
|
|
D3DXMATRIX world;
|
|
D3DXMATRIX rotation;
|
|
UINT cPasses = 1;
|
|
|
|
ROOM_INFO* room = &Rooms[roomIndex];
|
|
MESH_INFO* sobj = &room->mesh[staticIndex];
|
|
RendererObject* obj = m_staticObjects[sobj->staticNumber];
|
|
RendererMesh* mesh = obj->ObjectMeshes[0];
|
|
RendererBucket* bucket = mesh->GetBucket(bucketIndex);
|
|
if (bucket->NumVertices == 0)
|
|
return true;
|
|
|
|
// Bind buffers
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
LPD3DXEFFECT effect;
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_DEPTH)
|
|
{
|
|
effect = m_depthShader->GetEffect();
|
|
if (bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST ||
|
|
bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS)
|
|
{
|
|
m_depthShader->SetBlendMode(BLENDMODE_ALPHATEST);
|
|
}
|
|
else
|
|
{
|
|
m_depthShader->SetBlendMode(BLENDMODE_OPAQUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
effect = m_mainShader->GetEffect();
|
|
m_mainShader->SetModelType(MODEL_TYPES::MODEL_TYPE_STATIC);
|
|
}
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
|
|
D3DXMatrixTranslation(&world, sobj->x, sobj->y, sobj->z);
|
|
D3DXMatrixRotationY(&rotation, TR_ANGLE_TO_RAD(sobj->yRot));
|
|
D3DXMatrixMultiply(&world, &rotation, &world);
|
|
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_DEPTH)
|
|
m_depthShader->SetWorld(&world);
|
|
else
|
|
m_mainShader->SetWorld(&world);
|
|
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0,
|
|
bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Renderer::UpdateLaraAnimations()
|
|
{
|
|
D3DXMATRIX translation;
|
|
D3DXMATRIX rotation;
|
|
D3DXMATRIX lastMatrix;
|
|
D3DXMATRIX hairMatrix;
|
|
D3DXMATRIX identity;
|
|
D3DXMATRIX world;
|
|
|
|
RendererObject* laraObj = m_moveableObjects[ID_LARA];
|
|
|
|
// Lara world matrix
|
|
D3DXMatrixTranslation(&translation, LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos);
|
|
D3DXMatrixRotationYawPitchRoll(&rotation,
|
|
TR_ANGLE_TO_RAD(LaraItem->pos.yRot),
|
|
TR_ANGLE_TO_RAD(LaraItem->pos.xRot),
|
|
TR_ANGLE_TO_RAD(LaraItem->pos.zRot));
|
|
D3DXMatrixMultiply(&m_LaraWorldMatrix, &rotation, &translation);
|
|
|
|
// Update first Lara's animations
|
|
laraObj->LinearizedBones[TORSO]->ExtraRotation = D3DXVECTOR3(TR_ANGLE_TO_RAD(Lara.torsoXrot),
|
|
TR_ANGLE_TO_RAD(Lara.torsoYrot), TR_ANGLE_TO_RAD(Lara.torsoZrot));
|
|
laraObj->LinearizedBones[HEAD]->ExtraRotation = D3DXVECTOR3(TR_ANGLE_TO_RAD(Lara.headXrot),
|
|
TR_ANGLE_TO_RAD(Lara.headYrot), TR_ANGLE_TO_RAD(Lara.headZrot));
|
|
|
|
// First calculate matrices for legs, hips, head and torso
|
|
__int32 mask = (1 << HIPS) | (1 << THIGH_L) | (1 << CALF_L) | (1 << FOOT_L) |
|
|
(1 << THIGH_R) | (1 << CALF_R) | (1 << FOOT_R) | (1 << TORSO) | (1 << HEAD);
|
|
__int16 *framePtr[2];
|
|
__int32 rate;
|
|
__int32 frac = GetFrame_D2(LaraItem, framePtr, &rate);
|
|
BuildAnimationPose(laraObj, framePtr, frac, rate, mask);
|
|
|
|
// Then the arms, based on current weapon status
|
|
if ((Lara.gunStatus == LG_NO_ARMS || Lara.gunStatus == LG_HANDS_BUSY) && Lara.gunType != WEAPON_FLARE)
|
|
{
|
|
// Both arms
|
|
mask = (1 << UARM_L) | (1 << LARM_L) | (1 << HAND_L) | (1 << UARM_R) |
|
|
(1 << LARM_R) | (1 << HAND_R);
|
|
frac = GetFrame_D2(LaraItem, framePtr, &rate);
|
|
BuildAnimationPose(laraObj, framePtr, frac, rate, mask);
|
|
}
|
|
else
|
|
{
|
|
// While handling weapon some extra rotation could be applied to arms
|
|
laraObj->LinearizedBones[UARM_L]->ExtraRotation += D3DXVECTOR3(TR_ANGLE_TO_RAD(Lara.leftArm.xRot),
|
|
TR_ANGLE_TO_RAD(Lara.leftArm.yRot), TR_ANGLE_TO_RAD(Lara.leftArm.zRot));
|
|
laraObj->LinearizedBones[UARM_R]->ExtraRotation += D3DXVECTOR3(TR_ANGLE_TO_RAD(Lara.rightArm.xRot),
|
|
TR_ANGLE_TO_RAD(Lara.rightArm.yRot), TR_ANGLE_TO_RAD(Lara.rightArm.zRot));
|
|
|
|
if (Lara.gunType != WEAPON_FLARE)
|
|
{
|
|
// HACK: shotgun must be handled differently (and probably also crossbow)
|
|
if (Lara.gunType == WEAPON_SHOTGUN)
|
|
{
|
|
// Left arm
|
|
mask = (1 << UARM_L) | (1 << LARM_L) | (1 << HAND_L);
|
|
__int16* shotgunFramePtr = Lara.leftArm.frameBase + (Lara.leftArm.frameNumber) * (Anims[Lara.leftArm.animNumber].interpolation >> 8);
|
|
BuildAnimationPose(laraObj, &shotgunFramePtr, 0, 1, mask);
|
|
|
|
// Right arm
|
|
mask = (1 << UARM_R) | (1 << LARM_R) | (1 << HAND_R);
|
|
shotgunFramePtr = Lara.rightArm.frameBase + (Lara.rightArm.frameNumber) * (Anims[Lara.rightArm.animNumber].interpolation >> 8);
|
|
BuildAnimationPose(laraObj, &shotgunFramePtr, 0, 1, mask);
|
|
}
|
|
else
|
|
{
|
|
// Left arm
|
|
mask = (1 << UARM_L) | (1 << LARM_L) | (1 << HAND_L);
|
|
frac = GetFrame(Lara.leftArm.animNumber, Lara.leftArm.frameNumber, framePtr, &rate);
|
|
BuildAnimationPose(laraObj, framePtr, frac, rate, mask);
|
|
|
|
// Right arm
|
|
mask = (1 << UARM_R) | (1 << LARM_R) | (1 << HAND_R);
|
|
frac = GetFrame(Lara.rightArm.animNumber, Lara.rightArm.frameNumber, framePtr, &rate);
|
|
BuildAnimationPose(laraObj, framePtr, frac, rate, mask);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Left arm
|
|
mask = (1 << UARM_L) | (1 << LARM_L) | (1 << HAND_L);
|
|
frac = GetFrame(Lara.leftArm.animNumber, Lara.leftArm.frameNumber, framePtr, &rate);
|
|
BuildAnimationPose(laraObj, framePtr, frac, rate, mask);
|
|
|
|
// Right arm
|
|
mask = (1 << UARM_R) | (1 << LARM_R) | (1 << HAND_R);
|
|
frac = GetFrame_D2(LaraItem, framePtr, &rate);
|
|
BuildAnimationPose(laraObj, framePtr, frac, rate, mask);
|
|
}
|
|
}
|
|
|
|
// At this point, Lara's matrices are ready. Now let's do ponytails...
|
|
if (m_moveableObjects.find(ID_HAIR) != m_moveableObjects.end())
|
|
{
|
|
RendererObject* hairsObj = m_moveableObjects[ID_HAIR];
|
|
|
|
D3DXMatrixIdentity(&lastMatrix);
|
|
D3DXMatrixIdentity(&identity);
|
|
|
|
D3DXVECTOR3 parentVertices[6][4];
|
|
D3DXMATRIX headMatrix;
|
|
|
|
RendererObject* objSkin = m_moveableObjects[ID_LARA_SKIN];
|
|
RendererObject* objLara = m_moveableObjects[ID_LARA];
|
|
RendererMesh* parentMesh = objSkin->ObjectMeshes[HEAD];
|
|
RendererBone* parentBone = objSkin->LinearizedBones[HEAD];
|
|
|
|
D3DXMatrixMultiply(&world, &objLara->AnimationTransforms[HEAD], &m_LaraWorldMatrix);
|
|
|
|
__int32 lastVertex = 0;
|
|
__int32 lastIndex = 0;
|
|
|
|
ZeroMemory(m_hairVertices, m_numHairVertices * 2 * sizeof(RendererObject));
|
|
ZeroMemory(m_hairIndices, m_numHairIndices * 2 * 4);
|
|
|
|
for (__int32 p = 0; p < ((gfLevelFlags & 1) ? 2 : 1); p++)
|
|
{
|
|
// We can't use hardware skinning here, however hairs have just a few vertices so
|
|
// it's not so bad doing skinning in software
|
|
if (gfLevelFlags & 1)
|
|
{
|
|
if (p == 1)
|
|
{
|
|
D3DXVec3TransformCoord(&parentVertices[0][0], &parentMesh->Positions[68], &world);
|
|
D3DXVec3TransformCoord(&parentVertices[0][1], &parentMesh->Positions[69], &world);
|
|
D3DXVec3TransformCoord(&parentVertices[0][2], &parentMesh->Positions[70], &world);
|
|
D3DXVec3TransformCoord(&parentVertices[0][3], &parentMesh->Positions[71], &world);
|
|
}
|
|
else
|
|
{
|
|
D3DXVec3TransformCoord(&parentVertices[0][0], &parentMesh->Positions[79], &world);
|
|
D3DXVec3TransformCoord(&parentVertices[0][1], &parentMesh->Positions[78], &world);
|
|
D3DXVec3TransformCoord(&parentVertices[0][2], &parentMesh->Positions[76], &world);
|
|
D3DXVec3TransformCoord(&parentVertices[0][3], &parentMesh->Positions[77], &world);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
D3DXVec3TransformCoord(&parentVertices[0][0], &parentMesh->Positions[37], &world);
|
|
D3DXVec3TransformCoord(&parentVertices[0][1], &parentMesh->Positions[39], &world);
|
|
D3DXVec3TransformCoord(&parentVertices[0][2], &parentMesh->Positions[40], &world);
|
|
D3DXVec3TransformCoord(&parentVertices[0][3], &parentMesh->Positions[38], &world);
|
|
}
|
|
|
|
for (__int32 i = 0; i < 6; i++)
|
|
{
|
|
RendererMesh* mesh = hairsObj->ObjectMeshes[i];
|
|
RendererBucket* bucket = mesh->GetBucket(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID);
|
|
|
|
D3DXMatrixTranslation(&translation, Hairs[7 * p + i].pos.xPos, Hairs[7 * p + i].pos.yPos, Hairs[7 * p + i].pos.zPos);
|
|
D3DXMatrixRotationYawPitchRoll(&rotation,
|
|
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));
|
|
D3DXMatrixMultiply(&m_hairsMatrices[6 * p + i], &rotation, &translation);
|
|
|
|
__int32 baseVertex = lastVertex;
|
|
|
|
for (__int32 j = 0; j < bucket->Vertices.size(); j++)
|
|
{
|
|
__int32 oldVertexIndex = (__int32)bucket->Vertices[j].boneAndFlags;
|
|
if (oldVertexIndex < 4)
|
|
{
|
|
m_hairVertices[lastVertex].x = parentVertices[i][oldVertexIndex].x;
|
|
m_hairVertices[lastVertex].y = parentVertices[i][oldVertexIndex].y;
|
|
m_hairVertices[lastVertex].z = parentVertices[i][oldVertexIndex].z;
|
|
m_hairVertices[lastVertex].u = bucket->Vertices[j].u;
|
|
m_hairVertices[lastVertex].v = bucket->Vertices[j].v;
|
|
|
|
D3DXVECTOR3 n = D3DXVECTOR3(bucket->Vertices[j].nx, bucket->Vertices[j].ny, bucket->Vertices[j].nz);
|
|
D3DXVec3Normalize(&n, &n);
|
|
D3DXVec3TransformCoord(&n, &n, &m_hairsMatrices[6 * p + i]);
|
|
D3DXVec3Normalize(&n, &n);
|
|
|
|
m_hairVertices[lastVertex].nx = n.x;
|
|
m_hairVertices[lastVertex].ny = n.y;
|
|
m_hairVertices[lastVertex].nz = n.z;
|
|
|
|
lastVertex++;
|
|
}
|
|
else
|
|
{
|
|
D3DXVECTOR3 in = D3DXVECTOR3(bucket->Vertices[j].x, bucket->Vertices[j].y, bucket->Vertices[j].z);
|
|
D3DXVECTOR4 out;
|
|
|
|
D3DXVec3Transform(&out, &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].x = out.x;
|
|
m_hairVertices[lastVertex].y = out.y;
|
|
m_hairVertices[lastVertex].z = out.z;
|
|
m_hairVertices[lastVertex].u = bucket->Vertices[j].u;
|
|
m_hairVertices[lastVertex].v = bucket->Vertices[j].v;
|
|
|
|
D3DXVECTOR3 n = D3DXVECTOR3(bucket->Vertices[j].nx, bucket->Vertices[j].ny, bucket->Vertices[j].nz);
|
|
D3DXVec3Normalize(&n, &n);
|
|
D3DXVec3TransformCoord(&n, &n, &m_hairsMatrices[6 * p + i]);
|
|
D3DXVec3Normalize(&n, &n);
|
|
|
|
m_hairVertices[lastVertex].nx = n.x;
|
|
m_hairVertices[lastVertex].ny = n.y;
|
|
m_hairVertices[lastVertex].nz = n.z;
|
|
|
|
lastVertex++;
|
|
}
|
|
}
|
|
|
|
for (__int32 j = 0; j < bucket->Indices.size(); j++)
|
|
{
|
|
m_hairIndices[lastIndex] = baseVertex + bucket->Indices[j];
|
|
lastIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Renderer::UpdateItemsAnimations()
|
|
{
|
|
D3DXMATRIX translation;
|
|
D3DXMATRIX rotation;
|
|
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
RendererItemToDraw* itemToDraw = m_itemsToDraw[i];
|
|
ITEM_INFO* item = itemToDraw->Item;
|
|
|
|
// Lara has her own routine
|
|
if (item->objectNumber == ID_LARA || item->objectNumber == 434)
|
|
continue;
|
|
|
|
OBJECT_INFO* obj = &Objects[item->objectNumber];
|
|
RendererObject* moveableObj = m_moveableObjects[item->objectNumber];
|
|
|
|
// Update animation matrices
|
|
if (obj->animIndex != -1)
|
|
{
|
|
__int16 *framePtr[2];
|
|
__int32 rate;
|
|
__int32 frac = GetFrame_D2(item, framePtr, &rate);
|
|
BuildAnimationPose(moveableObj, framePtr, frac, rate, 0xFFFFFFFF);
|
|
}
|
|
|
|
// Update world matrix
|
|
D3DXMatrixTranslation(&translation, item->pos.xPos, item->pos.yPos, item->pos.zPos);
|
|
D3DXMatrixRotationYawPitchRoll(&rotation, TR_ANGLE_TO_RAD(item->pos.yRot),
|
|
TR_ANGLE_TO_RAD(item->pos.xRot), TR_ANGLE_TO_RAD(item->pos.zRot));
|
|
D3DXMatrixMultiply(&itemToDraw->World, &rotation, &translation);
|
|
}
|
|
}
|
|
|
|
__int32 Renderer::DumpGameScene()
|
|
{
|
|
return DrawSceneLightPrePass(true);
|
|
}
|
|
|
|
__int32 Renderer::BeginRenderToTexture()
|
|
{
|
|
/*m_backBufferTarget = NULL;
|
|
m_device->GetRenderTarget(0, &m_backBufferTarget);
|
|
|
|
LPDIRECT3DSURFACE9 surface;
|
|
m_renderTarget->GetSurfaceLevel(0, &surface);
|
|
m_device->SetRenderTarget(0, surface);
|
|
surface->Release();
|
|
|
|
m_backBufferDepth = NULL;
|
|
m_device->GetDepthStencilSurface(&m_backBufferDepth);
|
|
m_device->SetDepthStencilSurface(m_renderTargetDepth);
|
|
*/
|
|
return 1;
|
|
}
|
|
|
|
__int32 Renderer::EndRenderToTexture()
|
|
{
|
|
/*m_device->SetRenderTarget(0, m_backBufferTarget);
|
|
m_device->SetDepthStencilSurface(m_backBufferDepth);*/
|
|
|
|
return 1;
|
|
}
|
|
|
|
__int32 Renderer::Draw()
|
|
{
|
|
return DrawSceneLightPrePass(false);
|
|
}
|
|
|
|
void Renderer::InsertLine2D(__int32 x1, __int32 y1, __int32 x2, __int32 y2, byte r, byte g, byte b)
|
|
{
|
|
m_lines[m_numLines].Vertices[0] = D3DXVECTOR2(x1, y1);
|
|
m_lines[m_numLines].Vertices[1] = D3DXVECTOR2(x2, y2);
|
|
m_lines[m_numLines].Color = D3DCOLOR_XRGB(r, g, b);
|
|
m_numLines++;
|
|
}
|
|
|
|
void Renderer::DrawAllLines2D()
|
|
{
|
|
m_line->SetWidth(1);
|
|
m_line->SetPattern(0xffffffff);
|
|
m_line->Begin();
|
|
|
|
for (__int32 i = 0; i < m_numLines; i++)
|
|
{
|
|
m_line->Draw(m_lines[i].Vertices, 2, m_lines[i].Color);
|
|
}
|
|
|
|
m_line->End();
|
|
}
|
|
|
|
void Renderer::DrawBar(__int32 x, __int32 y, __int32 w, __int32 h, __int32 percent, __int32 color1, __int32 color2)
|
|
{
|
|
byte r1 = (color1 >> 16) & 0xFF;
|
|
byte g1 = (color1 >> 8) & 0xFF;
|
|
byte b1 = (color1 >> 0) & 0xFF;
|
|
|
|
byte r2 = (color2 >> 16) & 0xFF;
|
|
byte g2 = (color2 >> 8) & 0xFF;
|
|
byte b2 = (color2 >> 0) & 0xFF;
|
|
|
|
float factor = ScreenWidth / 800.0f;
|
|
|
|
__int32 realX = x * factor;
|
|
__int32 realY = y * factor;
|
|
__int32 realW = w * factor;
|
|
__int32 realH = h * factor;
|
|
|
|
__int32 realPercent = percent / 100.0f * realW;
|
|
|
|
for (__int32 i = 0; i < realH; i++)
|
|
InsertLine2D(realX, realY + i, realX + realW, realY + i, 0, 0, 0);
|
|
|
|
for (__int32 i = 0; i < realH; i++)
|
|
InsertLine2D(realX, realY + i, realX + realPercent, realY + i, r1, g1, b1);
|
|
|
|
InsertLine2D(realX, realY, realX + realW, realY, 255, 255, 255);
|
|
InsertLine2D(realX, realY + realH, realX + realW, realY + realH, 255, 255, 255);
|
|
InsertLine2D(realX, realY, realX, realY + realH, 255, 255, 255);
|
|
InsertLine2D(realX + realW, realY, realX + realW, realY + realH + 1, 255, 255, 255);
|
|
}
|
|
|
|
void Renderer::DrawGameInfo()
|
|
{
|
|
__int32 flashState = FlashIt();
|
|
|
|
UpdateHealtBar(flashState);
|
|
UpdateAirBar(flashState);
|
|
DrawDashBar();
|
|
}
|
|
|
|
void Renderer::DrawDashBar()
|
|
{
|
|
if (DashTimer < 120)
|
|
DrawBar(460, 32, 150, 12, 100 * (unsigned __int16)DashTimer / 120, 0xA0A000, 0xA000);
|
|
}
|
|
|
|
void Renderer::DrawAirBar(__int32 percentual)
|
|
{
|
|
//if (CurrentLevel)
|
|
//{
|
|
DrawBar(450, 10, 150, 12, percentual, 0x0000A0, 0x0050A0);
|
|
//}
|
|
}
|
|
|
|
void Renderer::DrawHealthBar(__int32 percentual)
|
|
{
|
|
//if (CurrentLevel)
|
|
//{
|
|
__int32 color2 = 0xA00000;
|
|
if (Lara.poisoned || Lara.gassed)
|
|
color2 = 0xA0A000;
|
|
DrawBar(10, 10, 150, 12, percentual, 0xA00000, color2);
|
|
//}
|
|
}
|
|
|
|
void Renderer::DrawDebugInfo()
|
|
{
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_CCW);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_OPAQUE);
|
|
SetDepthWrite(true);
|
|
|
|
if (UseSpotCam)
|
|
{
|
|
sprintf_s(&m_message[0], 255, "Spotcam.camera = %d Spotcam.flags = %d Current: %d", SpotCam[CurrentSplineCamera].camera, SpotCam[CurrentSplineCamera].flags, CurrentSplineCamera);
|
|
PrintDebugMessage(10, 70, 255, 255, 255, 255, m_message);
|
|
}
|
|
|
|
__int32 y = 100;
|
|
|
|
sprintf_s(&m_message[0], 255, "TR5Main Alpha");
|
|
PrintDebugMessage(10, 80+y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "LaraItem.currentAnimState = %d", LaraItem->currentAnimState);
|
|
PrintDebugMessage(10, 90 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "LaraItem.animNumber = %d", LaraItem->animNumber);
|
|
PrintDebugMessage(10, 100 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "LaraItem.frameNumber = %d", LaraItem->frameNumber);
|
|
PrintDebugMessage(10, 110 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "LaraItem.roomNumber = %d", LaraItem->roomNumber);
|
|
PrintDebugMessage(10, 120 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "LaraItem.pos = < %d %d %d >", LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos);
|
|
PrintDebugMessage(10, 130 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "NumVertices = %d", m_numVertices);
|
|
PrintDebugMessage(10, 140 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "NumTriangles = %d", m_numTriangles);
|
|
PrintDebugMessage(10, 150 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Camera.pos = < %d %d %d >", Camera.pos.x, Camera.pos.y, Camera.pos.z);
|
|
PrintDebugMessage(10, 160 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Camera.target = < %d %d %d >", Camera.target.x, Camera.target.y, Camera.target.z);
|
|
PrintDebugMessage(10, 170 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "CurrentLevel: %d", CurrentLevel);
|
|
PrintDebugMessage(10, 180 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.backGun: %d", Lara.backGun);
|
|
PrintDebugMessage(10, 190 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.leftArm.animNumber: %d", Lara.leftArm.animNumber);
|
|
PrintDebugMessage(10, 200 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.leftArm.frameNumber: %d", Lara.leftArm.frameNumber);
|
|
PrintDebugMessage(10, 210 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.rightArm.animNumber: %d", Lara.rightArm.animNumber);
|
|
PrintDebugMessage(10, 220 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.rightArm.frameNumber: %d", Lara.rightArm.frameNumber);
|
|
PrintDebugMessage(10, 230 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.weaponItem: %d", Lara.weaponItem);
|
|
PrintDebugMessage(10, 240 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.gunType: %d", Lara.gunType);
|
|
PrintDebugMessage(10, 250 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.gunStatus: %d", Lara.gunStatus);
|
|
PrintDebugMessage(10, 260 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.crowbar: %d", Lara.crowbar);
|
|
PrintDebugMessage(10, 270 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.leftArm.rot: %d %d %d", Lara.leftArm.xRot, Lara.leftArm.yRot, Lara.leftArm.zRot);
|
|
PrintDebugMessage(10, 280 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.rightArm.rot: %d %d %d", Lara.rightArm.xRot, Lara.rightArm.yRot, Lara.rightArm.zRot);
|
|
PrintDebugMessage(10, 290 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.torsoRot: < %d %d %d >", Lara.torsoXrot, Lara.torsoYrot, Lara.torsoZrot);
|
|
PrintDebugMessage(10, 300 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.headRot: < %d %d %d >", Lara.headXrot, Lara.headYrot, Lara.headZrot);
|
|
PrintDebugMessage(10, 310 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.leftArm.lock: %d", Lara.leftArm.lock);
|
|
PrintDebugMessage(10, 320 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Lara.rightArm.lock: %d", Lara.rightArm.lock);
|
|
PrintDebugMessage(10, 330 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Autotarget: %d", OptionAutoTarget);
|
|
PrintDebugMessage(10, 340 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "NumberDrawnRooms: %d", m_roomsToDraw.size());
|
|
PrintDebugMessage(10, 350 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Camera.pos.roomNumber = %d", Camera.pos.roomNumber);
|
|
PrintDebugMessage(10, 360 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "NumberDrawnItems = %d", m_itemsToDraw.size());
|
|
PrintDebugMessage(10, 370 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "Update = %d, ShadowMap = %d, Clear = %d, Fill = %d, Light = %d, Final = %d, Z-Buffer = %d",
|
|
m_timeUpdate, m_timePrepareShadowMap, m_timeClearGBuffer, m_timeFillGBuffer, m_timeLight, m_timeCombine, m_timeReconstructZBuffer);
|
|
PrintDebugMessage(10, 380 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "DrawCalls = %d", m_numDrawCalls);
|
|
PrintDebugMessage(10, 390 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "NumLights = %d", m_lights.size());
|
|
PrintDebugMessage(10, 400 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "DrawSceneTime = %d", m_timeDrawScene);
|
|
PrintDebugMessage(10, 410 + y, 255, 255, 255, 255, m_message);
|
|
|
|
sprintf_s(&m_message[0], 255, "SkyPos = %d", SkyPos1);
|
|
PrintDebugMessage(10, 420 + y, 255, 255, 255, 255, m_message);
|
|
|
|
m_sprite->Begin(0);
|
|
|
|
D3DXMATRIX scale;
|
|
D3DXMatrixScaling(&scale, 150.0f / 800.0f, 150.0f / 800.0f, 150.0f / 800.0f);
|
|
|
|
m_sprite->SetTransform(&scale);
|
|
m_sprite->Draw(m_colorBuffer->GetTexture(), NULL, &D3DXVECTOR3(0, 0, 0), &D3DXVECTOR3(0, 0, 0), 0xFFFFFFFF);
|
|
m_sprite->SetTransform(&scale);
|
|
m_sprite->Draw(m_normalBuffer->GetTexture(), NULL, &D3DXVECTOR3(0, 0, 0), &D3DXVECTOR3(1200, 0, 0), 0xFFFFFFFF);
|
|
m_sprite->SetTransform(&scale);
|
|
m_sprite->Draw(m_vertexLightBuffer->GetTexture(), NULL, &D3DXVECTOR3(0, 0, 0), &D3DXVECTOR3(2400, 0, 0), 0xFFFFFFFF);
|
|
m_sprite->SetTransform(&scale);
|
|
m_sprite->Draw(m_lightBuffer->GetTexture(), NULL, &D3DXVECTOR3(0, 0, 0), &D3DXVECTOR3(3600, 0, 0), 0xFFFFFFFF);
|
|
|
|
m_sprite->End();
|
|
|
|
}
|
|
|
|
__int32 Renderer::DrawPauseMenu(__int32 selectedIndex, bool resetBlink)
|
|
{
|
|
if (resetBlink)
|
|
ResetBlink();
|
|
|
|
RECT rect;
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = ScreenWidth;
|
|
rect.bottom = ScreenHeight;
|
|
|
|
m_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
|
|
m_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
|
|
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
|
|
|
|
m_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
|
|
m_device->BeginScene();
|
|
|
|
m_sprite->Begin(0);
|
|
m_sprite->Draw(m_renderTarget->GetTexture(), &rect, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DCOLOR_ARGB(255, 128, 128, 128));
|
|
m_sprite->End();
|
|
|
|
PrintString(400, 200, (char*)"Paused", D3DCOLOR_ARGB(255, 216, 117, 49), PRINTSTRING_CENTER);
|
|
PrintString(400, 230, (char*)"Statistics", D3DCOLOR_ARGB(255, 255, 255, 255), PRINTSTRING_CENTER | (selectedIndex == 0 ? PRINTSTRING_BLINK : 0));
|
|
PrintString(400, 260, (char*)"Settings", D3DCOLOR_ARGB(255, 255, 255, 255), PRINTSTRING_CENTER | (selectedIndex == 1 ? PRINTSTRING_BLINK : 0));
|
|
PrintString(400, 290, (char*)"Exit to Title", D3DCOLOR_ARGB(255, 255, 255, 255), PRINTSTRING_CENTER | (selectedIndex == 2 ? PRINTSTRING_BLINK : 0));
|
|
|
|
m_device->EndScene();
|
|
m_device->Present(NULL, NULL, NULL, NULL);
|
|
|
|
return 1;
|
|
}
|
|
|
|
__int32 Renderer::DrawStatisticsMenu()
|
|
{
|
|
char buffer[255];
|
|
|
|
RECT rect;
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = ScreenWidth;
|
|
rect.bottom = ScreenHeight;
|
|
|
|
m_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
|
|
m_device->BeginScene();
|
|
|
|
m_sprite->Begin(0);
|
|
m_sprite->Draw(m_renderTarget->GetTexture(), &rect, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DCOLOR_ARGB(255, 64, 64, 64));
|
|
m_sprite->End();
|
|
|
|
PrintString(400, 140, (char*)"Statistics", D3DCOLOR_ARGB(255, 216, 117, 49), PRINTSTRING_CENTER);
|
|
|
|
PrintString(100, 170, (char*)"Time elapsed", D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
PrintString(100, 200, (char*)"Distance traveled", D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
PrintString(100, 230, (char*)"Ammo used", D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
PrintString(100, 260, (char*)"Medipacks used", D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
PrintString(100, 290, (char*)"Secrets found", D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
|
|
sprintf_s(&buffer[0], 255, "%d", GameTimer / 30);
|
|
PrintString(500, 170, buffer, D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
sprintf_s(&buffer[0], 255, "%d", Savegame.Game.Distance / 419);
|
|
PrintString(500, 200, buffer, D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
sprintf_s(&buffer[0], 255, "%d", Savegame.Game.AmmoUsed);
|
|
PrintString(500, 230, buffer, D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
sprintf_s(&buffer[0], 255, "%d", Savegame.Game.HealthUsed);
|
|
PrintString(500, 260, buffer, D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
sprintf_s(&buffer[0], 255, "%d", Savegame.Game.Secrets);
|
|
PrintString(500, 290, buffer, D3DCOLOR_ARGB(255, 255, 255, 255), 0);
|
|
|
|
m_device->EndScene();
|
|
m_device->Present(NULL, NULL, NULL, NULL);
|
|
|
|
return 1;
|
|
}
|
|
|
|
__int32 Renderer::DrawSettingsMenu(__int32 selectedIndex, bool resetBlink)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
__int32 Renderer::DrawInventory()
|
|
{
|
|
return DrawInventoryScene();
|
|
}
|
|
|
|
__int32 Renderer::DrawObjectOn2DPosition(__int16 x, __int16 y, __int16 objectNum, __int16 rotX, __int16 rotY, __int16 rotZ)
|
|
{
|
|
/*D3DXMATRIX translation;
|
|
D3DXMATRIX rotation;
|
|
D3DXMATRIX world;
|
|
D3DXMATRIX view;
|
|
D3DXMATRIX projection;
|
|
D3DXMATRIX scale;
|
|
|
|
UINT cPasses = 1;
|
|
|
|
D3DXMatrixLookAtRH(&view, &D3DXVECTOR3(0.0f, 0.0f, 2048.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, -1.0f, 0.0f));
|
|
D3DXMatrixOrthoRH(&projection, ScreenWidth, ScreenHeight, -1024.0f, 1024.0f);
|
|
|
|
OBJECT_INFO* obj = &Objects[objectNum];
|
|
RendererObject* moveableObj = m_moveableObjects[objectNum];
|
|
|
|
if (obj->animIndex != -1)
|
|
{
|
|
BuildAnimationPose(moveableObj, &Anims[obj->animIndex].framePtr, 0, 0, 0xFFFFFFFF);
|
|
}
|
|
|
|
D3DXVECTOR3 pos = D3DXVECTOR3(x, y, 1);
|
|
D3DXMatrixIdentity(&world);
|
|
|
|
D3DVIEWPORT9 viewport;
|
|
m_device->GetViewport(&viewport);
|
|
|
|
D3DXVec3Unproject(&pos, &pos, &viewport, &projection, &view, &world);
|
|
|
|
m_shader->SetMatrix(m_shader->GetParameterByName(NULL, "View"), &view);
|
|
m_shader->SetMatrix(m_shader->GetParameterByName(NULL, "Projection"), &projection);
|
|
|
|
m_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
|
|
|
|
for (__int32 i = 0; i < moveableObj->ObjectMeshes.size(); i++)
|
|
{
|
|
RendererMesh* mesh = moveableObj->ObjectMeshes[i];
|
|
|
|
for (__int32 j = 0; j < NUM_BUCKETS; j++)
|
|
{
|
|
RendererBucket* bucket = mesh->Buckets[j];
|
|
if (bucket->NumVertices == 0)
|
|
continue;
|
|
|
|
D3DXMatrixTranslation(&translation, pos.x, pos.y, pos.z + 1024);
|
|
D3DXMatrixRotationYawPitchRoll(&rotation, TR_ANGLE_TO_RAD(rotY), TR_ANGLE_TO_RAD(rotX), TR_ANGLE_TO_RAD(rotZ));
|
|
D3DXMatrixScaling(&scale, 0.5f, 0.5f, 0.5f);
|
|
D3DXMatrixMultiply(&world, &scale, &rotation);
|
|
D3DXMatrixMultiply(&world, &world, &translation);
|
|
if (obj->animIndex != -1)
|
|
D3DXMatrixMultiply(&world, &moveableObj->AnimationTransforms[i], &world);
|
|
else
|
|
D3DXMatrixMultiply(&world, &moveableObj->BindPoseTransforms[i], &world);
|
|
|
|
m_device->SetStreamSource(0, bucket->VertexBuffer, 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->IndexBuffer);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
m_shader->BeginPass(iPass);
|
|
m_shader->SetMatrix(m_shader->GetParameterByName(NULL, "World"), &world);
|
|
m_shader->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0,
|
|
bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
m_shader->EndPass();
|
|
}
|
|
}
|
|
}*/
|
|
|
|
return 1;
|
|
}
|
|
|
|
__int32 Renderer::DrawPickup(__int16 objectNum)
|
|
{
|
|
DrawObjectOn2DPosition(600 + PickupX, 450, objectNum, 0, m_pickupRotation, 0);
|
|
m_pickupRotation += 45 * 360 / 30;
|
|
return 0;
|
|
}
|
|
|
|
__int32 Renderer::SyncRenderer()
|
|
{
|
|
// Sync the renderer
|
|
__int32 nf = Sync();
|
|
if (nf < 2)
|
|
{
|
|
__int32 i = 2 - nf;
|
|
nf = 2;
|
|
do
|
|
{
|
|
while (!Sync());
|
|
i--;
|
|
} while (i);
|
|
}
|
|
|
|
GnFrameCounter++;
|
|
return nf;
|
|
}
|
|
|
|
__int32 Renderer::DrawLoadGameMenu(__int32 selectedIndex, bool resetBlink)
|
|
{
|
|
char buffer[128];
|
|
|
|
// Load all savegames
|
|
LoadSavegameInfos();
|
|
|
|
RECT rect;
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = ScreenWidth;
|
|
rect.bottom = ScreenHeight;
|
|
|
|
m_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
|
|
m_device->BeginScene();
|
|
|
|
m_sprite->Begin(0);
|
|
m_sprite->Draw(m_renderTarget->GetTexture(), &rect, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DCOLOR_ARGB(255, 64, 64, 64));
|
|
m_sprite->End();
|
|
|
|
PrintString(400, 20, (char*)"Load game", D3DCOLOR_ARGB(255, 216, 117, 49), PRINTSTRING_CENTER);
|
|
|
|
__int16 lastY = 44;
|
|
|
|
for (__int32 i = 0; i < MAX_SAVEGAMES; i++)
|
|
{
|
|
if (!g_SavegameInfos[i].present)
|
|
PrintString(400, lastY, (char*)"Not saved", D3DCOLOR_ARGB(255, 255, 255, 255),
|
|
PRINTSTRING_CENTER | (selectedIndex == i ? PRINTSTRING_BLINK : 0));
|
|
else
|
|
{
|
|
sprintf(buffer, "%05d", g_SavegameInfos[i].saveNumber);
|
|
PrintString(20, lastY, buffer, D3DCOLOR_ARGB(255, 255, 255, 255), (selectedIndex == i ? PRINTSTRING_BLINK | PRINTSTRING_DONT_UPDATE_BLINK : 0));
|
|
|
|
PrintString(100, lastY, g_SavegameInfos[i].levelName, D3DCOLOR_ARGB(255, 255, 255, 255), (selectedIndex == i ? PRINTSTRING_BLINK | PRINTSTRING_DONT_UPDATE_BLINK : 0));
|
|
|
|
sprintf(buffer, "%02d days %02d:%02d:%02d", g_SavegameInfos[i].days, g_SavegameInfos[i].hours, g_SavegameInfos[i].minutes, g_SavegameInfos[i].seconds);
|
|
PrintString(600, lastY, buffer, D3DCOLOR_ARGB(255, 255, 255, 255), (selectedIndex == i ? PRINTSTRING_BLINK : 0));
|
|
}
|
|
|
|
lastY += 24;
|
|
}
|
|
|
|
m_device->EndScene();
|
|
m_device->Present(NULL, NULL, NULL, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
__int32 Renderer::DrawSaveGameMenu(__int32 selectedIndex, bool resetBlink)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
__int32 Renderer::DrawInventoryScene()
|
|
{
|
|
char stringBuffer[255];
|
|
|
|
RECT rect;
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = ScreenWidth;
|
|
rect.bottom = ScreenHeight;
|
|
|
|
// Clear screen
|
|
m_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
|
|
m_device->BeginScene();
|
|
|
|
// Set basic render states
|
|
m_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
|
|
m_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
|
|
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
|
|
m_device->SetRenderState(D3DRS_ALPHATESTENABLE, false);
|
|
|
|
byte colorComponent = 1.0f; // (m_fadeTimer < 15.0f ? 255.0f / (15.0f - min(m_fadeTimer, 15.0f)) : 255);
|
|
|
|
// Draw the full screen background
|
|
if (g_Inventory->GetType() == INV_TYPE_TITLE)
|
|
{
|
|
// Scale matrix for drawing full screen background
|
|
D3DXMatrixScaling(&m_tempScale, ScreenWidth / 640.0f, ScreenHeight / 480.0f, 0.0f);
|
|
|
|
m_sprite->Begin(0);
|
|
m_sprite->SetTransform(&m_tempScale);
|
|
m_sprite->Draw(m_titleScreen, &rect, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DCOLOR_ARGB(255, colorComponent, colorComponent, colorComponent));
|
|
m_sprite->End();
|
|
}
|
|
else
|
|
{
|
|
D3DXMatrixScaling(&m_tempScale, 1.0f, 1.0f, 1.0f);
|
|
|
|
m_sprite->Begin(0);
|
|
m_sprite->SetTransform(&m_tempScale);
|
|
m_sprite->Draw(m_renderTarget->GetTexture(), &rect, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DCOLOR_ARGB(255, 64, 64, 64));
|
|
m_sprite->End();
|
|
}
|
|
|
|
// Clear the Z-Buffer after drawing the background
|
|
m_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
|
|
|
|
UINT cPasses = 1;
|
|
LPD3DXEFFECT effect = m_shaderBasic->GetEffect();
|
|
effect->Begin(&cPasses, 0);
|
|
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "ModelTexture"), m_textureAtlas);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "View"), &m_tempView);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "Projection"), &m_tempProjection);
|
|
|
|
// Setup a nice directional light
|
|
effect->SetVector(effect->GetParameterByName(NULL, "LightDirection"), &D3DXVECTOR4(-1.0f, 0.707f, -1.0f, 1.0f));
|
|
effect->SetVector(effect->GetParameterByName(NULL, "LightColor"), &D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f));
|
|
effect->SetFloat(effect->GetParameterByName(NULL, "LightIntensity"), 0.8f);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "AmbientLight"), &D3DXVECTOR4(0.5f, 0.5f, 0.5f, 1.0f));
|
|
|
|
__int32 activeRing = g_Inventory->GetActiveRing();
|
|
__int32 lastRing = 0;
|
|
for (__int32 k = 0; k < 3; k++)
|
|
{
|
|
InventoryRing* ring = g_Inventory->GetRing(k);
|
|
if (!ring->draw || ring->numObjects == 0)
|
|
continue;
|
|
|
|
// Inventory camera
|
|
if (k == g_Inventory->GetActiveRing())
|
|
{
|
|
float cameraY = -384.0f + g_Inventory->GetVerticalOffset() + lastRing * INV_RINGS_OFFSET;
|
|
float targetY = g_Inventory->GetVerticalOffset() + lastRing * INV_RINGS_OFFSET;
|
|
|
|
D3DXMatrixLookAtRH(&m_tempView, &D3DXVECTOR3(3072.0f, cameraY, 0.0f), &D3DXVECTOR3(0.0f, targetY, 0.0f), &D3DXVECTOR3(0.0f, -1.0f, 0.0f));
|
|
D3DXMatrixPerspectiveFovRH(&m_tempProjection, 80.0f * RADIAN, g_Renderer->ScreenWidth / (float)g_Renderer->ScreenHeight, 1.0f, 200000.0f);
|
|
}
|
|
|
|
// Setup the GPU
|
|
m_device->SetVertexDeclaration(m_vertexDeclaration);
|
|
|
|
// Fade timer
|
|
//if (m_fadeTimer < 15)
|
|
// m_shader->SetFloat(m_shader->GetParameterByName(NULL, "FadeTimer"), m_fadeTimer++);
|
|
|
|
__int16 numObjects = ring->numObjects;
|
|
float deltaAngle = 360.0f / numObjects;
|
|
__int32 objectIndex = 0;
|
|
objectIndex = ring->currentObject;
|
|
|
|
for (__int32 i = 0; i < numObjects; i++)
|
|
{
|
|
__int16 objectNumber = g_Inventory->GetInventoryObject(ring->objects[objectIndex].inventoryObject)->objectNumber;
|
|
|
|
// Calculate the inventory object position and rotation
|
|
float currentAngle = 0.0f;
|
|
__int16 steps = -objectIndex + ring->currentObject;
|
|
if (steps < 0) steps += numObjects;
|
|
currentAngle = steps * deltaAngle;
|
|
currentAngle += ring->movement;
|
|
|
|
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;
|
|
|
|
__int32 x = 2048.0f * cos(currentAngle * RADIAN);
|
|
__int32 z = 2048.0f * sin(currentAngle * RADIAN);
|
|
__int32 y = lastRing * INV_RINGS_OFFSET;
|
|
|
|
// Prepare the object transform
|
|
D3DXMatrixScaling(&m_tempScale, ring->objects[objectIndex].scale, ring->objects[objectIndex].scale, ring->objects[objectIndex].scale);
|
|
D3DXMatrixTranslation(&m_tempTranslation, x, y, z);
|
|
D3DXMatrixRotationY(&m_tempRotation, TR_ANGLE_TO_RAD(ring->objects[objectIndex].rotation + 16384));
|
|
D3DXMatrixMultiply(&m_tempTransform, &m_tempScale, &m_tempRotation);
|
|
D3DXMatrixMultiply(&m_tempTransform, &m_tempTransform, &m_tempTranslation);
|
|
|
|
OBJECT_INFO* obj = &Objects[objectNumber];
|
|
RendererObject* moveableObj = m_moveableObjects[objectNumber];
|
|
|
|
// Build the object animation matrices
|
|
if (ring->focusState == INV_FOCUS_STATE_FOCUSED && obj->animIndex != -1 &&
|
|
objectIndex == ring->currentObject && k == g_Inventory->GetActiveRing())
|
|
{
|
|
__int16* framePtr[2];
|
|
__int32 rate = 0;
|
|
GetFrame(obj->animIndex, ring->frameIndex, framePtr, &rate);
|
|
BuildAnimationPose(moveableObj, framePtr, 0, 1, 0xFFFFFFFF);
|
|
}
|
|
else
|
|
{
|
|
if (obj->animIndex != -1)
|
|
BuildAnimationPose(moveableObj, &Anims[obj->animIndex].framePtr, 0, 1, 0xFFFFFFFF);
|
|
}
|
|
|
|
for (__int32 n = 0; n < moveableObj->ObjectMeshes.size(); n++)
|
|
{
|
|
RendererMesh* mesh = moveableObj->ObjectMeshes[n];
|
|
|
|
// Finish the world matrix
|
|
if (obj->animIndex != -1)
|
|
D3DXMatrixMultiply(&m_tempWorld, &moveableObj->AnimationTransforms[n], &m_tempTransform);
|
|
else
|
|
D3DXMatrixMultiply(&m_tempWorld, &moveableObj->BindPoseTransforms[n], &m_tempTransform);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &m_tempWorld);
|
|
|
|
for (__int32 m = 0; m < NUM_BUCKETS; m++)
|
|
{
|
|
RendererBucket* bucket = mesh->GetBucket(m);
|
|
if (bucket->NumVertices == 0)
|
|
continue;
|
|
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0,
|
|
bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
}
|
|
|
|
__int16 inventoryItem = ring->objects[objectIndex].inventoryObject;
|
|
|
|
// Draw special stuff if needed
|
|
if (objectIndex == ring->currentObject && k == g_Inventory->GetActiveRing())
|
|
{
|
|
if (g_Inventory->GetActiveRing() == INV_RING_OPTIONS)
|
|
{
|
|
if (inventoryItem == INV_OBJECT_PASSAPORT && ring->focusState == INV_FOCUS_STATE_FOCUSED)
|
|
{
|
|
// Draw savegames menu
|
|
if (ring->passportAction == INV_WHAT_PASSPORT_LOAD_GAME || ring->passportAction == INV_WHAT_PASSPORT_SAVE_GAME)
|
|
{
|
|
__int16 lastY = 44;
|
|
|
|
for (__int32 n = 0; n < MAX_SAVEGAMES; n++)
|
|
{
|
|
if (!g_SavegameInfos[i].present)
|
|
PrintString(400, lastY, (char*)"Not saved", D3DCOLOR_ARGB(255, 255, 255, 255),
|
|
PRINTSTRING_CENTER | PRINTSTRING_OUTLINE | (ring->selectedIndex == n ? PRINTSTRING_BLINK : 0));
|
|
else
|
|
{
|
|
sprintf(stringBuffer, "%05d", g_SavegameInfos[n].saveNumber);
|
|
PrintString(20, lastY, stringBuffer, D3DCOLOR_ARGB(255, 255, 255, 255), PRINTSTRING_OUTLINE |
|
|
(ring->selectedIndex == n ? PRINTSTRING_BLINK | PRINTSTRING_DONT_UPDATE_BLINK : 0));
|
|
|
|
PrintString(100, lastY, g_SavegameInfos[n].levelName, D3DCOLOR_ARGB(255, 255, 255, 255), PRINTSTRING_OUTLINE |
|
|
(ring->selectedIndex == n ? PRINTSTRING_BLINK | PRINTSTRING_DONT_UPDATE_BLINK : 0));
|
|
|
|
sprintf(stringBuffer, "%02d days %02d:%02d:%02d", g_SavegameInfos[n].days, g_SavegameInfos[n].hours, g_SavegameInfos[n].minutes, g_SavegameInfos[n].seconds);
|
|
PrintString(600, lastY, stringBuffer, D3DCOLOR_ARGB(255, 255, 255, 255),
|
|
PRINTSTRING_OUTLINE | (ring->selectedIndex == n ? PRINTSTRING_BLINK : 0));
|
|
}
|
|
|
|
lastY += 24;
|
|
}
|
|
}
|
|
char* string = (char*)g_NewStrings[0].c_str();
|
|
switch (ring->passportAction)
|
|
{
|
|
case INV_WHAT_PASSPORT_NEW_GAME:
|
|
string = (char*)g_NewStrings[STRING_INV_NEW_GAME].c_str();
|
|
break;
|
|
case INV_WHAT_PASSPORT_LOAD_GAME:
|
|
string = (char*)g_NewStrings[STRING_INV_LOAD_GAME].c_str();
|
|
break;
|
|
case INV_WHAT_PASSPORT_SAVE_GAME:
|
|
string = (char*)g_NewStrings[STRING_INV_SAVE_GAME].c_str();
|
|
break;
|
|
case INV_WHAT_PASSPORT_EXIT_GAME:
|
|
string = (char*)g_NewStrings[STRING_INV_EXIT_GAME].c_str();
|
|
break;
|
|
case INV_WHAT_PASSPORT_EXIT_TO_TITLE:
|
|
string = (char*)g_NewStrings[STRING_INV_EXIT_TO_TITLE].c_str();
|
|
break;
|
|
}
|
|
|
|
PrintString(400, 550, string, PRINTSTRING_COLOR_ORANGE, PRINTSTRING_CENTER | PRINTSTRING_OUTLINE);
|
|
}
|
|
else
|
|
{
|
|
// Draw the description below the object
|
|
char* string = (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
|
|
{
|
|
__int16 inventoryItem = g_Inventory->GetRing(k)->objects[objectIndex].inventoryObject;
|
|
char* string = &AllStrings[AllStringsOffsets[InventoryObjectsList[inventoryItem].objectName]];
|
|
|
|
__int32 quantity = -1;
|
|
switch (objectNumber)
|
|
{
|
|
case ID_BIGMEDI_ITEM:
|
|
quantity = Lara.numLargeMedipack;
|
|
break;
|
|
case ID_SMALLMEDI_ITEM:
|
|
quantity = Lara.numSmallMedipack;
|
|
break;
|
|
case ID_FLARE_INV_ITEM:
|
|
quantity = Lara.numFlares;
|
|
break;
|
|
case ID_SHOTGUN_AMMO1_ITEM:
|
|
quantity = Lara.numShotgunAmmo1;
|
|
if (quantity != -1)
|
|
quantity /= 6;
|
|
break;
|
|
case ID_SHOTGUN_AMMO2_ITEM:
|
|
quantity = Lara.numShotgunAmmo2;
|
|
if (quantity != -1)
|
|
quantity /= 6;
|
|
break;
|
|
case ID_HK_AMMO_ITEM:
|
|
quantity = Lara.numHKammo1;
|
|
break;
|
|
case ID_CROSSBOW_AMMO1_ITEM:
|
|
quantity = Lara.numCrossbowAmmo1;
|
|
break;
|
|
case ID_CROSSBOW_AMMO2_ITEM:
|
|
quantity = Lara.numCrossbowAmmo2;
|
|
break;
|
|
case ID_REVOLVER_AMMO_ITEM:
|
|
quantity = Lara.numRevolverAmmo;
|
|
break;
|
|
case ID_UZI_AMMO_ITEM:
|
|
quantity = Lara.numUziAmmo;
|
|
break;
|
|
case ID_BOTTLE:
|
|
quantity = Lara.bottle;
|
|
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++;
|
|
}
|
|
|
|
effect->End();
|
|
|
|
m_device->EndScene();
|
|
m_device->Present(NULL, NULL, NULL, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
__int32 Renderer::GetFrame(__int16 animation, __int16 frame, __int16** framePtr, __int32* rate)
|
|
{
|
|
ITEM_INFO item;
|
|
item.animNumber = animation;
|
|
item.frameNumber = frame;
|
|
|
|
return GetFrame_D2(&item, framePtr, rate);
|
|
}
|
|
|
|
void Renderer::UpdateGunFlashes()
|
|
{
|
|
/*RendererObject* laraObj = m_moveableObjects[ID_LARA];
|
|
|
|
__int32 numArms = 0;
|
|
D3DXVECTOR4 flashPosition = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
if (Lara.leftArm.flash_gun)
|
|
{
|
|
numArms++;
|
|
|
|
// Get Lara left joint absolute position
|
|
D3DXVECTOR4 handPos;
|
|
D3DXMATRIX world;
|
|
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[HAND_L], &m_LaraWorldMatrix);
|
|
D3DXVec3Transform(&handPos, &laraObj->LinearizedBones[HAND_L]->GlobalTranslation, &world);
|
|
|
|
flashPosition += handPos;
|
|
}
|
|
|
|
if (Lara.rightArm.flash_gun)
|
|
{
|
|
numArms++;
|
|
|
|
// Get Lara right joint absolute position
|
|
D3DXVECTOR4 handPos;
|
|
D3DXMATRIX world;
|
|
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[HAND_R], &m_LaraWorldMatrix);
|
|
D3DXVec3Transform(&handPos, &laraObj->LinearizedBones[HAND_R]->GlobalTranslation, &world);
|
|
|
|
flashPosition += handPos;
|
|
}
|
|
|
|
if (numArms != 0)
|
|
{
|
|
RendererLight* flashLight = new RendererLight();
|
|
|
|
flashLight->Position = flashPosition / numArms;
|
|
flashLight->Color = D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f);
|
|
flashLight->Out = 3072.0f;
|
|
flashLight->Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
|
|
flashLight->Dynamic = true;
|
|
flashLight->Intensity = 2.0f;
|
|
|
|
m_dynamicLights.push_back(flashLight);
|
|
}*/
|
|
}
|
|
|
|
void Renderer::UpdateFlares()
|
|
{
|
|
// Flare in Lara's hand
|
|
/*if (Lara.flareAge > 0)
|
|
{
|
|
RendererObject* laraObj = m_moveableObjects[ID_LARA];
|
|
|
|
D3DXVECTOR4 handPos;
|
|
D3DXMATRIX world;
|
|
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[HAND_L], &m_LaraWorldMatrix);
|
|
D3DXVec3Transform(&handPos, &laraObj->LinearizedBones[HAND_L]->GlobalTranslation, &world);
|
|
|
|
RendererLight* flareLight = new RendererLight();
|
|
|
|
flareLight->Position = handPos;
|
|
flareLight->Color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);
|
|
flareLight->Out = 3072.0f;
|
|
flareLight->Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
|
|
flareLight->Dynamic = true;
|
|
flareLight->Intensity = 2.0f;
|
|
|
|
m_dynamicLights.push_back(flareLight);
|
|
}
|
|
|
|
// Flares throwed away
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
RendererItemToDraw* itemToDraw = m_itemsToDraw[i];
|
|
ITEM_INFO* item = itemToDraw->Item;
|
|
if (item->objectNumber != ID_FLARE_ITEM)
|
|
continue;
|
|
|
|
RendererLight* flareLight = new RendererLight();
|
|
|
|
flareLight->Position = D3DXVECTOR4(item->pos.xPos, item->pos.yPos - 128.0f, item->pos.zPos, 1.0f);
|
|
flareLight->Color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);
|
|
flareLight->Out = 3072.0f;
|
|
flareLight->Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
|
|
flareLight->Dynamic = true;
|
|
flareLight->Intensity = 2.0f;
|
|
|
|
m_dynamicLights.push_back(flareLight);
|
|
}*/
|
|
}
|
|
|
|
void Renderer::UpdateFires()
|
|
{
|
|
/*for (__int32 i = 0; i < 32; i++)
|
|
{
|
|
FIRE_LIST* fire = &Fires[i];
|
|
|
|
// Is the fire active and visible?
|
|
if (!fire->on)
|
|
continue;
|
|
|
|
RendererLight* flareLight = new RendererLight();
|
|
|
|
flareLight->Position = D3DXVECTOR4(fire->x, fire->y, fire->z, 1.0f);
|
|
flareLight->Color = D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f);
|
|
flareLight->Out = 2048.0f;
|
|
flareLight->Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
|
|
flareLight->Dynamic = true;
|
|
flareLight->Intensity = 2.0f;
|
|
|
|
m_dynamicLights.push_back(flareLight);
|
|
}*/
|
|
|
|
for (__int32 i = 0; i < 64; i++)
|
|
{
|
|
DYNAMIC* dynamic = &Dynamics[i];
|
|
if (dynamic->on)
|
|
{
|
|
RendererLight* flareLight = new RendererLight();
|
|
|
|
flareLight->Position = D3DXVECTOR4(dynamic->x, dynamic->y, dynamic->z, 1.0f);
|
|
flareLight->Color = D3DXVECTOR4(dynamic->r / 255.0f, dynamic->g / 255.0f, dynamic->b / 255.0f, 1.0f);
|
|
flareLight->Out = dynamic->falloff;
|
|
flareLight->Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
|
|
flareLight->Dynamic = true;
|
|
flareLight->Intensity = 1.0f;
|
|
|
|
m_dynamicLights.push_back(flareLight);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Renderer::CollectSceneItems()
|
|
{
|
|
CollectRooms();
|
|
CollectItems();
|
|
CollectLightsLPP();
|
|
}
|
|
|
|
bool Renderer::DrawScene(RENDERER_PASSES pass)
|
|
{
|
|
/*if (pass == RENDERER_PASSES::RENDERER_PASS_GBUFFER)
|
|
{
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER, false);
|
|
|
|
// Draw static objects
|
|
ROOM_INFO* r = room->Room;
|
|
if (r->numMeshes != 0)
|
|
{
|
|
for (__int32 j = 0; j < r->numMeshes; j++)
|
|
{
|
|
MESH_INFO* sobj = &r->mesh[j];
|
|
RendererObject* staticObj = m_staticObjects[sobj->staticNumber];
|
|
RendererMesh* staticMesh = staticObj->ObjectMeshes[0];
|
|
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
RendererObject* obj = m_moveableObjects[Items[m_itemsToDraw[i]->Id].objectNumber];
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
}
|
|
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
|
|
// Draw alpha tested geometry
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER, false);
|
|
|
|
// Draw static objects
|
|
ROOM_INFO* r = room->Room;
|
|
if (r->numMeshes != 0)
|
|
{
|
|
for (__int32 j = 0; j < r->numMeshes; j++)
|
|
{
|
|
MESH_INFO* sobj = &r->mesh[j];
|
|
RendererObject* staticObj = m_staticObjects[sobj->staticNumber];
|
|
RendererMesh* staticMesh = staticObj->ObjectMeshes[0];
|
|
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
}
|
|
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
}
|
|
else
|
|
{
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT, false);
|
|
|
|
// Draw static objects
|
|
ROOM_INFO* r = room->Room;
|
|
if (r->numMeshes != 0)
|
|
{
|
|
for (__int32 j = 0; j < r->numMeshes; j++)
|
|
{
|
|
MESH_INFO* sobj = &r->mesh[j];
|
|
RendererObject* staticObj = m_staticObjects[sobj->staticNumber];
|
|
RendererMesh* staticMesh = staticObj->ObjectMeshes[0];
|
|
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
RendererObject* obj = m_moveableObjects[Items[m_itemsToDraw[i]->Id].objectNumber];
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
}
|
|
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
}*/
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::DrawSceneLightPrePass(bool dump)
|
|
{
|
|
// HACK:
|
|
LaraItem->hitPoints = 1000;
|
|
|
|
m_timeClearGBuffer = 0;
|
|
m_timePrepareShadowMap = 0;
|
|
m_timeFillGBuffer = 0;
|
|
m_timeLight = 0;
|
|
m_timeCombine = 0;
|
|
m_timeUpdate = 0;
|
|
m_numDrawCalls = 0;
|
|
m_numTriangles = 0;
|
|
m_numVertices = 0;
|
|
m_timeDrawScene = 0;
|
|
m_timeReconstructZBuffer = 0;
|
|
|
|
LPD3DXEFFECT effect;
|
|
UINT cPasses = 1;
|
|
|
|
auto time1 = chrono::high_resolution_clock::now();
|
|
auto timeScene1 = chrono::high_resolution_clock::now();
|
|
|
|
D3DXMatrixMultiply(&m_viewProjection, &ViewMatrix, &ProjectionMatrix);
|
|
D3DXMatrixInverse(&m_inverseViewProjection, NULL, &m_viewProjection);
|
|
|
|
// Collect scene items and update animations
|
|
CollectSceneItems();
|
|
UpdateLaraAnimations();
|
|
UpdateItemsAnimations();
|
|
if (GnFrameCounter % 2 == 0)
|
|
UpdateAnimatedTextures();
|
|
|
|
auto time2 = chrono::high_resolution_clock::now();
|
|
m_timeUpdate = (chrono::duration_cast<ns>(time2 - time1)).count();
|
|
time1 = time2;
|
|
|
|
// Prepare the shadow map for the main light
|
|
PrepareShadowMaps();
|
|
|
|
time2 = chrono::high_resolution_clock::now();
|
|
m_timePrepareShadowMap = (chrono::duration_cast<ns>(time2 - time1)).count();
|
|
time1 = time2;
|
|
|
|
// Set basic GPU state
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_CCW);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_OPAQUE);
|
|
SetDepthWrite(true);
|
|
m_device->SetVertexDeclaration(m_vertexDeclaration);
|
|
|
|
// Clear the G-Buffer
|
|
BindRenderTargets(m_colorBuffer, m_normalBuffer, m_depthBuffer, m_vertexLightBuffer);
|
|
m_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE(0.0f, 0.0f, 0.0f, 1.0f), 1.0f, 0);
|
|
|
|
effect = m_shaderClearGBuffer->GetEffect();
|
|
m_device->BeginScene();
|
|
effect->Begin(&cPasses, 0);
|
|
effect->BeginPass(0);
|
|
effect->CommitChanges();
|
|
m_device->DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 6, 2, m_quadIndices, D3DFORMAT::D3DFMT_INDEX32,
|
|
m_quadVertices, sizeof(RendererVertex));
|
|
effect->EndPass();
|
|
effect->End();
|
|
m_device->EndScene();
|
|
|
|
time2 = chrono::high_resolution_clock::now();
|
|
m_timeClearGBuffer = (chrono::duration_cast<ns>(time2 - time1)).count();
|
|
time1 = time2;
|
|
|
|
// Fill the G-Buffer
|
|
effect = m_shaderFillGBuffer->GetEffect();
|
|
m_device->BeginScene();
|
|
effect->Begin(&cPasses, 0);
|
|
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "View"), &ViewMatrix);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "Projection"), &ProjectionMatrix);
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "TextureAtlas"), m_textureAtlas);
|
|
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), false);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "Color"), &D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f));
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "CausticsMap"), m_caustics[m_currentCausticsFrame / 2]);
|
|
|
|
m_currentCausticsFrame++;
|
|
m_currentCausticsFrame %= 32;
|
|
|
|
D3DXMATRIX world;
|
|
|
|
// Draw opaque geometry
|
|
DrawSkyLPP();
|
|
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER, true);
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER, true);
|
|
|
|
// Draw static objects
|
|
ROOM_INFO* r = room->Room;
|
|
if (r->numMeshes != 0)
|
|
{
|
|
for (__int32 j = 0; j < r->numMeshes; j++)
|
|
{
|
|
MESH_INFO* sobj = &r->mesh[j];
|
|
RendererObject* staticObj = m_staticObjects[sobj->staticNumber];
|
|
RendererMesh* staticMesh = staticObj->ObjectMeshes[0];
|
|
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
RendererObject* obj = m_moveableObjects[Items[m_itemsToDraw[i]->Id].objectNumber];
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
}
|
|
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
|
|
// Draw alpha tested geometry
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER, true);
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER, true);
|
|
|
|
// Draw static objects
|
|
ROOM_INFO* r = room->Room;
|
|
if (r->numMeshes != 0)
|
|
{
|
|
for (__int32 j = 0; j < r->numMeshes; j++)
|
|
{
|
|
MESH_INFO* sobj = &r->mesh[j];
|
|
RendererObject* staticObj = m_staticObjects[sobj->staticNumber];
|
|
RendererMesh* staticMesh = staticObj->ObjectMeshes[0];
|
|
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
}
|
|
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
|
|
|
|
effect->EndPass();
|
|
effect->End();
|
|
m_device->EndScene();
|
|
|
|
time2 = chrono::high_resolution_clock::now();
|
|
m_timeFillGBuffer = (chrono::duration_cast<ns>(time2 - time1)).count();
|
|
time1 = time2;
|
|
|
|
// Reset the back-buffer
|
|
RestoreBackBuffer();
|
|
|
|
// Bind the light target
|
|
RestoreBackBuffer();
|
|
BindRenderTargets(m_shadowBuffer, NULL, NULL, NULL);
|
|
m_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE(1.0f, 0.0f, 0.0f, 1.0f), 1.0f, 0);
|
|
m_device->BeginScene();
|
|
m_device->EndScene();
|
|
|
|
RestoreBackBuffer();
|
|
BindRenderTargets(m_lightBuffer, NULL, NULL, NULL);
|
|
|
|
effect = m_shaderLight->GetEffect();
|
|
|
|
// Setup additive blending
|
|
/* m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
|
m_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
|
m_device->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
|
|
m_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);*/
|
|
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_NONE);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_ALPHABLEND);
|
|
|
|
// Clear the screen and disable Z write
|
|
m_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
|
|
//m_device->SetRenderState(D3DRS_ZWRITEENABLE, false);
|
|
SetDepthWrite(false);
|
|
|
|
m_device->BeginScene();
|
|
effect->Begin(&cPasses, 0);
|
|
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "View"), &ViewMatrix);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "Projection"), &ProjectionMatrix);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "ViewProjectionInverse"), &m_inverseViewProjection);
|
|
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "ColorMap"), m_colorBuffer->GetTexture());
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "NormalMap"), m_normalBuffer->GetTexture());
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "DepthMap"), m_depthBuffer->GetTexture());
|
|
|
|
effect->SetBool(effect->GetParameterByName(NULL, "AmbientPass"), false);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "CameraPosition"), &D3DXVECTOR4(Camera.pos.x, Camera.pos.y, Camera.pos.z, 1.0f));
|
|
effect->SetFloat(effect->GetParameterByName(NULL, "HalfPixelX"), m_halfPixelX);
|
|
effect->SetFloat(effect->GetParameterByName(NULL, "HalfPixelY"), m_halfPixelY);
|
|
|
|
effect->SetInt(effect->GetParameterByName(NULL, "LightType"), LIGHT_TYPES::LIGHT_TYPE_POINT);
|
|
|
|
m_device->SetStreamSource(0, m_sphereMesh->VertexBuffer, 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(m_sphereMesh->IndexBuffer);
|
|
|
|
for (int j = 0; j < m_lights.size(); j++)
|
|
{
|
|
RendererLight* light = m_lights[j];
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
|
|
D3DXMATRIX translation;
|
|
D3DXMATRIX scale;
|
|
|
|
effect->SetBool(effect->GetParameterByName(NULL, "CastShadows"), false);
|
|
effect->SetBool(effect->GetParameterByName(NULL, "AmbientPass"), false);
|
|
effect->SetBool(effect->GetParameterByName(NULL, "LightDynamic"), light->Dynamic);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "LightPosition"), &light->Position);
|
|
effect->SetFloat(effect->GetParameterByName(NULL, "LightIntensity"), light->Intensity);
|
|
effect->SetFloat(effect->GetParameterByName(NULL, "LightIn"), light->In);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "LightColor"), &light->Color);
|
|
effect->SetFloat(effect->GetParameterByName(NULL, "LightOut"), light->Out);
|
|
D3DXMatrixTranslation(&translation, light->Position.x, light->Position.y, light->Position.z);
|
|
D3DXMatrixScaling(&scale, light->Out / 1024.0f, light->Out / 1024.0f, light->Out / 1024.0f);
|
|
D3DXMatrixMultiply(&world, &scale, &translation);
|
|
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, m_sphereMesh->NumVertices, 0, m_sphereMesh->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
|
|
effect->End();
|
|
m_device->EndScene();
|
|
|
|
time2 = chrono::high_resolution_clock::now();
|
|
m_timeLight = (chrono::duration_cast<ns>(time2 - time1)).count();
|
|
time1 = time2;
|
|
|
|
RestoreBackBuffer();
|
|
|
|
if (dump)
|
|
BindRenderTargets(m_renderTarget, NULL, NULL, NULL);
|
|
|
|
// Combine stage
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_CCW);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_OPAQUE);
|
|
SetDepthWrite(true);
|
|
|
|
effect = m_shaderCombine->GetEffect();
|
|
m_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
|
|
m_device->BeginScene();
|
|
effect->Begin(&cPasses, 0);
|
|
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "ColorMap"), m_colorBuffer->GetTexture());
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "LightMap"), m_lightBuffer->GetTexture());
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "VertexColorMap"), m_vertexLightBuffer->GetTexture());
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "NormalMap"), m_normalBuffer->GetTexture());
|
|
effect->SetFloat(effect->GetParameterByName(NULL, "HalfPixelX"), m_halfPixelX);
|
|
effect->SetFloat(effect->GetParameterByName(NULL, "HalfPixelY"), m_halfPixelY);
|
|
|
|
if (m_shadowLight != NULL)
|
|
{
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "ViewProjectionInverse"), &m_inverseViewProjection);
|
|
effect->SetBool(effect->GetParameterByName(NULL, "CastShadows"), true);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "LightView"), &m_lightView);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "LightProjection"), &m_lightProjection);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "LightPosition"), &m_shadowLight->Position);
|
|
effect->SetFloat(effect->GetParameterByName(NULL, "LightOut"), m_shadowLight->Out);
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "ShadowMap"), m_shadowMap->GetTexture());
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "DepthMap"), m_depthBuffer->GetTexture());
|
|
}
|
|
else
|
|
{
|
|
effect->SetBool(effect->GetParameterByName(NULL, "CastShadows"), false);
|
|
}
|
|
|
|
effect->BeginPass(0);
|
|
effect->CommitChanges();
|
|
m_device->DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 6, 2, m_quadIndices, D3DFORMAT::D3DFMT_INDEX32,
|
|
m_quadVertices, sizeof(RendererVertex));
|
|
effect->EndPass();
|
|
effect->End();
|
|
m_device->EndScene();
|
|
|
|
time2 = chrono::high_resolution_clock::now();
|
|
m_timeCombine = (chrono::duration_cast<ns>(time2 - time1)).count();
|
|
time1 = time2;
|
|
|
|
// Clear depth and start reconstructing Z-Buffer
|
|
m_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0xFFFFFFFF, 1.0f, 0);
|
|
|
|
// We need to use alpha blending because we need to write only to the Z-Buffer
|
|
//SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_SPECIAL_Z_BUFFER);
|
|
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
|
|
|
effect = m_shaderReconstructZBuffer->GetEffect();
|
|
m_device->BeginScene();
|
|
effect->Begin(&cPasses, 0);
|
|
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "View"), &ViewMatrix);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "Projection"), &ProjectionMatrix);
|
|
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH, true);
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH, true);
|
|
|
|
// Draw static objects
|
|
ROOM_INFO* r = room->Room;
|
|
if (r->numMeshes != 0)
|
|
{
|
|
for (__int32 j = 0; j < r->numMeshes; j++)
|
|
{
|
|
MESH_INFO* sobj = &r->mesh[j];
|
|
RendererObject* staticObj = m_staticObjects[sobj->staticNumber];
|
|
RendererMesh* staticMesh = staticObj->ObjectMeshes[0];
|
|
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
}
|
|
|
|
// Draw alpha tested geometry
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH, false);
|
|
|
|
// Draw static objects
|
|
ROOM_INFO* r = room->Room;
|
|
if (r->numMeshes != 0)
|
|
{
|
|
for (__int32 j = 0; j < r->numMeshes; j++)
|
|
{
|
|
MESH_INFO* sobj = &r->mesh[j];
|
|
RendererObject* staticObj = m_staticObjects[sobj->staticNumber];
|
|
RendererMesh* staticMesh = staticObj->ObjectMeshes[0];
|
|
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
|
|
}
|
|
|
|
m_device->EndScene();
|
|
effect->End();
|
|
|
|
// Transparent pass:
|
|
effect = m_shaderTransparent->GetEffect();
|
|
m_device->BeginScene();
|
|
effect->Begin(&cPasses, 0);
|
|
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "View"), &ViewMatrix);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "Projection"), &ProjectionMatrix);
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_ROOM);
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "TextureAtlas"), m_textureAtlas);
|
|
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), false);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "Color"), &D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f));
|
|
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT, true);
|
|
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT, false);
|
|
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT, true);
|
|
|
|
// Draw static objects
|
|
ROOM_INFO* r = room->Room;
|
|
if (r->numMeshes != 0)
|
|
{
|
|
for (__int32 j = 0; j < r->numMeshes; j++)
|
|
{
|
|
MESH_INFO* sobj = &r->mesh[j];
|
|
RendererObject* staticObj = m_staticObjects[sobj->staticNumber];
|
|
RendererMesh* staticMesh = staticObj->ObjectMeshes[0];
|
|
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
DrawStaticLPP(m_roomsToDraw[i], j, RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
}
|
|
}
|
|
}
|
|
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
DrawLaraLPP(RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
|
|
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
|
|
{
|
|
RendererObject* obj = m_moveableObjects[Items[m_itemsToDraw[i]->Id].objectNumber];
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
DrawItemLPP(m_itemsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
}
|
|
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
DrawGunshells(RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
|
|
|
|
effect->End();
|
|
m_device->EndScene();
|
|
|
|
// Prepare sprites
|
|
// TODO: preallocate big buffer and avoica memory allocations!
|
|
for (vector<RendererSpriteToDraw*>::iterator it = m_spritesToDraw.begin(); it != m_spritesToDraw.end(); ++it)
|
|
delete (*it);
|
|
m_spritesToDraw.clear();
|
|
for (vector<RendererLine3DToDraw*>::iterator it = m_lines3DToDraw.begin(); it != m_lines3DToDraw.end(); ++it)
|
|
delete (*it);
|
|
m_lines3DToDraw.clear();
|
|
|
|
DrawFires();
|
|
DrawSmokes();
|
|
DrawBlood();
|
|
DrawSparks();
|
|
DrawBubbles();
|
|
DrawDrips();
|
|
DrawRipples();
|
|
DrawUnderwaterDust();
|
|
|
|
// Do weather
|
|
if (WeatherType == WEATHER_TYPES::WEATHER_RAIN)
|
|
DoRain();
|
|
else if (WeatherType == WEATHER_TYPES::WEATHER_SNOW)
|
|
DoSnow();
|
|
|
|
// Draw sprites
|
|
DrawSprites();
|
|
DrawGunFlashes();
|
|
DrawLines3D();
|
|
|
|
time2 = chrono::high_resolution_clock::now();
|
|
m_timeReconstructZBuffer = (chrono::duration_cast<ns>(time2 - time1)).count();
|
|
time1 = time2;
|
|
|
|
auto timeScene2 = chrono::high_resolution_clock::now();
|
|
m_timeDrawScene = (chrono::duration_cast<ns>(timeScene2 - timeScene1)).count() / 1000;
|
|
|
|
if (!dump)
|
|
{
|
|
DrawDebugInfo();
|
|
m_device->Present(NULL, NULL, NULL, NULL);
|
|
}
|
|
else
|
|
RestoreBackBuffer();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::BindRenderTargets(RenderTarget2D* rt1, RenderTarget2D* rt2, RenderTarget2D* rt3, RenderTarget2D* rt4)
|
|
{
|
|
HRESULT res;
|
|
|
|
m_backBufferTarget = NULL;
|
|
res = m_device->GetRenderTarget(0, &m_backBufferTarget);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
m_backBufferDepth = NULL;
|
|
res = m_device->GetDepthStencilSurface(&m_backBufferDepth);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
if (rt1 != NULL)
|
|
{
|
|
LPDIRECT3DSURFACE9 surface;
|
|
res = rt1->GetTexture()->GetSurfaceLevel(0, &surface);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
res = m_device->SetRenderTarget(0, surface);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
surface->Release();
|
|
}
|
|
|
|
if (rt2 != NULL)
|
|
{
|
|
LPDIRECT3DSURFACE9 surface;
|
|
res = rt2->GetTexture()->GetSurfaceLevel(0, &surface);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
res = m_device->SetRenderTarget(1, surface);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
surface->Release();
|
|
}
|
|
|
|
if (rt3 != NULL)
|
|
{
|
|
LPDIRECT3DSURFACE9 surface;
|
|
res = rt3->GetTexture()->GetSurfaceLevel(0, &surface);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
res = m_device->SetRenderTarget(2, surface);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
surface->Release();
|
|
}
|
|
|
|
if (rt4 != NULL)
|
|
{
|
|
LPDIRECT3DSURFACE9 surface;
|
|
res = rt4->GetTexture()->GetSurfaceLevel(0, &surface);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
res = m_device->SetRenderTarget(3, surface);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
surface->Release();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::RestoreBackBuffer()
|
|
{
|
|
m_device->SetRenderTarget(0, m_backBufferTarget);
|
|
m_device->SetRenderTarget(1, NULL);
|
|
m_device->SetRenderTarget(2, NULL);
|
|
m_device->SetRenderTarget(3, NULL);
|
|
|
|
m_device->SetDepthStencilSurface(m_backBufferDepth);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::DrawLaraLPP(RENDERER_BUCKETS bucketIndex, RENDERER_PASSES pass)
|
|
{
|
|
D3DXMATRIX world;
|
|
D3DXMATRIX translation;
|
|
D3DXMATRIX rotation;
|
|
UINT cPasses = 1;
|
|
|
|
RendererObject* laraObj = m_moveableObjects[ID_LARA];
|
|
RendererObject* laraSkin = m_moveableObjects[ID_LARA_SKIN];
|
|
|
|
ITEM_INFO* item = LaraItem;
|
|
OBJECT_INFO* obj = &Objects[0];
|
|
|
|
RendererLightInfo* light = &m_itemsLightInfo[0];
|
|
LPD3DXEFFECT effect;
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_SHADOW_MAP)
|
|
effect = m_depthShader->GetEffect();
|
|
else if (pass == RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH)
|
|
effect = m_shaderReconstructZBuffer->GetEffect();
|
|
else if (pass == RENDERER_PASSES::RENDERER_PASS_GBUFFER)
|
|
effect = m_shaderFillGBuffer->GetEffect();
|
|
else
|
|
effect = m_shaderTransparent->GetEffect();
|
|
|
|
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), true);
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_LARA);
|
|
effect->SetMatrixArray(effect->GetParameterByName(NULL, "Bones"), laraObj->AnimationTransforms, laraObj->ObjectMeshes.size());
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &m_LaraWorldMatrix);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "AmbientLight"), &m_rooms[LaraItem->roomNumber]->AmbientLight);
|
|
|
|
if (bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID || bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS)
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_OPAQUE);
|
|
else
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_ALPHATEST);
|
|
|
|
for (__int32 i = 0; i < laraObj->ObjectMeshes.size(); i++)
|
|
{
|
|
// Lara has meshes overriden by weapons, crowbar, etc
|
|
RendererMesh* mesh = MeshPointersToMesh[Lara.meshPtrs[i]];
|
|
RendererBucket* bucket = mesh->GetBucket(bucketIndex);
|
|
|
|
if (bucket->NumVertices != 0)
|
|
{
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
// Bind buffers
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
|
|
// Draw joints, if present
|
|
if (m_moveableObjects.find(ID_LARA_SKIN_JOINTS) != m_moveableObjects.end())
|
|
{
|
|
RendererObject* laraSkinJoints = m_moveableObjects[ID_LARA_SKIN_JOINTS];
|
|
RendererMesh* jointMesh = laraSkinJoints->ObjectMeshes[i];
|
|
bucket = jointMesh->GetBucket(bucketIndex);
|
|
|
|
if (bucket->NumVertices != 0)
|
|
{
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
// Bind buffers
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Disable skinning, following will use the old way
|
|
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), false);
|
|
|
|
if (m_moveableObjects.find(Lara.holster) != m_moveableObjects.end())
|
|
{
|
|
// Draw holsters
|
|
OBJECT_INFO* objHolsters = &Objects[Lara.holster];
|
|
RendererObject* modelHolster = m_moveableObjects[Lara.holster];
|
|
|
|
RendererMesh* leftHolster = modelHolster->ObjectMeshes[4];
|
|
RendererMesh* rightHolster = modelHolster->ObjectMeshes[8];
|
|
|
|
RendererBucket* bucket = leftHolster->GetBucket(bucketIndex);
|
|
if (bucket->NumVertices != 0)
|
|
{
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[THIGH_L], &m_LaraWorldMatrix);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
|
|
bucket = rightHolster->GetBucket(bucketIndex);
|
|
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[THIGH_R], &m_LaraWorldMatrix);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
|
|
// Draw back gun
|
|
if (Lara.backGun)
|
|
{
|
|
OBJECT_INFO* backGunObject = &Objects[Lara.backGun];
|
|
RendererObject* modelBackGun = m_moveableObjects[Lara.backGun];
|
|
RendererMesh* backGunMesh = modelBackGun->ObjectMeshes[HEAD];
|
|
|
|
RendererBucket* bucket = backGunMesh->GetBucket(bucketIndex);
|
|
if (bucket->NumVertices != 0)
|
|
{
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[HEAD], &m_LaraWorldMatrix);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw Lara's hairs
|
|
if (bucketIndex == 0)
|
|
{
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
if (m_moveableObjects.find(ID_HAIR) != m_moveableObjects.end())
|
|
{
|
|
RendererObject* hairsObj = m_moveableObjects[ID_HAIR];
|
|
D3DXMatrixIdentity(&world);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
effect->CommitChanges();
|
|
|
|
m_device->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0,
|
|
m_numHairVertices*((gfLevelFlags & 1) ? 2 : 1),
|
|
m_numHairIndices*((gfLevelFlags & 1) ? 2 : 1) / 3,
|
|
m_hairIndices, D3DFMT_INDEX32, m_hairVertices, sizeof(RendererVertex));
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::DrawItemLPP(RendererItemToDraw* itemToDraw, RENDERER_BUCKETS bucketIndex, RENDERER_PASSES pass)
|
|
{
|
|
D3DXMATRIX world;
|
|
UINT cPasses = 1;
|
|
|
|
ITEM_INFO* item = itemToDraw->Item;
|
|
if (item->objectNumber == ID_LARA || item->objectNumber == 434)
|
|
return true;
|
|
|
|
OBJECT_INFO* obj = &Objects[item->objectNumber];
|
|
RendererObject* moveableObj = m_moveableObjects[item->objectNumber];
|
|
if (moveableObj->DoNotDraw)
|
|
return true;
|
|
|
|
if (!moveableObj->HasDataInBucket[bucketIndex])
|
|
return true;
|
|
|
|
LPD3DXEFFECT effect;
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_SHADOW_MAP)
|
|
effect = m_depthShader->GetEffect();
|
|
else if (pass == RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH)
|
|
effect = m_shaderReconstructZBuffer->GetEffect();
|
|
else if (pass == RENDERER_PASSES::RENDERER_PASS_GBUFFER)
|
|
effect = m_shaderFillGBuffer->GetEffect();
|
|
else
|
|
effect = m_shaderTransparent->GetEffect();
|
|
|
|
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), true);
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_MOVEABLE);
|
|
effect->SetMatrixArray(effect->GetParameterByName(NULL, "Bones"), moveableObj->AnimationTransforms, moveableObj->ObjectMeshes.size());
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &itemToDraw->World);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "AmbientLight"), &m_rooms[item->roomNumber]->AmbientLight);
|
|
|
|
if (bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID || bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS)
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_OPAQUE);
|
|
else
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_ALPHATEST);
|
|
|
|
for (__int32 i = 0; i < moveableObj->ObjectMeshes.size(); i++)
|
|
{
|
|
RendererMesh* mesh = moveableObj->ObjectMeshes[i];
|
|
RendererBucket* bucket = mesh->GetBucket(bucketIndex);
|
|
if (bucket->NumVertices == 0)
|
|
continue;
|
|
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::DrawRoomLPP(__int32 roomIndex, RENDERER_BUCKETS bucketIndex, RENDERER_PASSES pass, bool animated)
|
|
{
|
|
D3DXMATRIX world;
|
|
UINT cPasses = 1;
|
|
|
|
RendererRoom* room = m_rooms[roomIndex];
|
|
ROOM_INFO* r = room->Room;
|
|
RendererObject* roomObj = room->RoomObject;
|
|
|
|
if ((!animated && !roomObj->HasDataInBucket[bucketIndex]) ||
|
|
(animated && !roomObj->HasDataInAnimatedBucket[bucketIndex]))
|
|
return true;
|
|
|
|
if (roomObj->ObjectMeshes.size() == 0)
|
|
return true;
|
|
|
|
RendererMesh* mesh = roomObj->ObjectMeshes[0];
|
|
|
|
LPD3DXEFFECT effect;
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_SHADOW_MAP)
|
|
effect = m_depthShader->GetEffect();
|
|
else if (pass == RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH)
|
|
effect = m_shaderReconstructZBuffer->GetEffect();
|
|
else if (pass == RENDERER_PASSES::RENDERER_PASS_GBUFFER)
|
|
effect = m_shaderFillGBuffer->GetEffect();
|
|
else
|
|
effect = m_shaderTransparent->GetEffect();
|
|
|
|
D3DXMatrixTranslation(&world, r->x, r->y, r->z);
|
|
|
|
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), false);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
|
|
if (bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID || bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS)
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_OPAQUE);
|
|
else
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_ALPHATEST);
|
|
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_GBUFFER)
|
|
{
|
|
if (IsRoomUnderwater(roomIndex))
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_ROOM_UNDERWATER);
|
|
else
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_ROOM);
|
|
}
|
|
|
|
if (!animated)
|
|
{
|
|
// Non animated buckets are rendered with vertex buffers
|
|
RendererBucket* bucket = mesh->GetBucket(bucketIndex);
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RendererBucket* bucket = mesh->GetAnimatedBucket(bucketIndex);
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
m_device->DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, bucket->NumVertices, bucket->NumIndices / 3,
|
|
bucket->Indices.data(), D3DFORMAT::D3DFMT_INDEX32, bucket->Vertices.data(), sizeof(RendererVertex));
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::DrawStaticLPP(__int32 roomIndex, __int32 staticIndex, RENDERER_BUCKETS bucketIndex, RENDERER_PASSES pass)
|
|
{
|
|
D3DXMATRIX world;
|
|
D3DXMATRIX rotation;
|
|
UINT cPasses = 1;
|
|
|
|
ROOM_INFO* room = &Rooms[roomIndex];
|
|
MESH_INFO* sobj = &room->mesh[staticIndex];
|
|
RendererObject* obj = m_staticObjects[sobj->staticNumber];
|
|
if (!obj->HasDataInBucket[bucketIndex])
|
|
return true;
|
|
|
|
RendererMesh* mesh = obj->ObjectMeshes[0];
|
|
RendererBucket* bucket = mesh->GetBucket(bucketIndex);
|
|
if (bucket->NumVertices == 0)
|
|
return true;
|
|
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
LPD3DXEFFECT effect;
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_SHADOW_MAP)
|
|
effect = m_depthShader->GetEffect();
|
|
else if (pass == RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH)
|
|
effect = m_shaderReconstructZBuffer->GetEffect();
|
|
else if (pass == RENDERER_PASSES::RENDERER_PASS_GBUFFER)
|
|
effect = m_shaderFillGBuffer->GetEffect();
|
|
else
|
|
effect = m_shaderTransparent->GetEffect();
|
|
|
|
D3DXMatrixTranslation(&world, sobj->x, sobj->y, sobj->z);
|
|
D3DXMatrixRotationY(&rotation, TR_ANGLE_TO_RAD(sobj->yRot));
|
|
D3DXMatrixMultiply(&world, &rotation, &world);
|
|
|
|
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), false);
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_STATIC);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "AmbientLight"), &m_rooms[roomIndex]->AmbientLight);
|
|
|
|
if (bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID || bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS)
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_OPAQUE);
|
|
else
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_ALPHATEST);
|
|
|
|
/*if (pass == RENDERER_PASSES::RENDERER_PASS_GBUFFER)
|
|
{
|
|
if (IsRoomUnderwater(roomIndex))
|
|
effect->SetBool(effect->GetParameterByName(NULL, "Underwater"), true);
|
|
else
|
|
effect->SetBool(effect->GetParameterByName(NULL, "Underwater"), false);
|
|
}*/
|
|
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::DrawGunFlashes(/*RENDERER_PASSES pass*/)
|
|
{
|
|
D3DXMATRIX world;
|
|
D3DXMATRIX translation;
|
|
D3DXMATRIX rotation;
|
|
UINT cPasses = 1;
|
|
|
|
RendererObject* laraObj = m_moveableObjects[ID_LARA];
|
|
RendererObject* laraSkin = m_moveableObjects[ID_LARA_SKIN];
|
|
|
|
ITEM_INFO* item = LaraItem;
|
|
OBJECT_INFO* obj = &Objects[0];
|
|
|
|
RendererLightInfo* light = &m_itemsLightInfo[0];
|
|
LPD3DXEFFECT effect;
|
|
/*if (pass == RENDERER_PASSES::RENDERER_PASS_SHADOW_MAP)
|
|
effect = m_depthShader->GetEffect();
|
|
else if (pass == RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH)
|
|
effect = m_shaderReconstructZBuffer->GetEffect();
|
|
else
|
|
effect = m_shaderFillGBuffer->GetEffect();*/
|
|
effect = m_shaderBasic->GetEffect();
|
|
|
|
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), false);
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_MOVEABLE);
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "ModelTexture"), m_textureAtlas);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "View"), &ViewMatrix);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "Projection"), &ProjectionMatrix);
|
|
|
|
__int16 length = 0;
|
|
__int16 zOffset = 0;
|
|
__int16 rotationX = 0;
|
|
|
|
if (Lara.weaponItem != WEAPON_FLARE && Lara.weaponItem != WEAPON_SHOTGUN && Lara.weaponItem != WEAPON_CROSSBOW)
|
|
{
|
|
if (Lara.weaponItem == WEAPON_REVOLVER)
|
|
{
|
|
length = 192;
|
|
zOffset = 68;
|
|
rotationX = -14560;
|
|
}
|
|
else if (Lara.weaponItem == WEAPON_UZI)
|
|
{
|
|
length = 190;
|
|
zOffset = 50;
|
|
}
|
|
else if (Lara.weaponItem == WEAPON_HK)
|
|
{
|
|
length = 300;
|
|
zOffset = 92;
|
|
rotationX = -14560;
|
|
}
|
|
else
|
|
{
|
|
length = 180;
|
|
zOffset = 40;
|
|
rotationX = -16830;
|
|
}
|
|
|
|
OBJECT_INFO* flashObj = &Objects[ID_GUN_FLASH];
|
|
RendererObject* flashMoveable = m_moveableObjects[ID_GUN_FLASH];
|
|
RendererMesh* flashMesh = flashMoveable->ObjectMeshes[0];
|
|
|
|
for (__int32 b = 0; b < NUM_BUCKETS; b++)
|
|
{
|
|
RendererBucket* flashBucket = flashMesh->GetBucket(b);
|
|
|
|
if (flashBucket->NumVertices != 0)
|
|
{
|
|
m_device->SetStreamSource(0, flashBucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(flashBucket->GetIndexBuffer());
|
|
|
|
D3DXMATRIX offset;
|
|
D3DXMatrixTranslation(&offset, 0, length, zOffset);
|
|
|
|
D3DXMATRIX rotation2;
|
|
D3DXMatrixRotationX(&rotation2, TR_ANGLE_TO_RAD(rotationX));
|
|
|
|
if (Lara.leftArm.flash_gun)
|
|
{
|
|
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[HAND_L], &m_LaraWorldMatrix);
|
|
D3DXMatrixMultiply(&world, &offset, &world);
|
|
D3DXMatrixMultiply(&world, &rotation2, &world);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, flashBucket->NumVertices, 0, flashBucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
|
|
if (Lara.rightArm.flash_gun)
|
|
{
|
|
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[HAND_R], &m_LaraWorldMatrix);
|
|
D3DXMatrixMultiply(&world, &offset, &world);
|
|
D3DXMatrixMultiply(&world, &rotation2, &world);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, flashBucket->NumVertices, 0, flashBucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Renderer::CollectLightsLPP()
|
|
{
|
|
m_lights.clear();
|
|
|
|
// Add rooms lights
|
|
for (__int32 i = 0; i < m_roomsToDraw.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[m_roomsToDraw[i]];
|
|
if (room == NULL)
|
|
continue;
|
|
|
|
for (__int32 j = 0; j < room->Lights.size(); j++)
|
|
{
|
|
D3DXVECTOR3 laraPos = D3DXVECTOR3(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos);
|
|
D3DXVECTOR3 lightVector = D3DXVECTOR3(room->Lights[j]->Position.x, room->Lights[j]->Position.y, room->Lights[j]->Position.z);
|
|
|
|
if (D3DXVec3Length(&(laraPos-lightVector)) >= 1024.0f * 20.0f)
|
|
continue;
|
|
|
|
m_lights.push_back(room->Lights[j]);
|
|
}
|
|
}
|
|
|
|
// Add dynamic lights
|
|
for (__int32 i = 0; i < m_dynamicLights.size(); i++)
|
|
m_lights.push_back(m_dynamicLights[i]);
|
|
|
|
// 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)
|
|
{
|
|
for (__int32 j = 0; j < room->Lights.size(); j++)
|
|
{
|
|
RendererLight* light = room->Lights[j];
|
|
|
|
D3DXVECTOR4 itemPos = D3DXVECTOR4(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos, 1.0f);
|
|
D3DXVECTOR4 lightVector = itemPos - light->Position;
|
|
|
|
float distance = D3DXVec4Length(&lightVector);
|
|
D3DXVec4Normalize(&lightVector, &lightVector);
|
|
|
|
float intensity;
|
|
float attenuation;
|
|
float angle;
|
|
float d;
|
|
float attenuationRange;
|
|
float attenuationAngle;
|
|
|
|
switch (light->Type)
|
|
{
|
|
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;
|
|
}
|
|
|
|
bool Renderer::DrawSkyLPP()
|
|
{
|
|
D3DXVECTOR4 color = D3DXVECTOR4(SkyColor1.r / 255.0f, SkyColor1.g / 255.0f, SkyColor1.b / 255.0f, 1.0f);
|
|
|
|
// First update the sky in the case of storm
|
|
if (gfLevelFlags & 0x40 || true)
|
|
{
|
|
if (Unk_00E6D74C || Unk_00E6D73C)
|
|
{
|
|
UpdateStorm();
|
|
if (StormTimer > -1)
|
|
StormTimer--;
|
|
if (!StormTimer)
|
|
SoundEffect(SFX_THUNDER_RUMBLE, NULL, 0);
|
|
}
|
|
else if (!(rand() & 0x7F))
|
|
{
|
|
Unk_00E6D74C = (rand() & 0x1F) + 16;
|
|
Unk_00E6E4DC = rand() + 256;
|
|
StormTimer = (rand() & 3) + 12;
|
|
}
|
|
|
|
color = D3DXVECTOR4((SkyStormColor[0] + 44) / 255.0f, SkyStormColor[1] / 255.0f, SkyStormColor[2] / 255.0f, 1.0f);
|
|
}
|
|
|
|
D3DXMATRIX world;
|
|
D3DXMATRIX translation;
|
|
D3DXMATRIX rotation;
|
|
D3DXMATRIX scale;
|
|
UINT cPasses = 1;
|
|
|
|
LPD3DXEFFECT effect = m_shaderFillGBuffer->GetEffect();
|
|
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "TextureAtlas"), m_skyTexture);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "Color"), &color);
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_SKY);
|
|
|
|
m_device->SetStreamSource(0, m_skyQuad->VertexBuffer, 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(m_skyQuad->IndexBuffer);
|
|
|
|
// Quads have normal up, so I must rotate the plane by X (or Z)
|
|
D3DXMatrixRotationX(&m_tempRotation, PI);
|
|
|
|
// Hardcoded kingdom :)
|
|
for (__int32 i = 0; i < 2; i++)
|
|
{
|
|
D3DXMatrixTranslation(&m_tempTranslation, Camera.pos.x + SkyPos1 - i * 9728.0f, Camera.pos.y - 1536.0f, Camera.pos.z);
|
|
D3DXMatrixMultiply(&world, &m_tempRotation, &m_tempTranslation);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, m_quad->NumVertices, 0, m_quad->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
|
|
// Draw the horizon
|
|
RendererObject* horizonObj = m_moveableObjects[ID_HORIZON];
|
|
RendererMesh* mesh = horizonObj->ObjectMeshes[0];
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_HORIZON);
|
|
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "TextureAtlas"), m_textureAtlas);
|
|
effect->SetVector(effect->GetParameterByName(NULL, "Color"), &D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f));
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_OPAQUE);
|
|
|
|
D3DXMatrixTranslation(&world, Camera.pos.x, Camera.pos.y, Camera.pos.z);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
|
|
for (__int32 i = 0; i < NUM_BUCKETS; i++)
|
|
{
|
|
RendererBucket* bucket = mesh->GetBucket(i);
|
|
|
|
// Bind buffers
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
SetGpuStateForBucket((RENDERER_BUCKETS)i);
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_OPAQUE);
|
|
|
|
m_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
|
|
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
|
|
|
|
return true;
|
|
}
|
|
|
|
void Renderer::AddDynamicLight(__int32 x, __int32 y, __int32 z, __int16 falloff, byte r, byte g, byte b)
|
|
{
|
|
RendererLight* dynamicLight = new RendererLight();
|
|
|
|
dynamicLight->Position = D3DXVECTOR4(x, y, z, 1.0f);
|
|
dynamicLight->Color = D3DXVECTOR4(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
|
|
dynamicLight->Out = falloff * 256.0f;
|
|
dynamicLight->Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
|
|
dynamicLight->Dynamic = true;
|
|
dynamicLight->Intensity = 2.0f;
|
|
|
|
m_dynamicLights.push_back(dynamicLight);
|
|
NumDynamics++;
|
|
}
|
|
|
|
void Renderer::ClearDynamicLights()
|
|
{
|
|
for (vector<RendererLight*>::iterator it = m_dynamicLights.begin(); it != m_dynamicLights.end(); ++it)
|
|
delete (*it);
|
|
m_dynamicLights.clear();
|
|
NumDynamics = 0;
|
|
}
|
|
|
|
void Renderer::CreateBillboardMatrix(D3DXMATRIX* out, D3DXVECTOR3* particlePos, D3DXVECTOR3* cameraPos)
|
|
{
|
|
D3DXVECTOR3 look = *particlePos;
|
|
look = look - *cameraPos;
|
|
D3DXVec3Normalize(&look, &look);
|
|
|
|
D3DXVECTOR3 cameraUp = D3DXVECTOR3(0.0f, -1.0f, 0.0f);
|
|
|
|
D3DXVECTOR3 right;
|
|
D3DXVec3Cross(&right, &cameraUp, &look);
|
|
D3DXVec3Normalize(&right, &right);
|
|
|
|
D3DXVECTOR3 up;
|
|
D3DXVec3Cross(&up, &look, &right);
|
|
D3DXVec3Normalize(&up, &up);
|
|
|
|
D3DXMatrixIdentity(out);
|
|
|
|
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;
|
|
}
|
|
|
|
bool Renderer::DrawSprites()
|
|
{
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_NONE);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_ADDITIVE);
|
|
SetDepthWrite(false);
|
|
|
|
UINT cPasses = 1;
|
|
LPD3DXEFFECT effect = m_shaderSprites->GetEffect();
|
|
m_device->BeginScene();
|
|
effect->Begin(&cPasses, 0);
|
|
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "View"), &ViewMatrix);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "Projection"), &ProjectionMatrix);
|
|
effect->SetTexture(effect->GetParameterByName(NULL, "TextureAtlas"), m_textureAtlas);
|
|
|
|
__int32 numSpritesToDraw = m_spritesToDraw.size();
|
|
__int32 lastSprite = 0;
|
|
while (numSpritesToDraw > 0)
|
|
{
|
|
m_spritesVertices.clear();
|
|
m_spritesIndices.clear();
|
|
|
|
// Fill the buffer for sprites
|
|
__int32 maxSprite = min(m_spritesToDraw.size(), lastSprite + NUM_SPRITES_PER_BUCKET);
|
|
for (__int32 i = lastSprite; i < maxSprite; i++)
|
|
{
|
|
RendererSpriteToDraw* spr = m_spritesToDraw[i];
|
|
|
|
if (spr->Type == RENDERER_SPRITE_TYPE::SPRITE_TYPE_BILLBOARD)
|
|
{
|
|
float halfWidth = spr->Width / 2.0f;
|
|
float halfHeight = spr->Height / 2.0f;
|
|
|
|
D3DXMATRIX billboardMatrix;
|
|
CreateBillboardMatrix(&billboardMatrix, &D3DXVECTOR3(spr->X, spr->Y, spr->Z),
|
|
&D3DXVECTOR3(Camera.pos.x, Camera.pos.y, Camera.pos.z));
|
|
|
|
D3DXVECTOR3 p0 = D3DXVECTOR3(-halfWidth, -halfHeight, 0);
|
|
D3DXVECTOR3 p1 = D3DXVECTOR3(halfWidth, -halfHeight, 0);
|
|
D3DXVECTOR3 p2 = D3DXVECTOR3(halfWidth, halfHeight, 0);
|
|
D3DXVECTOR3 p3 = D3DXVECTOR3(-halfWidth, halfHeight, 0);
|
|
|
|
D3DXVECTOR4 p0t;
|
|
D3DXVECTOR4 p1t;
|
|
D3DXVECTOR4 p2t;
|
|
D3DXVECTOR4 p3t;
|
|
|
|
D3DXVec3Transform(&p0t, &p0, &billboardMatrix);
|
|
D3DXVec3Transform(&p1t, &p1, &billboardMatrix);
|
|
D3DXVec3Transform(&p2t, &p2, &billboardMatrix);
|
|
D3DXVec3Transform(&p3t, &p3, &billboardMatrix);
|
|
|
|
RendererVertex v;
|
|
__int32 baseVertex = m_spritesVertices.size();
|
|
|
|
v.x = p0t.x;
|
|
v.y = p0t.y;
|
|
v.z = p0t.z;
|
|
v.u = spr->Sprite->UV[0].x;
|
|
v.v = spr->Sprite->UV[0].y;
|
|
v.r = spr->R / 255.0f;
|
|
v.g = spr->G / 255.0f;
|
|
v.b = spr->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_spritesVertices.push_back(v);
|
|
|
|
v.x = p1t.x;
|
|
v.y = p1t.y;
|
|
v.z = p1t.z;
|
|
v.u = spr->Sprite->UV[1].x;
|
|
v.v = spr->Sprite->UV[1].y;
|
|
v.r = spr->R / 255.0f;
|
|
v.g = spr->G / 255.0f;
|
|
v.b = spr->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_spritesVertices.push_back(v);
|
|
|
|
v.x = p2t.x;
|
|
v.y = p2t.y;
|
|
v.z = p2t.z;
|
|
v.u = spr->Sprite->UV[2].x;
|
|
v.v = spr->Sprite->UV[2].y;
|
|
v.r = spr->R / 255.0f;
|
|
v.g = spr->G / 255.0f;
|
|
v.b = spr->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_spritesVertices.push_back(v);
|
|
|
|
v.x = p3t.x;
|
|
v.y = p3t.y;
|
|
v.z = p3t.z;
|
|
v.u = spr->Sprite->UV[3].x;
|
|
v.v = spr->Sprite->UV[3].y;
|
|
v.r = spr->R / 255.0f;
|
|
v.g = spr->G / 255.0f;
|
|
v.b = spr->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_spritesVertices.push_back(v);
|
|
|
|
m_spritesIndices.push_back(baseVertex + 0);
|
|
m_spritesIndices.push_back(baseVertex + 1);
|
|
m_spritesIndices.push_back(baseVertex + 2);
|
|
m_spritesIndices.push_back(baseVertex + 0);
|
|
m_spritesIndices.push_back(baseVertex + 2);
|
|
m_spritesIndices.push_back(baseVertex + 3);
|
|
}
|
|
else
|
|
{
|
|
D3DXVECTOR3 p0t = D3DXVECTOR3(spr->X1, spr->Y1, spr->Z1);
|
|
D3DXVECTOR3 p1t = D3DXVECTOR3(spr->X2, spr->Y2, spr->Z2);
|
|
D3DXVECTOR3 p2t = D3DXVECTOR3(spr->X3, spr->Y3, spr->Z3);
|
|
D3DXVECTOR3 p3t = D3DXVECTOR3(spr->X4, spr->Y4, spr->Z4);
|
|
|
|
RendererVertex v;
|
|
__int32 baseVertex = m_spritesVertices.size();
|
|
|
|
v.x = p0t.x;
|
|
v.y = p0t.y;
|
|
v.z = p0t.z;
|
|
v.u = spr->Sprite->UV[0].x;
|
|
v.v = spr->Sprite->UV[0].y;
|
|
v.r = spr->R / 255.0f;
|
|
v.g = spr->G / 255.0f;
|
|
v.b = spr->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_spritesVertices.push_back(v);
|
|
|
|
v.x = p1t.x;
|
|
v.y = p1t.y;
|
|
v.z = p1t.z;
|
|
v.u = spr->Sprite->UV[1].x;
|
|
v.v = spr->Sprite->UV[1].y;
|
|
v.r = spr->R / 255.0f;
|
|
v.g = spr->G / 255.0f;
|
|
v.b = spr->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_spritesVertices.push_back(v);
|
|
|
|
v.x = p2t.x;
|
|
v.y = p2t.y;
|
|
v.z = p2t.z;
|
|
v.u = spr->Sprite->UV[2].x;
|
|
v.v = spr->Sprite->UV[2].y;
|
|
v.r = spr->R / 255.0f;
|
|
v.g = spr->G / 255.0f;
|
|
v.b = spr->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_spritesVertices.push_back(v);
|
|
|
|
v.x = p3t.x;
|
|
v.y = p3t.y;
|
|
v.z = p3t.z;
|
|
v.u = spr->Sprite->UV[3].x;
|
|
v.v = spr->Sprite->UV[3].y;
|
|
v.r = spr->R / 255.0f;
|
|
v.g = spr->G / 255.0f;
|
|
v.b = spr->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_spritesVertices.push_back(v);
|
|
|
|
m_spritesIndices.push_back(baseVertex + 0);
|
|
m_spritesIndices.push_back(baseVertex + 1);
|
|
m_spritesIndices.push_back(baseVertex + 2);
|
|
m_spritesIndices.push_back(baseVertex + 0);
|
|
m_spritesIndices.push_back(baseVertex + 2);
|
|
m_spritesIndices.push_back(baseVertex + 3);
|
|
}
|
|
|
|
lastSprite++;
|
|
}
|
|
|
|
numSpritesToDraw -= NUM_SPRITES_PER_BUCKET;
|
|
|
|
HRESULT res;
|
|
|
|
void* vertices;
|
|
|
|
res = m_spritesVertexBuffer->Lock(0, 0, &vertices, 0);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
memcpy(vertices, m_spritesVertices.data(), m_spritesVertices.size() * sizeof(RendererVertex));
|
|
|
|
res = m_spritesVertexBuffer->Unlock();
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
void* indices;
|
|
|
|
res = m_spritesIndexBuffer->Lock(0, 0, &indices, 0);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
memcpy(indices, m_spritesIndices.data(), m_spritesIndices.size() * 4);
|
|
|
|
m_spritesIndexBuffer->Unlock();
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
m_device->SetStreamSource(0, m_spritesVertexBuffer, 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(m_spritesIndexBuffer);
|
|
|
|
// Draw the sprites
|
|
effect->BeginPass(0);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, m_spritesVertices.size(), 0, m_spritesIndices.size() / 3);
|
|
|
|
/*m_device->DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, m_spritesVertices.size(),
|
|
m_spritesIndices.size() / 3, m_spritesIndices.data(),
|
|
D3DFORMAT::D3DFMT_INDEX32, m_spritesVertices.data(), sizeof(RendererVertex));
|
|
*/
|
|
|
|
effect->EndPass();
|
|
}
|
|
|
|
effect->End();
|
|
m_device->EndScene();
|
|
|
|
return true;
|
|
}
|
|
|
|
void Renderer::AddSpriteBillboard(RendererSprite* sprite, float x, float y, float z, byte r, byte g, byte b, float rotation, float scale, float width, float height)
|
|
{
|
|
scale = 1.0f;
|
|
|
|
width *= scale;
|
|
height *= scale;
|
|
|
|
RendererSpriteToDraw* spr = new RendererSpriteToDraw();
|
|
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;
|
|
|
|
m_spritesToDraw.push_back(spr);
|
|
}
|
|
|
|
void Renderer::DrawFires()
|
|
{
|
|
for (__int32 k = 0; k < 32; k++)
|
|
{
|
|
FIRE_LIST* fire = &Fires[k];
|
|
if (fire->on)
|
|
{
|
|
for (__int32 i = 0; i < 20; i++)
|
|
{
|
|
FIRE_SPARKS* spark = &FireSparks[i];
|
|
if (spark->on)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Renderer::DrawSmokes()
|
|
{
|
|
for (__int32 i = 0; i < 32; i++)
|
|
{
|
|
SMOKE_SPARKS* spark = &SmokeSparks[i];
|
|
if (spark->On)
|
|
{
|
|
AddSpriteBillboard(m_sprites[spark->Def],
|
|
spark->x, spark->y, spark->z,
|
|
spark->Shade, spark->Shade, spark->Shade,
|
|
TR_ANGLE_TO_RAD(spark->RotAng), spark->Scalar, spark->Size * 4.0f, spark->Size * 4.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Renderer::DrawSparks()
|
|
{
|
|
for (__int32 i = 0; i < 1024; i++)
|
|
{
|
|
SPARKS* spark = &Sparks[i];
|
|
if (spark->on)
|
|
{
|
|
if (spark->flags & SP_DEF)
|
|
{
|
|
AddSpriteBillboard(m_sprites[spark->def],
|
|
spark->x, spark->y, spark->z,
|
|
spark->r, spark->g, spark->b,
|
|
TR_ANGLE_TO_RAD(spark->rotAng), spark->scalar, spark->size * 12.0f, spark->size * 12.0f);
|
|
}
|
|
else
|
|
{
|
|
D3DXVECTOR3 v = D3DXVECTOR3(spark->xVel, spark->yVel, spark->zVel);
|
|
D3DXVec3Normalize(&v, &v);
|
|
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 Renderer::DrawBlood()
|
|
{
|
|
for (__int32 i = 0; i < 32; i++)
|
|
{
|
|
BLOOD_STRUCT* blood = &Blood[i];
|
|
if (blood->On)
|
|
{
|
|
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + 15],
|
|
blood->x, blood->y, blood->z,
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Renderer::DrawGunshells(RENDERER_BUCKETS bucketIndex, RENDERER_PASSES pass)
|
|
{
|
|
D3DXMATRIX world;
|
|
UINT cPasses = 1;
|
|
|
|
LPD3DXEFFECT effect;
|
|
if (pass == RENDERER_PASSES::RENDERER_PASS_SHADOW_MAP)
|
|
effect = m_depthShader->GetEffect();
|
|
else
|
|
effect = m_shaderFillGBuffer->GetEffect();
|
|
|
|
for (__int32 i = 0; i < 24; i++)
|
|
{
|
|
GUNSHELL_STRUCT* gunshell = &GunShells[i];
|
|
if (gunshell->counter > 0)
|
|
{
|
|
OBJECT_INFO* obj = &Objects[gunshell->objectNumber];
|
|
RendererObject* moveableObj = m_moveableObjects[gunshell->objectNumber];
|
|
|
|
if (!moveableObj->HasDataInBucket[bucketIndex])
|
|
return true;
|
|
|
|
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), false);
|
|
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_MOVEABLE);
|
|
|
|
D3DXMatrixTranslation(&m_tempTranslation, gunshell->pos.xPos, gunshell->pos.yPos, gunshell->pos.zPos);
|
|
D3DXMatrixRotationYawPitchRoll(&m_tempRotation, TR_ANGLE_TO_RAD(gunshell->pos.yRot),
|
|
TR_ANGLE_TO_RAD(gunshell->pos.xRot),
|
|
TR_ANGLE_TO_RAD(gunshell->pos.zRot));
|
|
D3DXMatrixMultiply(&world, &m_tempRotation, &m_tempTranslation);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
|
|
|
|
if (bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID || bucketIndex == RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS)
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_OPAQUE);
|
|
else
|
|
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_ALPHATEST);
|
|
|
|
for (__int32 i = 0; i < moveableObj->ObjectMeshes.size(); i++)
|
|
{
|
|
RendererMesh* mesh = moveableObj->ObjectMeshes[i];
|
|
RendererBucket* bucket = mesh->GetBucket(bucketIndex);
|
|
if (bucket->NumVertices == 0)
|
|
continue;
|
|
|
|
SetGpuStateForBucket(bucketIndex);
|
|
|
|
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(bucket->GetIndexBuffer());
|
|
|
|
for (int iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
effect->BeginPass(iPass);
|
|
effect->CommitChanges();
|
|
|
|
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
|
|
|
|
effect->EndPass();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::DoRain()
|
|
{
|
|
if (m_firstWeather)
|
|
{
|
|
for (__int32 i = 0; i < NUM_RAIN_DROPS; i++)
|
|
m_rain[i].Reset = true;
|
|
}
|
|
|
|
for (__int32 i = 0; i < NUM_RAIN_DROPS; i++)
|
|
{
|
|
RendererWeatherParticle* drop = &m_rain[i];
|
|
|
|
if (drop->Reset)
|
|
{
|
|
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
|
|
__int16 roomNumber = Camera.pos.roomNumber;
|
|
FLOOR_INFO* floor = GetFloor(drop->X, drop->Y, drop->Z, &roomNumber);
|
|
ROOM_INFO* room = &Rooms[roomNumber];
|
|
if (!(room->flags & ENV_FLAG_OUTSIDE))
|
|
{
|
|
drop->Reset = true;
|
|
continue;
|
|
}
|
|
|
|
drop->Size = RAIN_SIZE + (rand() % 64);
|
|
drop->AngleH = (rand() % RAIN_MAX_ANGLE_H) * RADIAN;
|
|
drop->AngleV = (rand() % RAIN_MAX_ANGLE_V) * RADIAN;
|
|
drop->Reset = false;
|
|
}
|
|
|
|
float x1 = drop->X;
|
|
float y1 = drop->Y;
|
|
float z1 = drop->Z;
|
|
|
|
float radius = drop->Size * sin(drop->AngleV);
|
|
|
|
float dx = sin(drop->AngleH) * radius;
|
|
float dy = drop->Size * cos(drop->AngleV);
|
|
float dz = cos(drop->AngleH) * radius;
|
|
|
|
drop->X += dx;
|
|
drop->Y += RAIN_DELTA_Y;
|
|
drop->Z += dz;
|
|
|
|
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));
|
|
|
|
// If rain drop has hit the ground, then reset it and add a little drip
|
|
__int16 roomNumber = Camera.pos.roomNumber;
|
|
FLOOR_INFO* floor = GetFloor(drop->X, drop->Y, drop->Z, &roomNumber);
|
|
ROOM_INFO* room = &Rooms[roomNumber];
|
|
if (drop->Y >= room->y + room->minfloor)
|
|
{
|
|
drop->Reset = true;
|
|
AddWaterSparks(drop->X, room->y + room->minfloor, drop->Z, 1);
|
|
}
|
|
}
|
|
|
|
m_firstWeather = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Renderer::DoSnow()
|
|
{
|
|
if (m_firstWeather)
|
|
{
|
|
for (__int32 i = 0; i < NUM_SNOW_PARTICLES; i++)
|
|
m_snow[i].Reset = true;
|
|
}
|
|
|
|
for (__int32 i = 0; i < NUM_SNOW_PARTICLES; i++)
|
|
{
|
|
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
|
|
__int16 roomNumber = Camera.pos.roomNumber;
|
|
FLOOR_INFO* floor = GetFloor(snow->X, snow->Y, snow->Z, &roomNumber);
|
|
ROOM_INFO* room = &Rooms[roomNumber];
|
|
if (!(room->flags & ENV_FLAG_OUTSIDE))
|
|
continue;
|
|
|
|
snow->Size = SNOW_DELTA_Y + (rand() % 64);
|
|
snow->AngleH = (rand() % SNOW_MAX_ANGLE_H) * RADIAN;
|
|
snow->AngleV = (rand() % SNOW_MAX_ANGLE_V) * RADIAN;
|
|
snow->Reset = false;
|
|
}
|
|
|
|
float radius = snow->Size * sin(snow->AngleV);
|
|
|
|
float dx = sin(snow->AngleH) * radius;
|
|
float dz = cos(snow->AngleH) * radius;
|
|
|
|
snow->X += dx;
|
|
snow->Y += SNOW_DELTA_Y;
|
|
snow->Z += dz;
|
|
|
|
if (snow->X <= 0 || snow->Z <= 0 || snow->X >= 100 * 1024.0f || snow->Z >= 100 * 1024.0f)
|
|
{
|
|
snow->Reset = true;
|
|
continue;
|
|
}
|
|
|
|
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + 14], snow->X, snow->Y, snow->Z, 255, 255, 255,
|
|
0.0f, 1.0f, SNOW_SIZE, SNOW_SIZE);
|
|
|
|
__int16 roomNumber = Camera.pos.roomNumber;
|
|
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;
|
|
}
|
|
|
|
void Renderer::AddLine3D(__int32 x1, __int32 y1, __int32 z1, __int32 x2, __int32 y2, __int32 z2, byte r, byte g, byte b)
|
|
{
|
|
RendererLine3DToDraw* line = new RendererLine3DToDraw();
|
|
|
|
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.push_back(line);
|
|
}
|
|
|
|
bool Renderer::DrawLines3D()
|
|
{
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_NONE);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_ADDITIVE);
|
|
SetDepthWrite(false);
|
|
|
|
/*m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
|
m_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ZERO);
|
|
m_device->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO);
|
|
m_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
|
m_device->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
|
|
m_device->SetRenderState(D3DRS_ZWRITEENABLE, false);
|
|
m_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);*/
|
|
|
|
UINT cPasses = 1;
|
|
LPD3DXEFFECT effect = m_shaderRain->GetEffect();
|
|
m_device->BeginScene();
|
|
effect->Begin(&cPasses, 0);
|
|
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "View"), &ViewMatrix);
|
|
effect->SetMatrix(effect->GetParameterByName(NULL, "Projection"), &ProjectionMatrix);
|
|
|
|
__int32 numLinesToDraw = m_lines3DToDraw.size();
|
|
__int32 lastLine = 0;
|
|
while (numLinesToDraw > 0)
|
|
{
|
|
m_lines3DVertices.clear();
|
|
|
|
// Fill the buffer for lines
|
|
__int32 maxLine = min(m_lines3DToDraw.size(), lastLine + NUM_LINES_PER_BUCKET);
|
|
for (__int32 i = lastLine; i < maxLine; i++)
|
|
{
|
|
RendererLine3DToDraw* line = m_lines3DToDraw[i];
|
|
|
|
RendererVertex v;
|
|
|
|
v.x = line->X1;
|
|
v.y = line->Y1;
|
|
v.z = line->Z1;
|
|
v.r = line->R / 255.0f;
|
|
v.g = line->G / 255.0f;
|
|
v.b = line->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_lines3DVertices.push_back(v);
|
|
|
|
v.x = line->X2;
|
|
v.y = line->Y2;
|
|
v.z = line->Z2;
|
|
v.r = line->R / 255.0f;
|
|
v.g = line->G / 255.0f;
|
|
v.b = line->B / 255.0f;
|
|
v.a = 1.0f;
|
|
m_lines3DVertices.push_back(v);
|
|
|
|
lastLine++;
|
|
}
|
|
|
|
numLinesToDraw -= NUM_LINES_PER_BUCKET;
|
|
|
|
HRESULT res;
|
|
|
|
void* vertices;
|
|
|
|
res = m_linesVertexBuffer->Lock(0, 0, &vertices, 0);
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
memcpy(vertices, m_lines3DVertices.data(), m_lines3DVertices.size() * sizeof(RendererVertex));
|
|
|
|
res = m_linesVertexBuffer->Unlock();
|
|
if (res != S_OK)
|
|
return false;
|
|
|
|
m_device->SetStreamSource(0, m_linesVertexBuffer, 0, sizeof(RendererVertex));
|
|
m_device->SetIndices(NULL);
|
|
|
|
// Draw the sprites
|
|
effect->BeginPass(0);
|
|
effect->CommitChanges();
|
|
|
|
m_device->DrawPrimitive(D3DPRIMITIVETYPE::D3DPT_LINELIST, 0, m_lines3DVertices.size() / 2);
|
|
|
|
effect->EndPass();
|
|
}
|
|
|
|
effect->End();
|
|
m_device->EndScene();
|
|
|
|
return true;
|
|
}
|
|
|
|
void Renderer::DrawDrips()
|
|
{
|
|
for (__int32 i = 0; i < 32; i++)
|
|
{
|
|
DRIP_STRUCT* drip = &Drips[i];
|
|
|
|
if (drip->On)
|
|
{
|
|
AddLine3D(drip->x, drip->y, drip->z, drip->x, drip->y + 24.0f, drip->z, drip->R, drip->G, drip->B);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Renderer::SetCullMode(RENDERER_CULLMODE mode)
|
|
{
|
|
if (m_cullMode == mode)
|
|
return;
|
|
|
|
m_cullMode = mode;
|
|
|
|
if (m_cullMode == RENDERER_CULLMODE::CULLMODE_NONE)
|
|
m_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
|
else if (m_cullMode == RENDERER_CULLMODE::CULLMODE_CW)
|
|
m_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
|
|
else
|
|
m_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
|
|
}
|
|
|
|
void Renderer::SetBlendState(RENDERER_BLENDSTATE state)
|
|
{
|
|
if (m_blendState == state)
|
|
return;
|
|
|
|
m_blendState = state;
|
|
|
|
if (m_blendState == RENDERER_BLENDSTATE::BLENDSTATE_OPAQUE)
|
|
{
|
|
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
|
|
}
|
|
else if (m_blendState == RENDERER_BLENDSTATE::BLENDSTATE_ADDITIVE)
|
|
{
|
|
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
|
m_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ZERO);
|
|
m_device->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO);
|
|
m_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
|
m_device->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
|
|
}
|
|
else if (m_blendState == RENDERER_BLENDSTATE::BLENDSTATE_ALPHABLEND)
|
|
{
|
|
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
|
m_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_ONE);
|
|
m_device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
|
m_device->SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
|
|
}
|
|
else if (m_blendState == RENDERER_BLENDSTATE::BLENDSTATE_SPECIAL_Z_BUFFER)
|
|
{
|
|
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
|
}
|
|
}
|
|
|
|
void Renderer::SetDepthWrite(bool value)
|
|
{
|
|
if (m_enableZwrite == value)
|
|
return;
|
|
|
|
m_enableZwrite = value;
|
|
|
|
m_device->SetRenderState(D3DRS_ZWRITEENABLE, value);
|
|
}
|
|
|
|
void Renderer::SetGpuStateForBucket(RENDERER_BUCKETS bucket)
|
|
{
|
|
switch (bucket)
|
|
{
|
|
case RENDERER_BUCKETS::RENDERER_BUCKET_SOLID:
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_CCW);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_OPAQUE);
|
|
SetDepthWrite(true);
|
|
break;
|
|
|
|
case RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS:
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_NONE);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_OPAQUE);
|
|
SetDepthWrite(true);
|
|
break;
|
|
|
|
case RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST:
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_CCW);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_OPAQUE);
|
|
SetDepthWrite(true);
|
|
break;
|
|
|
|
case RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS:
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_NONE);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_OPAQUE);
|
|
SetDepthWrite(true);
|
|
break;
|
|
|
|
case RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT:
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_CCW);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_ADDITIVE);
|
|
SetDepthWrite(false);
|
|
break;
|
|
|
|
case RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS:
|
|
SetCullMode(RENDERER_CULLMODE::CULLMODE_NONE);
|
|
SetBlendState(RENDERER_BLENDSTATE::BLENDSTATE_ADDITIVE);
|
|
SetDepthWrite(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Renderer::DrawBubbles()
|
|
{
|
|
for (__int32 i = 0; i < 40; i++)
|
|
{
|
|
BUBBLE_STRUCT* bubble = &Bubbles[i];
|
|
|
|
if (bubble->size)
|
|
{
|
|
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + 13],
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Renderer::IsRoomUnderwater(__int16 roomNumber)
|
|
{
|
|
return (m_rooms[roomNumber]->Room->flags & 1);
|
|
}
|
|
|
|
bool Renderer::IsInRoom(__int32 x, __int32 y, __int32 z, __int16 roomNumber)
|
|
{
|
|
RendererRoom* room = m_rooms[roomNumber];
|
|
ROOM_INFO* r = room->Room;
|
|
|
|
return (x >= r->x && x <= r->x + r->xSize * 1024.0f &&
|
|
y >= r->maxceiling && y <= r->minfloor &&
|
|
z >= r->z && z <= r->z + r->ySize * 1024.0f);
|
|
}
|
|
|
|
void Renderer::DrawSplahes()
|
|
{
|
|
for (__int32 i = 0; i < 4; i++)
|
|
{
|
|
SPLASH_STRUCT* splash = &Splashes[i];
|
|
|
|
int x = 0;
|
|
}
|
|
}
|
|
|
|
void Renderer::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)
|
|
{
|
|
scale = 1.0f;
|
|
|
|
width *= scale;
|
|
height *= scale;
|
|
|
|
RendererSpriteToDraw* spr = new RendererSpriteToDraw();
|
|
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;
|
|
|
|
m_spritesToDraw.push_back(spr);
|
|
}
|
|
|
|
void Renderer::DrawRipples()
|
|
{
|
|
for (__int32 i = 0; i < 32; i++)
|
|
{
|
|
RIPPLE_STRUCT* ripple = &Ripples[i];
|
|
|
|
if (ripple->flags & 1)
|
|
{
|
|
float x1 = ripple->x - ripple->size;
|
|
float z1 = ripple->z - ripple->size;
|
|
float x2 = ripple->x + ripple->size;
|
|
float z2 = ripple->z + ripple->size;
|
|
float y = ripple->y;
|
|
|
|
byte color = (ripple->init ? ripple->init << 1 : ripple->life << 1);
|
|
|
|
AddSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + 9],
|
|
x1, y, z2, x2, y, z2, x2, y, z1, x1, y, z1, color, color, color, 0.0f, 1.0f, ripple->size, ripple->size);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Renderer::DrawUnderwaterDust()
|
|
{
|
|
if (m_firstUnderwaterDustParticles)
|
|
{
|
|
for (__int32 i = 0; i < NUM_UNDERWATER_DUST_PARTICLES; i++)
|
|
m_underwaterDustParticles[i].Reset = true;
|
|
}
|
|
|
|
for (__int32 i = 0; i < NUM_UNDERWATER_DUST_PARTICLES; i++)
|
|
{
|
|
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
|
|
__int16 roomNumber = Camera.pos.roomNumber;
|
|
FLOOR_INFO* floor = GetFloor(dust->X, dust->Y, dust->Z, &roomNumber);
|
|
if (!IsRoomUnderwater(roomNumber))
|
|
continue;
|
|
|
|
if (!IsInRoom(dust->X, dust->Y, dust->Z, roomNumber))
|
|
{
|
|
dust->Reset = true;
|
|
continue;
|
|
}
|
|
|
|
dust->Life = 0;
|
|
dust->Reset = false;
|
|
}
|
|
|
|
dust->Life++;
|
|
byte color = (dust->Life > 16 ? 32 - dust->Life : dust->Life) * 4;
|
|
|
|
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + 14], dust->X, dust->Y, dust->Z, color, color, color,
|
|
0.0f, 1.0f, UNDERWATER_DUST_PARTICLES_SIZE, UNDERWATER_DUST_PARTICLES_SIZE);
|
|
|
|
if (dust->Life >= 32)
|
|
dust->Reset = true;
|
|
}
|
|
|
|
m_firstUnderwaterDustParticles = false;
|
|
|
|
return;
|
|
}
|
|
|
|
__int32 Renderer::getAnimatedTextureInfo(__int16 textureId)
|
|
{
|
|
for (__int32 i = 0; i < m_animatedTextureSets.size(); i++)
|
|
{
|
|
RendererAnimatedTextureSet* set = m_animatedTextureSets[i];
|
|
for (__int32 j = 0; j < set->Textures.size(); j++)
|
|
{
|
|
if (set->Textures[j]->Id == textureId)
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void Renderer::UpdateAnimatedTextures()
|
|
{
|
|
for (__int32 i = 0; i < m_rooms.size(); i++)
|
|
{
|
|
RendererRoom* room = m_rooms[i];
|
|
RendererObject* roomObj = room->RoomObject;
|
|
if (roomObj->ObjectMeshes.size() == 0)
|
|
continue;
|
|
|
|
RendererMesh* mesh = roomObj->ObjectMeshes[0];
|
|
|
|
for (__int32 bucketIndex = 0; bucketIndex < NUM_BUCKETS; bucketIndex++)
|
|
{
|
|
RendererBucket* bucket = mesh->GetAnimatedBucket(bucketIndex);
|
|
if (bucket->Vertices.size() == 0)
|
|
continue;
|
|
|
|
for (__int32 p = 0; p < bucket->Polygons.size(); p++)
|
|
{
|
|
RendererPolygon* polygon = &bucket->Polygons[p];
|
|
RendererAnimatedTextureSet* set = m_animatedTextureSets[polygon->AnimatedSet];
|
|
__int32 textureIndex = -1;
|
|
for (__int32 j = 0; j < set->Textures.size(); j++)
|
|
{
|
|
if (set->Textures[j]->Id == polygon->TextureId)
|
|
{
|
|
textureIndex = j;
|
|
break;
|
|
}
|
|
}
|
|
if (textureIndex == -1)
|
|
continue;
|
|
|
|
if (textureIndex == set->Textures.size() - 1)
|
|
textureIndex = 0;
|
|
else
|
|
textureIndex++;
|
|
|
|
polygon->TextureId = set->Textures[textureIndex]->Id;
|
|
|
|
for (__int32 v = 0; v < (polygon->Shape == SHAPE_RECTANGLE ? 4 : 3); v++)
|
|
{
|
|
bucket->Vertices[polygon->Indices[v]].u = set->Textures[textureIndex]->UV[v].x;
|
|
bucket->Vertices[polygon->Indices[v]].v = set->Textures[textureIndex]->UV[v].y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |