diff --git a/Source/Render/ActionSpriteDrawing.cpp b/Source/Render/ActionSpriteDrawing.cpp new file mode 100644 index 0000000..3c3fc2e --- /dev/null +++ b/Source/Render/ActionSpriteDrawing.cpp @@ -0,0 +1,126 @@ +#include "Contents/Configuration/ServiceConfiguration.h" +#include "Render/ActionSpriteDrawing.h" +#include "Render/Renderer.h" +#include "Render/TextureQuad.h" +#include "Render/Textures/SpriteAtlas.h" +#include "Resource/ResourceMgr.h" +#include "Resource/Sprites/ActionResource.h" +#include "Resource/Sprites/SpriteResource.h" +#include "Utility/Math/AffineMatrix.h" + +// OFFSET: 0x00AD5A70 +// FUNCTION: fn_17825 +void DrawActionSprite( + CRenderSystemBase& system, int x, int y, const CActRes* action, const CSprRes* sprite, int animation, int frame, float scale, float angle, + std::uint32_t color, std::uint16_t flags +) { + if (!action || !sprite) { + return; + } + + SpriteAtlasRecord record{}; + const ActionFrame& current = action->Frame(animation, frame); + + for (int index = 0; index < current.cellCount; ++index) { + RenderPrimitive* primitive = g_renderer->primitives.Acquire(); + const SpriteFrameCell& cell = current.Cell(index); + if (cell.image == -1) { + continue; + } + + const float scaleX = cell.scaleX; + const SpriteRleImage* image = sprite->images[cell.imageType][cell.image]; + const float left = static_cast(cell.x) * scale; + const float scaledLeft = left * scaleX; + const float right = static_cast(image->width * (image->unknown_0004 + 1) - 1 + cell.x) * scale; + const float top = static_cast(cell.y) * scale * cell.scaleY; + const float scaledRight = right * scaleX; + const float bottom = static_cast(image->height * (image->unknown_0006 + 1) - 1 + cell.y) * scale * cell.scaleY; + + CTexture* texture; + if (cell.imageType == 0) { + texture = g_renderer->atlas.Find(image, sprite->palette, record); + if (!texture) { + texture = g_renderer->atlas.Insert(system, image, sprite->palette, record, g_serviceType, g_resourceReuseDelay); + } + } else { + texture = static_cast(const_cast(image->unknown_0008)); + } + primitive->texture = texture; + + float x0; + float y0; + float x1; + float y1; + float x2; + float y2; + float x3; + float y3; + if (angle == 0.0f) { + float first = scaledLeft; + float second = right; + if (cell.mirrored & 1) { + first = scaledRight; + second = left; + } + + const float originX = static_cast(x); + const float originY = static_cast(y); + x0 = first + originX; + y0 = originY + top; + x1 = scaleX * second + originX; + y1 = originY + top; + x2 = first + originX; + y2 = originY + bottom; + x3 = scaleX * second + originX; + y3 = originY + bottom; + } else { + const int degrees = static_cast(angle); + const float cosine = ClientCosine(degrees); + const float sine = ClientSine(degrees); + const float originX = static_cast(x); + const float originY = static_cast(y); + x0 = cosine * scaledLeft - sine * top + originX; + y0 = sine * scaledLeft + cosine * top + originY; + x1 = cosine * scaledRight - sine * top + originX; + y1 = sine * scaledRight + cosine * top + originY; + x2 = cosine * scaledRight - sine * bottom + originX; + y2 = cosine * bottom + sine * scaledRight + originY; + x3 = cosine * scaledLeft - sine * bottom + originX; + y3 = cosine * bottom + sine * scaledLeft + originY; + } + + RenderVertex* vertices = primitive->quad; + vertices[0].x = x0 + 0.5f; + vertices[0].y = y0 + 0.5f; + vertices[1].x = x1 + 0.5f; + vertices[1].y = y1 + 0.5f; + vertices[2].x = x2 + 0.5f; + vertices[2].y = y2 + 0.5f; + vertices[3].x = x3 + 0.5f; + vertices[3].y = y3 + 0.5f; + + vertices[0].z = 0.000001f; + vertices[0].rhw = 0.999999f; + vertices[0].u = record.u0; + vertices[0].v = record.v0; + vertices[0].diffuse = color; + vertices[1].z = 0.000001f; + vertices[1].rhw = 0.999999f; + vertices[1].u = record.u1; + vertices[1].v = record.v0; + vertices[1].diffuse = color; + vertices[2].z = 0.000001f; + vertices[2].rhw = 0.999999f; + vertices[2].u = record.u0; + vertices[2].v = record.v1; + vertices[2].diffuse = color; + vertices[3].z = 0.000001f; + vertices[3].rhw = 0.999999f; + vertices[3].u = record.u1; + vertices[3].v = record.v1; + vertices[3].diffuse = color; + + g_renderer->queues.Submit(primitive, flags, g_renderer->fog.supported != 0, g_depthStart, g_depthEnd); + } +} diff --git a/Source/Render/ActionSpriteDrawing.h b/Source/Render/ActionSpriteDrawing.h new file mode 100644 index 0000000..68bd072 --- /dev/null +++ b/Source/Render/ActionSpriteDrawing.h @@ -0,0 +1,15 @@ +#ifndef RAGNAROK_SOURCE_RENDER_ACTIONSPRITEDRAWING_H +#define RAGNAROK_SOURCE_RENDER_ACTIONSPRITEDRAWING_H + +#include + +class CActRes; +class CRenderSystemBase; +class CSprRes; + +void DrawActionSprite( + CRenderSystemBase& system, int x, int y, const CActRes* action, const CSprRes* sprite, int animation, int frame, float scale, float angle, + std::uint32_t color, std::uint16_t flags +); + +#endif diff --git a/Source/Render/SpriteQuad.cpp b/Source/Render/SpriteQuad.cpp new file mode 100644 index 0000000..0fd50c7 --- /dev/null +++ b/Source/Render/SpriteQuad.cpp @@ -0,0 +1,88 @@ +#include "Contents/Configuration/ServiceConfiguration.h" +#include "Render/Renderer.h" +#include "Render/SpriteQuad.h" +#include "Render/TextureQuad.h" +#include "Render/Textures/SpriteAtlas.h" +#include "Render/Textures/Texture.h" +#include "Resource/ResourceMgr.h" +#include "Utility/Math/AffineMatrix.h" + +// OFFSET: 0x00811FC0 +// FUNCTION: fn_10110 +RenderPrimitive* BuildSpriteQuad(CRenderSystemBase& system, const SpriteQuad& quad, const std::uint32_t* palette, int blend, float offsetX, float offsetY) { + SpriteAtlasRecord record{}; + const SpriteRleImage* image = quad.image; + CTexture* texture = static_cast(const_cast(image->unknown_0008)); + if (!texture) { + texture = g_renderer->atlas.Find(image, palette, record); + if (!texture) { + texture = g_renderer->atlas.Insert(system, image, palette, record, g_serviceType, g_resourceReuseDelay); + } + } else { + record.u0 = 0.0f; + record.v0 = 0.0f; + record.u1 = static_cast(texture->ImageWidth()) / static_cast(texture->TextureWidth()); + record.v1 = static_cast(texture->ImageHeight()) / static_cast(texture->TextureHeight()); + } + + const float bottomZ = RhwToDepth(quad.bottomRhw); + const float topZ = RhwToDepth(quad.topRhw); + RenderPrimitive* primitive = g_renderer->primitives.Acquire(); + RenderVertex* vertices = primitive->vertices; + primitive->texture = texture; + + if (quad.angle > 0.0f) { + const float cosine = ClientCosine(static_cast(quad.angle)); + const float sine = ClientSine(static_cast(quad.angle)); + const float halfWidth = (quad.right - quad.left) * 0.5f; + const float halfHeight = (quad.bottom - quad.top) * 0.5f; + const float centerX = quad.left + halfWidth + offsetX; + const float centerY = quad.top + halfHeight + offsetY; + const float minX = -halfWidth; + const float minY = -halfHeight; + + vertices[0].x = minX * cosine - minY * sine + centerX + 0.5f; + vertices[0].y = minY * cosine + minX * sine + centerY + 0.5f; + vertices[1].x = halfWidth * cosine - minY * sine + centerX + 0.5f; + vertices[1].y = minY * cosine + halfWidth * sine + centerY + 0.5f; + vertices[2].x = minX * cosine - halfHeight * sine + centerX + 0.5f; + vertices[2].y = halfHeight * cosine + minX * sine + centerY + 0.5f; + vertices[3].x = halfWidth * cosine - halfHeight * sine + centerX + 0.5f; + vertices[3].y = halfHeight * cosine + halfWidth * sine + centerY + 0.5f; + } else { + vertices[0].x = quad.left + 0.5f; + vertices[0].y = quad.top + 0.5f; + vertices[1].x = quad.right + 0.5f; + vertices[1].y = quad.top + 0.5f; + vertices[2].x = quad.left + 0.5f; + vertices[2].y = quad.bottom + 0.5f; + vertices[3].x = quad.right + 0.5f; + vertices[3].y = quad.bottom + 0.5f; + } + + vertices[0].z = topZ; + vertices[0].rhw = quad.topRhw; + vertices[0].u = record.u0; + vertices[0].v = record.v0; + vertices[0].diffuse = quad.color; + vertices[1].z = topZ; + vertices[1].rhw = quad.topRhw; + vertices[1].u = record.u1; + vertices[1].v = record.v0; + vertices[1].diffuse = quad.color; + vertices[2].z = bottomZ; + vertices[2].rhw = quad.bottomRhw; + vertices[2].u = record.u0; + vertices[2].v = record.v1; + vertices[2].diffuse = quad.color; + vertices[3].z = bottomZ; + vertices[3].rhw = quad.bottomRhw; + vertices[3].u = record.u1; + vertices[3].v = record.v1; + vertices[3].diffuse = quad.color; + + primitive->unknown_0018 = 5; + primitive->unknown_001C = blend != 5 ? 6 : 2; + + return primitive; +} diff --git a/Source/Render/SpriteQuad.h b/Source/Render/SpriteQuad.h new file mode 100644 index 0000000..fe4686e --- /dev/null +++ b/Source/Render/SpriteQuad.h @@ -0,0 +1,31 @@ +#ifndef RAGNAROK_SOURCE_RENDER_SPRITEQUAD_H +#define RAGNAROK_SOURCE_RENDER_SPRITEQUAD_H + +#include +#include + +class CRenderSystemBase; +struct RenderPrimitive; +struct SpriteRleImage; + +struct SpriteQuad { + /* 0000 */ float top; + /* 0004 */ float left; + /* 0008 */ float bottom; + /* 000C */ float right; + /* 0010 */ float bottomRhw; + /* 0014 */ float topRhw; + /* 0018 */ std::uint32_t color; + /* 001C */ float angle; + /* 0020 */ std::int32_t unknown_0020[3]; + /* 002C */ const SpriteRleImage* image; +}; + +RenderPrimitive* BuildSpriteQuad(CRenderSystemBase& system, const SpriteQuad& quad, const std::uint32_t* palette, int blend, float offsetX, float offsetY); + +#if defined(_WIN32) && !defined(_WIN64) +static_assert(offsetof(SpriteQuad, angle) == 0x001C); +static_assert(offsetof(SpriteQuad, image) == 0x002C); +#endif + +#endif diff --git a/data/compile.json b/data/compile.json index b8ac9a6..1ce24df 100644 --- a/data/compile.json +++ b/data/compile.json @@ -481,6 +481,7 @@ "Source/Network/Packets/PartyJoinRequest.cpp": 2, "Source/Network/Packets/SkillUpdatePacket.cpp": 4, "Source/Network/TextEncoding.cpp": 0, + "Source/Render/ActionSpriteDrawing.cpp": 0, "Source/Render/AlphaQueuesDX7.cpp": 0, "Source/Render/AlphaRectangle.cpp": 0, "Source/Render/AuxiliaryQueuesDX7.cpp": 0, @@ -548,6 +549,7 @@ "Source/Render/ScreenGeometry.cpp": 0, "Source/Render/ScreenRectangle.cpp": 0, "Source/Render/SpriteGeometry.cpp": 0, + "Source/Render/SpriteQuad.cpp": 0, "Source/Render/Text/FontCache.cpp": 0, "Source/Render/Text/TextContext.cpp": 0, "Source/Render/TextureQuad.cpp": 0,