diff --git a/TombEngine/Game/control/control.cpp b/TombEngine/Game/control/control.cpp index e1bd97d1db..24bd07b048 100644 --- a/TombEngine/Game/control/control.cpp +++ b/TombEngine/Game/control/control.cpp @@ -45,6 +45,7 @@ #include "Objects/Generic/Object/rope.h" #include "Objects/Generic/Switches/generic_switch.h" #include "Objects/TR3/Entity/FishSwarm.h" +#include "Objects/TR3/Emitter/tr3_bats_emitter.h" #include "Objects/TR4/Entity/tr4_beetle_swarm.h" #include "Objects/TR4/Entity/Locust.h" #include "Objects/TR5/Emitter/tr5_bats_emitter.h" @@ -87,6 +88,7 @@ using namespace TEN::Entities::Effects; using namespace TEN::Entities::Generic; using namespace TEN::Entities::Switches; using namespace TEN::Entities::Traps; +using namespace TEN::Entities::TR3; using namespace TEN::Entities::TR4; using namespace TEN::Collision::Floordata; using namespace TEN::Control::Volumes; @@ -212,6 +214,7 @@ GameStatus GamePhase(bool insideMenu) UpdateRats(); UpdateRipples(); UpdateBats(); + UpdateTr3Bats(); UpdateSpiders(); UpdateSparkParticles(); UpdateSmokeParticles(); diff --git a/TombEngine/Objects/TR3/Emitter/tr3_bats_emitter.cpp b/TombEngine/Objects/TR3/Emitter/tr3_bats_emitter.cpp new file mode 100644 index 0000000000..a9c1dcb8e6 --- /dev/null +++ b/TombEngine/Objects/TR3/Emitter/tr3_bats_emitter.cpp @@ -0,0 +1,265 @@ +#include "framework.h" +#include "Objects/TR3/Emitter/tr3_bats_emitter.h" + +#include "Game/collision/collide_room.h" +#include "Game/control/control.h" +#include "Game/effects/effects.h" +#include "Game/items.h" +#include "Renderer/Structures/RendererSpriteToDraw.h" +#include "Game/Setup.h" +#include "Sound/sound.h" +#include "Specific/level.h" + +namespace TEN::Entities::TR3 +{ + using namespace TEN::Renderer::Structures; + + constexpr auto TR3_BAT_SPRITE_ID = 3; + constexpr auto TR3_BAT_LIFE_MIN = 144; + constexpr auto TR3_BAT_SPEED_MIN = 64; + constexpr auto TR3_BAT_SPEED_MAX = 300; + constexpr auto TR3_BAT_SPEED_ACCEL = 12; + constexpr auto TR3_BAT_SPEED_DIVISOR = 6; + constexpr auto TR3_BAT_BODY_WING_AMPLITUDE = 16.0f; + constexpr auto TR3_BAT_OUTER_WING_AMPLITUDE = 256.0f; + + constexpr std::array TR3_BAT_MESH = + { + Vector3(-192.0f, 0.0f, -48.0f), + Vector3(-192.0f, 0.0f, 48.0f), + Vector3(96.0f, 0.0f, 0.0f), + Vector3(-144.0f, 0.0f, -192.0f), + Vector3(-144.0f, 0.0f, 192.0f) + }; + + constexpr std::array, 3> TR3_BAT_TRIANGLES = + { { + { 0, 1, 2 }, + { 3, 0, 2 }, + { 1, 4, 2 } + } }; + + constexpr std::array, 3> TR3_BAT_TRIANGLE_UV = + { { + { 0, 2, 3 }, + { 1, 0, 2 }, + { 0, 1, 2 } + } }; + + Tr3BatData Tr3Bats[NUM_TR3_BATS]; + + static void ResetTr3BatInterpolationData(Tr3BatData& bat) + { + bat.PrevPosition = bat.Pose.Position; + bat.PrevWingYoff = bat.WingYoff; + } + + void ClearTr3Bats() + { + for (auto& bat : Tr3Bats) + { + bat = {}; + bat.RoomNumber = NO_VALUE; + ResetTr3BatInterpolationData(bat); + } + } + + void InitializeTr3BatsEmitter(short itemNumber) + { + auto& item = g_Level.Items[itemNumber]; + + item.TriggerFlags = 0; + + if (Objects[ID_TR3_BATS_EMITTER].loaded) + ClearTr3Bats(); + } + + void TriggerTr3Bats(ItemInfo* item) + { + short angle = ((item->Pose.Orientation.y >> 4) - 1024) & 0xFFF; + + for (int i = 0; i < NUM_TR3_BATS; i++) + { + auto& bat = Tr3Bats[i]; + + bat.RoomNumber = item->RoomNumber; + bat.Pose.Position.x = (GetRandomControl() & 0x1FF) + item->Pose.Position.x - 256; + bat.Pose.Position.y = item->Pose.Position.y - (GetRandomControl() & 0xFF) + 256; + bat.Pose.Position.z = (GetRandomControl() & 0x1FF) + item->Pose.Position.z - 256; + bat.Pose.Orientation.x = 0; + bat.Pose.Orientation.y = (((GetRandomControl() & 0x7F) + angle - 64) & 0xFFF) << 4; + bat.Pose.Orientation.z = 0; + bat.Velocity = (GetRandomControl() & 0x1F) + TR3_BAT_SPEED_MIN; + bat.Counter = (GetRandomControl() & 7) + TR3_BAT_LIFE_MIN; + bat.WingYoff = GetRandomControl() & 0x3F; + bat.On = true; + ResetTr3BatInterpolationData(bat); + } + } + + void Tr3BatsEmitterControl(short itemNumber) + { + auto& item = g_Level.Items[itemNumber]; + + if (!TriggerActive(&item)) + return; + + TriggerTr3Bats(&item); + KillItem(itemNumber); + } + + void UpdateTr3Bats() + { + if (!Objects[ID_TR3_BATS_EMITTER].loaded) + return; + + for (int i = 0; i < NUM_TR3_BATS; i++) + { + auto& bat = Tr3Bats[i]; + + if (!bat.On) + continue; + + bat.StoreInterpolationData(); + + if (!(i & 3) && !(GetRandomControl() & 7)) + SoundEffect(SFX_TR4_BATS, &bat.Pose); + + int velocity = bat.Velocity / TR3_BAT_SPEED_DIVISOR; + + bat.Pose.Position.x -= velocity * phd_cos(bat.Pose.Orientation.y); + bat.Pose.Position.y -= GetRandomControl() & 3; + bat.Pose.Position.z += velocity * phd_sin(bat.Pose.Orientation.y); + bat.WingYoff = (bat.WingYoff + 11) & 0x3F; + + if (bat.Counter < 128) + { + bat.Pose.Position.y += -4 - (i >> 1); + + if (!(GetRandomControl() & 3)) + { + bat.Pose.Orientation.y += ((GetRandomControl() & 0xFF) - 128) << 4; + bat.Velocity += GetRandomControl() & 3; + } + } + + bat.Velocity += TR3_BAT_SPEED_ACCEL; + + if (bat.Velocity > TR3_BAT_SPEED_MAX) + bat.Velocity = TR3_BAT_SPEED_MAX; + + if (bat.Counter && (Wibble & 4)) + { + bat.Counter--; + + if (!bat.Counter) + bat.On = false; + } + + GetFloor(bat.Pose.Position.x, bat.Pose.Position.y, bat.Pose.Position.z, &bat.RoomNumber); + } + } + + int GetTr3BatSpriteId() + { + return TR3_BAT_SPRITE_ID; + } + + static void MatchOriginalDoubleSidedWinding(RendererSpriteToDraw& batSprite, const Matrix& viewProjection) + { + auto projected0 = Vector4::Transform(Vector4(batSprite.vtx1.x, batSprite.vtx1.y, batSprite.vtx1.z, 1.0f), viewProjection); + auto projected1 = Vector4::Transform(Vector4(batSprite.vtx2.x, batSprite.vtx2.y, batSprite.vtx2.z, 1.0f), viewProjection); + auto projected2 = Vector4::Transform(Vector4(batSprite.vtx3.x, batSprite.vtx3.y, batSprite.vtx3.z, 1.0f), viewProjection); + + if (projected0.w == 0.0f || projected1.w == 0.0f || projected2.w == 0.0f) + return; + + projected0.x /= projected0.w; + projected0.y /= projected0.w; + projected1.x /= projected1.w; + projected1.y /= projected1.w; + projected2.x /= projected2.w; + projected2.y /= projected2.w; + + float winding = + (projected2.x - projected1.x) * (projected0.y - projected1.y) - + (projected0.x - projected1.x) * (projected2.y - projected1.y); + + if (winding >= 0.0f) + return; + + std::swap(batSprite.vtx2, batSprite.vtx3); + std::swap(batSprite.CustomUV[1], batSprite.CustomUV[2]); + batSprite.vtx4 = batSprite.vtx3; + batSprite.CustomUV[3] = batSprite.CustomUV[2]; + } + + void AddTr3BatSpritesToDraw( + std::vector& spritesToDraw, + RendererSprite* sprite, + const Tr3BatData& bat, + const Vector4& ambient, + const Matrix& viewProjection, + float interpolationFactor) + { + auto pos = Vector3::Lerp( + bat.PrevPosition.ToVector3(), + bat.Pose.Position.ToVector3(), + interpolationFactor); + + float prevWing = (float)bat.PrevWingYoff; + float currWing = (float)bat.WingYoff; + + if (currWing < prevWing) + currWing += 64.0f; + + float wing = fmod(Vector2::Lerp(Vector2(prevWing, 0.0f), Vector2(currWing, 0.0f), interpolationFactor).x, 64.0f); + float bodyWing = fmod(wing - 32.0f + 64.0f, 64.0f); + float bodyYOffset = sin((bodyWing / 64.0f) * PI_MUL_2) * TR3_BAT_BODY_WING_AMPLITUDE - 512.0f; + float outerWingYOffset = sin((wing / 64.0f) * PI_MUL_2) * TR3_BAT_OUTER_WING_AMPLITUDE - 512.0f; + auto transform = bat.Pose.Orientation.ToRotationMatrix() * Matrix::CreateTranslation(pos); + auto batColor = Vector4(ambient.x, ambient.y, ambient.z, 1.0f); + std::array vertices = {}; + + for (int i = 0; i < TR3_BAT_MESH.size(); i++) + { + auto vertex = TR3_BAT_MESH[i]; + + if (i < 3) + vertex.y += bodyYOffset; + else + vertex.y += outerWingYOffset; + + vertices[i] = Vector3::Transform(vertex, transform); + } + + for (int i = 0; i < TR3_BAT_TRIANGLES.size(); i++) + { + const auto& tri = TR3_BAT_TRIANGLES[i]; + const auto& uv = TR3_BAT_TRIANGLE_UV[i]; + auto batSprite = RendererSpriteToDraw{}; + + batSprite.Type = SpriteType::ThreeD; + batSprite.Sprite = sprite; + batSprite.vtx1 = vertices[tri[0]]; + batSprite.vtx2 = vertices[tri[1]]; + batSprite.vtx3 = vertices[tri[2]]; + batSprite.vtx4 = vertices[tri[2]]; + batSprite.c1 = batColor; + batSprite.c2 = batColor; + batSprite.c3 = batColor; + batSprite.c4 = batColor; + batSprite.CustomUV[0] = sprite->UV[uv[0]]; + batSprite.CustomUV[1] = sprite->UV[uv[1]]; + batSprite.CustomUV[2] = sprite->UV[uv[2]]; + batSprite.CustomUV[3] = sprite->UV[uv[2]]; + batSprite.BlendMode = BlendMode::AlphaBlend; + batSprite.pos = (batSprite.vtx1 + batSprite.vtx2 + batSprite.vtx3) / 3.0f; + batSprite.SoftParticle = true; + batSprite.UseCustomUV = true; + + MatchOriginalDoubleSidedWinding(batSprite, viewProjection); + spritesToDraw.push_back(batSprite); + } + } +} diff --git a/TombEngine/Objects/TR3/Emitter/tr3_bats_emitter.h b/TombEngine/Objects/TR3/Emitter/tr3_bats_emitter.h new file mode 100644 index 0000000000..2fb927743a --- /dev/null +++ b/TombEngine/Objects/TR3/Emitter/tr3_bats_emitter.h @@ -0,0 +1,51 @@ +#pragma once +#include + +#include "Game/items.h" + +namespace TEN::Renderer::Structures +{ + struct RendererSprite; + struct RendererSpriteToDraw; +} + +namespace TEN::Entities::TR3 +{ + constexpr auto NUM_TR3_BATS = 32; + + struct Tr3BatData + { + bool On = false; + Pose Pose = {}; + Vector3i PrevPosition = Vector3i::Zero; + short RoomNumber = NO_VALUE; + + short Velocity = 0; + short Counter = 0; + short WingYoff = 0; + short PrevWingYoff = 0; + + void StoreInterpolationData() + { + PrevPosition = Pose.Position; + PrevWingYoff = WingYoff; + } + }; + + extern Tr3BatData Tr3Bats[NUM_TR3_BATS]; + + void ClearTr3Bats(); + void InitializeTr3BatsEmitter(short itemNumber); + void Tr3BatsEmitterControl(short itemNumber); + void TriggerTr3Bats(ItemInfo* item); + void UpdateTr3Bats(); + + int GetTr3BatSpriteId(); + void AddTr3BatSpritesToDraw( + std::vector& spritesToDraw, + TEN::Renderer::Structures::RendererSprite* sprite, + const Tr3BatData& bat, + const Vector4& ambient, + const Matrix& viewProjection, + float interpolationFactor); +} diff --git a/TombEngine/Objects/TR3/tr3_objects.cpp b/TombEngine/Objects/TR3/tr3_objects.cpp index 64ae51de02..a0ea4557c2 100644 --- a/TombEngine/Objects/TR3/tr3_objects.cpp +++ b/TombEngine/Objects/TR3/tr3_objects.cpp @@ -32,6 +32,7 @@ #include "Objects/TR3/Entity/tr3_tiger.h" #include "Objects/TR3/Entity/tr3_trex.h" #include "Objects/TR3/Entity/tr3_tribesman.h" +#include "Objects/TR3/Emitter/tr3_bats_emitter.h" // Effects #include "Objects/Effects/Boss.h" @@ -500,6 +501,17 @@ static void StartObject(ObjectInfo* obj) } } +static void StartEmitter(ObjectInfo* obj) +{ + obj = &Objects[ID_TR3_BATS_EMITTER]; + if (obj->loaded) + { + obj->Hidden = true; + obj->Initialize = InitializeTr3BatsEmitter; + obj->control = Tr3BatsEmitterControl; + } +} + static void StartTrap(ObjectInfo* obj) { obj = &Objects[ID_TRAIN]; @@ -662,6 +674,7 @@ void InitializeTR3Objects() ObjectInfo* objectPtr = nullptr; StartEntity(objectPtr); StartObject(objectPtr); + StartEmitter(objectPtr); StartTrap(objectPtr); StartVehicles(objectPtr); StartProjectiles(objectPtr); diff --git a/TombEngine/Objects/game_object_ids.h b/TombEngine/Objects/game_object_ids.h index 8ea73088c3..fb16559d56 100644 --- a/TombEngine/Objects/game_object_ids.h +++ b/TombEngine/Objects/game_object_ids.h @@ -157,6 +157,7 @@ enum GAME_OBJECT_ID : short ID_CYBORG, ID_SNIPER, ID_CHEF, + ID_TR3_BATS_EMITTER = 198, ID_KOLD = 219, ID_WINGED_MUMMY, diff --git a/TombEngine/Renderer/Renderer.h b/TombEngine/Renderer/Renderer.h index b7ac436078..be5de72fba 100644 --- a/TombEngine/Renderer/Renderer.h +++ b/TombEngine/Renderer/Renderer.h @@ -428,6 +428,7 @@ namespace TEN::Renderer void PrepareRopes(RenderView& view); void DrawFishSwarm(RenderView& view, RendererPass rendererPass); void DrawBats(RenderView& view, RendererPass rendererPass); + void PrepareTr3Bats(RenderView& view); void DrawRats(RenderView& view, RendererPass rendererPass); void DrawScarabs(RenderView& view, RendererPass rendererPass); void DrawSpiders(RenderView& view, RendererPass rendererPass); @@ -781,4 +782,4 @@ namespace TEN::Renderer }; extern Renderer g_Renderer; -} \ No newline at end of file +} diff --git a/TombEngine/Renderer/RendererDraw.cpp b/TombEngine/Renderer/RendererDraw.cpp index 062280f969..4e3f9e9066 100644 --- a/TombEngine/Renderer/RendererDraw.cpp +++ b/TombEngine/Renderer/RendererDraw.cpp @@ -22,10 +22,12 @@ #include "Game/Setup.h" #include "Objects/Generic/Object/rope.h" #include "Objects/TR3/Entity/FishSwarm.h" +#include "Objects/TR3/Emitter/tr3_bats_emitter.h" #include "Objects/TR4/Entity/tr4_beetle_swarm.h" #include "Objects/TR4/Entity/Locust.h" #include "Objects/TR5/Emitter/tr5_bats_emitter.h" #include "Objects/TR5/Emitter/tr5_rats_emitter.h" +#include "Objects/Utils/object_helper.h" #include "Renderer/RenderView.h" #include "Renderer/Renderer.h" #include "Renderer/Structures/RendererSortableObject.h" @@ -895,6 +897,42 @@ namespace TEN::Renderer } } + void Renderer::PrepareTr3Bats(RenderView& view) + { + if (!Objects[ID_TR3_BATS_EMITTER].loaded) + return; + + if (!CheckIfSlotExists(ID_MISC_SPRITES, "TR3 bats rendering")) + return; + + int spriteIndex = Objects[ID_MISC_SPRITES].meshIndex + TEN::Entities::TR3::GetTr3BatSpriteId(); + + if (spriteIndex < 0 || spriteIndex >= (int)_sprites.size()) + return; + + auto* sprite = &_sprites[spriteIndex]; + float interpolationFactor = GetInterpolationFactor(); + + view.SpritesToDraw.reserve(view.SpritesToDraw.size() + TEN::Entities::TR3::NUM_TR3_BATS * 3); + + for (const auto& bat : TEN::Entities::TR3::Tr3Bats) + { + if (!bat.On) + continue; + + if (IgnoreReflectionPassForRoom(bat.RoomNumber)) + continue; + + TEN::Entities::TR3::AddTr3BatSpritesToDraw( + view.SpritesToDraw, + sprite, + bat, + _rooms[bat.RoomNumber].AmbientLight, + view.Camera.ViewProjection, + interpolationFactor); + } + } + void Renderer::DrawScarabs(RenderView& view, RendererPass rendererPass) { if (!Objects[ID_LITTLE_BEETLE].loaded) @@ -1851,6 +1889,7 @@ namespace TEN::Renderer PrepareLaserBarriers(view); PrepareSingleLaserBeam(view); PrepareFireflies(view); + PrepareTr3Bats(view); // Sprites grouped in buckets for instancing. Non-commutative sprites are collected at a later stage. SortAndPrepareSprites(view); @@ -3763,10 +3802,10 @@ namespace TEN::Renderer p3t = Vector3(-0.5, -0.5, 0); } - uv0 = spr->Sprite->UV[0]; - uv1 = spr->Sprite->UV[1]; - uv2 = spr->Sprite->UV[2]; - uv3 = spr->Sprite->UV[3]; + uv0 = spr->UseCustomUV ? spr->CustomUV[0] : spr->Sprite->UV[0]; + uv1 = spr->UseCustomUV ? spr->CustomUV[1] : spr->Sprite->UV[1]; + uv2 = spr->UseCustomUV ? spr->CustomUV[2] : spr->Sprite->UV[2]; + uv3 = spr->UseCustomUV ? spr->CustomUV[3] : spr->Sprite->UV[3]; auto world = GetWorldMatrixForSprite(*currentObject->Sprite, view); diff --git a/TombEngine/Renderer/RendererSprites.cpp b/TombEngine/Renderer/RendererSprites.cpp index d7bbf7ae1d..1c1bc9cbb1 100644 --- a/TombEngine/Renderer/RendererSprites.cpp +++ b/TombEngine/Renderer/RendererSprites.cpp @@ -338,7 +338,7 @@ namespace TEN::Renderer _stInstancedSpriteBuffer.Sprites[0].IsSoftParticle = spriteBucket.IsSoftParticle ? 1.0f : 0.0f; _stInstancedSpriteBuffer.Sprites[0].RenderType = (int)spriteBucket.RenderType; - _stInstancedSpriteBuffer.Sprites[0].PerVertexColor = 1; + _stInstancedSpriteBuffer.Sprites[0].PerVertexColor = spriteBucket.SpritesToDraw[0].UseCustomUV ? 2 : 1; _stInstancedSpriteBuffer.Sprites[0].IsSoftParticle = spriteBucket.IsSoftParticle ? 1.0f : 0.0f; PackSpriteTextureCoordinates(0, spriteBucket.Sprite); @@ -353,7 +353,7 @@ namespace TEN::Renderer { auto vertex0 = Vertex{}; vertex0.Position = rDrawSprite.vtx1; - vertex0.UV = rDrawSprite.Sprite->UV[0]; + vertex0.UV = rDrawSprite.UseCustomUV ? rDrawSprite.CustomUV[0] : rDrawSprite.Sprite->UV[0]; vertex0.Color = VectorColorToRGBA(rDrawSprite.c1); vertex0.Effects = 0 << INDEX_IN_POLY_VERTEX_SHIFT; @@ -361,7 +361,7 @@ namespace TEN::Renderer auto vertex1 = Vertex{}; vertex1.Position = rDrawSprite.vtx2; - vertex1.UV = rDrawSprite.Sprite->UV[1]; + vertex1.UV = rDrawSprite.UseCustomUV ? rDrawSprite.CustomUV[1] : rDrawSprite.Sprite->UV[1]; vertex1.Color = VectorColorToRGBA(rDrawSprite.c2); vertex1.Effects = 1 << INDEX_IN_POLY_VERTEX_SHIFT; @@ -369,7 +369,7 @@ namespace TEN::Renderer auto vertex2 = Vertex{}; vertex2.Position = rDrawSprite.vtx3; - vertex2.UV = rDrawSprite.Sprite->UV[2]; + vertex2.UV = rDrawSprite.UseCustomUV ? rDrawSprite.CustomUV[2] : rDrawSprite.Sprite->UV[2]; vertex2.Color = VectorColorToRGBA(rDrawSprite.c3); vertex2.Effects = 2 << INDEX_IN_POLY_VERTEX_SHIFT; @@ -377,7 +377,7 @@ namespace TEN::Renderer auto vertex3 = Vertex{}; vertex3.Position = rDrawSprite.vtx4; - vertex3.UV = rDrawSprite.Sprite->UV[3]; + vertex3.UV = rDrawSprite.UseCustomUV ? rDrawSprite.CustomUV[3] : rDrawSprite.Sprite->UV[3]; vertex3.Color = VectorColorToRGBA(rDrawSprite.c4); vertex3.Effects = 3 << INDEX_IN_POLY_VERTEX_SHIFT; @@ -426,7 +426,7 @@ namespace TEN::Renderer _stInstancedSpriteBuffer.Sprites[0].World = object->Sprite->Type != SpriteType::ThreeD ? GetWorldMatrixForSprite(*object->Sprite, view) : Matrix::Identity; - _stInstancedSpriteBuffer.Sprites[0].PerVertexColor = 1; + _stInstancedSpriteBuffer.Sprites[0].PerVertexColor = object->Sprite->Type != SpriteType::ThreeD ? 0 : (object->Sprite->UseCustomUV ? 2 : 1); _stInstancedSpriteBuffer.Sprites[0].IsSoftParticle = object->Sprite->SoftParticle ? 1 : 0; _stInstancedSpriteBuffer.Sprites[0].RenderType = (int)object->Sprite->renderType; @@ -445,25 +445,25 @@ namespace TEN::Renderer { auto vertex0 = Vertex{}; vertex0.Position = object->Sprite->vtx1; - vertex0.UV = object->Sprite->Sprite->UV[0]; + vertex0.UV = object->Sprite->UseCustomUV ? object->Sprite->CustomUV[0] : object->Sprite->Sprite->UV[0]; vertex0.Color = VectorColorToRGBA(object->Sprite->c1); vertex0.Effects = 0 << INDEX_IN_POLY_VERTEX_SHIFT; auto vertex1 = Vertex{}; vertex1.Position = object->Sprite->vtx2; - vertex1.UV = object->Sprite->Sprite->UV[1]; + vertex1.UV = object->Sprite->UseCustomUV ? object->Sprite->CustomUV[1] : object->Sprite->Sprite->UV[1]; vertex1.Color = VectorColorToRGBA(object->Sprite->c2); vertex1.Effects = 1 << INDEX_IN_POLY_VERTEX_SHIFT; auto vertex2 = Vertex{}; vertex2.Position = object->Sprite->vtx3; - vertex2.UV = object->Sprite->Sprite->UV[2]; + vertex2.UV = object->Sprite->UseCustomUV ? object->Sprite->CustomUV[2] : object->Sprite->Sprite->UV[2]; vertex2.Color = VectorColorToRGBA(object->Sprite->c3); vertex2.Effects = 2 << INDEX_IN_POLY_VERTEX_SHIFT; auto vertex3 = Vertex{}; vertex3.Position = object->Sprite->vtx4; - vertex3.UV = object->Sprite->Sprite->UV[3]; + vertex3.UV = object->Sprite->UseCustomUV ? object->Sprite->CustomUV[3] : object->Sprite->Sprite->UV[3]; vertex3.Color = VectorColorToRGBA(object->Sprite->c4); vertex3.Effects = 3 << INDEX_IN_POLY_VERTEX_SHIFT; @@ -501,7 +501,7 @@ namespace TEN::Renderer _graphicsDevice->UpdateVertexBuffer(_sortedPolygonsVertexBuffer.get(), 0, (int)_sortedPolygonsVertices.size(), _sortedPolygonsVertices.data()); _stInstancedSpriteBuffer.Sprites[0].World = Matrix::Identity; - _stInstancedSpriteBuffer.Sprites[0].PerVertexColor = 1; + _stInstancedSpriteBuffer.Sprites[0].PerVertexColor = objectInfo->Sprite->UseCustomUV ? 2 : 1; _stInstancedSpriteBuffer.Sprites[0].IsSoftParticle = objectInfo->Sprite->SoftParticle ? 1 : 0; _stInstancedSpriteBuffer.Sprites[0].RenderType = (int)objectInfo->Sprite->renderType; diff --git a/TombEngine/Renderer/Structures/RendererSpriteToDraw.h b/TombEngine/Renderer/Structures/RendererSpriteToDraw.h index 2a2f2da156..0f302e221f 100644 --- a/TombEngine/Renderer/Structures/RendererSpriteToDraw.h +++ b/TombEngine/Renderer/Structures/RendererSpriteToDraw.h @@ -1,5 +1,6 @@ -#pragma once -#include +#pragma once +#include +#include #include "Renderer/Structures/RendererSprite.h" #include "Renderer/RendererEnums.h" @@ -14,10 +15,11 @@ namespace TEN::Renderer::Structures float Scale; Vector3 pos; Vector3 vtx1; - Vector3 vtx2; - Vector3 vtx3; - Vector3 vtx4; - Vector4 c1; + Vector3 vtx2; + Vector3 vtx3; + Vector3 vtx4; + std::array CustomUV = {}; + Vector4 c1; Vector4 c2; Vector4 c3; Vector4 c4; @@ -27,8 +29,9 @@ namespace TEN::Renderer::Structures float Height; BlendMode BlendMode; Vector3 ConstrainAxis; - Vector3 LookAtAxis; - bool SoftParticle; - SpriteRenderType renderType = SpriteRenderType::Default; - }; -} + Vector3 LookAtAxis; + bool SoftParticle; + bool UseCustomUV = false; + SpriteRenderType renderType = SpriteRenderType::Default; + }; +} diff --git a/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h b/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h index d32e337174..c439144510 100644 --- a/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h +++ b/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h @@ -463,6 +463,9 @@ static const std::unordered_map GAME_OBJECT_IDS { // @mem CHEF { "CHEF", ID_CHEF }, /// Object ID. + // @mem TR3_BATS_EMITTER + { "TR3_BATS_EMITTER", ID_TR3_BATS_EMITTER }, + /// Object ID. // @mem KOLD { "KOLD", ID_KOLD }, /// Object ID. diff --git a/TombEngine/Shaders/InstancedSprites.hlsl b/TombEngine/Shaders/InstancedSprites.hlsl index 96f00fa001..dc378bd3b9 100644 --- a/TombEngine/Shaders/InstancedSprites.hlsl +++ b/TombEngine/Shaders/InstancedSprites.hlsl @@ -67,7 +67,7 @@ PixelShaderInput VS(VertexShaderInput input, uint InstanceID : SV_InstanceID) output.PositionCopy = output.Position; output.Color = lerp(sprite.Color, input.Color, saturate((float)sprite.PerVertexColor)); - output.UV = float2(sprite.UV[0][polyIndex], sprite.UV[1][polyIndex]); + output.UV = sprite.PerVertexColor == 2 ? input.UV : float2(sprite.UV[0][polyIndex], sprite.UV[1][polyIndex]); output.InstanceID = InstanceID; output.FogBulbs = DoFogBulbsForVertex(worldPosition); @@ -120,4 +120,4 @@ float4 PS(PixelShaderInput input) : SV_TARGET output = ApplyBlendModeColor(output, input.PositionCopy, true); return output; -} \ No newline at end of file +} diff --git a/TombEngine/TombEngine.vcxproj b/TombEngine/TombEngine.vcxproj index 9b549868d1..18816e106a 100644 --- a/TombEngine/TombEngine.vcxproj +++ b/TombEngine/TombEngine.vcxproj @@ -720,9 +720,10 @@ if not exist "%ScriptsDir%\Strings.lua" xcopy /Y "$(SolutionDir)Scripts\Strings. - - - + + + + @@ -1326,9 +1327,10 @@ if not exist "%ScriptsDir%\Strings.lua" xcopy /Y "$(SolutionDir)Scripts\Strings. - - - + + + + @@ -1765,4 +1767,4 @@ if not exist "%ScriptsDir%\Strings.lua" xcopy /Y "$(SolutionDir)Scripts\Strings. - \ No newline at end of file + diff --git a/Tools/Enum generation/objIDs.txt b/Tools/Enum generation/objIDs.txt index b2798a47ab..a4fde2834c 100644 --- a/Tools/Enum generation/objIDs.txt +++ b/Tools/Enum generation/objIDs.txt @@ -146,6 +146,7 @@ GLADIATOR ID_GLADIATOR HITMAN ID_HITMAN SNIPER ID_SNIPER CHEF ID_CHEF +TR3_BATS_EMITTER ID_TR3_BATS_EMITTER WINGED_MUMMY ID_WINGED_MUMMY CENTAUR_MUTANT ID_CENTAUR_MUTANT LARA_DOPPELGANGER ID_LARA_DOPPELGANGER