TombEngine/TR5Main/Renderer/Renderer.cpp

5879 lines
191 KiB
C++
Raw Normal View History

2018-08-19 09:46:58 +02:00
#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>
2018-08-19 09:46:58 +02:00
#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"
2018-08-19 09:46:58 +02:00
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;
2018-08-19 09:46:58 +02:00
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;
2018-08-21 18:59:31 +02:00
m_shaderRain = new Shader(m_device, (char*)"Rain.fx");
m_shaderRain->Compile();
if (m_shaderRain->GetEffect() == NULL)
return false;
2018-08-19 10:21:22 +02:00
/*m_shaderFXAA = new Shader(m_device, (char*)"FXAA.fx");
2018-08-19 09:46:58 +02:00
m_shaderFXAA->Compile();
if (m_shaderFXAA->GetEffect() == NULL)
2018-08-19 10:21:22 +02:00
return false;*/
2018-08-19 09:46:58 +02:00
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;
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
m_halfPixelX = 0.5f / (float)ScreenWidth;
m_halfPixelY = 0.5f / (float)ScreenHeight;
2018-08-19 09:46:58 +02:00
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]);
}
2018-08-19 09:46:58 +02:00
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;
2018-08-19 09:46:58 +02:00
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;
2018-08-19 09:46:58 +02:00
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)
2018-08-19 09:46:58 +02:00
{
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;
}
2018-08-19 09:46:58 +02:00
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]];
2018-08-19 09:46:58 +02:00
if (isHairs)
vertex.boneAndFlags = indices[v];
2018-08-19 09:46:58 +02:00
/*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]];
2018-08-19 09:46:58 +02:00
if (isHairs)
vertex.boneAndFlags = indices[v];
2018-08-19 09:46:58 +02:00
/*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 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);
}
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
// 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;
2018-08-19 09:46:58 +02:00
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;
2018-08-19 09:46:58 +02:00
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 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;
}
bucket = mesh->GetBucket(bucketIndex);
roomObject->HasDataInBucket[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;
2018-08-19 09:46:58 +02:00
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);
2018-08-21 21:07:18 +02:00
roomObject->NumVertices++;
2018-08-19 09:46:58 +02:00
}
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);
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;
2018-08-19 09:46:58 +02:00
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 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;
}
bucket = mesh->GetBucket(bucketIndex);
roomObject->HasDataInBucket[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;
2018-08-19 09:46:58 +02:00
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);
2018-08-21 21:07:18 +02:00
roomObject->NumVertices++;
2018-08-19 09:46:58 +02:00
}
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);
polygons += sizeof(tr4_mesh_face3);
}
}
}
if (room->numLights != 0)
{
tr5_room_light* oldLight = room->light;
2018-08-19 09:46:58 +02:00
for (__int32 l = 0; l < room->numLights; l++)
2018-08-19 09:46:58 +02:00
{
// DEBUG: only point lights
2018-08-19 09:46:58 +02:00
RendererLight* light = new RendererLight();
/*if (oldLight->LightType == LIGHT_TYPES::LIGHT_TYPE_SUN)
2018-08-19 09:46:58 +02:00
{
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;
2018-08-19 09:46:58 +02:00
}
r->Lights.push_back(light);
2018-08-19 09:46:58 +02:00
}
}
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];
2018-08-19 09:46:58 +02:00
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;
}
2018-08-19 09:46:58 +02:00
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];
2018-08-19 09:46:58 +02:00
RendererMesh* mesh = GetRendererMeshFromTrMesh(moveable,
meshPtr,
Meshes[obj->meshIndex + 2 * j],
boneIndex, MoveablesIds[i] == ID_LARA_SKIN_JOINTS,
2018-08-19 09:46:58 +02:00
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)
2018-08-19 09:46:58 +02:00
{
RendererMesh* skinMesh = objSkin->ObjectMeshes[jointVertex->boneAndFlags];
RendererBone* skinBone = objSkin->LinearizedBones[jointVertex->boneAndFlags];
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
}
// 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));
}
2018-08-19 09:46:58 +02:00
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];
2018-08-19 09:46:58 +02:00
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));
2018-08-19 09:46:58 +02:00
// 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),
2018-08-19 09:46:58 +02:00
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),
2018-08-19 09:46:58 +02:00
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);
}
2018-08-19 09:46:58 +02:00
}
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);
2018-08-19 09:46:58 +02:00
D3DXVECTOR3 parentVertices[6][4];
D3DXMATRIX headMatrix;
2018-08-19 09:46:58 +02:00
RendererObject* objSkin = m_moveableObjects[ID_LARA_SKIN];
RendererObject* objLara = m_moveableObjects[ID_LARA];
RendererMesh* parentMesh = objSkin->ObjectMeshes[HEAD];
RendererBone* parentBone = objSkin->LinearizedBones[HEAD];
2018-08-19 09:46:58 +02:00
D3DXMatrixMultiply(&world, &objLara->AnimationTransforms[HEAD], &m_LaraWorldMatrix);
2018-08-19 09:46:58 +02:00
__int32 lastVertex = 0;
__int32 lastIndex = 0;
2018-08-19 09:46:58 +02:00
ZeroMemory(m_hairVertices, m_numHairVertices * 2 * sizeof(RendererObject));
ZeroMemory(m_hairIndices, m_numHairIndices * 2 * 4);
2018-08-19 09:46:58 +02:00
for (__int32 p = 0; p < ((gfLevelFlags & 1) ? 2 : 1); p++)
2018-08-19 09:46:58 +02:00
{
// We can't use hardware skinning here, however hairs have just a few vertices so
// it's not so bad doing skinning in software
if (gfLevelFlags & 1)
{
if (p == 1)
2018-08-19 09:46:58 +02:00
{
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
__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]);
2018-08-19 09:46:58 +02:00
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;
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
m_hairVertices[lastVertex].nx = n.x;
m_hairVertices[lastVertex].ny = n.y;
m_hairVertices[lastVertex].nz = n.z;
2018-08-19 09:46:58 +02:00
lastVertex++;
}
}
2018-08-19 09:46:58 +02:00
for (__int32 j = 0; j < bucket->Indices.size(); j++)
{
m_hairIndices[lastIndex] = baseVertex + bucket->Indices[j];
lastIndex++;
}
2018-08-19 09:46:58 +02:00
}
}
}
}
2018-08-19 09:46:58 +02:00
void Renderer::UpdateItemsAnimations()
{
D3DXMATRIX translation;
D3DXMATRIX rotation;
2018-08-19 09:46:58 +02:00
for (__int32 i = 0; i < m_itemsToDraw.size(); i++)
2018-08-19 09:46:58 +02:00
{
RendererItemToDraw* itemToDraw = m_itemsToDraw[i];
ITEM_INFO* item = itemToDraw->Item;
2018-08-19 09:46:58 +02:00
// Lara has her own routine
if (item->objectNumber == ID_LARA || item->objectNumber == 434)
continue;
2018-08-19 09:46:58 +02:00
OBJECT_INFO* obj = &Objects[item->objectNumber];
RendererObject* moveableObj = m_moveableObjects[item->objectNumber];
2018-08-19 09:46:58 +02:00
// 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);
}
2018-08-19 09:46:58 +02:00
// 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);
}
2018-08-19 09:46:58 +02:00
}
__int32 Renderer::DumpGameScene()
{
return DrawSceneLightPrePass(true);
2018-08-19 09:46:58 +02:00
}
__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);
2018-08-19 09:46:58 +02:00
}
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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(800, 0, 0), 0xFFFFFFFF);
m_sprite->SetTransform(&scale);
m_sprite->Draw(m_vertexLightBuffer->GetTexture(), NULL, &D3DXVECTOR3(0, 0, 0), &D3DXVECTOR3(1600, 0, 0), 0xFFFFFFFF);
2018-08-19 09:46:58 +02:00
m_sprite->SetTransform(&scale);
m_sprite->Draw(m_lightBuffer->GetTexture(), NULL, &D3DXVECTOR3(0, 0, 0), &D3DXVECTOR3(2400, 0, 0), 0xFFFFFFFF);
2018-08-19 09:46:58 +02:00
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);
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
// 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);
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
// 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);
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
// 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;
}
2018-08-19 09:46:58 +02:00
bool Renderer::DrawSceneLightPrePass(bool dump)
{
// HACK:
LaraItem->hitPoints = 1000;
2018-08-19 09:46:58 +02:00
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();
2018-08-19 09:46:58 +02:00
UpdateLaraAnimations();
UpdateItemsAnimations();
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
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
// 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);
2018-08-19 09:46:58 +02:00
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;
2018-08-19 09:46:58 +02:00
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);
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
// 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);
2018-08-19 09:46:58 +02:00
}
}
}
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];
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
// 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);
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_GBUFFER);
// 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);
2018-08-19 09:46:58 +02:00
}
}
}
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
// 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);
2018-08-19 09:46:58 +02:00
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());
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-21 18:59:31 +02:00
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
2018-08-21 18:59:31 +02:00
effect = m_shaderReconstructZBuffer->GetEffect();
2018-08-19 09:46:58 +02:00
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);
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_SOLID_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
2018-08-19 09:46:58 +02:00
// 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);
2018-08-19 09:46:58 +02:00
}
}
}
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
}
// 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);
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_ALPHA_TEST_DS, RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH);
2018-08-19 09:46:58 +02:00
// 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);
2018-08-19 09:46:58 +02:00
}
}
}
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
}
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);
DrawRoomLPP(m_roomsToDraw[i], RENDERER_BUCKETS::RENDERER_BUCKET_TRANSPARENT_DS, RENDERER_PASSES::RENDERER_PASS_TRANSPARENT);
// 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();
2018-08-19 09:46:58 +02:00
DrawFires();
DrawSmokes();
DrawBlood();
DrawSparks();
DrawBubbles();
DrawDrips();
DrawRipples();
DrawUnderwaterDust();
2018-08-21 18:59:31 +02:00
// Do weather
if (WeatherType == WEATHER_TYPES::WEATHER_RAIN)
DoRain();
else if (WeatherType == WEATHER_TYPES::WEATHER_SNOW)
DoSnow();
2018-08-21 23:34:54 +02:00
// Draw sprites
DrawSprites();
DrawGunFlashes();
DrawLines3D();
2018-08-19 09:46:58 +02:00
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];
2018-08-19 09:46:58 +02:00
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)
2018-08-19 09:46:58 +02:00
effect = m_shaderFillGBuffer->GetEffect();
else
effect = m_shaderTransparent->GetEffect();
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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++)
{
2018-08-19 09:46:58 +02:00
// 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);
2018-08-19 09:46:58 +02:00
// 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);
2018-08-19 09:46:58 +02:00
// 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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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,
2018-08-19 09:46:58 +02:00
m_hairIndices, D3DFMT_INDEX32, m_hairVertices, sizeof(RendererVertex));
effect->EndPass();
}
}
}
return true;
}
bool Renderer::DrawItemLPP(RendererItemToDraw* itemToDraw, RENDERER_BUCKETS bucketIndex, RENDERER_PASSES pass)
{
2018-08-19 09:46:58 +02:00
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;
2018-08-19 09:46:58 +02:00
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)
2018-08-19 09:46:58 +02:00
effect = m_shaderFillGBuffer->GetEffect();
else
effect = m_shaderTransparent->GetEffect();
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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;
}
2018-08-19 09:46:58 +02:00
bool Renderer::DrawRoomLPP(__int32 roomIndex, RENDERER_BUCKETS bucketIndex, RENDERER_PASSES pass)
{
D3DXMATRIX world;
UINT cPasses = 1;
RendererRoom* room = m_rooms[roomIndex];
ROOM_INFO* r = room->Room;
RendererObject* roomObj = room->RoomObject;
if (!roomObj->HasDataInBucket[bucketIndex])
return true;
if (roomObj->ObjectMeshes.size() == 0)
return true;
RendererMesh* mesh = roomObj->ObjectMeshes[0];
RendererBucket* bucket = mesh->GetBucket(bucketIndex);
SetGpuStateForBucket(bucketIndex);
2018-08-19 09:46:58 +02:00
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)
2018-08-19 09:46:58 +02:00
effect = m_shaderFillGBuffer->GetEffect();
else
effect = m_shaderTransparent->GetEffect();
2018-08-19 09:46:58 +02:00
D3DXMatrixTranslation(&world, r->x, r->y, r->z);
effect->SetBool(effect->GetParameterByName(NULL, "UseSkinning"), false);
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
2018-08-19 09:46:58 +02:00
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);
}
2018-08-19 09:46:58 +02:00
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::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);
2018-08-19 09:46:58 +02:00
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)
2018-08-19 09:46:58 +02:00
effect = m_shaderFillGBuffer->GetEffect();
else
effect = m_shaderTransparent->GetEffect();
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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);
}*/
2018-08-19 09:46:58 +02:00
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*/)
2018-08-19 09:46:58 +02:00
{
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)
2018-08-19 09:46:58 +02:00
effect = m_depthShader->GetEffect();
else if (pass == RENDERER_PASSES::RENDERER_PASS_RECONSTRUCT_DEPTH)
effect = m_shaderReconstructZBuffer->GetEffect();
2018-08-19 09:46:58 +02:00
else
effect = m_shaderFillGBuffer->GetEffect();*/
effect = m_shaderBasic->GetEffect();
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
__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++)
2018-08-19 09:46:58 +02:00
{
RendererBucket* flashBucket = flashMesh->GetBucket(b);
2018-08-19 09:46:58 +02:00
if (flashBucket->NumVertices != 0)
{
m_device->SetStreamSource(0, flashBucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
m_device->SetIndices(flashBucket->GetIndexBuffer());
2018-08-19 09:46:58 +02:00
D3DXMATRIX offset;
D3DXMatrixTranslation(&offset, 0, length, zOffset);
2018-08-19 09:46:58 +02:00
D3DXMATRIX rotation2;
D3DXMatrixRotationX(&rotation2, TR_ANGLE_TO_RAD(rotationX));
2018-08-19 09:46:58 +02:00
if (Lara.leftArm.flash_gun)
2018-08-19 09:46:58 +02:00
{
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[HAND_L], &m_LaraWorldMatrix);
D3DXMatrixMultiply(&world, &offset, &world);
D3DXMatrixMultiply(&world, &rotation2, &world);
2018-08-19 09:46:58 +02:00
for (int iPass = 0; iPass < cPasses; iPass++)
{
effect->BeginPass(iPass);
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
effect->CommitChanges();
2018-08-19 09:46:58 +02:00
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, flashBucket->NumVertices, 0, flashBucket->NumIndices / 3);
2018-08-19 09:46:58 +02:00
effect->EndPass();
}
}
2018-08-19 09:46:58 +02:00
if (Lara.rightArm.flash_gun)
2018-08-19 09:46:58 +02:00
{
D3DXMatrixMultiply(&world, &laraObj->AnimationTransforms[HAND_R], &m_LaraWorldMatrix);
D3DXMatrixMultiply(&world, &offset, &world);
D3DXMatrixMultiply(&world, &rotation2, &world);
2018-08-19 09:46:58 +02:00
for (int iPass = 0; iPass < cPasses; iPass++)
{
effect->BeginPass(iPass);
effect->SetMatrix(effect->GetParameterByName(NULL, "World"), &world);
effect->CommitChanges();
2018-08-19 09:46:58 +02:00
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, flashBucket->NumVertices, 0, flashBucket->NumIndices / 3);
effect->EndPass();
}
2018-08-19 09:46:58 +02:00
}
}
}
}
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);
2018-08-19 09:46:58 +02:00
if (D3DXVec3Length(&(laraPos-lightVector)) >= 1024.0f * 20.0f)
2018-08-19 09:46:58 +02:00
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()
{
2018-08-21 21:07:18 +02:00
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)
2018-08-21 21:07:18 +02:00
{
if (Unk_00E6D74C || Unk_00E6D73C)
{
UpdateStorm();
if (StormTimer > -1)
StormTimer--;
if (!StormTimer)
SoundEffect(SFX_THUNDER_RUMBLE, NULL, 0);
2018-08-21 21:07:18 +02:00
}
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);
2018-08-21 21:07:18 +02:00
}
2018-08-19 09:46:58 +02:00
D3DXMATRIX world;
D3DXMATRIX translation;
D3DXMATRIX rotation;
D3DXMATRIX scale;
UINT cPasses = 1;
2018-08-19 09:46:58 +02:00
LPD3DXEFFECT effect = m_shaderFillGBuffer->GetEffect();
effect->SetTexture(effect->GetParameterByName(NULL, "TextureAtlas"), m_skyTexture);
2018-08-21 21:07:18 +02:00
effect->SetVector(effect->GetParameterByName(NULL, "Color"), &color);
effect->SetInt(effect->GetParameterByName(NULL, "ModelType"), MODEL_TYPES::MODEL_TYPE_SKY);
2018-08-19 09:46:58 +02:00
m_device->SetStreamSource(0, m_skyQuad->VertexBuffer, 0, sizeof(RendererVertex));
m_device->SetIndices(m_skyQuad->IndexBuffer);
2018-08-19 09:46:58 +02:00
// 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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
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++)
2018-08-19 09:46:58 +02:00
{
RendererBucket* bucket = mesh->GetBucket(i);
2018-08-19 09:46:58 +02:00
// Bind buffers
m_device->SetStreamSource(0, bucket->GetVertexBuffer(), 0, sizeof(RendererVertex));
m_device->SetIndices(bucket->GetIndexBuffer());
2018-08-19 09:46:58 +02:00
SetGpuStateForBucket((RENDERER_BUCKETS)i);
for (int iPass = 0; iPass < cPasses; iPass++)
{
effect->BeginPass(iPass);
effect->CommitChanges();
2018-08-19 09:46:58 +02:00
DrawPrimitives(D3DPRIMITIVETYPE::D3DPT_TRIANGLELIST, 0, 0, bucket->NumVertices, 0, bucket->NumIndices / 3);
2018-08-19 09:46:58 +02:00
effect->EndPass();
}
2018-08-19 09:46:58 +02:00
}
effect->SetInt(effect->GetParameterByName(NULL, "BlendMode"), BLEND_MODES::BLENDMODE_OPAQUE);
2018-08-19 09:46:58 +02:00
m_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
2018-08-19 09:46:58 +02:00
return true;
}
2018-08-19 09:46:58 +02:00
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;
2018-08-19 09:46:58 +02:00
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)
2018-08-19 09:46:58 +02:00
{
D3DXVECTOR3 look = *particlePos;
look = look - *cameraPos;
D3DXVec3Normalize(&look, &look);
2018-08-19 09:46:58 +02:00
D3DXVECTOR3 cameraUp = D3DXVECTOR3(0.0f, -1.0f, 0.0f);
2018-08-19 09:46:58 +02:00
D3DXVECTOR3 right;
D3DXVec3Cross(&right, &cameraUp, &look);
D3DXVec3Normalize(&right, &right);
2018-08-19 09:46:58 +02:00
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;
}
2018-08-19 09:46:58 +02:00
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()
{
2018-08-19 09:46:58 +02:00
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);
2018-08-19 09:46:58 +02:00
}
}
}
}
}
2018-08-19 09:46:58 +02:00
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);
}
}
}
2018-08-19 09:46:58 +02:00
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()
{
2018-08-19 09:46:58 +02:00
for (__int32 i = 0; i < 32; i++)
{
BLOOD_STRUCT* blood = &Blood[i];
if (blood->On)
2018-08-19 09:46:58 +02:00
{
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);
2018-08-19 09:46:58 +02:00
}
}
}
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();
}
}
}
}
2018-08-21 18:59:31 +02:00
return true;
}
bool Renderer::DoRain()
{
2018-08-22 08:53:34 +02:00
if (m_firstWeather)
{
2018-08-22 08:53:34 +02:00
for (__int32 i = 0; i < NUM_RAIN_DROPS; i++)
m_rain[i].Reset = true;
}
2018-08-21 18:59:31 +02:00
for (__int32 i = 0; i < NUM_RAIN_DROPS; i++)
{
2018-08-22 08:53:34 +02:00
RendererWeatherParticle* drop = &m_rain[i];
2018-08-21 18:59:31 +02:00
if (drop->Reset)
{
2018-08-22 08:53:34 +02:00
drop->X = LaraItem->pos.xPos + rand() % WEATHER_RADIUS - WEATHER_RADIUS / 2.0f;
drop->Y = LaraItem->pos.yPos - (m_firstWeather ? rand() % WEATHER_HEIGHT : WEATHER_HEIGHT);
2018-08-22 08:53:34 +02:00
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;
}
2018-08-22 08:53:34 +02:00
drop->Size = RAIN_SIZE + (rand() % 64);
drop->AngleH = (rand() % RAIN_MAX_ANGLE_H) * RADIAN;
drop->AngleV = (rand() % RAIN_MAX_ANGLE_V) * RADIAN;
2018-08-21 18:59:31 +02:00
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
2018-08-21 18:59:31 +02:00
__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)
{
2018-08-21 18:59:31 +02:00
drop->Reset = true;
AddWaterSparks(drop->X, room->y + room->minfloor, drop->Z, 1);
}
2018-08-21 18:59:31 +02:00
}
2018-08-21 23:34:54 +02:00
m_firstWeather = false;
return true;
}
bool Renderer::DoSnow()
{
2018-08-22 08:53:34 +02:00
if (m_firstWeather)
{
2018-08-22 08:53:34 +02:00
for (__int32 i = 0; i < NUM_SNOW_PARTICLES; i++)
m_snow[i].Reset = true;
}
2018-08-22 08:53:34 +02:00
for (__int32 i = 0; i < NUM_SNOW_PARTICLES; i++)
2018-08-21 23:34:54 +02:00
{
2018-08-22 08:53:34 +02:00
RendererWeatherParticle* snow = &m_snow[i];
if (snow->Reset)
2018-08-21 23:34:54 +02:00
{
2018-08-22 08:53:34 +02:00
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;
2018-08-22 08:53:34 +02:00
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;
2018-08-21 23:34:54 +02:00
}
2018-08-22 08:53:34 +02:00
float radius = snow->Size * sin(snow->AngleV);
2018-08-21 23:34:54 +02:00
2018-08-22 08:53:34 +02:00
float dx = sin(snow->AngleH) * radius;
float dz = cos(snow->AngleH) * radius;
2018-08-21 23:34:54 +02:00
2018-08-22 08:53:34 +02:00
snow->X += dx;
snow->Y += SNOW_DELTA_Y;
snow->Z += dz;
2018-08-21 23:34:54 +02:00
2018-08-22 08:53:34 +02:00
if (snow->X <= 0 || snow->Z <= 0 || snow->X >= 100 * 1024.0f || snow->Z >= 100 * 1024.0f)
2018-08-21 23:34:54 +02:00
{
2018-08-22 08:53:34 +02:00
snow->Reset = true;
2018-08-21 23:34:54 +02:00
continue;
}
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + 14], snow->X, snow->Y, snow->Z, 255, 255, 255,
2018-08-22 08:53:34 +02:00
0.0f, 1.0f, SNOW_SIZE, SNOW_SIZE);
2018-08-21 23:34:54 +02:00
__int16 roomNumber = Camera.pos.roomNumber;
2018-08-22 08:53:34 +02:00
FLOOR_INFO* floor = GetFloor(snow->X, snow->Y, snow->Z, &roomNumber);
2018-08-21 23:34:54 +02:00
ROOM_INFO* room = &Rooms[roomNumber];
2018-08-22 08:53:34 +02:00
if (snow->Y >= room->y + room->minfloor)
snow->Reset = true;
2018-08-21 23:34:54 +02:00
}
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 (!IsRoomUnderwater(Camera.pos.roomNumber))
return;
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;
2018-08-19 09:46:58 +02:00
}