From 8e834befc85084ee17bc3e3dd972cc65a98563f9 Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Sun, 12 Jan 2020 10:50:45 +0100 Subject: [PATCH 01/11] Removed Preallocated vector and using std::vector with a predefined capacity --- TR5Main/Renderer/Renderer11.h | 143 +------------------ TR5Main/Renderer/Renderer11Compatibility.cpp | 2 +- TR5Main/Renderer/Renderer11Draw.cpp | 12 +- TR5Main/Renderer/Renderer11DrawEffect.cpp | 12 +- TR5Main/Renderer/Renderer11Frame.cpp | 12 +- TR5Main/Renderer/Renderer11Init.cpp | 4 +- TR5Main/Renderer/Renderer11Lara.cpp | 4 +- 7 files changed, 26 insertions(+), 163 deletions(-) diff --git a/TR5Main/Renderer/Renderer11.h b/TR5Main/Renderer/Renderer11.h index 6baae800b..cd891ebfc 100644 --- a/TR5Main/Renderer/Renderer11.h +++ b/TR5Main/Renderer/Renderer11.h @@ -32,143 +32,6 @@ using namespace DirectX; using namespace DirectX::SimpleMath; using namespace std; -template -class PreallocatedVector -{ -private: - T** m_objects; - int m_maxItems; - int m_numItems; - int m_startSize; - -public: - PreallocatedVector() - { - m_objects = NULL; - m_maxItems = 0; - m_startSize = 0; - m_numItems = 0; - } - - ~PreallocatedVector() - { - } - - inline void Reserve(int numItems) - { - m_objects = (T**)malloc(sizeof(T*) * numItems); - ZeroMemory(m_objects, sizeof(T*) * m_maxItems); - m_maxItems = numItems; - m_numItems = 0; - m_startSize = numItems; - } - - inline void Clear() - { - m_numItems = 0; - ZeroMemory(m_objects, sizeof(T*) * m_maxItems); - } - - inline int Size() - { - return m_numItems; - } - - inline void Sort(int(*compareFunc)(T*, T*)) - { - qsort(m_objects, m_numItems, sizeof(T), compareFunc); - } - - inline T*& operator[] (int x) { - if (x >= m_maxItems) - return m_objects[0]; - return m_objects[x]; - } - - inline void Add(T* value) - { - if (m_numItems >= m_maxItems) - return; - m_objects[m_numItems++] = value; - } -}; - -template -class PreallocatedDictionary -{ -private: - T** m_keys; - U** m_objects; - int m_maxItems; - int m_numItems; - int m_startSize; - -public: - PreallocatedDictionary() - { - m_keys = NULL; - m_objects = NULL; - m_maxItems = 0; - m_startSize = 0; - m_numItems = 0; - } - - ~PreallocatedDictionary() - { - free(m_keys); - free(m_objects); - } - - inline void Reserve(int numItems) - { - m_keys = (T**)malloc(sizeof(T*) * numItems); - m_objects = (U**)malloc(sizeof(U*) * numItems); - ZeroMemory(m_keys, sizeof(T*) * m_maxItems); - ZeroMemory(m_objects, sizeof(U*) * m_maxItems); - m_maxItems = numItems; - m_numItems = 0; - m_startSize = numItems; - } - - inline void Clear() - { - m_numItems = 0; - ZeroMemory(m_keys, sizeof(T*) * m_maxItems); - ZeroMemory(m_objects, sizeof(T*) * m_maxItems); - } - - inline int Size() - { - return m_numItems; - } - - inline T*& operator[] (int x) { - return m_objects[x]; - } - - inline bool KeyExists(T* key) - { - for (int i = 0; i < m_numItems; i++) - if (m_keys[i] == key) - return true; - return false; - } - - inline U* Get(T* key) - { - for (int i = 0; i < m_numItems; i++) - if (m_keys[i] == key) - return m_objects[i]; - return NULL; - } - - inline void Add(T* key, U* value) - { - m_keys[m_numItems] = key; - m_objects[m_numItems++] = value; - } -}; - struct RendererDisplayMode { int Width; int Height; @@ -635,7 +498,7 @@ struct RendererRoom bool Visited; float Distance; int RoomNumber; - PreallocatedVector LightsToDraw; + vector LightsToDraw; }; struct RendererRoomNode { @@ -653,7 +516,7 @@ struct RendererItem { Matrix Scale; Matrix AnimationTransforms[32]; int NumMeshes; - PreallocatedVector Lights; + vector Lights; }; struct RendererMesh @@ -668,7 +531,7 @@ struct RendererEffect { FX_INFO* Effect; Matrix World; RendererMesh* Mesh; - PreallocatedVector Lights; + vector Lights; }; struct RendererObject diff --git a/TR5Main/Renderer/Renderer11Compatibility.cpp b/TR5Main/Renderer/Renderer11Compatibility.cpp index 433e6a2ff..58e7bfa76 100644 --- a/TR5Main/Renderer/Renderer11Compatibility.cpp +++ b/TR5Main/Renderer/Renderer11Compatibility.cpp @@ -142,7 +142,7 @@ bool Renderer11::PrepareDataForTheRenderer() r.RoomNumber = i; r.Room = room; r.AmbientLight = Vector4(room->ambient.b / 255.0f, room->ambient.g / 255.0f, room->ambient.r / 255.0f, 1.0f); - r.LightsToDraw.Reserve(32); + r.LightsToDraw = vector(MAX_LIGHTS); if (room->NumVertices == 0) continue; diff --git a/TR5Main/Renderer/Renderer11Draw.cpp b/TR5Main/Renderer/Renderer11Draw.cpp index 3341abfbc..f6af90728 100644 --- a/TR5Main/Renderer/Renderer11Draw.cpp +++ b/TR5Main/Renderer/Renderer11Draw.cpp @@ -385,8 +385,8 @@ bool Renderer11::drawGunShells() m_stItem.AmbientLight = room.AmbientLight; memcpy(m_stItem.BonesMatrices, &Matrix::Identity, sizeof(Matrix)); - m_stLights.NumLights = item->Lights.Size(); - for (int j = 0; j < item->Lights.Size(); j++) + m_stLights.NumLights = item->Lights.size(); + for (int j = 0; j < item->Lights.size(); j++) memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight)); updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer)); m_context->PSSetConstantBuffers(2, 1, &m_cbLights); @@ -2165,8 +2165,8 @@ bool Renderer11::drawAnimatingItem(RendererItem* item, bool transparent, bool an updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer)); m_context->VSSetConstantBuffers(1, 1, &m_cbItem); - m_stLights.NumLights = item->Lights.Size(); - for (int j = 0; j < item->Lights.Size(); j++) + m_stLights.NumLights = item->Lights.size(); + for (int j = 0; j < item->Lights.size(); j++) memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight)); updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer)); m_context->PSSetConstantBuffers(2, 1, &m_cbLights); @@ -2339,8 +2339,8 @@ bool Renderer11::drawRooms(bool transparent, bool animated) { RendererRoom* room = m_roomsToDraw[i]; - m_stLights.NumLights = room->LightsToDraw.Size(); - for (int j = 0; j < room->LightsToDraw.Size(); j++) + m_stLights.NumLights = room->LightsToDraw.size(); + for (int j = 0; j < room->LightsToDraw.size(); j++) memcpy(&m_stLights.Lights[j], room->LightsToDraw[j], sizeof(ShaderLight)); updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer)); m_context->PSSetConstantBuffers(1, 1, &m_cbLights); diff --git a/TR5Main/Renderer/Renderer11DrawEffect.cpp b/TR5Main/Renderer/Renderer11DrawEffect.cpp index 02230c509..9c68d2b13 100644 --- a/TR5Main/Renderer/Renderer11DrawEffect.cpp +++ b/TR5Main/Renderer/Renderer11DrawEffect.cpp @@ -306,8 +306,8 @@ bool Renderer11::drawGunFlashes() m_stItem.AmbientLight = room.AmbientLight; memcpy(m_stItem.BonesMatrices, &Matrix::Identity, sizeof(Matrix)); - m_stLights.NumLights = item->Lights.Size(); - for (int j = 0; j < item->Lights.Size(); j++) + m_stLights.NumLights = item->Lights.size(); + for (int j = 0; j < item->Lights.size(); j++) memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight)); updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer)); m_context->PSSetConstantBuffers(2, 1, &m_cbLights); @@ -653,8 +653,8 @@ bool Renderer11::drawEffect(RendererEffect* effect, bool transparent) updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer)); m_context->VSSetConstantBuffers(1, 1, &m_cbItem); - m_stLights.NumLights = effect->Lights.Size(); - for (int j = 0; j < effect->Lights.Size(); j++) + m_stLights.NumLights = effect->Lights.size(); + for (int j = 0; j < effect->Lights.size(); j++) memcpy(&m_stLights.Lights[j], effect->Lights[j], sizeof(ShaderLight)); updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer)); m_context->PSSetConstantBuffers(2, 1, &m_cbLights); @@ -746,8 +746,8 @@ bool Renderer11::drawWaterfalls() updateConstantBuffer(m_cbItem, &m_stItem, sizeof(CItemBuffer)); m_context->VSSetConstantBuffers(1, 1, &m_cbItem); - m_stLights.NumLights = item->Lights.Size(); - for (int j = 0; j < item->Lights.Size(); j++) + m_stLights.NumLights = item->Lights.size(); + for (int j = 0; j < item->Lights.size(); j++) memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight)); updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer)); m_context->PSSetConstantBuffers(2, 1, &m_cbLights); diff --git a/TR5Main/Renderer/Renderer11Frame.cpp b/TR5Main/Renderer/Renderer11Frame.cpp index a92ee22a9..e29591dcf 100644 --- a/TR5Main/Renderer/Renderer11Frame.cpp +++ b/TR5Main/Renderer/Renderer11Frame.cpp @@ -6,7 +6,7 @@ void Renderer11::collectRooms() for (int i = 0; i < NumberRooms; i++) { m_rooms[i].Visited = false; - m_rooms[i].LightsToDraw.Clear(); + m_rooms[i].LightsToDraw.clear(); } Vector4 vp = Vector4(-1.0f, -1.0f, 1.0f, 1.0f); @@ -92,7 +92,7 @@ void Renderer11::collectStatics(short roomNumber) void Renderer11::collectLightsForEffect(short roomNumber, RendererEffect * effect) { - effect->Lights.Clear(); + effect->Lights.clear(); if (m_rooms.size() <= roomNumber) { return; } @@ -188,13 +188,13 @@ void Renderer11::collectLightsForEffect(short roomNumber, RendererEffect * effec for (int i = 0; i < min(MAX_LIGHTS_PER_ITEM, m_tempItemLights.size()); i++) { - effect->Lights.Add(m_tempItemLights[i]); + effect->Lights.push_back(m_tempItemLights[i]); } } void Renderer11::collectLightsForItem(short roomNumber, RendererItem * item) { - item->Lights.Clear(); + item->Lights.clear(); if (m_rooms.size() <= roomNumber) { return; } @@ -303,7 +303,7 @@ void Renderer11::collectLightsForItem(short roomNumber, RendererItem * item) for (int i = 0; i < min(MAX_LIGHTS_PER_ITEM, m_tempItemLights.size()); i++) { - item->Lights.Add(m_tempItemLights[i]); + item->Lights.push_back(m_tempItemLights[i]); } if (item->Item->objectNumber == ID_LARA) @@ -355,7 +355,7 @@ void Renderer11::collectLightsForRoom(short roomNumber) // If the distance is less than the circle's radius, an intersection occurs float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY); if (distanceSquared < SQUARE(light->Out)) - room.LightsToDraw.Add(light); + room.LightsToDraw.push_back(light); } } diff --git a/TR5Main/Renderer/Renderer11Init.cpp b/TR5Main/Renderer/Renderer11Init.cpp index 4369f0e68..17b48e093 100644 --- a/TR5Main/Renderer/Renderer11Init.cpp +++ b/TR5Main/Renderer/Renderer11Init.cpp @@ -193,8 +193,8 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h for (int i = 0; i < NUM_ITEMS; i++) { - m_items[i].Lights.Reserve(MAX_LIGHTS_PER_ITEM); - m_effects[i].Lights.Reserve(MAX_LIGHTS_PER_ITEM); + m_items[i].Lights = vector(MAX_LIGHTS_PER_ITEM); + m_effects[i].Lights = vector(MAX_LIGHTS_PER_ITEM); } m_textureAtlas = NULL; diff --git a/TR5Main/Renderer/Renderer11Lara.cpp b/TR5Main/Renderer/Renderer11Lara.cpp index 3f93e1a32..fa8a7b911 100644 --- a/TR5Main/Renderer/Renderer11Lara.cpp +++ b/TR5Main/Renderer/Renderer11Lara.cpp @@ -304,8 +304,8 @@ bool Renderer11::drawLara(bool transparent, bool shadowMap) if (!shadowMap) { - m_stLights.NumLights = item->Lights.Size(); - for (int j = 0; j < item->Lights.Size(); j++) + m_stLights.NumLights = item->Lights.size(); + for (int j = 0; j < item->Lights.size(); j++) memcpy(&m_stLights.Lights[j], item->Lights[j], sizeof(ShaderLight)); updateConstantBuffer(m_cbLights, &m_stLights, sizeof(CLightBuffer)); m_context->PSSetConstantBuffers(2, 1, &m_cbLights); From 9727238be217857b53d5ea6f4140cd1a9954414e Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Sun, 12 Jan 2020 11:07:55 +0100 Subject: [PATCH 02/11] Animated Textures are now internally vector and AnimatedTextureSets are now vector --- TR5Main/Renderer/Render11Helper.cpp | 20 ++++++++++---------- TR5Main/Renderer/Renderer11.cpp | 4 ---- TR5Main/Renderer/Renderer11.h | 11 ++--------- TR5Main/Renderer/Renderer11Compatibility.cpp | 20 +++++++++----------- 4 files changed, 21 insertions(+), 34 deletions(-) diff --git a/TR5Main/Renderer/Render11Helper.cpp b/TR5Main/Renderer/Render11Helper.cpp index b92f474d6..8fe533726 100644 --- a/TR5Main/Renderer/Render11Helper.cpp +++ b/TR5Main/Renderer/Render11Helper.cpp @@ -81,11 +81,11 @@ void Renderer11::updateAnimatedTextures() for (int p = 0; p < bucket->Polygons.size(); p++) { RendererPolygon* polygon = &bucket->Polygons[p]; - RendererAnimatedTextureSet* set = m_animatedTextureSets[polygon->AnimatedSet]; + RendererAnimatedTextureSet& const set = m_animatedTextureSets[polygon->AnimatedSet]; int textureIndex = -1; - for (int j = 0; j < set->NumTextures; j++) + for (int j = 0; j < set.NumTextures; j++) { - if (set->Textures[j]->Id == polygon->TextureId) + if (set.Textures[j].Id == polygon->TextureId) { textureIndex = j; break; @@ -94,17 +94,17 @@ void Renderer11::updateAnimatedTextures() if (textureIndex == -1) continue; - if (textureIndex == set->NumTextures - 1) + if (textureIndex == set.NumTextures - 1) textureIndex = 0; else textureIndex++; - polygon->TextureId = set->Textures[textureIndex]->Id; + polygon->TextureId = set.Textures[textureIndex].Id; for (int v = 0; v < (polygon->Shape == SHAPE_RECTANGLE ? 4 : 3); v++) { - bucket->Vertices[polygon->Indices[v]].UV.x = set->Textures[textureIndex]->UV[v].x; - bucket->Vertices[polygon->Indices[v]].UV.y = set->Textures[textureIndex]->UV[v].y; + bucket->Vertices[polygon->Indices[v]].UV.x = set.Textures[textureIndex].UV[v].x; + bucket->Vertices[polygon->Indices[v]].UV.y = set.Textures[textureIndex].UV[v].y; } } } @@ -668,10 +668,10 @@ int Renderer11::getAnimatedTextureInfo(short textureId) { for (int i = 0; i < m_numAnimatedTextureSets; i++) { - RendererAnimatedTextureSet* set = m_animatedTextureSets[i]; - for (int j = 0; j < set->NumTextures; j++) + RendererAnimatedTextureSet& const set = m_animatedTextureSets[i]; + for (int j = 0; j < set.NumTextures; j++) { - if (set->Textures[j]->Id == textureId) + if (set.Textures[j].Id == textureId) return i; } } diff --git a/TR5Main/Renderer/Renderer11.cpp b/TR5Main/Renderer/Renderer11.cpp index ce17b0924..b5d557657 100644 --- a/TR5Main/Renderer/Renderer11.cpp +++ b/TR5Main/Renderer/Renderer11.cpp @@ -112,10 +112,6 @@ void Renderer11::FreeRendererData() m_rooms.clear(); - for (int i = 0; i < m_numAnimatedTextureSets; i++) - DX11_DELETE(m_animatedTextureSets[i]); - free(m_animatedTextureSets); - DX11_DELETE(m_textureAtlas); DX11_DELETE(m_skyTexture); DX11_DELETE(m_roomsVertexBuffer); diff --git a/TR5Main/Renderer/Renderer11.h b/TR5Main/Renderer/Renderer11.h index cd891ebfc..fb9ab4069 100644 --- a/TR5Main/Renderer/Renderer11.h +++ b/TR5Main/Renderer/Renderer11.h @@ -457,14 +457,7 @@ struct RendererAnimatedTexture struct RendererAnimatedTextureSet { int NumTextures; - RendererAnimatedTexture** Textures; - - ~RendererAnimatedTextureSet() - { - for (int i = 0; i < NumTextures; i++) - delete Textures[i]; - free(Textures); - } + vector Textures; }; struct RendererBucket @@ -760,7 +753,7 @@ private: RendererSpriteSequence** m_spriteSequences; unordered_map m_meshPointersToMesh; Matrix m_LaraWorldMatrix; - RendererAnimatedTextureSet** m_animatedTextureSets; + vector m_animatedTextureSets; int m_numAnimatedTextureSets; int m_currentCausticsFrame; RendererUnderwaterDustParticle m_underwaterDustParticles[NUM_UNDERWATER_DUST_PARTICLES]; diff --git a/TR5Main/Renderer/Renderer11Compatibility.cpp b/TR5Main/Renderer/Renderer11Compatibility.cpp index 58e7bfa76..a9f39789c 100644 --- a/TR5Main/Renderer/Renderer11Compatibility.cpp +++ b/TR5Main/Renderer/Renderer11Compatibility.cpp @@ -23,17 +23,18 @@ bool Renderer11::PrepareDataForTheRenderer() short* animatedPtr = AnimatedTextureRanges; animatedPtr++; - m_animatedTextureSets = (RendererAnimatedTextureSet * *)malloc(sizeof(RendererAnimatedTextureSet*) * NUM_ANIMATED_SETS); + m_animatedTextureSets = vector(NUM_ANIMATED_SETS); m_numAnimatedTextureSets = numSets; for (int i = 0; i < numSets; i++) { - RendererAnimatedTextureSet* set = new RendererAnimatedTextureSet(); + m_animatedTextureSets[i] = RendererAnimatedTextureSet(); + RendererAnimatedTextureSet& const set = m_animatedTextureSets[i]; short numTextures = *animatedPtr + 1; animatedPtr++; - set->Textures = (RendererAnimatedTexture * *)malloc(sizeof(RendererAnimatedTexture) * numTextures); - set->NumTextures = numTextures; + set.Textures = vector(numTextures); + set.NumTextures = numTextures; for (int j = 0; j < numTextures; j++) { @@ -42,22 +43,19 @@ bool Renderer11::PrepareDataForTheRenderer() OBJECT_TEXTURE* texture = &ObjectTextures[textureId]; int tile = texture->tileAndFlag & 0x7FFF; - - RendererAnimatedTexture* newTexture = new RendererAnimatedTexture(); - newTexture->Id = textureId; + set.Textures[j] = RendererAnimatedTexture(); + RendererAnimatedTexture& const newTexture = set.Textures[j]; + newTexture.Id = textureId; for (int k = 0; k < 4; k++) { float x = (texture->vertices[k].x * 256.0f + 0.5f + GET_ATLAS_PAGE_X(tile)) / (float)TEXTURE_ATLAS_SIZE; float y = (texture->vertices[k].y * 256.0f + 0.5f + GET_ATLAS_PAGE_Y(tile)) / (float)TEXTURE_ATLAS_SIZE; - newTexture->UV[k] = Vector2(x, y); + newTexture.UV[k] = Vector2(x, y); } - set->Textures[j] = newTexture; } - - m_animatedTextureSets[i] = set; } // Step 1: create the texture atlas From 9821018cab5e7947b1869a0598c258a23c3d9c8d Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Sun, 12 Jan 2020 11:29:41 +0100 Subject: [PATCH 03/11] changed SpriteSequences to vector and using vectorinternally --- TR5Main/Renderer/Renderer11.cpp | 4 --- TR5Main/Renderer/Renderer11.h | 28 ++++++++++++++------ TR5Main/Renderer/Renderer11Compatibility.cpp | 9 +++---- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/TR5Main/Renderer/Renderer11.cpp b/TR5Main/Renderer/Renderer11.cpp index b5d557657..316c4ca22 100644 --- a/TR5Main/Renderer/Renderer11.cpp +++ b/TR5Main/Renderer/Renderer11.cpp @@ -102,10 +102,6 @@ void Renderer11::FreeRendererData() DX11_DELETE(m_sprites[i]); free(m_sprites); - for (int i = 0; i < ID_NUMBER_OBJECTS; i++) - DX11_DELETE(m_spriteSequences[i]); - free(m_spriteSequences); - for (int i = 0; i < NUM_STATICS; i++) DX11_DELETE(m_staticObjects[i]); free(m_staticObjects); diff --git a/TR5Main/Renderer/Renderer11.h b/TR5Main/Renderer/Renderer11.h index fb9ab4069..957ce981c 100644 --- a/TR5Main/Renderer/Renderer11.h +++ b/TR5Main/Renderer/Renderer11.h @@ -556,21 +556,33 @@ struct RendererSprite { struct RendererSpriteSequence { int Id; - RendererSprite** SpritesList; + vector SpritesList; int NumSprites; + RendererSpriteSequence() + { + } RendererSpriteSequence(int id, int num) { Id = id; NumSprites = num; - SpritesList = (RendererSprite**)malloc(sizeof(RendererSprite*) * num); + SpritesList = vector(NumSprites); } - ~RendererSpriteSequence() - { - /*for (int i = 0; i < NumSprites; i++) - delete SpritesList[i]; - free(SpritesList);*/ + RendererSpriteSequence(const RendererSpriteSequence& rhs) { + Id = rhs.Id; + NumSprites = rhs.NumSprites; + SpritesList = rhs.SpritesList; + } + + RendererSpriteSequence& operator=(const RendererSpriteSequence& other) { + if (this != &other) { + Id = other.Id; + NumSprites = other.NumSprites; + SpritesList = vector(NumSprites); + std::copy(other.SpritesList.begin(), other.SpritesList.end(),back_inserter(SpritesList)); + } + return *this; } }; @@ -750,7 +762,7 @@ private: int m_numStatics; int m_numSprites; int m_numSpritesSequences; - RendererSpriteSequence** m_spriteSequences; + vector m_spriteSequences; unordered_map m_meshPointersToMesh; Matrix m_LaraWorldMatrix; vector m_animatedTextureSets; diff --git a/TR5Main/Renderer/Renderer11Compatibility.cpp b/TR5Main/Renderer/Renderer11Compatibility.cpp index a9f39789c..8368c33b7 100644 --- a/TR5Main/Renderer/Renderer11Compatibility.cpp +++ b/TR5Main/Renderer/Renderer11Compatibility.cpp @@ -8,8 +8,7 @@ bool Renderer11::PrepareDataForTheRenderer() m_moveableObjects = (RendererObject * *)malloc(sizeof(RendererObject*) * ID_NUMBER_OBJECTS); ZeroMemory(m_moveableObjects, sizeof(RendererObject*) * ID_NUMBER_OBJECTS); - m_spriteSequences = (RendererSpriteSequence * *)malloc(sizeof(RendererSpriteSequence*) * ID_NUMBER_OBJECTS); - ZeroMemory(m_spriteSequences, sizeof(RendererSpriteSequence*) * ID_NUMBER_OBJECTS); + m_spriteSequences = vector(ID_NUMBER_OBJECTS); m_staticObjects = (RendererObject * *)malloc(sizeof(RendererObject*) * NUM_STATICS); ZeroMemory(m_staticObjects, sizeof(RendererObject*) * NUM_STATICS); @@ -799,12 +798,12 @@ bool Renderer11::PrepareDataForTheRenderer() { short numSprites = abs(obj->nmeshes); short baseSprite = obj->meshIndex; - - RendererSpriteSequence* sequence = new RendererSpriteSequence(MoveablesIds[i], numSprites); + m_spriteSequences[MoveablesIds[i]] = RendererSpriteSequence(MoveablesIds[i], numSprites); + RendererSpriteSequence& sequence = m_spriteSequences[MoveablesIds[i]]; for (int j = baseSprite; j < baseSprite + numSprites; j++) { - sequence->SpritesList[j - baseSprite] = m_sprites[j]; + sequence.SpritesList[j - baseSprite] = m_sprites[j]; } m_spriteSequences[MoveablesIds[i]] = sequence; From bdc95e85460708f8ab5b243ddbe83ed301b1075e Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Sun, 12 Jan 2020 17:28:04 +0100 Subject: [PATCH 04/11] New HUD Buffer, new RendererHUDBar struct --- Build/D3DX11d_43.pdb | Bin 0 -> 314368 bytes Build/Shaders/DX11_HUD.fx | 35 ++++++++ TR5Main/Game/healt.cpp | 24 +++--- TR5Main/Renderer/Renderer11.cpp | 113 ++++++++++++++++++++++++++ TR5Main/Renderer/Renderer11.h | 24 ++++-- TR5Main/Renderer/Renderer11Draw.cpp | 6 +- TR5Main/Renderer/Renderer11Draw2D.cpp | 69 +++++++++------- TR5Main/Renderer/Renderer11Init.cpp | 13 ++- TR5Main/Shaders/DX11_HUD.fx | 35 ++++++++ TR5Main/TR5Main.vcxproj | 7 ++ TR5Main/TR5Main.vcxproj.filters | 3 +- 11 files changed, 276 insertions(+), 53 deletions(-) create mode 100644 Build/D3DX11d_43.pdb create mode 100644 Build/Shaders/DX11_HUD.fx create mode 100644 TR5Main/Shaders/DX11_HUD.fx diff --git a/Build/D3DX11d_43.pdb b/Build/D3DX11d_43.pdb new file mode 100644 index 0000000000000000000000000000000000000000..8c15330688bed4bbbd51d305b71d53464b07b1c4 GIT binary patch literal 314368 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

XvNMGm=qNn%)l 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

H>lHHdZr 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, 32, 150, 12, value, 0xA00000, color2); + g_Renderer->DrawBar(value, g_HealthBar); } } @@ -34,12 +34,12 @@ void DrawHealthBar(int value) { if (CurrentLevel) { - int color2; - if (Lara.poisoned || Lara.gassed) - color2 = 0xA0A000; - else - color2 = 0xA00000; - g_Renderer->DrawBar(20, 32, 150, 12, value, 0xA00000, color2); + //int color2; + //if (Lara.poisoned || Lara.gassed) + // color2 = 0xA0A000; + //else + // color2 = 0xA00000; + g_Renderer->DrawBar(value,g_HealthBar); } } @@ -101,7 +101,7 @@ void DrawAirBar(int value) { if (CurrentLevel) { - g_Renderer->DrawBar(20, 10, 150, 12, value, 0x0000A0, 0x0050A0); + g_Renderer->DrawBar(value, g_HealthBar); } } @@ -128,12 +128,12 @@ void UpdateAirBar(int flash) if (air <= 450) { if (flash) - DrawAirBar((air * 100) / 1800); + DrawAirBar(air/ 1800.0f); else DrawAirBar(0); } else - DrawAirBar((air * 100) / 1800); + DrawAirBar(air / 1800.0f); if (Lara.gassed) { @@ -147,7 +147,7 @@ void DrawDashBar(int value) { if (CurrentLevel) { - g_Renderer->DrawBar(630, 32, 150, 12, value, 0xA0A000, 0x00A000); + g_Renderer->DrawBar(value, g_HealthBar); } } diff --git a/TR5Main/Renderer/Renderer11.cpp b/TR5Main/Renderer/Renderer11.cpp index 316c4ca22..b43008327 100644 --- a/TR5Main/Renderer/Renderer11.cpp +++ b/TR5Main/Renderer/Renderer11.cpp @@ -263,3 +263,116 @@ ID3D11Buffer* Renderer11::createConstantBuffer(int size) +RendererHUDBar::RendererHUDBar(ID3D11Device* m_device,int x, int y, int w, int h, int borderSize, array colors) +{ + + array barVertices = { + Vector3(x, y, 0), + Vector3(x + (w / 2.0f), y, 0), + Vector3(x + w, y, 0), + Vector3(x, (y + h / 2.0f), 0), + Vector3(x + (w / 2.0f), (y + h / 2.0f), 0), + Vector3(x + w, (y + h / 2.0f), 0), + Vector3(x, y + h, 0), + Vector3(x + (w / 2.0f), y + h, 0), + Vector3(x + w, y + h, 0), + + }; + array barBorderVertices = { + //top left + Vector3(x - HUD_UNIT_X,y - HUD_UNIT_Y,0), + Vector3(x,y - HUD_UNIT_Y,0), + Vector3(x,y,0), + Vector3(x - HUD_UNIT_X,y,0), + //top right + Vector3(x + w,y - HUD_UNIT_Y,0), + Vector3(x + w + HUD_UNIT_X,y - HUD_UNIT_Y,0), + Vector3(x + w + HUD_UNIT_X,y,0), + Vector3(x + w,y,0), + //bottom right + Vector3(x + w,1,0), + Vector3(x + w + HUD_UNIT_X,y + h,0), + Vector3(x + w + HUD_UNIT_X,y + h + HUD_UNIT_Y,0), + Vector3(x + w,y + h + HUD_UNIT_Y,0), + //bottom left + Vector3(x - HUD_UNIT_X,y + h,0), + Vector3(x,y + h,0), + Vector3(x,y + h + HUD_UNIT_Y,0), + Vector3(x - HUD_UNIT_X,y + h + HUD_UNIT_Y,0) + }; + + array barUVs = { + Vector2(0,0), + Vector2(0.5,0), + Vector2(1,0), + Vector2(0,0.5), + Vector2(0.5,0.5), + Vector2(1,0.5), + Vector2(0,1), + Vector2(0.5,1), + Vector2(1,1), + }; + array barBorderUVs = { + //top left + Vector2(0,0), + Vector2(0.25,0), + Vector2(0.25,0.25), + Vector2(0,0.25), + //top right + Vector2(0.75,0), + Vector2(1,0), + Vector2(1,0.25), + Vector2(0.75,0.25), + //bottom right + Vector2(0.75,0.75), + Vector2(1,0.75), + Vector2(1,1), + Vector2(0.75,1), + //bottom left + Vector2(0,0.75), + Vector2(0.25,0.75), + Vector2(0.25,1), + Vector2(0,1), + }; + + array barIndices = { + 0,1,3,1,4,3, + // + 1,2,4,2,5,4, + // + 3,4,6,4,7,6, + // + 4,5,7,5,8,7 + }; + array barBorderIndices = { + //top left + 0,1,3,1,2,3, + //top center + 1,4,2,4,7,2, + //top right + 4,5,7,5,6,7, + //right + 7,6,8,6,9,8, + //bottom right + 8,9,11,9,10,11, + //bottom + 13,8,14,8,11,14, + //bottom left + 12,13,15,13,14,15, + //left + 3,2,12,2,13,12, + //center + 2,7,13,7,8,13 + }; + Matrix hudMatrix = Matrix::CreateLookAt(Vector3::Zero, Vector3(0, 0, 1), Vector3(0, -1, 0))* Matrix::CreateOrthographic(REFERENCE_RES_WIDTH, REFERENCE_RES_HEIGHT, -10, 10); + Vector4 vec = XMVector4Transform(Vector4(x + (w / 2.0f), y, 0, 1), hudMatrix); + array vertices; + for (int i = 0; i < 9; i++) { + + vertices[i].Position = barVertices[i]; + vertices[i].Color = colors[i]; + vertices[i].UV = barUVs[i]; + } + vertexBuffer = VertexBuffer::Create(m_device, vertices.size(), vertices._Elems); + indexBuffer = IndexBuffer::Create(m_device, barIndices.size(), barIndices._Elems); +} diff --git a/TR5Main/Renderer/Renderer11.h b/TR5Main/Renderer/Renderer11.h index 957ce981c..a0d13651d 100644 --- a/TR5Main/Renderer/Renderer11.h +++ b/TR5Main/Renderer/Renderer11.h @@ -27,7 +27,10 @@ #define DX11_RELEASE(x) if (x != NULL) x->Release() #define DX11_DELETE(x) if (x != NULL) { delete x; x = NULL; } - +constexpr int REFERENCE_RES_WIDTH = 800; +constexpr int REFERENCE_RES_HEIGHT = 600; +constexpr float HUD_UNIT_X = 1.0f / REFERENCE_RES_WIDTH; +constexpr float HUD_UNIT_Y = 1.0f / REFERENCE_RES_HEIGHT; using namespace DirectX; using namespace DirectX::SimpleMath; using namespace std; @@ -37,7 +40,6 @@ struct RendererDisplayMode { int Height; int RefreshRate; }; - struct RendererVideoAdapter { string Name; int Index; @@ -338,6 +340,11 @@ public: } }; +typedef struct RendererHUDBar { + VertexBuffer* vertexBuffer; + IndexBuffer* indexBuffer; + RendererHUDBar(ID3D11Device* m_device, int x, int y, int w, int h, int borderSize, array colors); +}; struct RendererStringToDraw { float X; @@ -404,6 +411,9 @@ struct ShaderLight { float Range; }; +struct CHUDBuffer { + Matrix ViewProjection; +}; struct CCameraMatrixBuffer { Matrix View; @@ -681,7 +691,8 @@ private: ID3D11PixelShader* m_psFullScreenQuad; ID3D11VertexShader* m_vsShadowMap; ID3D11PixelShader* m_psShadowMap; - + ID3D11VertexShader* m_vsHUD; + ID3D11PixelShader* m_psHUD; ID3D11ShaderResourceView* m_shadowMapRV; ID3D11Texture2D* m_shadowMapTexture; @@ -703,7 +714,8 @@ private: ID3D11Buffer* m_cbRoom; CShadowLightBuffer m_stShadowMap; ID3D11Buffer* m_cbShadowMap; - + CHUDBuffer m_stHUD; + ID3D11Buffer* m_cbHUD; // Text and sprites SpriteFont* m_gameFont; SpriteBatch* m_spriteBatch; @@ -879,7 +891,7 @@ private: bool isInRoom(int x, int y, int z, short roomNumber); bool drawColoredQuad(int x, int y, int w, int h, Vector4 color); bool initialiseScreen(int w, int h, int refreshRate, bool windowed, HWND handle, bool reset); - + bool initialiseBars(); public: Matrix View; Matrix Projection; @@ -923,7 +935,7 @@ public: 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); + bool DrawBar(float percent, const RendererHUDBar* const bar); private: void drawFootprints(); }; \ No newline at end of file diff --git a/TR5Main/Renderer/Renderer11Draw.cpp b/TR5Main/Renderer/Renderer11Draw.cpp index f6af90728..5d564ff8b 100644 --- a/TR5Main/Renderer/Renderer11Draw.cpp +++ b/TR5Main/Renderer/Renderer11Draw.cpp @@ -847,7 +847,7 @@ int Renderer11::drawInventoryScene() PrintString(200, y, g_GameFlow->GetString(STRING_MUSIC_VOLUME), PRINTSTRING_COLOR_ORANGE, PRINTSTRING_OUTLINE | (ring->selectedIndex == 2 ? PRINTSTRING_BLINK : 0)); - DrawBar(400, y + 4, 150, 18, ring->Configuration.MusicVolume, 0x0000FF, 0x0000FF); + //DrawBar(400, y + 4, 150, 18, ring->Configuration.MusicVolume, 0x0000FF, 0x0000FF); y += 25; @@ -855,7 +855,7 @@ int Renderer11::drawInventoryScene() PrintString(200, y, g_GameFlow->GetString(STRING_SFX_VOLUME), PRINTSTRING_COLOR_ORANGE, PRINTSTRING_OUTLINE | (ring->selectedIndex == 3 ? PRINTSTRING_BLINK : 0)); - DrawBar(400, y + 4, 150, 18, ring->Configuration.SfxVolume, 0x0000FF, 0x0000FF); + //DrawBar(400, y + 4, 150, 18, ring->Configuration.SfxVolume, 0x0000FF, 0x0000FF); y += 25; @@ -2024,7 +2024,7 @@ bool Renderer11::drawScene(bool dump) // Bars int flash = FlashIt(); if (DashTimer < 120) - DrawBar(630, 32, 150, 12, 100 * (unsigned short)DashTimer / 120, 0xA0A000, 0xA000); + //DrawBar(630, 32, 150, 12, 100 * (unsigned short)DashTimer / 120, 0xA0A000, 0xA000); UpdateHealtBar(flash); UpdateAirBar(flash); DrawAllPickups(); diff --git a/TR5Main/Renderer/Renderer11Draw2D.cpp b/TR5Main/Renderer/Renderer11Draw2D.cpp index 5776fb1f4..fb218c4bf 100644 --- a/TR5Main/Renderer/Renderer11Draw2D.cpp +++ b/TR5Main/Renderer/Renderer11Draw2D.cpp @@ -1,36 +1,45 @@ #include "Renderer11.h" -bool Renderer11::DrawBar(int x, int y, int w, int h, int percent, int color1, int color2) +RendererHUDBar* g_HealthBar; +RendererHUDBar* g_AirBar; +RendererHUDBar* g_DashBar; + +bool Renderer11::initialiseBars() { - byte r1 = (color1 >> 16) & 0xFF; - byte g1 = (color1 >> 8) & 0xFF; - byte b1 = (color1 >> 0) & 0xFF; - - byte r2 = (color2 >> 16) & 0xFF; - byte g2 = (color2 >> 8) & 0xFF; - byte b2 = (color2 >> 0) & 0xFF; - - float factorX = ScreenWidth / 800.0f; - float factorY = ScreenHeight / 600.0f; - - int realX = x * factorX; - int realY = y * factorY; - int realW = w * factorX; - int realH = h * factorY; - - int realPercent = percent / 100.0f * realW; - - for (int i = 0; i < realH; i++) - AddLine2D(realX, realY + i, realX + realW, realY + i, 0, 0, 0, 255); - - for (int i = 0; i < realH; i++) - AddLine2D(realX, realY + i, realX + realPercent, realY + i, r1, g1, b1, 255); - - AddLine2D(realX, realY, realX + realW, realY, 255, 255, 255, 255); - AddLine2D(realX, realY + realH, realX + realW, realY + realH, 255, 255, 255, 255); - AddLine2D(realX, realY, realX, realY + realH, 255, 255, 255, 255); - AddLine2D(realX + realW, realY, realX + realW, realY + realH + 1, 255, 255, 255, 255); - + array healthColors = { + //top + Vector4(82 / 255.0f,0,0,1), + Vector4(36 / 255.0f,46 / 255.0f,0,1), + Vector4(0,82 / 255.0f,0,1), + //center + Vector4(159 / 255.0f,0,0,1), + Vector4(78 / 255.0f,81 / 255.0f,0,1), + Vector4(0,158 / 255.0f,0,1), + //bottom + Vector4(82 / 255.0f,0,0,1), + Vector4(36 / 255.0f,46 / 255.0f,0,1), + Vector4(0,82 / 255.0f,0,1), + }; + g_HealthBar = new RendererHUDBar(m_device, 0, 0, 800, 600, 3, healthColors); + return true; +} +bool Renderer11::DrawBar(float percent,const RendererHUDBar* const bar) +{ + UINT strides = 0; + UINT offset = 0; + m_context->ClearDepthStencilView(m_currentRenderTarget->DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + m_context->IASetInputLayout(m_inputLayout); + m_context->IASetVertexBuffers(0, 1, &bar->vertexBuffer->Buffer, &strides, &offset); + m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_context->IASetIndexBuffer(bar->indexBuffer->Buffer, DXGI_FORMAT_R32_SINT, 0); + m_context->VSSetConstantBuffers(0, 1, &m_cbHUD); + m_context->VSSetShader(m_vsHUD,NULL,0); + m_context->PSSetShader(m_psHUD, NULL,0); + m_context->OMSetBlendState(m_states->Opaque(), NULL,0xFFFFFFFF); + m_context->OMSetDepthStencilState(m_states->DepthNone(),0); + m_context->RSSetState(m_states->CullNone()); + m_context->DrawIndexed(24, 0, 0); + return true; } diff --git a/TR5Main/Renderer/Renderer11Init.cpp b/TR5Main/Renderer/Renderer11Init.cpp index 17b48e093..4e0ed3584 100644 --- a/TR5Main/Renderer/Renderer11Init.cpp +++ b/TR5Main/Renderer/Renderer11Init.cpp @@ -164,6 +164,13 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h if (m_psShadowMap == NULL) return false; + m_vsHUD = compileVertexShader("Shaders\\DX11_HUD.fx", "VS", "vs_4_0", &blob); + if (m_vsHUD == NULL) + return false; + m_psHUD = compilePixelShader("Shaders\\DX11_HUD.fx", "PS", "ps_4_0", &blob); + if (m_psHUD == NULL) + return false; + // Initialise constant buffers m_cbCameraMatrices = createConstantBuffer(sizeof(CCameraMatrixBuffer)); m_cbItem = createConstantBuffer(sizeof(CItemBuffer)); @@ -172,6 +179,10 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h m_cbMisc = createConstantBuffer(sizeof(CMiscBuffer)); m_cbShadowMap = createConstantBuffer(sizeof(CShadowLightBuffer)); m_cbRoom = createConstantBuffer(sizeof(CRoomBuffer)); + //Prepare HUD Constant buffer + m_cbHUD = createConstantBuffer(sizeof(CHUDBuffer)); + m_stHUD.ViewProjection = Matrix::CreateLookAt(Vector3::Zero, Vector3(0, 0, -1), Vector3(0, -1, 0))* Matrix::CreateOrthographic(REFERENCE_RES_WIDTH, REFERENCE_RES_HEIGHT, -10, 10); + updateConstantBuffer(m_cbHUD, &m_stHUD, sizeof(CHUDBuffer)); m_currentCausticsFrame = 0; m_firstWeather = true; @@ -211,7 +222,7 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h blendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; blendStateDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; m_device->CreateBlendState(&blendStateDesc, &m_subtractiveBlendState); - + initialiseBars(); return true; } diff --git a/TR5Main/Shaders/DX11_HUD.fx b/TR5Main/Shaders/DX11_HUD.fx new file mode 100644 index 000000000..f52a5fd2e --- /dev/null +++ b/TR5Main/Shaders/DX11_HUD.fx @@ -0,0 +1,35 @@ +cbuffer HUDBuffer : register(b0) +{ + float4x4 ViewProjection; +}; + +struct VertexShaderInput +{ + float3 Position: POSITION; + float3 Normal: NORMAL; + float2 UV: TEXCOORD; + float4 Color: COLOR; + float Bone : BLENDINDICES; +}; + +struct PixelShaderInput +{ + float4 Position: SV_POSITION; + float2 UV: TEXCOORD; + float4 Color: COLOR; +}; + + +PixelShaderInput VS(VertexShaderInput input) +{ + PixelShaderInput output; + output.Position = mul(float4(input.Position, 1.0f), ViewProjection); + output.Color = input.Color; + output.UV = input.UV; + return output; +} + +half4 PS(PixelShaderInput input) : SV_TARGET +{ + return input.Color; +} \ No newline at end of file diff --git a/TR5Main/TR5Main.vcxproj b/TR5Main/TR5Main.vcxproj index a20a2152e..e48a0327e 100644 --- a/TR5Main/TR5Main.vcxproj +++ b/TR5Main/TR5Main.vcxproj @@ -628,6 +628,13 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts" + + + true + true + Document + + diff --git a/TR5Main/TR5Main.vcxproj.filters b/TR5Main/TR5Main.vcxproj.filters index 572c117df..796e6f9c1 100644 --- a/TR5Main/TR5Main.vcxproj.filters +++ b/TR5Main/TR5Main.vcxproj.filters @@ -871,12 +871,13 @@ - + + From a283c63df3e66fed87680f626191e87a336406d5 Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Sun, 12 Jan 2020 18:07:05 +0100 Subject: [PATCH 05/11] Split Bar Shader into VS and PS --- TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl | 11 +++++++++++ TR5Main/Shaders/{DX11_HUD.fx => HUD/DX11_VS_HUD.hlsl} | 5 ----- 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl rename TR5Main/Shaders/{DX11_HUD.fx => HUD/DX11_VS_HUD.hlsl} (88%) diff --git a/TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl b/TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl new file mode 100644 index 000000000..9a38473d0 --- /dev/null +++ b/TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl @@ -0,0 +1,11 @@ +struct PixelShaderInput +{ + float4 Position: SV_POSITION; + float2 UV: TEXCOORD; + float4 Color: COLOR; +}; + +half4 PS(PixelShaderInput input) : SV_TARGET +{ + return input.Color; +} \ No newline at end of file diff --git a/TR5Main/Shaders/DX11_HUD.fx b/TR5Main/Shaders/HUD/DX11_VS_HUD.hlsl similarity index 88% rename from TR5Main/Shaders/DX11_HUD.fx rename to TR5Main/Shaders/HUD/DX11_VS_HUD.hlsl index f52a5fd2e..9cd1a10ae 100644 --- a/TR5Main/Shaders/DX11_HUD.fx +++ b/TR5Main/Shaders/HUD/DX11_VS_HUD.hlsl @@ -27,9 +27,4 @@ PixelShaderInput VS(VertexShaderInput input) output.Color = input.Color; output.UV = input.UV; return output; -} - -half4 PS(PixelShaderInput input) : SV_TARGET -{ - return input.Color; } \ No newline at end of file From 595e9a0de376363105e392828497933a2d6b896c Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Sun, 12 Jan 2020 23:10:38 +0100 Subject: [PATCH 06/11] cherry pick merge conflict --- Build/DX11_PS_HUD.cso | Bin 0 -> 12736 bytes Build/Shaders/HUD/DX11_PS_HUD.hlsl | 19 ++++++ Build/Shaders/HUD/DX11_VS_HUD.hlsl | 31 ++++++++++ Build/bar_border.png | Bin 0 -> 314 bytes Build/savegame.0 | Bin 0 -> 19796 bytes TR5Main/Game/healt.cpp | 6 +- TR5Main/Renderer/Renderer11.cpp | 81 +++++++++++++++----------- TR5Main/Renderer/Renderer11.h | 21 ++++++- TR5Main/Renderer/Renderer11Draw.cpp | 3 +- TR5Main/Renderer/Renderer11Draw2D.cpp | 63 ++++++++++++++++++-- TR5Main/Renderer/Renderer11Init.cpp | 18 ++++-- TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl | 10 +++- TR5Main/Shaders/HUD/DX11_VS_HUD.hlsl | 5 +- TR5Main/TR5Main.vcxproj | 15 ++++- TR5Main/TR5Main.vcxproj.filters | 5 +- 15 files changed, 218 insertions(+), 59 deletions(-) create mode 100644 Build/DX11_PS_HUD.cso create mode 100644 Build/Shaders/HUD/DX11_PS_HUD.hlsl create mode 100644 Build/Shaders/HUD/DX11_VS_HUD.hlsl create mode 100644 Build/bar_border.png create mode 100644 Build/savegame.0 diff --git a/Build/DX11_PS_HUD.cso b/Build/DX11_PS_HUD.cso new file mode 100644 index 0000000000000000000000000000000000000000..fd40af86ef4e49a6a393369debbc74d10801166c GIT binary patch literal 12736 zcmZ>XaB{xj)uMBvtA~oq>VDhJk^BgNcE`gNcD5z<`0_ zi~$3Kgdqb%k0AqtV}73H5k>|E5N2Td|9=4^1A__!2!Kdb%*gcr|G)n+3@%Qg?ivgX z3@#u`7#J8pR0;zF12Y2yLk0r_0}}%SgA5}BLjy>SRg6o1c4=;EUP)?9NRX*-VrCwk z4$eqSNi8al@d$N^afvWAj1LHo_Xu^-%g8CtVOYHyWCsJo|Nj+?3=BLB3=A!d3=CWh z3=9((85jbB8CEkgFf%YRuz>9cxftXQkZYJ2n89vaa z6U+noy#*Q;Qy3s&u?8f=2yztzg8(A~gKuVXQGRiLT8V;2kfwr%Pq2>yBt#UP^K%O_ zb5e^G3=Q-Q8RQ{B+Q7)5zkw0V)^A{BcmiQ_=r=GhJZbpY5hV8PHZlD$9T{SKQ@`tVqp)3`lr_Mo@UUs(HCM({l0?OH34CqbXJj!C~a*$OOgH`czWhCaLnJ5GVYoI$_0XzhxsQ`9uh+~ku zYY4CIK=OBnR^!NX;l793cQo zTTTo%f}k;K21d{rcMC(ZD~u*~)S7|8j=@%t5j2+XmXnxX%wSMq$^hbpBo?KomM|0) z$D70(#OI`zrRKz2#v6m>T=PnbDnWz$ppejF5D)~>1)#*lz`!5@;y`J30R{%p7zHE4 zf&kE%v>t<L_R11-N>lA{2NF~UWF`}iumXu=3oDQ~wy*+;qlXm}0~^B^ zXuN{T1Odi(4|J-2Xk1p2p0@vJ{&)8z28K@z3=AGn_b@Ur!uuwmxB-ZVIim(B&A`MUf`Y#>Fff4hf{cXGAoeI`VBkJw$O!KH2{15l2tek(xETKb2ZhuB z|B%rkP&k7yC=YHv);9F)$19iZVm{ z6R;K~!$*)9qX0-aGz_E;#0T{`BpARgGzK*WR*)_RCQya~S8 zN>8A2L5M+G)D;@%0u11WA_EtLgea>3Xg-dSfscVh0F*z(K{JX-=0c4hQ516ggTfu; zd2Y1$2Z@d1;TZy;@qQ^z{g0r$4O%w<%0nPLJbjDRSD+#ctHh|_Xb24V5D;Qe1-H99 zz-wH<&1<-qVPykcV3aZJLI7X$XEgqYU36o32o%TVoQ9ww8U|hlhCV(9`xt&`{|nUS z2lXdmeKC+`(AqCa5CaLr+6$n51o~VN69Xqh38*u`z`#%gE@K!NDi*(mih$Sl<>lw4 zGU)Eo`-tBhCh+=3PzxU9W{~wD`#^0L5E~{2qCtH|kUEe!1w)z)u(46FyTAmeewr^L2WS5k`quUTR}q*R4;*sMnTI!L2@8r(2^7-&=OY=hk=3N&ge8W zG$hERK;=IupC1PGml+utycrqb<1H(o>v}|7T@nU;wd+oq_NScK6GH z?n?lbIRPMZpzRG%`2^yE%AFVx1ByZ7Ah&|(RHzt;0`Wm%z|YUXfHdRH0Gs1x08eQ% mto9Ff_XCxIATvOAg33{leh>zk0ir>628YE%=Aju@uLb~=4U9qn literal 0 HcmV?d00001 diff --git a/Build/Shaders/HUD/DX11_PS_HUD.hlsl b/Build/Shaders/HUD/DX11_PS_HUD.hlsl new file mode 100644 index 000000000..a9911cff4 --- /dev/null +++ b/Build/Shaders/HUD/DX11_PS_HUD.hlsl @@ -0,0 +1,19 @@ +struct PixelShaderInput +{ + float4 Position: SV_POSITION; + float2 UV: TEXCOORD; + float4 Color: COLOR; +}; +Texture2D Texture : register(t0); +SamplerState Sampler : register(s0); + +half4 PSColored(PixelShaderInput input) : SV_TARGET +{ + return input.Color; +} + +half4 PSTextured(PixelShaderInput input) : SV_TARGET +{ + float4 output = Texture.Sample(Sampler, input.UV); + return output; +} \ No newline at end of file diff --git a/Build/Shaders/HUD/DX11_VS_HUD.hlsl b/Build/Shaders/HUD/DX11_VS_HUD.hlsl new file mode 100644 index 000000000..1470c2b2e --- /dev/null +++ b/Build/Shaders/HUD/DX11_VS_HUD.hlsl @@ -0,0 +1,31 @@ +cbuffer HUDBuffer : register(b0) +{ + float4x4 View; + float4x4 Projection; +}; + +struct VertexShaderInput +{ + float3 Position: POSITION; + float3 Normal: NORMAL; + float2 UV: TEXCOORD; + float4 Color: COLOR; + float Bone : BLENDINDICES; +}; + +struct PixelShaderInput +{ + float4 Position: SV_POSITION; + float2 UV: TEXCOORD; + float4 Color: COLOR; +}; + + +PixelShaderInput VS(VertexShaderInput input) +{ + PixelShaderInput output; + output.Position = mul(mul(float4(input.Position, 1.0f), View),Projection); + output.Color = input.Color; + output.UV = input.UV; + return output; +} \ No newline at end of file diff --git a/Build/bar_border.png b/Build/bar_border.png new file mode 100644 index 0000000000000000000000000000000000000000..408f65204e5af7f5475066134163493cd4ddbdac GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4kiW$h6xih%orFLI14-?iy0XB4ude`@%$Aj z3=9l!JY5_^DsD}kq|M#pAmXMwoAoF=*CI!@BafI}QZN5o-|M#cV#XFJFlCZ=_q`Q| z@bSs#{#smi`)TKrIm>Ng+oNr{Pvrydl*+zQWi;ygy{~J7#mOz%!;%zG{= zcF*9L6JyyyS;?cPHyv0s+oDgo@kf)jQP=g-R#neQ%QELZkDRuY>4ssEyW7WYxf>Q~ zoZ7VJ^{!Q`f*91@-ks36_g(heGzQ6|#|sbG2`Mc8VdMXEzstw>iuFq#>~#n?yOYnr Pz`)??>gTe~DWM4fzTAeN literal 0 HcmV?d00001 diff --git a/Build/savegame.0 b/Build/savegame.0 new file mode 100644 index 0000000000000000000000000000000000000000..6c4456604eb0d358aae8fa6bd24fb50d402ffbf5 GIT binary patch literal 19796 zcmWFuGWBI(U|DUoyC>$Rg4C22FMHa+z))Y$@Q;Ck3nCX>;+E6g(7?dRz=$ToiYdZ~ zu0{YujR1xkAq+L5m?9Xu#4*%}W2lkDP$P{gf}u;A3EdY;7`l`&bSYz~F~krt#SpQ> z6u~gr9z%^iikg;&28M$SD2hNrhcJbXU=zYH>j(o%0D#Oo!oZ9iCJ-SOOd(cGAvR1Q zc1$4-Od(Emp`)0t|B6ir!$aRORefi`Q1ug2)lY1yFaqZfrp7;*8vkOd`irTm1vQ(2 z0=f-TXeOr6EKH$Am_p0231Ni9Doj$5eF$n-GS^Ba9e9cpFpWb4;Pvm_qL{ zg+5>keZds^&By>R9a9T~%bUQZBdolHi7+yti!fn`Fk^_YV2H3X@IXpax17qPN;gn> z%5aefMGO?xj13KpD1sn`OlV>tmolT82hz)et`{W8iY^G!%!a9%9h*81RCOS&oR~sf zm_ppBLLg7@97Odk$S__^Wqb!YQ2Y<_1OLGu)Ib3V3Se`vAgX~NJA_b$Kw5>-wSoji zunCGDJb|hmWTF_RkT|Lk$iEU;VpkH~4v=wDsCq#{(wIUrs6rqcWYKH@>6AlN1`?9T z6jHzxQbZL3nXiNv6(GZuQI&y&R2VoRDcd>44a8?a<1?c1nb7#mXnYnlJ}VlZ4UNx^ z#^*rebE5IN(D>YFd>%ADFB+c@jn9w97eM0+qVa{$_`+y>5j4Ii8ea^JFOJ5SK;uiI z@ukrC(rA1cG`=hvUk;5gkH%L(<13=^mC*RgXngeaq>3i5hQ?P%<7=StHPQH5Xnbun zz785+7mcrn#@9#V8=&zG(fCGad}B1e2^!xNjcUWN8*EujRVL907&2Xbb;6C0&ma--l7Y< zLl=0DF7N?e;3K-gCv<_&=mKBR1-_ySd_x!bjxO*6UEn9Wz%O)x-{=B=&;|aY3;aVD z_>V5ofZSjJl^>1h0!`=w&FBIx=mM?i0&VC5?FfOyT-0_9gpV$dXvaY05$zZVAKs2} z%Lzs?56Xv|2j#=fgYx0#LHX$B!P`Ypd3d`B%7?d$pnQ0{2+D`Ii=cdXy9mmMw~L^B zc)JM7hqsHMe0aME%7?d$pnQ0{2+D`Ii=cdXy9mmMw~L^Bc)JM7hqsHMe0aME%7?d$ zpnQ0{2+D`Ii=cdXy9mmMw~L^Bc)JM7hqsHMe0aME%7?d$pnQ0{2+D`Ii=cdXy9mmM zw~L^Bc)JM7hqsHMe0aME%7?d$pnQ0{2+D`Ii=cdXy9mmMw~L^Bc)JM7hqsHMe0aME z%7?d$pnQ0{2+D`Ii=cdXy9mmMw~L^Bc)JM7hqsHMe0aME%7?d$pnQ0{2+D`Ii=cdX zy9mmMw~L^Bc)JM7hqsHMe0aME%7?d$+;W0J#TcSp1QkHEi=YCCb`ewn(Jq1tAlgMx z0Ytk9Du8GgK?M-)BB%hOT?7?Cw2Pnuh;|WF0MRaj3Lx4=Pys}{2r7VR7eNIO?INfE zqFn?PK(vdX0*H1IQ~=Q~f(jtoMNk1my9g?PXcs{R5bYwU0HR$46+pC$paO_?5mW%t zE`kam+C@+SM7szofM^#%1rY5br~sl}1QkHEi=YCCb`ewn(Jq1tAlgMx0Ytk9Du8Gg zK?M-)BB%hOT?7?Cw2Pnuh;|WF0MRaj3Lx4=Pys}{2r7VR7eNIO?INfEqFn?PK(vdX z0*H1IQ~=Q~f(jtoMNk1my9g?PXcs{R5bYwU0HR$46+pC$paO_?5mW%tE`kam+C@+S zM7szofM^#%1rY5br~sl}1QkHEi=YCCb`ewn(Jq1tAlgMx0Ytk9Du8GgK?M-)BB($I za>E5wuyvvfbfF7$qYLz)3-qE3^q~v%qYF$x7nq1HFbQ2?GP=MNbb+bp0@Kh1rlSkY zKo^*aE-(vSU^cqI9CU%X=mPW51?Hm*EI=1nh%T@QU0^Y~z!G$UrRW07&;^#G3#>pF zScxvM3SD3|y1*KAfwkxY>(B+(qYG?67ubj{unApYGrGVQbb+nt0^869wxbK|Ko{7F zF0cz-U^lwJ9&~}d=mPuD1@@y096%R1h%RslUEnafz!7wTqv!(1&;^d83!Fd~IEgNB z3SHndy1*H9fwSlW=g7r2Nna0y-DGP=MObb+hr0@u(5uA>XwKo_`)E^rH7 z;5NFz9dv=a=mPi91@5B@JU|zCh%WF5UEndgz!P+Vr|1ID&;_2O3%o!Vc!@6X3SHne zy1*NBfw$-a@6ZL_qYHdM7x;)S@CjYuGrGVRbb+tv0^iUDzM~8LKo|IlF7OLo;5WL! zA9R7g=mP(c1boqkE5Lkod8FYAusqUm1(=UCTmj}I4Of8qNW&FiKGJXnn2$7E0p=qO zSAh9Q!xdmY(r^Wsk2G8X<|7SPfcZ$n6<|Kna0Qr;G+Y7ZBMn!8`AEYRU_R1t1(=UC zTmj}I4Of8qNW&FiKGJXnn2$7E0p=qOSAh9Q!xdmY(r^Wsk2G8X<|7SPfcZ$n6<|Kn za0Qr;G+Y7ZBMn!8`AEYRU_R1t1(=UCTmj}I4Of8qNW&FiKGJXnn2$7E0p=qOSAh9Q z!xdmY(r^Wsk2G8X<|7SPfcZ$n6<|Kna0Qr;G+Y7ZBMn!8`AEYRU_R1t1(=UCTmj}I z4Of8qNW&FiKGJXnn2$7E0p=qOSAh9Q!xdmY(r^Wsk2G8X<|7SPfcZ$n6<|KnaD^|Z zRgXMe0Tw_Wt^f-l4_AN%kcTV40?5M^U;*Ue3a|k3a0OTZdAI^BfIM6Q7C;`Z01F@w zSAYeOhbzDW$io$20p#HdumJLK1y}%ixB@JIJX`@5Kpw6D3m^|yfCZ3;E5HKC!xdlw z(-@^A%M0C~6q zEPy;*0Tw_Wt^f-l4_AN%kcTV40?5M^U;*Ue3a|k3a0OTZdAI^BfIM6Q7C;`Z01F@w zSAYeOhbzDW$io$20p#HdumJLK1y}%ixB@JIJX`@5Kpw6D3m^|yfCZ3;E5HKC!xdlw z(-@^A%M0C~6q zEPy;*0Tw_Wt^f-l4_AN%kcTV40?5M^U;*Ue3a|k3a0OTZdAI^BfIM6Q7C;`Z01F@w zSAYeOhbzDW$io$20p#HdumJLK1y}%ixB@JIJX`@5Kpw6D3m^|yfCZ3;E5HKC!xdlw z(-@^A%M0C~6q zEPy;*0Tw_Wt^f-l4_AN%kcTV40?5M^U;*Ue3a|k3a0OTZdAI^BfIM6Q7C;`Z01F@w zSAYeOhbzDW$io$20p#HdumJLK1y}%ixB@JIJX`@5Kpw6D3m^|yfCZ3;E5HKC!xdlw z(-@^A%M0C~6q zEPy;*0Tw_Wt^f-l4_AN%kcTV40?5M^U;*Ue3a|k3a0OTZdAI^BfIM6Q7C;`Z01F@w zSAYeOhbzDW$io$20p#HdumJLK1y}%ixB@JIJX`@5Kpw6D3m^|yfCZ3;E5HKC!xdlw z(-@^A%M0C~6q zEPy;*0Tw_Wt^f-l4_AN%kcTV40?5M^U;*Ue3a|k3a0OTZdAI^BfIM6Q7C;`Z01F@w zSAYeOhbzDW$io$20p#HdumJLK1y}%ixB@JIJX`@5Kpw6D3m^|yfCZ3;E5HKC!xdlw z+8KSucW6raSR z#7|8P49W})pe-s4jL@AeAnN~r4t5ZYivRzI@f~0cD9r+*>p=u27O-PrnBdI75aQ0j zaK)Q}p~9bm!6ul2VNW;%LqaqI!-*^g2Af<4h6VWy3{MIf7$Qm-81|GgFfddio8@%@ znRn#oQx^LhpYi7`~Uy{{|}ts^%jQ$BpWbQFf%YRFk=Y+{}0+N#K6GN@E3#_ z758EH)S(2JN3%q!qVGa`m13yF=NYte?H@A|J5nUl81H*D=ViYnl zFnnMnMj*Ll&{$t7#s8Ftie-P?&+? zK2g3FAvQgV5}O{y7#Q{ufOdUimd()3Hl8JpdAY^y4Gj!T zObnM8esDr}J$aS{Ff1Y}nQ9Yj zwGOcgb&0K~^oUJ;`V0&Uh>95l28Inp1&<-IQD{W0LSqKd##kcSBqj_D+lY!8QwE0Z zL@6{QR-rku3N46LXi2O>D`FK|6RXgMScSF>44}p;W{HH}TC`(eSWi^yv1eddLNI1# zH#9IDU?5iIL84V2B3k8PqE#LtTIEp&Vsbag@5dO3Y2txY9%o=+SV2^Ho*>%HlSHdL z#XwB+1mw=s3=9l+i7JQAFfcIa5^CLoj6BOgOsf^7@*D#(r6ow^c?M#NOOQ%X4{-}o z0e_K!fq^)cmlzlrE)onRknNX=_R$rh6WvvinFOm`knPtP7#Nxe=5~kPzn7(gm- z5S2hcDsM6{Ff1Y}lx~5tCP9^;Uh!=P1_paVi4LUj4zUXF5~C309Z(zlD^Y=YpMinl z8&N7BFfcIuA}T5$GB7Y~A}Sd_VqjocLzK$L3=9nGh*J54fq`KjQ9gRgz`!tvD3#BM z_WN_9Gv*7TRlWp;62T+~ig!>Ko^Yodr1CXUr7S3QzF}ZsuqBj?K}Lcqb>f2a9RmYH zBT)hWo`Hd3CQ;G;f#_29BT-%l`REe^1H&bv0{%0o$|OqV7X}7~okaQQE67Jgsr*KC z8ULN=kpICzO#cEDN}w*)I-+6|RD6I`<8S(b%=}GsDE%SYoqrh^7(gc=5w`sw(V+wy zPbNHA0P;}-BLl-4qCyFjGYAi{fy@NemxRM}ZbJh@Gb2Mo0~07k;rBgAZ3_u%TS-vc zMuOUQ64Z7OsTLGsos7h`#kv@YZDn*b5;MF5vb~3q*fwJ?BLl-Mf_WblTYX^Pe;`=) wfYkOAsTSnc2}Jv9A|tW+Y7!#@!zZHhz+^^Z`uQMtP9a+5R7RX#CD4!+06vJI;Q#;t literal 0 HcmV?d00001 diff --git a/TR5Main/Game/healt.cpp b/TR5Main/Game/healt.cpp index 14e0d5866..d67f0584c 100644 --- a/TR5Main/Game/healt.cpp +++ b/TR5Main/Game/healt.cpp @@ -15,6 +15,8 @@ int FlashCount = 0; int PoisonFlag = 0; int DashTimer = 0; extern RendererHUDBar* g_HealthBar; +extern RendererHUDBar* g_DashBar; +extern RendererHUDBar* g_AirBar; extern LaraExtraInfo g_LaraExtra; void DrawHealthBarOverlay(int value) @@ -101,7 +103,7 @@ void DrawAirBar(int value) { if (CurrentLevel) { - g_Renderer->DrawBar(value, g_HealthBar); + g_Renderer->DrawBar(value, g_AirBar); } } @@ -147,7 +149,7 @@ void DrawDashBar(int value) { if (CurrentLevel) { - g_Renderer->DrawBar(value, g_HealthBar); + g_Renderer->DrawBar(value, g_DashBar); } } diff --git a/TR5Main/Renderer/Renderer11.cpp b/TR5Main/Renderer/Renderer11.cpp index b43008327..56cb4443e 100644 --- a/TR5Main/Renderer/Renderer11.cpp +++ b/TR5Main/Renderer/Renderer11.cpp @@ -157,8 +157,8 @@ ID3D11VertexShader* Renderer11::compileVertexShader(const char* fileName, const ID3DBlob* errors = NULL; printf("Compiling vertex shader: %s\n", fileName); - - res = D3DX11CompileFromFileA(fileName, NULL, NULL, function, model, D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, bytecode, &errors, NULL); + UINT flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG; + res = D3DX11CompileFromFileA(fileName, NULL, NULL, function, model, flags, 0, NULL, bytecode, &errors, NULL); if (FAILED(res)) { printf("Compilation failed: %s\n", errors->GetBufferPointer()); @@ -181,8 +181,8 @@ ID3D11PixelShader* Renderer11::compilePixelShader(const char* fileName, const ch ID3DBlob* errors = NULL; printf("Compiling pixel shader: %s\n", fileName); - - res = D3DX11CompileFromFileA(fileName, NULL, NULL, function, model, D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, bytecode, &errors, NULL); + UINT flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG; + res = D3DX11CompileFromFileA(fileName, NULL, NULL, function, model, flags, 0, NULL, bytecode, &errors, NULL); if (FAILED(res)) { printf("Compilation failed: %s\n", errors->GetBufferPointer()); @@ -265,40 +265,41 @@ ID3D11Buffer* Renderer11::createConstantBuffer(int size) RendererHUDBar::RendererHUDBar(ID3D11Device* m_device,int x, int y, int w, int h, int borderSize, array colors) { - array barVertices = { - Vector3(x, y, 0), - Vector3(x + (w / 2.0f), y, 0), - Vector3(x + w, y, 0), - Vector3(x, (y + h / 2.0f), 0), - Vector3(x + (w / 2.0f), (y + h / 2.0f), 0), - Vector3(x + w, (y + h / 2.0f), 0), - Vector3(x, y + h, 0), - Vector3(x + (w / 2.0f), y + h, 0), - Vector3(x + w, y + h, 0), + Vector3(x, HUD_ZERO_Y +y, 0.5), + Vector3(x + (w / 2.0f), HUD_ZERO_Y + y, 0.5), + Vector3(x + w, HUD_ZERO_Y + y, 0.5), + Vector3(x, HUD_ZERO_Y + (y + h / 2.0f), 0.5), + Vector3(x + (w / 2.0f), HUD_ZERO_Y + (y + h / 2.0f), 0.5), + Vector3(x + w, HUD_ZERO_Y + (y + h / 2.0f), 0.5), + Vector3(x, HUD_ZERO_Y + y + h, 0.5), + Vector3(x + (w / 2.0f), HUD_ZERO_Y + y + h, 0.5), + Vector3(x + w, HUD_ZERO_Y + y + h, 0.5), }; + const float HUD_BORDER_WIDTH = borderSize * (REFERENCE_RES_WIDTH/ REFERENCE_RES_HEIGHT); + const float HUD_BORDER_HEIGT = borderSize; array barBorderVertices = { //top left - Vector3(x - HUD_UNIT_X,y - HUD_UNIT_Y,0), - Vector3(x,y - HUD_UNIT_Y,0), - Vector3(x,y,0), - Vector3(x - HUD_UNIT_X,y,0), + Vector3(x - HUD_BORDER_WIDTH ,HUD_ZERO_Y+y - HUD_BORDER_HEIGT,0), + Vector3(x ,HUD_ZERO_Y+y - HUD_BORDER_HEIGT,0), + Vector3(x ,HUD_ZERO_Y+y,0), + Vector3(x - HUD_BORDER_WIDTH ,HUD_ZERO_Y+y,0), //top right - Vector3(x + w,y - HUD_UNIT_Y,0), - Vector3(x + w + HUD_UNIT_X,y - HUD_UNIT_Y,0), - Vector3(x + w + HUD_UNIT_X,y,0), - Vector3(x + w,y,0), + Vector3(x + w ,HUD_ZERO_Y+y - HUD_BORDER_HEIGT,0), + Vector3(x + w + HUD_BORDER_WIDTH,HUD_ZERO_Y+y - HUD_BORDER_HEIGT,0), + Vector3(x + w + HUD_BORDER_WIDTH,HUD_ZERO_Y+y,0), + Vector3(x + w ,HUD_ZERO_Y+y,0), //bottom right - Vector3(x + w,1,0), - Vector3(x + w + HUD_UNIT_X,y + h,0), - Vector3(x + w + HUD_UNIT_X,y + h + HUD_UNIT_Y,0), - Vector3(x + w,y + h + HUD_UNIT_Y,0), + Vector3(x + w ,HUD_ZERO_Y+y + h,0), + Vector3(x + w + HUD_BORDER_WIDTH,HUD_ZERO_Y+y + h,0), + Vector3(x + w + HUD_BORDER_WIDTH,HUD_ZERO_Y+y + h + HUD_BORDER_HEIGT,0), + Vector3(x + w ,HUD_ZERO_Y+y + h + HUD_BORDER_HEIGT,0), //bottom left - Vector3(x - HUD_UNIT_X,y + h,0), - Vector3(x,y + h,0), - Vector3(x,y + h + HUD_UNIT_Y,0), - Vector3(x - HUD_UNIT_X,y + h + HUD_UNIT_Y,0) + Vector3(x - HUD_BORDER_WIDTH ,HUD_ZERO_Y+y + h,0), + Vector3(x ,HUD_ZERO_Y+y + h,0), + Vector3(x ,HUD_ZERO_Y+y + h + HUD_BORDER_HEIGT,0), + Vector3(x - HUD_BORDER_WIDTH ,HUD_ZERO_Y+y + h + HUD_BORDER_HEIGT,0) }; array barUVs = { @@ -364,15 +365,27 @@ RendererHUDBar::RendererHUDBar(ID3D11Device* m_device,int x, int y, int w, int h //center 2,7,13,7,8,13 }; - Matrix hudMatrix = Matrix::CreateLookAt(Vector3::Zero, Vector3(0, 0, 1), Vector3(0, -1, 0))* Matrix::CreateOrthographic(REFERENCE_RES_WIDTH, REFERENCE_RES_HEIGHT, -10, 10); - Vector4 vec = XMVector4Transform(Vector4(x + (w / 2.0f), y, 0, 1), hudMatrix); array vertices; for (int i = 0; i < 9; i++) { vertices[i].Position = barVertices[i]; vertices[i].Color = colors[i]; vertices[i].UV = barUVs[i]; + vertices[i].Normal = Vector3(0, 0, 0); + vertices[i].Bone = 0.0f; } - vertexBuffer = VertexBuffer::Create(m_device, vertices.size(), vertices._Elems); - indexBuffer = IndexBuffer::Create(m_device, barIndices.size(), barIndices._Elems); + vertexBuffer = VertexBuffer::Create(m_device, vertices.size(), vertices.data()); + indexBuffer = IndexBuffer::Create(m_device, barIndices.size(), barIndices.data()); + + array verticesBorder; + for (int i = 0; i < barBorderVertices.size(); i++) { + verticesBorder[i].Position = barBorderVertices[i]; + verticesBorder[i].Color = Vector4(1, 1, 1, 1); + verticesBorder[i].UV = barBorderUVs[i]; + verticesBorder[i].Normal = Vector3(0, 0, 0); + verticesBorder[i].Bone = 0.0f; + } + vertexBufferBorder = VertexBuffer::Create(m_device, verticesBorder.size(), verticesBorder.data()); + indexBufferBorder = IndexBuffer::Create(m_device, barBorderIndices.size(), barBorderIndices.data()); + } diff --git a/TR5Main/Renderer/Renderer11.h b/TR5Main/Renderer/Renderer11.h index a0d13651d..03e21b681 100644 --- a/TR5Main/Renderer/Renderer11.h +++ b/TR5Main/Renderer/Renderer11.h @@ -28,9 +28,10 @@ #define DX11_RELEASE(x) if (x != NULL) x->Release() #define DX11_DELETE(x) if (x != NULL) { delete x; x = NULL; } constexpr int REFERENCE_RES_WIDTH = 800; -constexpr int REFERENCE_RES_HEIGHT = 600; +constexpr int REFERENCE_RES_HEIGHT = 450; constexpr float HUD_UNIT_X = 1.0f / REFERENCE_RES_WIDTH; constexpr float HUD_UNIT_Y = 1.0f / REFERENCE_RES_HEIGHT; +constexpr float HUD_ZERO_Y = -REFERENCE_RES_HEIGHT; using namespace DirectX; using namespace DirectX::SimpleMath; using namespace std; @@ -341,8 +342,19 @@ public: }; typedef struct RendererHUDBar { + VertexBuffer* vertexBufferBorder; + IndexBuffer* indexBufferBorder; VertexBuffer* vertexBuffer; IndexBuffer* indexBuffer; + /* + Initialises a new Bar for rendering. the Coordinates are set in the Reference Resolution (default 800x600). + The colors are setup like this + 0-----------1-----------2 + | | | + 3-----------4-----------5 + | | | + 6-----------7-----------8 + */ RendererHUDBar(ID3D11Device* m_device, int x, int y, int w, int h, int borderSize, array colors); }; struct RendererStringToDraw @@ -412,7 +424,8 @@ struct ShaderLight { }; struct CHUDBuffer { - Matrix ViewProjection; + Matrix View; + Matrix Projection; }; struct CCameraMatrixBuffer { @@ -692,7 +705,8 @@ private: ID3D11VertexShader* m_vsShadowMap; ID3D11PixelShader* m_psShadowMap; ID3D11VertexShader* m_vsHUD; - ID3D11PixelShader* m_psHUD; + ID3D11PixelShader* m_psHUDColor; + ID3D11PixelShader* m_psHUDTexture; ID3D11ShaderResourceView* m_shadowMapRV; ID3D11Texture2D* m_shadowMapTexture; @@ -725,6 +739,7 @@ private: PrimitiveBatch* m_primitiveBatch; // System resources + Texture2D* m_HUDBarBorderTexture; Texture2D* m_caustics[NUM_CAUSTICS_TEXTURES]; Texture2D* m_binocularsTexture; Texture2D* m_whiteTexture; diff --git a/TR5Main/Renderer/Renderer11Draw.cpp b/TR5Main/Renderer/Renderer11Draw.cpp index 5d564ff8b..e292ff29f 100644 --- a/TR5Main/Renderer/Renderer11Draw.cpp +++ b/TR5Main/Renderer/Renderer11Draw.cpp @@ -1328,7 +1328,6 @@ bool Renderer11::drawLines2D() m_context->VSSetShader(m_vsSolid, NULL, 0); m_context->PSSetShader(m_psSolid, NULL, 0); - Matrix world = Matrix::CreateOrthographicOffCenter(0, ScreenWidth, ScreenHeight, 0, m_viewport.MinDepth, m_viewport.MaxDepth); m_stCameraMatrices.View = Matrix::Identity; @@ -1782,7 +1781,7 @@ void Renderer11::DrawLoadingScreen(char* fileName) m_context->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); m_swapChain->Present(0, 0); - + m_context->ClearState(); if (m_fadeStatus == RENDERER_FADE_STATUS::FADE_IN && m_fadeFactor >= 1.0f) { m_fadeStatus = RENDERER_FADE_STATUS::NO_FADE; diff --git a/TR5Main/Renderer/Renderer11Draw2D.cpp b/TR5Main/Renderer/Renderer11Draw2D.cpp index fb218c4bf..83d19b92e 100644 --- a/TR5Main/Renderer/Renderer11Draw2D.cpp +++ b/TR5Main/Renderer/Renderer11Draw2D.cpp @@ -20,26 +20,77 @@ bool Renderer11::initialiseBars() Vector4(36 / 255.0f,46 / 255.0f,0,1), Vector4(0,82 / 255.0f,0,1), }; - g_HealthBar = new RendererHUDBar(m_device, 0, 0, 800, 600, 3, healthColors); + + array airColors = { + //top + Vector4(0 ,0,90 / 255.0f,1), + Vector4(0 / 255.0f,28 / 255.0f,84 / 255.0f,1), + Vector4(0 ,47 / 255.0f,96/255.0f,1), + //center + Vector4(0,3 / 255,153 / 255.0f,1), + Vector4(0,39 / 255,155 / 255.0f,1), + Vector4(0,78 / 255.0f,159/255.0f,1), + //bottom + Vector4(0 ,0,90 / 255.0f,1), + Vector4(0 / 255.0f,28 / 255.0f,84 / 255.0f,1), + Vector4(0 ,47 / 255.0f,96 / 255.0f,1), + }; + + array dashColors = { + //top + Vector4(0,0,84/255.0f,1), + Vector4(0,25 / 255.0f,84 / 255.0f,1), + Vector4(0,82 / 255.0f,0,1), + //center + Vector4(159 / 255.0f,159/255.0f,0,1), + Vector4(0,84 / 255,159/255.0f,1), + Vector4(13,134 / 255.0f,1,1), + //bottom + Vector4(0,0,84 / 255.0f,1), + Vector4(0,25/255.0f,84 / 255.0f,1), + Vector4(0,82 / 255.0f,0,1), + }; + + g_HealthBar = new RendererHUDBar(m_device, 20, 32, 150, 8, 2, healthColors); + g_AirBar = new RendererHUDBar(m_device, 630, 32, 150, 8, 2, airColors); + g_DashBar = new RendererHUDBar(m_device, 630, 32+8+4, 150, 8, 2, dashColors); return true; } bool Renderer11::DrawBar(float percent,const RendererHUDBar* const bar) { - UINT strides = 0; + UINT strides = sizeof(RendererVertex); UINT offset = 0; - m_context->ClearDepthStencilView(m_currentRenderTarget->DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + float color[] = { 0,0,0,1.0f }; + m_context->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.0f, 0xFF); + m_context->IASetInputLayout(m_inputLayout); + m_context->IASetVertexBuffers(0, 1, &bar->vertexBufferBorder->Buffer, &strides, &offset); + m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_context->IASetIndexBuffer(bar->indexBufferBorder->Buffer, DXGI_FORMAT_R32_UINT, 0); + m_context->VSSetConstantBuffers(0, 1, &m_cbHUD); + m_context->VSSetShader(m_vsHUD, NULL, 0); + m_context->PSSetShaderResources(0, 1, &m_HUDBarBorderTexture->ShaderResourceView); + ID3D11SamplerState* sampler = m_states->LinearClamp(); + m_context->PSSetSamplers(0, 1, &sampler); + m_context->PSSetShader(m_psHUDTexture, NULL, 0); + m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF); + m_context->OMSetDepthStencilState(m_states->DepthNone(), NULL); + m_context->RSSetState(m_states->CullNone()); + m_context->DrawIndexed(56, 0, 0); + + m_context->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.0f, 0xFF); m_context->IASetInputLayout(m_inputLayout); m_context->IASetVertexBuffers(0, 1, &bar->vertexBuffer->Buffer, &strides, &offset); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - m_context->IASetIndexBuffer(bar->indexBuffer->Buffer, DXGI_FORMAT_R32_SINT, 0); + m_context->IASetIndexBuffer(bar->indexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0); m_context->VSSetConstantBuffers(0, 1, &m_cbHUD); m_context->VSSetShader(m_vsHUD,NULL,0); - m_context->PSSetShader(m_psHUD, NULL,0); + m_context->PSSetShader(m_psHUDColor, NULL,0); m_context->OMSetBlendState(m_states->Opaque(), NULL,0xFFFFFFFF); - m_context->OMSetDepthStencilState(m_states->DepthNone(),0); + m_context->OMSetDepthStencilState(m_states->DepthNone(),NULL); m_context->RSSetState(m_states->CullNone()); m_context->DrawIndexed(24, 0, 0); + return true; } diff --git a/TR5Main/Renderer/Renderer11Init.cpp b/TR5Main/Renderer/Renderer11Init.cpp index 4e0ed3584..192e8cb2c 100644 --- a/TR5Main/Renderer/Renderer11Init.cpp +++ b/TR5Main/Renderer/Renderer11Init.cpp @@ -49,7 +49,9 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h if (m_caustics[i] == NULL) return false; } - + m_HUDBarBorderTexture = Texture2D::LoadFromFile(m_device, "bar_border.png"); + if (!m_HUDBarBorderTexture) + return false; m_titleScreen = Texture2D::LoadFromFile(m_device, (char*)g_GameFlow->GetLevel(0)->Background.c_str()); if (m_titleScreen == NULL) return false; @@ -164,11 +166,14 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h if (m_psShadowMap == NULL) return false; - m_vsHUD = compileVertexShader("Shaders\\DX11_HUD.fx", "VS", "vs_4_0", &blob); + m_vsHUD = compileVertexShader("Shaders\\HUD\\DX11_VS_HUD.hlsl", "VS", "vs_4_0", &blob); if (m_vsHUD == NULL) return false; - m_psHUD = compilePixelShader("Shaders\\DX11_HUD.fx", "PS", "ps_4_0", &blob); - if (m_psHUD == NULL) + m_psHUDColor = compilePixelShader("Shaders\\HUD\\DX11_PS_HUD.hlsl", "PSColored", "ps_4_0", &blob); + if (m_psHUDColor == NULL) + return false; + m_psHUDTexture = compilePixelShader("Shaders\\HUD\\DX11_PS_HUD.hlsl", "PSTextured", "ps_4_0", &blob); + if (m_psHUDTexture == NULL) return false; // Initialise constant buffers @@ -181,7 +186,8 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h m_cbRoom = createConstantBuffer(sizeof(CRoomBuffer)); //Prepare HUD Constant buffer m_cbHUD = createConstantBuffer(sizeof(CHUDBuffer)); - m_stHUD.ViewProjection = Matrix::CreateLookAt(Vector3::Zero, Vector3(0, 0, -1), Vector3(0, -1, 0))* Matrix::CreateOrthographic(REFERENCE_RES_WIDTH, REFERENCE_RES_HEIGHT, -10, 10); + m_stHUD.View = Matrix::CreateLookAt(Vector3::Zero, Vector3(0, 0, 1),Vector3(0,-1,0)).Transpose(); + m_stHUD.Projection = Matrix::CreateOrthographicOffCenter(0, REFERENCE_RES_WIDTH, 0, REFERENCE_RES_HEIGHT, 0, 1.0f).Transpose(); updateConstantBuffer(m_cbHUD, &m_stHUD, sizeof(CHUDBuffer)); m_currentCausticsFrame = 0; m_firstWeather = true; @@ -413,7 +419,7 @@ bool Renderer11::Create() #ifdef _RELEASE res = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, levels, 1, D3D11_SDK_VERSION, &m_device, &featureLevel, &m_context); #else - res = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, levels, 1, D3D11_SDK_VERSION, &m_device, &featureLevel, &m_context); // D3D11_CREATE_DEVICE_DEBUG + res = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_DEBUG, levels, 1, D3D11_SDK_VERSION, &m_device, &featureLevel, &m_context); // D3D11_CREATE_DEVICE_DEBUG #endif if (FAILED(res)) diff --git a/TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl b/TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl index 9a38473d0..a9911cff4 100644 --- a/TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl +++ b/TR5Main/Shaders/HUD/DX11_PS_HUD.hlsl @@ -4,8 +4,16 @@ struct PixelShaderInput float2 UV: TEXCOORD; float4 Color: COLOR; }; +Texture2D Texture : register(t0); +SamplerState Sampler : register(s0); -half4 PS(PixelShaderInput input) : SV_TARGET +half4 PSColored(PixelShaderInput input) : SV_TARGET { return input.Color; +} + +half4 PSTextured(PixelShaderInput input) : SV_TARGET +{ + float4 output = Texture.Sample(Sampler, input.UV); + return output; } \ No newline at end of file diff --git a/TR5Main/Shaders/HUD/DX11_VS_HUD.hlsl b/TR5Main/Shaders/HUD/DX11_VS_HUD.hlsl index 9cd1a10ae..1470c2b2e 100644 --- a/TR5Main/Shaders/HUD/DX11_VS_HUD.hlsl +++ b/TR5Main/Shaders/HUD/DX11_VS_HUD.hlsl @@ -1,6 +1,7 @@ cbuffer HUDBuffer : register(b0) { - float4x4 ViewProjection; + float4x4 View; + float4x4 Projection; }; struct VertexShaderInput @@ -23,7 +24,7 @@ struct PixelShaderInput PixelShaderInput VS(VertexShaderInput input) { PixelShaderInput output; - output.Position = mul(float4(input.Position, 1.0f), ViewProjection); + output.Position = mul(mul(float4(input.Position, 1.0f), View),Projection); output.Color = input.Color; output.UV = input.UV; return output; diff --git a/TR5Main/TR5Main.vcxproj b/TR5Main/TR5Main.vcxproj index e48a0327e..2b3b090c1 100644 --- a/TR5Main/TR5Main.vcxproj +++ b/TR5Main/TR5Main.vcxproj @@ -82,6 +82,7 @@ md "$(TargetDir)\Shaders" xcopy /Y "$(ProjectDir)Shaders\*.fx" "$(TargetDir)\Shaders" +xcopy /Y "$(ProjectDir)Shaders\HUD\*.hlsl" "$(TargetDir)\Shaders\HUD\" md "$(TargetDir)\Scripts" xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts" @@ -629,11 +630,21 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts" - - true + + PS + Pixel + false true Document + + true + true + Document + VS + Vertex + false + diff --git a/TR5Main/TR5Main.vcxproj.filters b/TR5Main/TR5Main.vcxproj.filters index 796e6f9c1..f58a0fecd 100644 --- a/TR5Main/TR5Main.vcxproj.filters +++ b/TR5Main/TR5Main.vcxproj.filters @@ -877,7 +877,7 @@ - + @@ -895,4 +895,7 @@ File di risorse + + + \ No newline at end of file From 82ef1a74cf2cde0483a21560cb336195f999ca7f Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Mon, 13 Jan 2020 00:02:32 +0100 Subject: [PATCH 07/11] Added Percentage to the Bars --- Build/Shaders/HUD/DX11_PS_HUDBar.hlsl | 30 +++++++++++++++++++++++++ TR5Main/Game/healt.cpp | 8 +++---- TR5Main/Game/healt.h | 4 ++-- TR5Main/Renderer/Renderer11.cpp | 2 +- TR5Main/Renderer/Renderer11.h | 6 +++++ TR5Main/Renderer/Renderer11Draw.cpp | 3 ++- TR5Main/Renderer/Renderer11Draw2D.cpp | 12 ++++++---- TR5Main/Renderer/Renderer11Init.cpp | 8 +++++-- TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl | 30 +++++++++++++++++++++++++ TR5Main/TR5Main.vcxproj | 5 +++++ TR5Main/TR5Main.vcxproj.filters | 1 + 11 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 Build/Shaders/HUD/DX11_PS_HUDBar.hlsl create mode 100644 TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl diff --git a/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl b/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl new file mode 100644 index 000000000..59a9c7f97 --- /dev/null +++ b/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl @@ -0,0 +1,30 @@ +cbuffer HUDBarBuffer : register(b0) +{ + float Percent; +}; + +struct PixelShaderInput +{ + float4 Position: SV_POSITION; + float2 UV: TEXCOORD; + float4 Color: COLOR; +}; +Texture2D Texture : register(t0); +SamplerState Sampler : register(s0); + +half4 PSColored(PixelShaderInput input) : SV_TARGET +{ + if (input.UV.x > Percent) { + discard; + } + return input.Color; +} + +half4 PSTextured(PixelShaderInput input) : SV_TARGET +{ + if (input.UV.x > Percent) { + discard; + } + float4 output = Texture.Sample(Sampler, input.UV); + return output; +} \ No newline at end of file diff --git a/TR5Main/Game/healt.cpp b/TR5Main/Game/healt.cpp index d67f0584c..afac264fa 100644 --- a/TR5Main/Game/healt.cpp +++ b/TR5Main/Game/healt.cpp @@ -32,7 +32,7 @@ void DrawHealthBarOverlay(int value) } } -void DrawHealthBar(int value) +void DrawHealthBar(float value) { if (CurrentLevel) { @@ -87,11 +87,11 @@ void UpdateHealtBar(int flash) { if (!BinocularRange && !SniperOverlay) { - DrawHealthBar(hitPoints / 10); + DrawHealthBar(hitPoints / 1000.0f); } else { - DrawHealthBarOverlay(hitPoints / 10); + DrawHealthBarOverlay(hitPoints / 1000.0f); } } @@ -99,7 +99,7 @@ void UpdateHealtBar(int flash) PoisonFlag--; } -void DrawAirBar(int value) +void DrawAirBar(float value) { if (CurrentLevel) { diff --git a/TR5Main/Game/healt.h b/TR5Main/Game/healt.h index 1d3dc0bbf..662c09007 100644 --- a/TR5Main/Game/healt.h +++ b/TR5Main/Game/healt.h @@ -5,9 +5,9 @@ #define MAX_COLLECTED_PICKUPS 32 void DrawHealthBarOverlay(int value); -void DrawHealthBar(int value); +void DrawHealthBar(float value); void UpdateHealtBar(int flash); -void DrawAirBar(int value); +void DrawAirBar(float value); void UpdateAirBar(int flash); void DrawDashBar(int value); void AddDisplayPickup(short objectNumber); diff --git a/TR5Main/Renderer/Renderer11.cpp b/TR5Main/Renderer/Renderer11.cpp index 56cb4443e..a3da80453 100644 --- a/TR5Main/Renderer/Renderer11.cpp +++ b/TR5Main/Renderer/Renderer11.cpp @@ -248,7 +248,7 @@ ID3D11Buffer* Renderer11::createConstantBuffer(int size) D3D11_BUFFER_DESC desc; ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC)); - desc.ByteWidth = ceil(size / 16) * 16; // Constant buffer must have a size multiple of 16 bytes + desc.ByteWidth = ceil(size / 16.0f) * 16; // Constant buffer must have a size multiple of 16 bytes desc.Usage = D3D11_USAGE_DYNAMIC; desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; diff --git a/TR5Main/Renderer/Renderer11.h b/TR5Main/Renderer/Renderer11.h index 03e21b681..dc4aa9ff0 100644 --- a/TR5Main/Renderer/Renderer11.h +++ b/TR5Main/Renderer/Renderer11.h @@ -427,6 +427,9 @@ struct CHUDBuffer { Matrix View; Matrix Projection; }; +struct CHUDBarBuffer { + float Percent; +}; struct CCameraMatrixBuffer { Matrix View; @@ -707,6 +710,7 @@ private: ID3D11VertexShader* m_vsHUD; ID3D11PixelShader* m_psHUDColor; ID3D11PixelShader* m_psHUDTexture; + ID3D11PixelShader* m_psHUDBarColor; ID3D11ShaderResourceView* m_shadowMapRV; ID3D11Texture2D* m_shadowMapTexture; @@ -730,6 +734,8 @@ private: ID3D11Buffer* m_cbShadowMap; CHUDBuffer m_stHUD; ID3D11Buffer* m_cbHUD; + CHUDBarBuffer m_stHUDBar; + ID3D11Buffer* m_cbHUDBar; // Text and sprites SpriteFont* m_gameFont; SpriteBatch* m_spriteBatch; diff --git a/TR5Main/Renderer/Renderer11Draw.cpp b/TR5Main/Renderer/Renderer11Draw.cpp index e292ff29f..d0c0d3743 100644 --- a/TR5Main/Renderer/Renderer11Draw.cpp +++ b/TR5Main/Renderer/Renderer11Draw.cpp @@ -12,6 +12,7 @@ #include "../Game/rope.h" #include "../Game/tomb4fx.h" extern GUNSHELL_STRUCT Gunshells[MAX_GUNSHELL]; +extern RendererHUDBar* g_DashBar; int Renderer11::DrawPickup(short objectNum) { drawObjectOn2DPosition(700 + PickupX, 450, objectNum, 0, m_pickupRotation, 0); // TODO: + PickupY @@ -2023,7 +2024,7 @@ bool Renderer11::drawScene(bool dump) // Bars int flash = FlashIt(); if (DashTimer < 120) - //DrawBar(630, 32, 150, 12, 100 * (unsigned short)DashTimer / 120, 0xA0A000, 0xA000); + DrawBar(DashTimer / 120.0f, g_DashBar); UpdateHealtBar(flash); UpdateAirBar(flash); DrawAllPickups(); diff --git a/TR5Main/Renderer/Renderer11Draw2D.cpp b/TR5Main/Renderer/Renderer11Draw2D.cpp index 83d19b92e..29520cf60 100644 --- a/TR5Main/Renderer/Renderer11Draw2D.cpp +++ b/TR5Main/Renderer/Renderer11Draw2D.cpp @@ -51,9 +51,9 @@ bool Renderer11::initialiseBars() Vector4(0,82 / 255.0f,0,1), }; - g_HealthBar = new RendererHUDBar(m_device, 20, 32, 150, 8, 2, healthColors); - g_AirBar = new RendererHUDBar(m_device, 630, 32, 150, 8, 2, airColors); - g_DashBar = new RendererHUDBar(m_device, 630, 32+8+4, 150, 8, 2, dashColors); + g_HealthBar = new RendererHUDBar(m_device, 20, 32, 150, 8, 1, healthColors); + g_AirBar = new RendererHUDBar(m_device, 630, 32, 150, 8, 1, airColors); + g_DashBar = new RendererHUDBar(m_device, 630, 32+8+4, 150, 8, 1, dashColors); return true; } bool Renderer11::DrawBar(float percent,const RendererHUDBar* const bar) @@ -76,15 +76,19 @@ bool Renderer11::DrawBar(float percent,const RendererHUDBar* const bar) m_context->OMSetDepthStencilState(m_states->DepthNone(), NULL); m_context->RSSetState(m_states->CullNone()); m_context->DrawIndexed(56, 0, 0); + m_context->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.0f, 0xFF); m_context->IASetInputLayout(m_inputLayout); m_context->IASetVertexBuffers(0, 1, &bar->vertexBuffer->Buffer, &strides, &offset); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetIndexBuffer(bar->indexBuffer->Buffer, DXGI_FORMAT_R32_UINT, 0); + m_stHUDBar.Percent = percent; + updateConstantBuffer(m_cbHUDBar, &m_stHUDBar, sizeof(CHUDBarBuffer)); m_context->VSSetConstantBuffers(0, 1, &m_cbHUD); + m_context->PSSetConstantBuffers(0, 1, &m_cbHUDBar); m_context->VSSetShader(m_vsHUD,NULL,0); - m_context->PSSetShader(m_psHUDColor, NULL,0); + m_context->PSSetShader(m_psHUDBarColor, NULL,0); m_context->OMSetBlendState(m_states->Opaque(), NULL,0xFFFFFFFF); m_context->OMSetDepthStencilState(m_states->DepthNone(),NULL); m_context->RSSetState(m_states->CullNone()); diff --git a/TR5Main/Renderer/Renderer11Init.cpp b/TR5Main/Renderer/Renderer11Init.cpp index 192e8cb2c..d60bdc84f 100644 --- a/TR5Main/Renderer/Renderer11Init.cpp +++ b/TR5Main/Renderer/Renderer11Init.cpp @@ -175,6 +175,9 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h m_psHUDTexture = compilePixelShader("Shaders\\HUD\\DX11_PS_HUD.hlsl", "PSTextured", "ps_4_0", &blob); if (m_psHUDTexture == NULL) return false; + m_psHUDBarColor = compilePixelShader("Shaders\\HUD\\DX11_PS_HUDBar.hlsl", "PSColored", "ps_4_0", &blob); + if (m_psHUDBarColor == NULL) + return false; // Initialise constant buffers m_cbCameraMatrices = createConstantBuffer(sizeof(CCameraMatrixBuffer)); @@ -185,9 +188,10 @@ bool Renderer11::Initialise(int w, int h, int refreshRate, bool windowed, HWND h m_cbShadowMap = createConstantBuffer(sizeof(CShadowLightBuffer)); m_cbRoom = createConstantBuffer(sizeof(CRoomBuffer)); //Prepare HUD Constant buffer + m_cbHUDBar = createConstantBuffer(sizeof(CHUDBarBuffer)); m_cbHUD = createConstantBuffer(sizeof(CHUDBuffer)); - m_stHUD.View = Matrix::CreateLookAt(Vector3::Zero, Vector3(0, 0, 1),Vector3(0,-1,0)).Transpose(); - m_stHUD.Projection = Matrix::CreateOrthographicOffCenter(0, REFERENCE_RES_WIDTH, 0, REFERENCE_RES_HEIGHT, 0, 1.0f).Transpose(); + m_stHUD.View = Matrix::CreateLookAt(Vector3::Zero, Vector3(0, 0, 1), Vector3(0, -1, 0)).Transpose(); + m_stHUD.Projection =Matrix::CreateOrthographicOffCenter(0, REFERENCE_RES_WIDTH, 0, REFERENCE_RES_HEIGHT, 0, 1.0f).Transpose(); updateConstantBuffer(m_cbHUD, &m_stHUD, sizeof(CHUDBuffer)); m_currentCausticsFrame = 0; m_firstWeather = true; diff --git a/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl b/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl new file mode 100644 index 000000000..59a9c7f97 --- /dev/null +++ b/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl @@ -0,0 +1,30 @@ +cbuffer HUDBarBuffer : register(b0) +{ + float Percent; +}; + +struct PixelShaderInput +{ + float4 Position: SV_POSITION; + float2 UV: TEXCOORD; + float4 Color: COLOR; +}; +Texture2D Texture : register(t0); +SamplerState Sampler : register(s0); + +half4 PSColored(PixelShaderInput input) : SV_TARGET +{ + if (input.UV.x > Percent) { + discard; + } + return input.Color; +} + +half4 PSTextured(PixelShaderInput input) : SV_TARGET +{ + if (input.UV.x > Percent) { + discard; + } + float4 output = Texture.Sample(Sampler, input.UV); + return output; +} \ No newline at end of file diff --git a/TR5Main/TR5Main.vcxproj b/TR5Main/TR5Main.vcxproj index 2b3b090c1..93080001a 100644 --- a/TR5Main/TR5Main.vcxproj +++ b/TR5Main/TR5Main.vcxproj @@ -637,6 +637,11 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts" true Document + + false + true + Document + true true diff --git a/TR5Main/TR5Main.vcxproj.filters b/TR5Main/TR5Main.vcxproj.filters index f58a0fecd..c62f1023e 100644 --- a/TR5Main/TR5Main.vcxproj.filters +++ b/TR5Main/TR5Main.vcxproj.filters @@ -878,6 +878,7 @@ + From 919025b785d72f73e48f5ae8f705fa9c786064a8 Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Mon, 13 Jan 2020 19:51:08 +0100 Subject: [PATCH 08/11] Added glass overlay for Bar Shader --- Build/Shaders/HUD/DX11_PS_HUDBar.hlsl | 17 ++++++++++++++--- TR5Main/Game/healt.cpp | 4 ++-- TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl | 17 ++++++++++++++--- TR5Main/TR5Main.vcxproj | 2 ++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl b/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl index 59a9c7f97..9260a085e 100644 --- a/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl +++ b/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl @@ -12,12 +12,23 @@ struct PixelShaderInput Texture2D Texture : register(t0); SamplerState Sampler : register(s0); +half4 glassOverlay(float2 UVs, half4 originalColor) { + float y = UVs.y; + y -= 0.15f; + y = distance(0.1f, y); + y = 1 - y; + y = pow(y, 7); + y = saturate(y); + half4 color = originalColor; + return lerp(color, (color * 1.2f)+half4(0.4f, 0.4f, 0.4f, 0.0f), y); +} + half4 PSColored(PixelShaderInput input) : SV_TARGET { if (input.UV.x > Percent) { discard; } - return input.Color; + return glassOverlay(input.UV,input.Color); } half4 PSTextured(PixelShaderInput input) : SV_TARGET @@ -25,6 +36,6 @@ half4 PSTextured(PixelShaderInput input) : SV_TARGET if (input.UV.x > Percent) { discard; } - float4 output = Texture.Sample(Sampler, input.UV); - return output; + float4 color = Texture.Sample(Sampler, input.UV); + return glassOverlay(input.UV, color); } \ No newline at end of file diff --git a/TR5Main/Game/healt.cpp b/TR5Main/Game/healt.cpp index afac264fa..d8470f6db 100644 --- a/TR5Main/Game/healt.cpp +++ b/TR5Main/Game/healt.cpp @@ -68,14 +68,14 @@ void UpdateHealtBar(int flash) if (!BinocularRange) { if (flash) - DrawHealthBar(hitPoints / 10); + DrawHealthBar(hitPoints / 1000.0f); else DrawHealthBar(0); } else { if (flash) - DrawHealthBarOverlay(hitPoints / 10); + DrawHealthBarOverlay(hitPoints / 1000.0f); else DrawHealthBarOverlay(0); } diff --git a/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl b/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl index 59a9c7f97..9260a085e 100644 --- a/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl +++ b/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl @@ -12,12 +12,23 @@ struct PixelShaderInput Texture2D Texture : register(t0); SamplerState Sampler : register(s0); +half4 glassOverlay(float2 UVs, half4 originalColor) { + float y = UVs.y; + y -= 0.15f; + y = distance(0.1f, y); + y = 1 - y; + y = pow(y, 7); + y = saturate(y); + half4 color = originalColor; + return lerp(color, (color * 1.2f)+half4(0.4f, 0.4f, 0.4f, 0.0f), y); +} + half4 PSColored(PixelShaderInput input) : SV_TARGET { if (input.UV.x > Percent) { discard; } - return input.Color; + return glassOverlay(input.UV,input.Color); } half4 PSTextured(PixelShaderInput input) : SV_TARGET @@ -25,6 +36,6 @@ half4 PSTextured(PixelShaderInput input) : SV_TARGET if (input.UV.x > Percent) { discard; } - float4 output = Texture.Sample(Sampler, input.UV); - return output; + float4 color = Texture.Sample(Sampler, input.UV); + return glassOverlay(input.UV, color); } \ No newline at end of file diff --git a/TR5Main/TR5Main.vcxproj b/TR5Main/TR5Main.vcxproj index 93080001a..1ebacddb1 100644 --- a/TR5Main/TR5Main.vcxproj +++ b/TR5Main/TR5Main.vcxproj @@ -641,6 +641,8 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts" false true Document + PSColored + 2.0 true From 73e0c5559fa4bb9ae3d559ef3dec9680dbb0c3e5 Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Mon, 13 Jan 2020 21:00:43 +0100 Subject: [PATCH 09/11] Tweaked glass Overlay, Added colors for dash bar --- Build/Shaders/HUD/DX11_PS_HUDBar.hlsl | 4 ++-- TR5Main/Renderer/Renderer11Draw2D.cpp | 18 +++++++++--------- TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl b/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl index 9260a085e..e856d5e02 100644 --- a/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl +++ b/Build/Shaders/HUD/DX11_PS_HUDBar.hlsl @@ -17,10 +17,10 @@ half4 glassOverlay(float2 UVs, half4 originalColor) { y -= 0.15f; y = distance(0.1f, y); y = 1 - y; - y = pow(y, 7); + y = pow(y, 4); y = saturate(y); half4 color = originalColor; - return lerp(color, (color * 1.2f)+half4(0.4f, 0.4f, 0.4f, 0.0f), y); + return saturate(lerp(color, (color * 1.6f)+half4(0.4f, 0.4f, 0.4f, 0.0f), y)); } half4 PSColored(PixelShaderInput input) : SV_TARGET diff --git a/TR5Main/Renderer/Renderer11Draw2D.cpp b/TR5Main/Renderer/Renderer11Draw2D.cpp index 29520cf60..0bfa4cea5 100644 --- a/TR5Main/Renderer/Renderer11Draw2D.cpp +++ b/TR5Main/Renderer/Renderer11Draw2D.cpp @@ -38,17 +38,17 @@ bool Renderer11::initialiseBars() array dashColors = { //top - Vector4(0,0,84/255.0f,1), - Vector4(0,25 / 255.0f,84 / 255.0f,1), - Vector4(0,82 / 255.0f,0,1), + Vector4(78/255.0f,4/255.0f,0,1), + Vector4(161/255.0f,25 / 255.0f,84 / 255.0f,1), + Vector4(136 / 255.0f,117 / 255.0f,5 / 255.0f,1), //center - Vector4(159 / 255.0f,159/255.0f,0,1), - Vector4(0,84 / 255,159/255.0f,1), - Vector4(13,134 / 255.0f,1,1), + Vector4(211 / 255.0f,29/255.0f,23/255.0f,1), + Vector4(245/255.0f,119 / 255,24/255.0f,1), + Vector4(207/255.0f,183 / 255.0f,27/255.0f,1), //bottom - Vector4(0,0,84 / 255.0f,1), - Vector4(0,25/255.0f,84 / 255.0f,1), - Vector4(0,82 / 255.0f,0,1), + Vector4(78 / 255.0f,4 / 255.0f,0,1), + Vector4(161 / 255.0f,25 / 255.0f,84 / 255.0f,1), + Vector4(136/255.0f,117 / 255.0f,5/255.0f,1), }; g_HealthBar = new RendererHUDBar(m_device, 20, 32, 150, 8, 1, healthColors); diff --git a/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl b/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl index 9260a085e..e856d5e02 100644 --- a/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl +++ b/TR5Main/Shaders/HUD/DX11_PS_HUDBar.hlsl @@ -17,10 +17,10 @@ half4 glassOverlay(float2 UVs, half4 originalColor) { y -= 0.15f; y = distance(0.1f, y); y = 1 - y; - y = pow(y, 7); + y = pow(y, 4); y = saturate(y); half4 color = originalColor; - return lerp(color, (color * 1.2f)+half4(0.4f, 0.4f, 0.4f, 0.0f), y); + return saturate(lerp(color, (color * 1.6f)+half4(0.4f, 0.4f, 0.4f, 0.0f), y)); } half4 PSColored(PixelShaderInput input) : SV_TARGET From ee6be6d9e6e01a85262f6d973b682a6c2cdb57ee Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Tue, 14 Jan 2020 17:02:27 +0100 Subject: [PATCH 10/11] Fixed Gunflashes --- TR5Main/Renderer/Renderer11DrawEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TR5Main/Renderer/Renderer11DrawEffect.cpp b/TR5Main/Renderer/Renderer11DrawEffect.cpp index 9c68d2b13..06e593a6c 100644 --- a/TR5Main/Renderer/Renderer11DrawEffect.cpp +++ b/TR5Main/Renderer/Renderer11DrawEffect.cpp @@ -321,7 +321,7 @@ bool Renderer11::drawGunFlashes() short rotationX = 0; m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF); - m_context->OMSetDepthStencilState(m_states->DepthNone(), 0); + m_context->OMSetDepthStencilState(m_states->DepthRead(), 0); if (Lara.weaponItem != WEAPON_FLARE && Lara.weaponItem != WEAPON_SHOTGUN && Lara.weaponItem != WEAPON_CROSSBOW) { From 1ce73156293a78d1bd2583d6a4c4ee3b1abfddec Mon Sep 17 00:00:00 2001 From: Nils Gaitzsch Date: Tue, 14 Jan 2020 17:58:07 +0100 Subject: [PATCH 11/11] Added Music and Sound Volume Bars. TODO: Method to manually set the Position at runtime --- TR5Main/Renderer/Renderer11Draw.cpp | 9 +++++--- TR5Main/Renderer/Renderer11Draw2D.cpp | 33 ++++++++++++++++++++------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/TR5Main/Renderer/Renderer11Draw.cpp b/TR5Main/Renderer/Renderer11Draw.cpp index d0c0d3743..63f1b1d8a 100644 --- a/TR5Main/Renderer/Renderer11Draw.cpp +++ b/TR5Main/Renderer/Renderer11Draw.cpp @@ -13,6 +13,8 @@ #include "../Game/tomb4fx.h" extern GUNSHELL_STRUCT Gunshells[MAX_GUNSHELL]; extern RendererHUDBar* g_DashBar; +extern RendererHUDBar* g_SFXVolumeBar; +extern RendererHUDBar* g_MusicVolumeBar; int Renderer11::DrawPickup(short objectNum) { drawObjectOn2DPosition(700 + PickupX, 450, objectNum, 0, m_pickupRotation, 0); // TODO: + PickupY @@ -849,6 +851,7 @@ int Renderer11::drawInventoryScene() PRINTSTRING_COLOR_ORANGE, PRINTSTRING_OUTLINE | (ring->selectedIndex == 2 ? PRINTSTRING_BLINK : 0)); //DrawBar(400, y + 4, 150, 18, ring->Configuration.MusicVolume, 0x0000FF, 0x0000FF); + DrawBar(ring->Configuration.MusicVolume / 100.0f, g_MusicVolumeBar); y += 25; @@ -857,7 +860,7 @@ int Renderer11::drawInventoryScene() PRINTSTRING_COLOR_ORANGE, PRINTSTRING_OUTLINE | (ring->selectedIndex == 3 ? PRINTSTRING_BLINK : 0)); //DrawBar(400, y + 4, 150, 18, ring->Configuration.SfxVolume, 0x0000FF, 0x0000FF); - + DrawBar(ring->Configuration.SfxVolume / 100.0f, g_SFXVolumeBar); y += 25; // Apply and cancel @@ -1100,8 +1103,8 @@ int Renderer11::drawInventoryScene() if (g_Inventory->GetType() == INV_TYPE_TITLE && g_GameFlow->TitleType == TITLE_FLYBY && drawLogo) { // Draw main logo - float factorX = ScreenWidth / 800.0f; - float factorY = ScreenHeight / 600.0f; + float factorX = (float)ScreenWidth / REFERENCE_RES_WIDTH; + float factorY = (float)ScreenHeight / REFERENCE_RES_HEIGHT; RECT rect; rect.left = 250 * factorX; diff --git a/TR5Main/Renderer/Renderer11Draw2D.cpp b/TR5Main/Renderer/Renderer11Draw2D.cpp index 0bfa4cea5..1e61aa718 100644 --- a/TR5Main/Renderer/Renderer11Draw2D.cpp +++ b/TR5Main/Renderer/Renderer11Draw2D.cpp @@ -3,6 +3,8 @@ RendererHUDBar* g_HealthBar; RendererHUDBar* g_AirBar; RendererHUDBar* g_DashBar; +RendererHUDBar* g_MusicVolumeBar; +RendererHUDBar* g_SFXVolumeBar; bool Renderer11::initialiseBars() { @@ -38,22 +40,37 @@ bool Renderer11::initialiseBars() array dashColors = { //top - Vector4(78/255.0f,4/255.0f,0,1), - Vector4(161/255.0f,25 / 255.0f,84 / 255.0f,1), + Vector4(78 / 255.0f,4 / 255.0f,0,1), + Vector4(161 / 255.0f,25 / 255.0f,84 / 255.0f,1), Vector4(136 / 255.0f,117 / 255.0f,5 / 255.0f,1), //center - Vector4(211 / 255.0f,29/255.0f,23/255.0f,1), - Vector4(245/255.0f,119 / 255,24/255.0f,1), - Vector4(207/255.0f,183 / 255.0f,27/255.0f,1), + Vector4(211 / 255.0f,29 / 255.0f,23 / 255.0f,1), + Vector4(245 / 255.0f,119 / 255,24 / 255.0f,1), + Vector4(207 / 255.0f,183 / 255.0f,27 / 255.0f,1), //bottom Vector4(78 / 255.0f,4 / 255.0f,0,1), Vector4(161 / 255.0f,25 / 255.0f,84 / 255.0f,1), - Vector4(136/255.0f,117 / 255.0f,5/255.0f,1), + Vector4(136 / 255.0f,117 / 255.0f,5 / 255.0f,1), + }; + array soundSettingColors = { + //top + Vector4(0.18f,0.3f,0.72f,1), + Vector4(0.18f,0.3f,0.72f,1), + Vector4(0.18f,0.3f,0.72f,1), + //center + Vector4(0.18f,0.3f,0.72f,1), + Vector4(0.18f,0.3f,0.72f,1), + Vector4(0.18f,0.3f,0.72f,1), + //bottom + Vector4(0.18f,0.3f,0.72f,1), + Vector4(0.18f,0.3f,0.72f,1), + Vector4(0.18f,0.3f,0.72f,1), }; - g_HealthBar = new RendererHUDBar(m_device, 20, 32, 150, 8, 1, healthColors); g_AirBar = new RendererHUDBar(m_device, 630, 32, 150, 8, 1, airColors); - g_DashBar = new RendererHUDBar(m_device, 630, 32+8+4, 150, 8, 1, dashColors); + g_DashBar = new RendererHUDBar(m_device, 630, 32 + 8 + 4, 150, 8, 1, dashColors); + g_MusicVolumeBar = new RendererHUDBar(m_device, 400, 212, 150, 8, 1, soundSettingColors); + g_SFXVolumeBar = new RendererHUDBar(m_device, 400, 230, 150, 8, 1, soundSettingColors); return true; } bool Renderer11::DrawBar(float percent,const RendererHUDBar* const bar)