mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-11 21:16:55 +03:00
Merge branch 'Footstep'
This commit is contained in:
commit
61370fb826
14 changed files with 277 additions and 157 deletions
|
@ -43,11 +43,6 @@ PixelShaderInput VS(VertexShaderInput input)
|
|||
|
||||
float4 PS(PixelShaderInput input) : SV_TARGET
|
||||
{
|
||||
float4 output = Texture.Sample(Sampler, input.UV);
|
||||
if (AlphaTest)
|
||||
clip(output.w - 0.5f);
|
||||
output.xyz = output.xyz * input.Color.xyz;
|
||||
output.w = 1.0f;
|
||||
|
||||
float4 output = Texture.Sample(Sampler, input.UV)*input.Color;
|
||||
return output;
|
||||
}
|
|
@ -28,7 +28,7 @@
|
|||
#include "traps.h"
|
||||
#include "effects.h"
|
||||
#include "sphere.h"
|
||||
|
||||
#include "footprint.h"
|
||||
#include "..\Specific\roomload.h"
|
||||
#include "..\Specific\input.h"
|
||||
#include "..\Specific\init.h"
|
||||
|
@ -41,6 +41,7 @@ int KeyTriggerActive;
|
|||
PENDULUM CurrentPendulum;
|
||||
int number_los_rooms;
|
||||
short los_rooms[20];
|
||||
extern std::deque<FOOTPRINT_STRUCT> footprints;
|
||||
|
||||
// TODO: move to DLL after @ChocolateFan decompilation
|
||||
#define ClosestCoord VAR_U_(0x00EEF460, PHD_VECTOR)
|
||||
|
@ -394,6 +395,7 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode)
|
|||
UpdateBubbles();
|
||||
UpdateDebris();
|
||||
UpdateGunShells();
|
||||
updateFootprints();
|
||||
UpdateSplashes();
|
||||
UpdateDrips();
|
||||
UpdateRats();
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
#include "hair.h"
|
||||
#include "draw.h"
|
||||
#include "sphere.h"
|
||||
|
||||
#include "footprint.h"
|
||||
int wf = 256;
|
||||
extern std::deque<FOOTPRINT_STRUCT> footprints;
|
||||
|
||||
void(*effect_routines[59])(ITEM_INFO* item) =
|
||||
{
|
||||
|
@ -45,7 +46,7 @@ void(*effect_routines[59])(ITEM_INFO* item) =
|
|||
void_effect,
|
||||
LaraLocation,
|
||||
ClearSpidersPatch,
|
||||
void_effect /*AddFootprint*/,
|
||||
AddFootprint, /*AddFootprint*/
|
||||
void_effect /*ResetTest*/,
|
||||
void_effect,
|
||||
void_effect,
|
||||
|
@ -84,6 +85,38 @@ void TL_1(ITEM_INFO* item)
|
|||
}
|
||||
}
|
||||
|
||||
void AddFootprint(ITEM_INFO* item) {
|
||||
if (item != LaraItem) {
|
||||
return;
|
||||
}
|
||||
PHD_3DPOS footprintPosition;
|
||||
if (CheckFootOnFloor(*item, LM_LFOOT, footprintPosition)) {
|
||||
if (footprints.size() >= MAX_FOOTPRINTS) {
|
||||
footprints.pop_back();
|
||||
}
|
||||
FOOTPRINT_STRUCT footprint;
|
||||
footprint.pos = footprintPosition;
|
||||
footprint.lifeStartFading = 30 * 10;
|
||||
footprint.startOpacity = 64;
|
||||
footprint.life = 30 * 20;
|
||||
footprint.active = true;
|
||||
footprints.push_front(footprint);
|
||||
}
|
||||
if (CheckFootOnFloor(*item, LM_RFOOT, footprintPosition)) {
|
||||
if (footprints.size() >= MAX_FOOTPRINTS) {
|
||||
footprints.pop_back();
|
||||
}
|
||||
FOOTPRINT_STRUCT footprint;
|
||||
footprint.pos = footprintPosition;
|
||||
footprint.lifeStartFading = 30*10;
|
||||
footprint.startOpacity = 64;
|
||||
footprint.life = 30 * 20;
|
||||
footprint.active = true;
|
||||
footprints.push_front(footprint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TL_2(ITEM_INFO* item)
|
||||
{
|
||||
if (Savegame.TLCount <= 1u)
|
||||
|
|
|
@ -12,6 +12,7 @@ int ItemNearLara(PHD_3DPOS* pos, int radius);
|
|||
void StopSoundEffect(short sampleIndex);
|
||||
short DoBloodSplat(int x, int y, int z, short a4, short a5, short roomNumber);
|
||||
//void SoundEffects();
|
||||
void AddFootprint(ITEM_INFO* item);
|
||||
void ControlWaterfallMist(short itemNumber);
|
||||
void void_effect(ITEM_INFO* item);
|
||||
void finish_level_effect(ITEM_INFO* item);
|
||||
|
|
53
TR5Main/Game/footprint.cpp
Normal file
53
TR5Main/Game/footprint.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include "footprint.h"
|
||||
#include "control.h"
|
||||
#include "lara.h"
|
||||
#include "groundfx.h"
|
||||
|
||||
std::deque<FOOTPRINT_STRUCT> footprints = deque<FOOTPRINT_STRUCT>();
|
||||
bool CheckFootOnFloor(ITEM_INFO& const item, int mesh, PHD_3DPOS& outFootprintPosition){
|
||||
int x = item.pos.xPos;
|
||||
int y = item.pos.yPos;
|
||||
int z = item.pos.zPos;
|
||||
short roomNumber = item.roomNumber;
|
||||
FLOOR_INFO* floor = GetFloor(x, y, z, &roomNumber);
|
||||
if (!(floor->fx == GroundMaterial::Ice || floor->fx == GroundMaterial::Sand || floor->fx == GroundMaterial::Mud)) {
|
||||
return false;
|
||||
}
|
||||
int height = GetFloorHeight(floor, x, y, z);
|
||||
int diff;
|
||||
PHD_VECTOR pos;
|
||||
pos.x = pos.z = 0;
|
||||
pos.y = FOOT_HEIGHT_OFFSET;
|
||||
GetLaraJointPosition(&pos, mesh);
|
||||
outFootprintPosition.xPos = pos.x;
|
||||
outFootprintPosition.zPos = pos.z;
|
||||
outFootprintPosition.yPos = height-1;
|
||||
outFootprintPosition.yRot = item.pos.yRot;
|
||||
return abs(pos.y - height) < 32;
|
||||
}
|
||||
|
||||
void updateFootprints()
|
||||
{
|
||||
if (footprints.size() == 0) {
|
||||
return;
|
||||
}
|
||||
int numInvalidFootprints = 0;
|
||||
for (auto i = footprints.begin(); i != footprints.end(); i++) {
|
||||
FOOTPRINT_STRUCT& footprint = *i;
|
||||
footprint.life--;
|
||||
if (footprint.life <= 0) {
|
||||
numInvalidFootprints++;
|
||||
continue;
|
||||
}
|
||||
if (footprint.life > footprint.lifeStartFading) {
|
||||
footprint.opacity = footprint.startOpacity;
|
||||
}
|
||||
else {
|
||||
float opacity = lerp(0, footprint.startOpacity, fmax(0, fmin(1, footprint.life / (float)footprint.lifeStartFading)));
|
||||
footprint.opacity = opacity;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < numInvalidFootprints; i++) {
|
||||
footprints.pop_back();
|
||||
}
|
||||
}
|
18
TR5Main/Game/footprint.h
Normal file
18
TR5Main/Game/footprint.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include "../Global/types.h"
|
||||
#include "math.h"
|
||||
#include <queue>
|
||||
#pragma once
|
||||
|
||||
constexpr size_t MAX_FOOTPRINTS = 20;
|
||||
typedef struct footprint_t {
|
||||
PHD_3DPOS pos;
|
||||
int life;
|
||||
int lifeStartFading;
|
||||
byte startOpacity;
|
||||
byte opacity;
|
||||
bool active;
|
||||
}FOOTPRINT_STRUCT;
|
||||
|
||||
constexpr int FOOT_HEIGHT_OFFSET = 64;
|
||||
bool CheckFootOnFloor(ITEM_INFO& const item, int mesh, PHD_3DPOS& outFootprintPosition);
|
||||
void updateFootprints();
|
19
TR5Main/Game/groundfx.h
Normal file
19
TR5Main/Game/groundfx.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
enum GroundMaterial : unsigned char {
|
||||
Mud = 0,
|
||||
Snow = 1,
|
||||
Sand = 2,
|
||||
Gravel = 3,
|
||||
Ice = 4,
|
||||
Water = 5,
|
||||
Stone = 6,
|
||||
Wood = 7,
|
||||
Metal = 8,
|
||||
Marble = 9,
|
||||
Grass = 10,
|
||||
Concrete = 11,
|
||||
OldWood = 12,
|
||||
OldMetal = 13,
|
||||
Unknown14 = 14,
|
||||
Unknown15 = 15
|
||||
};
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
extern LaraExtraInfo g_LaraExtra;
|
||||
extern GameFlow* g_GameFlow;
|
||||
|
||||
extern void(*effect_routines[59])(ITEM_INFO* item);
|
||||
COLL_INFO coll;
|
||||
short SubsuitAir = 0;
|
||||
short FXType;
|
||||
|
@ -880,7 +880,7 @@ void AnimateLara(ITEM_INFO* item)
|
|||
}
|
||||
|
||||
FXType = cmd[1] & 0xC000;
|
||||
(*EffectRoutines[(int)(cmd[1] & 0x3fff)])(item);
|
||||
(*effect_routines[(int)(cmd[1] & 0x3fff)])(item);
|
||||
|
||||
cmd += 2;
|
||||
break;
|
||||
|
|
|
@ -40,7 +40,8 @@ typedef enum LIGHT_TYPES {
|
|||
typedef enum BLEND_MODES {
|
||||
BLENDMODE_OPAQUE = 0,
|
||||
BLENDMODE_ALPHATEST = 1,
|
||||
BLENDMODE_ALPHABLEND = 2
|
||||
BLENDMODE_ALPHABLEND = 2,
|
||||
BLENDMODE_SUBTRACTIVE = 3
|
||||
};
|
||||
|
||||
typedef enum RENDERER_CULLMODE {
|
||||
|
|
|
@ -18,14 +18,16 @@
|
|||
#include "..\Game\Camera.h"
|
||||
#include "..\Game\healt.h"
|
||||
#include "../Game/tomb4fx.h"
|
||||
|
||||
#include "math.h"
|
||||
#include <D3Dcompiler.h>
|
||||
#include <chrono>
|
||||
#include <stack>
|
||||
#include "../Game/misc.h"
|
||||
#include "../Game/footprint.h"
|
||||
|
||||
using ns = chrono::nanoseconds;
|
||||
using get_time = chrono::steady_clock;
|
||||
extern std::deque<FOOTPRINT_STRUCT> footprints;
|
||||
|
||||
int SortLightsFunction(RendererLight* a, RendererLight* b)
|
||||
{
|
||||
|
@ -630,6 +632,18 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h
|
|||
|
||||
m_textureAtlas = NULL;
|
||||
m_skyTexture = NULL;
|
||||
D3D11_BLEND_DESC blendStateDesc{};
|
||||
blendStateDesc.AlphaToCoverageEnable = FALSE;
|
||||
blendStateDesc.IndependentBlendEnable = FALSE;
|
||||
blendStateDesc.RenderTarget[0].BlendEnable = TRUE;
|
||||
blendStateDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||
blendStateDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
blendStateDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_REV_SUBTRACT;
|
||||
blendStateDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
||||
blendStateDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
|
||||
blendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
blendStateDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
m_device->CreateBlendState(&blendStateDesc,&m_subtractiveBlendState);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1598,6 +1612,7 @@ bool Renderer11::drawScene(bool dump)
|
|||
// Do special effects and weather
|
||||
drawFires();
|
||||
drawSmokes();
|
||||
drawFootprints();
|
||||
drawBlood();
|
||||
drawSparks();
|
||||
drawBubbles();
|
||||
|
@ -1607,6 +1622,8 @@ bool Renderer11::drawScene(bool dump)
|
|||
drawSplahes();
|
||||
drawShockwaves();
|
||||
|
||||
|
||||
|
||||
switch (level->Weather)
|
||||
{
|
||||
case WEATHER_NORMAL:
|
||||
|
@ -4749,8 +4766,8 @@ void Renderer11::drawBlood()
|
|||
if (blood->on)
|
||||
{
|
||||
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + 15],
|
||||
blood->x, blood->y, blood->z,
|
||||
blood->shade * 244, blood->shade * 0, blood->shade * 0,
|
||||
Vector3(blood->x, blood->y, blood->z),
|
||||
Vector4(blood->shade * 244/255.0f, blood->shade * 0, blood->shade * 0,1.0f),
|
||||
TR_ANGLE_TO_RAD(blood->rotAng), 1.0f, blood->size * 8.0f, blood->size * 8.0f,
|
||||
BLENDMODE_ALPHABLEND);
|
||||
}
|
||||
|
@ -4769,8 +4786,8 @@ void Renderer11::drawSparks()
|
|||
FX_INFO* fx = &Effects[spark->fxObj];
|
||||
|
||||
AddSpriteBillboard(m_sprites[spark->def],
|
||||
fx->pos.xPos + spark->x,fx->pos.yPos + spark->y, fx->pos.zPos + spark->z,
|
||||
spark->r, spark->g, spark->b,
|
||||
Vector3(fx->pos.xPos + spark->x,fx->pos.yPos + spark->y, fx->pos.zPos + spark->z),
|
||||
Vector4(spark->r/255.0f, spark->g / 255.0f, spark->b / 255.0f,1.0f),
|
||||
TR_ANGLE_TO_RAD(spark->rotAng), spark->scalar, spark->size * 12.0f, spark->size * 12.0f,
|
||||
BLENDMODE_ALPHABLEND);
|
||||
}
|
||||
|
@ -4778,7 +4795,7 @@ void Renderer11::drawSparks()
|
|||
{
|
||||
Vector3 v = Vector3(spark->xVel, spark->yVel, spark->zVel);
|
||||
v.Normalize();
|
||||
AddLine3D(spark->x, spark->y, spark->z, spark->x + v.x * 24.0f, spark->y + v.y * 24.0f, spark->z + v.z * 24.0f, spark->r, spark->g, spark->b);
|
||||
AddLine3D(Vector3(spark->x, spark->y, spark->z),Vector3( spark->x + v.x * 24.0f, spark->y + v.y * 24.0f, spark->z + v.z * 24.0f), Vector4(spark->r / 255.0f, spark->g / 255.0f, spark->b / 255.0f,1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4795,13 +4812,13 @@ void Renderer11::drawFires()
|
|||
{
|
||||
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, BLENDMODE_ALPHABLEND);
|
||||
AddSpriteBillboard(m_sprites[spark->def], Vector3(fire->x + spark->x, fire->y + spark->y, fire->z + spark->z), Vector4(spark->r / 255.0f, spark->g / 255.0f, spark->b / 255.0f,1.0f), TR_ANGLE_TO_RAD(spark->rotAng), spark->scalar, spark->size * 4.0f, spark->size * 4.0f, BLENDMODE_ALPHABLEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer11::AddSpriteBillboard(RendererSprite* sprite, float x, float y, float z, byte r, byte g, byte b, float rotation, float scale, float width, float height, BLEND_MODES blendMode)
|
||||
void Renderer11::AddSpriteBillboard(RendererSprite* sprite,Vector3 pos, Vector4 color, float rotation, float scale, float width, float height, BLEND_MODES blendMode)
|
||||
{
|
||||
if (m_nextSprite >= MAX_SPRITES)
|
||||
return;
|
||||
|
@ -4815,12 +4832,8 @@ void Renderer11::AddSpriteBillboard(RendererSprite* sprite, float x, float y, fl
|
|||
|
||||
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->pos = pos;
|
||||
spr->color = color;
|
||||
spr->Rotation = rotation;
|
||||
spr->Scale = scale;
|
||||
spr->Width = width;
|
||||
|
@ -4839,35 +4852,29 @@ void Renderer11::drawSmokes()
|
|||
if (spark->on)
|
||||
{
|
||||
AddSpriteBillboard(m_sprites[spark->def],
|
||||
spark->x, spark->y, spark->z,
|
||||
spark->shade, spark->shade, spark->shade,
|
||||
Vector3(spark->x, spark->y, spark->z),
|
||||
Vector4(spark->shade / 255.0f, spark->shade / 255.0f, spark->shade / 255.0f,1.0f),
|
||||
TR_ANGLE_TO_RAD(spark->rotAng), spark->scalar, spark->size * 4.0f, spark->size * 4.0f,
|
||||
BLENDMODE_ALPHABLEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer11::AddLine3D(int x1, int y1, int z1, int x2, int y2, int z2, byte r, byte g, byte b)
|
||||
void Renderer11::AddLine3D(Vector3 start, Vector3 end, Vector4 color)
|
||||
{
|
||||
if (m_nextLine3D >= MAX_LINES_3D)
|
||||
return;
|
||||
|
||||
RendererLine3D* line = &m_lines3DBuffer[m_nextLine3D++];
|
||||
|
||||
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;
|
||||
line->start = start;
|
||||
line->end = end;
|
||||
line->color = color;
|
||||
|
||||
m_lines3DToDraw.Add(line);
|
||||
}
|
||||
|
||||
void Renderer11::AddSprite3D(RendererSprite* sprite, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, byte r, byte g, byte b, float rotation, float scale, float width, float height, BLEND_MODES blendMode)
|
||||
void Renderer11::AddSprite3D(RendererSprite* sprite, Vector3 vtx1,Vector3 vtx2, Vector3 vtx3, Vector3 vtx4, Vector4 color, float rotation, float scale, float width, float height, BLEND_MODES blendMode)
|
||||
{
|
||||
if (m_nextSprite >= MAX_SPRITES)
|
||||
return;
|
||||
|
@ -4881,21 +4888,11 @@ void Renderer11::AddSprite3D(RendererSprite* sprite, float x1, float y1, float z
|
|||
|
||||
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->vtx1 = vtx1;
|
||||
spr->vtx2 = vtx2;
|
||||
spr->vtx3 = vtx3;
|
||||
spr->vtx4 = vtx4;
|
||||
spr->color = color;
|
||||
spr->Rotation = rotation;
|
||||
spr->Scale = scale;
|
||||
spr->Width = width;
|
||||
|
@ -4936,11 +4933,11 @@ void Renderer11::drawShockwaves()
|
|||
angle -= PI / 8.0f;
|
||||
|
||||
AddSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_SPLASH],
|
||||
x1, shockwave->y, z1,
|
||||
x2, shockwave->y, z2,
|
||||
x3, shockwave->y, z3,
|
||||
x4, shockwave->y, z4,
|
||||
color, color, color, 0, 1, 0, 0, BLENDMODE_ALPHABLEND);
|
||||
Vector3(x1, shockwave->y, z1),
|
||||
Vector3(x2, shockwave->y, z2),
|
||||
Vector3(x3, shockwave->y, z3),
|
||||
Vector3(x4, shockwave->y, z4),
|
||||
Vector4(color / 255.0f, color / 255.0f, color/255.0f,1.0f), 0, 1, 0, 0, BLENDMODE_ALPHABLEND);
|
||||
|
||||
x1 = x2;
|
||||
z1 = z2;
|
||||
|
@ -4967,7 +4964,7 @@ void Renderer11::drawRipples()
|
|||
|
||||
byte color = (ripple->init ? ripple->init << 1 : ripple->life << 1);
|
||||
|
||||
AddSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_RIPPLES], x1, y, z2, x2, y, z2, x2, y, z1, x1, y, z1, color, color, color, 0.0f, 1.0f, ripple->size, ripple->size, BLENDMODE_ALPHABLEND);
|
||||
AddSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_RIPPLES], Vector3(x1, y, z2),Vector3(x2, y, z2),Vector3( x2, y, z1),Vector3( x1, y, z1),Vector4( color / 255.0f, color / 255.0f, color/255.0f,1.0f), 0.0f, 1.0f, ripple->size, ripple->size, BLENDMODE_ALPHABLEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4980,7 +4977,7 @@ void Renderer11::drawDrips()
|
|||
|
||||
if (drip->on)
|
||||
{
|
||||
AddLine3D(drip->x, drip->y, drip->z, drip->x, drip->y + 24.0f, drip->z, drip->r, drip->g, drip->b);
|
||||
AddLine3D(Vector3(drip->x, drip->y, drip->z),Vector3( drip->x, drip->y + 24.0f, drip->z), Vector4(drip->r/255.0f, drip->g/255.0f, drip->b/255.0f,1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4991,7 +4988,7 @@ void Renderer11::drawBubbles()
|
|||
{
|
||||
BUBBLE_STRUCT* bubble = &Bubbles[i];
|
||||
if (bubble->size)
|
||||
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_BUBBLES], bubble->pos.x, bubble->pos.y, bubble->pos.z, bubble->shade * 255, bubble->shade * 255, bubble->shade * 255, 0.0f, 1.0f, bubble->size * 0.5f, bubble->size * 0.5f, BLENDMODE_ALPHABLEND);
|
||||
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_BUBBLES], Vector3(bubble->pos.x, bubble->pos.y, bubble->pos.z),Vector4( bubble->shade, bubble->shade, bubble->shade,1.0f), 0.0f, 1.0f, bubble->size * 0.5f, bubble->size * 0.5f, BLENDMODE_ALPHABLEND);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5041,7 +5038,7 @@ void Renderer11::drawSplahes()
|
|||
x2Outer += splash.x;
|
||||
z2Outer = outerRadius * cos(alpha * j * PI / 180);
|
||||
z2Outer += splash.z;
|
||||
AddSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + splash.spriteSequenceStart + (int)splash.animationPhase], xOuter, yOuter, zOuter, x2Outer, yOuter, z2Outer, x2Inner, yInner, z2Inner, xInner, yInner, zInner, color, color, color, 0, 1, 0, 0, BLENDMODE_ALPHABLEND);
|
||||
AddSprite3D(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + splash.spriteSequenceStart + (int)splash.animationPhase],Vector3( xOuter, yOuter, zOuter), Vector3(x2Outer, yOuter, z2Outer),Vector3( x2Inner, yInner, z2Inner), Vector3(xInner, yInner, zInner),Vector4( color / 255.0f, color / 255.0f, color / 255.0f,1.0f), 0, 1, 0, 0, BLENDMODE_ALPHABLEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5071,7 +5068,7 @@ bool Renderer11::drawSprites()
|
|||
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
m_context->IASetInputLayout(m_inputLayout);
|
||||
|
||||
for (int b = 0; b < 3; b++)
|
||||
for (int b = 0; b < 4; b++)
|
||||
{
|
||||
BLEND_MODES currentBlendMode = (BLEND_MODES)b;
|
||||
|
||||
|
@ -5086,14 +5083,22 @@ bool Renderer11::drawSprites()
|
|||
|
||||
if (spr->BlendMode != currentBlendMode)
|
||||
continue;
|
||||
|
||||
if (currentBlendMode == BLENDMODE_OPAQUE)
|
||||
{
|
||||
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (currentBlendMode) {
|
||||
case BLENDMODE_ALPHABLEND:
|
||||
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
|
||||
|
||||
break;
|
||||
case BLENDMODE_ALPHATEST:
|
||||
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
|
||||
|
||||
break;
|
||||
case BLENDMODE_OPAQUE:
|
||||
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
|
||||
break;
|
||||
case BLENDMODE_SUBTRACTIVE:
|
||||
m_context->OMSetBlendState(m_subtractiveBlendState, NULL, 0xFFFFFFFF);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (spr->Type == RENDERER_SPRITE_TYPE::SPRITE_TYPE_BILLBOARD)
|
||||
|
@ -5102,7 +5107,7 @@ bool Renderer11::drawSprites()
|
|||
float halfHeight = spr->Height / 2.0f;
|
||||
|
||||
Matrix billboardMatrix;
|
||||
createBillboardMatrix(&billboardMatrix, &Vector3(spr->X, spr->Y, spr->Z), &Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z), spr->Rotation);
|
||||
createBillboardMatrix(&billboardMatrix, &spr->pos, &Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z), spr->Rotation);
|
||||
|
||||
Vector3 p0 = Vector3(-halfWidth, -halfHeight, 0);
|
||||
Vector3 p1 = Vector3(halfWidth, -halfHeight, 0);
|
||||
|
@ -5120,10 +5125,7 @@ bool Renderer11::drawSprites()
|
|||
v0.Position.z = p0t.z;
|
||||
v0.UV.x = spr->Sprite->UV[0].x;
|
||||
v0.UV.y = spr->Sprite->UV[0].y;
|
||||
v0.Color.x = spr->R / 255.0f;
|
||||
v0.Color.y = spr->G / 255.0f;
|
||||
v0.Color.z = spr->B / 255.0f;
|
||||
v0.Color.w = 1.0f;
|
||||
v0.Color = spr->color;
|
||||
|
||||
RendererVertex v1;
|
||||
v1.Position.x = p1t.x;
|
||||
|
@ -5131,10 +5133,7 @@ bool Renderer11::drawSprites()
|
|||
v1.Position.z = p1t.z;
|
||||
v1.UV.x = spr->Sprite->UV[1].x;
|
||||
v1.UV.y = spr->Sprite->UV[1].y;
|
||||
v1.Color.x = spr->R / 255.0f;
|
||||
v1.Color.y = spr->G / 255.0f;
|
||||
v1.Color.z = spr->B / 255.0f;
|
||||
v1.Color.w = 1.0f;
|
||||
v1.Color = spr->color;
|
||||
|
||||
RendererVertex v2;
|
||||
v2.Position.x = p2t.x;
|
||||
|
@ -5142,10 +5141,7 @@ bool Renderer11::drawSprites()
|
|||
v2.Position.z = p2t.z;
|
||||
v2.UV.x = spr->Sprite->UV[2].x;
|
||||
v2.UV.y = spr->Sprite->UV[2].y;
|
||||
v2.Color.x = spr->R / 255.0f;
|
||||
v2.Color.y = spr->G / 255.0f;
|
||||
v2.Color.z = spr->B / 255.0f;
|
||||
v2.Color.w = 1.0f;
|
||||
v2.Color = spr->color;
|
||||
|
||||
RendererVertex v3;
|
||||
v3.Position.x = p3t.x;
|
||||
|
@ -5153,19 +5149,16 @@ bool Renderer11::drawSprites()
|
|||
v3.Position.z = p3t.z;
|
||||
v3.UV.x = spr->Sprite->UV[3].x;
|
||||
v3.UV.y = spr->Sprite->UV[3].y;
|
||||
v3.Color.x = spr->R / 255.0f;
|
||||
v3.Color.y = spr->G / 255.0f;
|
||||
v3.Color.z = spr->B / 255.0f;
|
||||
v3.Color.w = 1.0f;
|
||||
v3.Color = spr->color;
|
||||
|
||||
m_primitiveBatch->DrawQuad(v0, v1, v2, v3);
|
||||
}
|
||||
else if (spr->Type == RENDERER_SPRITE_TYPE::SPRITE_TYPE_3D)
|
||||
{
|
||||
Vector3 p0t = Vector3(spr->X1, spr->Y1, spr->Z1);
|
||||
Vector3 p1t = Vector3(spr->X2, spr->Y2, spr->Z2);
|
||||
Vector3 p2t = Vector3(spr->X3, spr->Y3, spr->Z3);
|
||||
Vector3 p3t = Vector3(spr->X4, spr->Y4, spr->Z4);
|
||||
Vector3 p0t = spr->vtx1;
|
||||
Vector3 p1t = spr->vtx2;
|
||||
Vector3 p2t = spr->vtx3;
|
||||
Vector3 p3t = spr->vtx4;
|
||||
|
||||
RendererVertex v0;
|
||||
v0.Position.x = p0t.x;
|
||||
|
@ -5173,10 +5166,7 @@ bool Renderer11::drawSprites()
|
|||
v0.Position.z = p0t.z;
|
||||
v0.UV.x = spr->Sprite->UV[0].x;
|
||||
v0.UV.y = spr->Sprite->UV[0].y;
|
||||
v0.Color.x = spr->R / 255.0f;
|
||||
v0.Color.y = spr->G / 255.0f;
|
||||
v0.Color.z = spr->B / 255.0f;
|
||||
v0.Color.w = 1.0f;
|
||||
v0.Color = spr->color;
|
||||
|
||||
RendererVertex v1;
|
||||
v1.Position.x = p1t.x;
|
||||
|
@ -5184,10 +5174,7 @@ bool Renderer11::drawSprites()
|
|||
v1.Position.z = p1t.z;
|
||||
v1.UV.x = spr->Sprite->UV[1].x;
|
||||
v1.UV.y = spr->Sprite->UV[1].y;
|
||||
v1.Color.x = spr->R / 255.0f;
|
||||
v1.Color.y = spr->G / 255.0f;
|
||||
v1.Color.z = spr->B / 255.0f;
|
||||
v1.Color.w = 1.0f;
|
||||
v1.Color = spr->color;
|
||||
|
||||
RendererVertex v2;
|
||||
v2.Position.x = p2t.x;
|
||||
|
@ -5195,10 +5182,7 @@ bool Renderer11::drawSprites()
|
|||
v2.Position.z = p2t.z;
|
||||
v2.UV.x = spr->Sprite->UV[2].x;
|
||||
v2.UV.y = spr->Sprite->UV[2].y;
|
||||
v2.Color.x = spr->R / 255.0f;
|
||||
v2.Color.y = spr->G / 255.0f;
|
||||
v2.Color.z = spr->B / 255.0f;
|
||||
v2.Color.w = 1.0f;
|
||||
v2.Color = spr->color;
|
||||
|
||||
RendererVertex v3;
|
||||
v3.Position.x = p3t.x;
|
||||
|
@ -5206,10 +5190,7 @@ bool Renderer11::drawSprites()
|
|||
v3.Position.z = p3t.z;
|
||||
v3.UV.x = spr->Sprite->UV[3].x;
|
||||
v3.UV.y = spr->Sprite->UV[3].y;
|
||||
v3.Color.x = spr->R / 255.0f;
|
||||
v3.Color.y = spr->G / 255.0f;
|
||||
v3.Color.z = spr->B / 255.0f;
|
||||
v3.Color.w = 1.0f;
|
||||
v3.Color = spr->color;
|
||||
|
||||
m_primitiveBatch->DrawQuad(v0, v1, v2, v3);
|
||||
}
|
||||
|
@ -5361,23 +5342,12 @@ bool Renderer11::drawLines3D()
|
|||
RendererLine3D* line = m_lines3DToDraw[i];
|
||||
|
||||
RendererVertex v1;
|
||||
v1.Position.x = line->X1;
|
||||
v1.Position.y = line->Y1;
|
||||
v1.Position.z = line->Z1;
|
||||
v1.Color.x = line->R / 255.0f;
|
||||
v1.Color.y = line->G / 255.0f;
|
||||
v1.Color.z = line->B / 255.0f;
|
||||
v1.Color.w = 1.0f;
|
||||
v1.Position = line->start;
|
||||
v1.Color = line->color;
|
||||
|
||||
RendererVertex v2;
|
||||
v2.Position.x = line->X2;
|
||||
v2.Position.y = line->Y2;
|
||||
v2.Position.z = line->Z2;
|
||||
v2.Color.x = line->R / 255.0f;
|
||||
v2.Color.y = line->G / 255.0f;
|
||||
v2.Color.z = line->B / 255.0f;
|
||||
v2.Color.w = 1.0f;
|
||||
|
||||
v2.Position = line->end;
|
||||
v2.Color = line->color;
|
||||
m_primitiveBatch->DrawLine(v1, v2);
|
||||
}
|
||||
|
||||
|
@ -5444,7 +5414,7 @@ bool Renderer11::doRain()
|
|||
drop->Z += dz;
|
||||
|
||||
if (drop->Draw)
|
||||
AddLine3D(x1, y1, z1, drop->X, drop->Y, drop->Z, (byte)(RAIN_COLOR * 255.0f), (byte)(RAIN_COLOR * 255.0f), (byte)(RAIN_COLOR * 255.0f));
|
||||
AddLine3D(Vector3(x1, y1, z1),Vector3( drop->X, drop->Y, drop->Z), Vector4(RAIN_COLOR, RAIN_COLOR, RAIN_COLOR,1.0f));
|
||||
|
||||
// If rain drop has hit the ground, then reset it and add a little drip
|
||||
short roomNumber = Camera.pos.roomNumber;
|
||||
|
@ -5508,7 +5478,7 @@ bool Renderer11::doSnow()
|
|||
continue;
|
||||
}
|
||||
|
||||
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], snow->X, snow->Y, snow->Z, 255, 255, 255,
|
||||
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], Vector3(snow->X, snow->Y, snow->Z), Vector4(1, 1, 1,1),
|
||||
0.0f, 1.0f, SNOW_SIZE, SNOW_SIZE,
|
||||
BLENDMODE_ALPHABLEND);
|
||||
|
||||
|
@ -6696,11 +6666,11 @@ bool Renderer11::drawRopes()
|
|||
Vector3 p4 = m_viewportToolkit->Unproject(Vector3(x4, y4, depth), Projection, View, world);
|
||||
|
||||
AddSprite3D(m_sprites[20],
|
||||
p1.x, p1.y, p1.z,
|
||||
p2.x, p2.y, p2.z,
|
||||
p3.x, p3.y, p3.z,
|
||||
p4.x, p4.y, p4.z,
|
||||
128, 128, 128, 0, 1, 0, 0, BLENDMODE_OPAQUE);
|
||||
Vector3(p1.x, p1.y, p1.z),
|
||||
Vector3(p2.x, p2.y, p2.z),
|
||||
Vector3(p3.x, p3.y, p3.z),
|
||||
Vector3(p4.x, p4.y, p4.z),
|
||||
Vector4(0.5f, 0.5f, 0.5f,1.0f), 0, 1, 0, 0, BLENDMODE_OPAQUE);
|
||||
|
||||
x1 = x4;
|
||||
y1 = y4;
|
||||
|
@ -6821,6 +6791,32 @@ bool Renderer11::DrawBar(int x, int y, int w, int h, int percent, int color1, in
|
|||
return true;
|
||||
}
|
||||
|
||||
void Renderer11::drawFootprints()
|
||||
{
|
||||
for (auto i = footprints.begin(); i != footprints.end();i++) {
|
||||
FOOTPRINT_STRUCT& footprint = *i;
|
||||
if (footprint.active) {
|
||||
float y = footprint.pos.yPos;
|
||||
Matrix rot = Matrix::CreateRotationY(TR_ANGLE_TO_RAD(footprint.pos.yRot) + PI);
|
||||
Vector3 p1 = Vector3(-64, 0, -64);
|
||||
Vector3 p2 = Vector3(64, 0, -64);
|
||||
Vector3 p3 = Vector3(64, 0, 64);
|
||||
Vector3 p4 = Vector3(-64, 0, 64);
|
||||
p1 = XMVector3Transform(p1, rot);
|
||||
p2 = XMVector3Transform(p2, rot);
|
||||
p3 = XMVector3Transform(p3, rot);
|
||||
p4 = XMVector3Transform(p4, rot);
|
||||
p1 += Vector3(footprint.pos.xPos, footprint.pos.yPos, footprint.pos.zPos);
|
||||
p2 += Vector3(footprint.pos.xPos, footprint.pos.yPos, footprint.pos.zPos);
|
||||
p3 += Vector3(footprint.pos.xPos, footprint.pos.yPos, footprint.pos.zPos);
|
||||
p4 += Vector3(footprint.pos.xPos, footprint.pos.yPos, footprint.pos.zPos);
|
||||
if(m_sprites[Objects[ID_MISC_SPRITES].meshIndex + 1] != nullptr )
|
||||
AddSprite3D(m_sprites[Objects[ID_MISC_SPRITES].meshIndex+1], p1,p2,p3,p4, Vector4(footprint.opacity / 255.0f, footprint.opacity / 255.0f, footprint.opacity / 255.0f, footprint.opacity / 255.0f),
|
||||
0, 1, 1, 1, BLENDMODE_SUBTRACTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer11::AddLine2D(int x1, int y1, int x2, int y2, byte r, byte g, byte b, byte a)
|
||||
{
|
||||
RendererLine2D* line = &m_lines2DBuffer[m_nextLine2D++];
|
||||
|
@ -7034,7 +7030,7 @@ void Renderer11::drawUnderwaterDust()
|
|||
dust->Life++;
|
||||
byte color = (dust->Life > 16 ? 32 - dust->Life : dust->Life) * 4;
|
||||
|
||||
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], dust->X, dust->Y, dust->Z, color, color, color, 0.0f, 1.0f, 12, 12, BLENDMODE_ALPHABLEND);
|
||||
AddSpriteBillboard(m_sprites[Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST], Vector3(dust->X, dust->Y, dust->Z),Vector4( color/255.0f, color/255.0f, color/255.0f,1.0f), 0.0f, 1.0f, 12, 12, BLENDMODE_ALPHABLEND);
|
||||
|
||||
if (dust->Life >= 32)
|
||||
dust->Reset = true;
|
||||
|
|
|
@ -724,14 +724,12 @@ struct RendererSpriteToDraw {
|
|||
RendererSprite* Sprite;
|
||||
float Distance;
|
||||
float Scale;
|
||||
float X, Y, Z;
|
||||
float X1, Y1, Z1;
|
||||
float X2, Y2, Z2;
|
||||
float X3, Y3, Z3;
|
||||
float X4, Y4, Z4;
|
||||
byte R;
|
||||
byte G;
|
||||
byte B;
|
||||
Vector3 pos;
|
||||
Vector3 vtx1;
|
||||
Vector3 vtx2;
|
||||
Vector3 vtx3;
|
||||
Vector3 vtx4;
|
||||
Vector4 color;
|
||||
float Rotation;
|
||||
float Width;
|
||||
float Height;
|
||||
|
@ -739,15 +737,9 @@ struct RendererSpriteToDraw {
|
|||
};
|
||||
|
||||
struct RendererLine3D {
|
||||
float X1;
|
||||
float Y1;
|
||||
float Z1;
|
||||
float X2;
|
||||
float Y2;
|
||||
float Z2;
|
||||
byte R;
|
||||
byte G;
|
||||
byte B;
|
||||
Vector3 start;
|
||||
Vector3 end;
|
||||
Vector4 color;
|
||||
};
|
||||
|
||||
struct RendererWeatherParticle {
|
||||
|
@ -781,6 +773,7 @@ private:
|
|||
IDXGISwapChain* m_swapChain = NULL;
|
||||
IDXGIDevice* m_dxgiDevice = NULL;
|
||||
CommonStates* m_states = NULL;
|
||||
ID3D11BlendState* m_subtractiveBlendState = nullptr;
|
||||
ID3D11InputLayout* m_inputLayout = NULL;
|
||||
D3D11_VIEWPORT m_viewport;
|
||||
D3D11_VIEWPORT m_shadowMapViewport;
|
||||
|
@ -1059,9 +1052,11 @@ public:
|
|||
vector<RendererVideoAdapter>* GetAdapters();
|
||||
bool DoTitleImage();
|
||||
void AddLine2D(int x1, int y1, int x2, int y2, byte r, byte g, byte b, byte a);
|
||||
void AddSpriteBillboard(RendererSprite* sprite, float x, float y, float z, byte r, byte g, byte b, float rotation, float scale, float width, float height, BLEND_MODES blendMode);
|
||||
void AddSprite3D(RendererSprite* sprite, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, byte r, byte g, byte b, float rotation, float scale, float width, float height, BLEND_MODES blendMode);
|
||||
void AddLine3D(int x1, int y1, int z1, int x2, int y2, int z2, byte r, byte g, byte b);
|
||||
void AddSpriteBillboard(RendererSprite* sprite, Vector3 pos,Vector4 color, float rotation, float scale, float width, float height, BLEND_MODES blendMode);
|
||||
void AddSprite3D(RendererSprite* sprite, Vector3 vtx1, Vector3 vtx2, Vector3 vtx3, Vector3 vtx4, Vector4 color, float rotation, float scale, float width, float height, BLEND_MODES blendMode);
|
||||
void AddLine3D(Vector3 start, Vector3 end, Vector4 color);
|
||||
bool ChangeScreenResolution(int width, int height, int frequency, bool windowed);
|
||||
bool DrawBar(int x, int y, int w, int h, int percent, int color1, int color2);
|
||||
private:
|
||||
void drawFootprints();
|
||||
};
|
|
@ -43,11 +43,6 @@ PixelShaderInput VS(VertexShaderInput input)
|
|||
|
||||
float4 PS(PixelShaderInput input) : SV_TARGET
|
||||
{
|
||||
float4 output = Texture.Sample(Sampler, input.UV);
|
||||
if (AlphaTest)
|
||||
clip(output.w - 0.5f);
|
||||
output.xyz = output.xyz * input.Color.xyz;
|
||||
output.w = 1.0f;
|
||||
|
||||
float4 output = Texture.Sample(Sampler, input.UV)*input.Color;
|
||||
return output;
|
||||
}
|
|
@ -116,6 +116,8 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts"</Command>
|
|||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Game\footprint.h" />
|
||||
<ClInclude Include="Game\groundfx.h" />
|
||||
<ClInclude Include="Game\swat.h" />
|
||||
<ClInclude Include="Game\lion.h" />
|
||||
<ClInclude Include="Libs\fixedpoint\fixed_point.hpp" />
|
||||
|
@ -215,6 +217,7 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts"</Command>
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="Game\footprint.cpp" />
|
||||
<ClCompile Include="Game\lion.cpp" />
|
||||
<ClCompile Include="Game\misc.cpp" />
|
||||
<ClCompile Include="Game\swat.cpp" />
|
||||
|
|
|
@ -303,6 +303,12 @@
|
|||
<ClInclude Include="Libs\fixedpoint\fixed_point.hpp">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Game\groundfx.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Game\footprint.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="TR5Main.cpp">
|
||||
|
@ -779,6 +785,9 @@
|
|||
<ClCompile Include="Objects\TR5\tr5_rats.cpp">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Game\footprint.cpp">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Objects\TR5\tr5_misc_objects.cpp">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue