diff --git a/Source/Contents/ActorGeometry.cpp b/Source/Contents/ActorGeometry.cpp index 24887108..b1067f5c 100644 --- a/Source/Contents/ActorGeometry.cpp +++ b/Source/Contents/ActorGeometry.cpp @@ -2,10 +2,17 @@ #include "Client/Mode/CGameMode.h" #include "Client/Session.h" #include "Contents/Actors/RenderObject.h" +#include "Contents/Configuration/ServiceOptions.h" +#include "Contents/Ground/GroundGeometry.h" #include "Contents/World/World.h" +#include "Render/Renderer.h" +#include "Render/SpriteGeometry.h" +#include "Render/Textures/SpritePixels.h" #include "Utility/Math/AffineMatrix.h" #include +#include +#include // OFFSET: 0x00CA9580 // FUNCTION: fn_21007 @@ -61,6 +68,150 @@ float CRenderObject::CalcDist(float x, float y, float z) const { return SquareRoot(horizontal * horizontal + deltaY * deltaY); } +// OFFSET: 0x00CA9770 +// FUNCTION: fn_21011 +bool CRenderObject::ProjectCell( + int unused, int layer, float scale, const SpriteFrameCell& cell, float x, float y, const float* position, float shift, float& bottomDepth, + float& topDepth, const SpriteRleImage& image, SpriteCellQuad& quad, tagRECT& bounds, SpriteColor& color, int offsetX, int offsetY, int flags +) { + const float depthBias = this->render.unknown_005C * g_cameraScaleX; + const double scaleY = static_cast(scale * cell.scaleY * this->render.scale); + const double scaleX = static_cast(scale * cell.scaleX * this->render.scale); + float top = static_cast(static_cast(cell.y + offsetY) * scaleY + static_cast(y)); + float bottom = static_cast( + static_cast((image.unknown_0006 + 1) * image.height + cell.y + offsetY) * scaleY + static_cast(y) + 1.0 + ); + float left; + float right; + + if (cell.mirrored & 1) { + left = static_cast(static_cast((image.unknown_0004 + 1) * image.width + cell.x + offsetX) * scaleX + static_cast(x)); + right = static_cast(static_cast(offsetX + cell.x) * scaleX + static_cast(x) + 1.0); + if (top >= static_cast(g_renderer->viewport.height) || bottom <= 0.0f || right >= static_cast(g_renderer->viewport.width) || + left <= 0.0f) { + return false; + } + } else { + left = static_cast(static_cast(cell.x + offsetX) * scaleX + static_cast(x)); + right = static_cast(static_cast((image.unknown_0004 + 1) * image.width + cell.x + offsetX) * scaleX + static_cast(x) + 1.0); + if (top >= static_cast(g_renderer->viewport.height) || bottom <= 0.0f || left >= static_cast(g_renderer->viewport.width) || + right <= 0.0f) { + return false; + } + } + + if ((this->render.flags & 0x80) != 0) { + const short phase = this->render.unknown_00F4; + float factor = 0.0f; + if (phase < 19) { + factor = g_sinTable[phase * 5] * 0.3f; + } else if (phase < 21) { + factor = 0.3f; + } else if (phase < 24) { + factor = static_cast(23 - phase) * 0.1f; + } + factor *= bottom - top; + top -= factor; + bottom -= factor; + } + + if ((this->render.flags & 0x20) != 0) { + const short phase = this->render.unknown_00F4; + float factor = 1.0f; + if (phase < 4) { + factor = (100.0f - static_cast(phase) * 20.0f) * 0.01f; + } else if (phase < 34) { + int remainder = std::rand() % 6; + if (remainder < 0) { + remainder = 0; + } + factor = 0.4f - static_cast(remainder) * 0.01f; + } + top += (bottom - top) * (1.0f - factor); + } + + if (this->render.unknown_00A2 != 0) { + bottomDepth = (static_cast(unused) * g_cameraScaleY + 0.1f - g_cameraScaleY * 20.0f) + + static_cast(static_cast(this->render.unknown_0080)) * g_cameraScaleY; + topDepth = (static_cast(unused) * g_cameraScaleY + 0.1f - g_cameraScaleY * 20.0f) + + static_cast(static_cast(this->render.unknown_0080)) * g_cameraScaleY; + } else { + const int depthLayer = static_cast(this->render.unknown_0080) + 3 + layer; + const float height = bottom - y; + const float rise = top - y; + if (this->render.isLieOnGround) { + bottomDepth = 1.0f / (position[2] - height * g_cotangent) + static_cast(depthLayer) * g_cameraScaleY + depthBias; + topDepth = 1.0f / (position[2] - rise * g_cotangent) + static_cast(depthLayer) * g_cameraScaleY + depthBias; + } else if (static_cast(flags) != 0) { + bottomDepth = 1.0f / (height * 0.06f + position[2]) + static_cast(depthLayer) * g_cameraScaleY + depthBias; + topDepth = 1.0f / (rise * 0.06f + position[2]) + static_cast(depthLayer) * g_cameraScaleY + depthBias; + } else { + bottomDepth = 1.0f / (height * g_tangent + position[2]) + static_cast(depthLayer) * g_cameraScaleY + depthBias; + topDepth = 1.0f / (rise * g_tangent + position[2]) + static_cast(depthLayer) * g_cameraScaleY + depthBias; + } + } + + quad.left = left + shift; + quad.top = top; + quad.bottom = bottom; + quad.right = right + shift; + quad.bottomDepth = bottomDepth; + quad.topDepth = topDepth; + quad.angle = static_cast(cell.unknown_001C + static_cast(this->render.unknown_007C)); + bounds.left = static_cast(left); + bounds.top = static_cast(top); + bounds.right = static_cast(right); + bounds.bottom = static_cast(bottom); + + float lightRed = 1.0f; + float lightGreen = 1.0f; + float lightBlue = 1.0f; + if (this->render.unknown_00B4 == 1 && g_serviceOptions.Get(0x77)) { + CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); + GroundGeometry* ground = mode->scene->ground; + if (ground->Slot10()) { + int column = 0; + int row = 0; + mode->WorldCell(this->render.position.x, this->render.position.z, column, row); + ground->Lighting(column, row, lightRed, lightGreen, lightBlue); + } + } + + if (this->render.isSingleColor && this->render.overrideColor != 0xFFFF0000) { + color = *reinterpret_cast(&this->render.overrideColor); + } else { + color.alpha = static_cast( + static_cast((static_cast((cell.color >> 24) & 0xFF) * static_cast((this->render.color >> 24) & 0xFF)) / 255.0f) + ); + color.red = static_cast( + static_cast((static_cast(cell.color & 0xFF) * static_cast((this->render.color >> 16) & 0xFF) * lightRed) / 255.0f) + ); + color.green = static_cast( + static_cast((static_cast((cell.color >> 8) & 0xFF) * static_cast((this->render.color >> 8) & 0xFF) * lightGreen) / 255.0f) + ); + color.blue = static_cast( + static_cast((static_cast((cell.color >> 16) & 0xFF) * static_cast(this->render.color & 0xFF) * lightBlue) / 255.0f) + ); + } + quad.color = color; + + if ((this->render.flags & 0x40) != 0) { + const short phase = this->render.unknown_00F4; + if (phase <= 36) { + float angle = 180.0f - g_sinTable[90 + phase * 5] * 180.0f; + quad.angle = angle; + if (angle >= 360.0f) { + quad.angle = angle - 360.0f; + return true; + } + } else { + quad.angle = 0.0f; + } + } + + return true; +} + // OFFSET: 0x00CAD9E0 // FUNCTION: fn_21057 bool CRenderObject::GetTargetPos(std::uint32_t targetAid, vector3d& targetPos) const { diff --git a/Source/Contents/Actors/RenderObject.h b/Source/Contents/Actors/RenderObject.h index 21babaa6..ed34a85a 100644 --- a/Source/Contents/Actors/RenderObject.h +++ b/Source/Contents/Actors/RenderObject.h @@ -7,9 +7,12 @@ #include +struct SpriteCellQuad; +struct SpriteColor; struct SpriteFrameCell; struct SpriteQuad; struct SpriteRleImage; +struct tagRECT; struct RenderBounds { /* 0000 */ float left; @@ -39,6 +42,10 @@ public: void Face(float x, float z); float CalcDist(float x, float z) const; float CalcDist(float x, float y, float z) const; + bool ProjectCell( + int unused, int layer, float scale, const SpriteFrameCell& cell, float x, float y, const float* position, float shift, float& bottomDepth, + float& topDepth, const SpriteRleImage& image, SpriteCellQuad& quad, tagRECT& bounds, SpriteColor& color, int offsetX, int offsetY, int flags + ); bool GetTargetPos(std::uint32_t targetAid, vector3d& targetPos) const; void UpdateTlvertex(const float* matrix); void SetAnimationSpeed(float speed);