diff --git a/Source/Contents/Actors/Pc.h b/Source/Contents/Actors/Pc.h index dbcdea5b..2f716060 100644 --- a/Source/Contents/Actors/Pc.h +++ b/Source/Contents/Actors/Pc.h @@ -121,7 +121,9 @@ public: /* 0490 */ unsigned char unknown_0490[0x0C]; /* 049C */ int unknown_049C; /* 04A0 */ int blend; - /* 04A4 */ unsigned char unknown_04A4[0x10]; + /* 04A4 */ int unknown_04A4; + /* 04A8 */ int unknown_04A8; + /* 04AC */ unsigned char unknown_04AC[0x08]; /* 04B4 */ std::vector equipSprites; /* 04C0 */ std::vector equipActions; /* 04CC */ int unknown_04CC; diff --git a/Source/Contents/SpriteLayerDrawing.cpp b/Source/Contents/SpriteLayerDrawing.cpp index cbfc5faa..493072ab 100644 --- a/Source/Contents/SpriteLayerDrawing.cpp +++ b/Source/Contents/SpriteLayerDrawing.cpp @@ -4,16 +4,191 @@ #include "Contents/Actors/ActorStateFlags.h" #include "Contents/Actors/Pc.h" #include "Contents/Configuration/ServiceOptions.h" +#include "Contents/Jobs/JobInheritance.h" +#include "Contents/MapSkyMgr.h" +#include "Contents/Skills/ClientSkills.h" +#include "Contents/SpriteLayerOrder.h" #include "Contents/SpriteRidingOffset.h" #include "Contents/SpriteRidingPolicy.h" +#include "Render/Renderer.h" +#include "Render/SpriteGeometry.h" +#include "Resource/ImfResource.h" #include "Resource/PaletteResource.h" #include "Resource/ResourceMgr.h" #include "Resource/Sprites/ActionResource.h" #include "Resource/Sprites/SpriteResource.h" #include "Script/LuaScript.h" +#include "Utility/Text/FormatString.h" #include +// OFFSET: 0x0063F500 +// FUNCTION: fn_04807 +void SpriteLayerRenderer::Render(const float* matrix, int unknown0030, char unknown0034) { + if (!this->pc) { + return; + } + + std::memcpy(this->matrix, matrix, sizeof(this->matrix)); + this->unknown_0030 = unknown0030; + this->unknown_0034 = unknown0034; + this->unknown_0060 = 0; + this->swingX = 0; + this->swingY = 0; + this->unknown_006C = false; + this->unknown_006D = false; + this->unknown_0094 = false; + + int slot = 2; + this->layerViews[slot] = this->pc->unknown_0450; + slot = 3; + this->layerViews[slot] = this->pc->unknown_0454; + slot = 4; + this->layerViews[slot] = this->pc->unknown_0458; + slot = 8; + this->layerViews[slot] = this->pc->unknown_049C; + this->LoadLayers(); + + const vector3d& origin = this->pc->render.position; + this->position.x = origin.x * matrix[0] + origin.y * matrix[3] + origin.z * matrix[6] + matrix[9]; + this->position.y = origin.x * matrix[1] + origin.y * matrix[4] + origin.z * matrix[7] + matrix[10]; + this->position.z = origin.x * matrix[2] + origin.y * matrix[5] + origin.z * matrix[8] + matrix[11]; + g_renderer->ProjectViewport(&this->pc->render.position.x, matrix, &this->x, &this->y, &this->rhw); + this->distanceScale = g_renderer->ScaleDistance(this->rhw); + this->pc->render.unknown_005C = this->distanceScale / g_heightScale; + this->pc->ScaleByPulse(this->distanceScale); + this->distanceScale *= GetSkillFactor(this->pc->GetEffectiveJob(-1)); + this->scale = g_renderer->UiScaleX() * (static_cast(static_cast(this->pc->render.unknown_0078)) * this->pc->render.scale) * + this->pc->render.unknown_005C; + + if (this->pc->HasAppearanceOverride()) { + const int layer = this->DrawBodyOutline(0); + this->pc->DrawBody( + reinterpret_cast(matrix), layer, &this->position.x, this->x, this->y, this->distanceScale, this->scale, this->rhw + ); + return; + } + + this->DrawRobe(false); + this->imf = static_cast(ResourceMgr::Instance().Load(this->pc->unknown_0418)); + this->bounds.Set(static_cast(g_renderer->viewport.width), static_cast(g_renderer->viewport.height), 0.0f, 0.0f, this->rhw); + + bool bodyDrawn = false; + bool swapped = false; + if (this->pc->unknown_04F4) { + this->DrawLayerOutlines(this->pc->unknown_04F4); + } + + for (int index = 8; index >= 0; --index) { + int layer = GetSpriteLayerOrder(this->imf, index, this->pc->render.animation, this->pc->render.previousAnimation, this->pc->render.curMotion); + if (!bodyDrawn) { + bodyDrawn = layer == 1; + } + + if (layer == 0) { + if (bodyDrawn == true) { + swapped = true; + layer = 4; + } + } else if (layer == 2) { + layer = swapped == true ? 0 : 4; + } else if (layer == 4) { + layer = 2; + } else if (static_cast(layer) > 8) { + continue; + } + + if (layer == 5 || layer == 6 || layer == 7) { + if (this->pc->IsCostumeOutfit() == true || !IsReadyOrAttackAction(this->pc->render.previousAnimation)) { + continue; + } + + if (layer == 7) { + const int job = this->pc->GetEffectiveJob(-1); + if (job == 0xFF6 || job == 0xFF7 || job == 0x1010) { + continue; + } + } else if (this->pc->unknown_02CC == 1) { + continue; + } + } + + if ((layer == 2 || layer == 3 || layer == 4) && this->unknown_006D == true) { + continue; + } + + if (layer == 8 && this->pc->unknown_04D9 == false) { + continue; + } + + const std::pair found = this->FindLayer(layer); + if (!found.first) { + continue; + } + + CActRes* action = found.second.action; + const int animation = this->pc->render.previousAnimation; + if (animation >= static_cast(action->animations.size())) { + continue; + } + + if (this->pc->render.curMotion >= static_cast(action->FrameCount(animation))) { + continue; + } + + int stanceAnimation; + int frameIndex = 0; + bool replaced = false; + const ActionFrame& frame = this->pc->SelectStanceFrame(layer, action, &stanceAnimation, &frameIndex, &replaced); + std::pair sound = this->GetLayerSound(layer, action, frame.sound); + if (sound.first == true) { + this->pc->unknown_0180 = 1; + std::string name = sound.second; + char* buffer = reinterpret_cast(this->pc->unknown_0190); + StringFormat(buffer, 0x80, static_cast(-1), "%s", name.size() == 0 ? buffer : name.c_str()); + } + + bool hasSynced = false; + const ActionFrame* synced = nullptr; + switch (layer) { + case 2: + case 3: + case 4: + case 8: { + const int bodyCount = static_cast(this->pc->GetEquipAction(1))->FrameCount(this->pc->render.previousAnimation); + const int layerCount = static_cast(this->pc->GetEquipAction(layer))->FrameCount(this->pc->render.previousAnimation); + if (bodyCount > 0 && layerCount > 0 && layerCount > bodyCount && layerCount % bodyCount == 0) { + synced = &action->Frame(this->pc->render.previousAnimation, this->pc->render.curMotion * (layerCount / bodyCount)); + hasSynced = true; + } + break; + } + } + + this->DrawLayer(index, layer, hasSynced == true ? synced : &frame, found.second.sprite, action, stanceAnimation, frameIndex, replaced); + } + + int depth = 0; + for (std::map::iterator it = this->quads.begin(); it != this->quads.end(); ++it, ++depth) { + SpriteQuad& quad = it->second.quad; + quad.bottomRhw = quad.bottom * this->depthScale + this->depthBias; + quad.topRhw = this->depthScale * quad.top + this->depthBias; + if (IsScreenShakeActive() == true) { + this->pc->DrawFlippedQuad(quad, it->second.palette, it->second.blend, this->x, this->y, depth); + } else { + this->pc->DrawQuad(quad, it->second.palette, it->second.blend, 0.0f, 0.0f, depth); + } + } + + if (this->unknown_0094 == true) { + this->pc->SetRenderInfo(&this->bounds.left, this->x, this->y); + } else { + this->pc->SetTlvert(this->x, this->y); + } + + this->pc->render.unknown_00ECBytes[0] = 1; +} + // OFFSET: 0x0063FC90 // FUNCTION: fn_04808 void SpriteLayerRenderer::QueueQuad(int layer, const SpriteQuad* quad, const std::uint32_t* palette, int blend) { @@ -142,6 +317,93 @@ void SpriteLayerRenderer::DrawLayerOutlines(std::uint32_t color) { } } +// OFFSET: 0x00640510 +// FUNCTION: fn_04810 +void SpriteLayerRenderer::DrawRobe(bool drawOnTop) { + if (this->pc->unknown_049C <= 0 || this->pc->unknown_04D9 == true || this->pc->render.unknown_0070 == 3 || + (this->pc->blend == -1 && this->pc->unknown_04A4 == -1 && this->pc->unknown_04A8 == -1)) { + return; + } + + if (drawOnTop != this->pc->IsDrawOnTop()) { + return; + } + + if (this->pc->unknown_0260 == 0) { + const int job = this->pc->GetEffectiveJob(-1); + if (job == 0xFF6 || job == 0xFF7 || job == 0x1010) { + return; + } + } + + std::string sprName = g_session.GetRobeSprName( + this->pc->GetEffectiveJob(-1), this->pc->unknown_04D4, this->pc->unknown_0260, this->pc->unknown_049C, this->pc->unknown_02CC, this->pc->Slot46() + ); + std::string actName = g_session.GetRobeActName( + this->pc->GetEffectiveJob(-1), this->pc->unknown_04D4, this->pc->unknown_0260, this->pc->unknown_049C, this->pc->unknown_02CC, this->pc->Slot46() + ); + if (!ResourceMgr::Instance().Exists(sprName.c_str()) || !ResourceMgr::Instance().Exists(actName.c_str())) { + return; + } + + CSprRes* sprite = static_cast(ResourceMgr::Instance().Load(sprName.c_str())); + CActRes* action = static_cast(ResourceMgr::Instance().Load(actName.c_str())); + if (!sprite || !action) { + return; + } + + int frameIndex = this->pc->render.curMotion; + int baseFrame = this->pc->render.curMotion; + const int animation = this->pc->render.previousAnimation; + if ((animation >= 0 && animation < 8) || (animation >= 16 && animation <= 22)) { + baseFrame = 0; + } + + g_session.GetSyncedFrame( + static_cast(this->pc->GetEquipAction(1)), action, animation, baseFrame, this->pc->render.unknown_008C, &frameIndex + ); + const ActionFrame& frame = action->Frame(this->pc->render.previousAnimation, frameIndex); + for (int index = 0; index < frame.cellCount; ++index) { + const SpriteFrameCell& cell = frame.Cell(index); + if (cell.image == -1) { + continue; + } + + reinterpret_cast(&const_cast(cell).color)[3] = + static_cast(g_session.GetRobeAlpha(this->pc->unknown_049C)); + const SpriteRleImage* image = sprite->images[cell.imageType][cell.image]; + + float bottomRhw = 0.0f; + float topRhw = 0.0f; + SpriteQuad quad; + int box[4]; + std::uint32_t quadColor; + this->pc->Slot09( + this->unknown_0060, this->unknown_0060, this->distanceScale, cell, this->x, this->y, &this->position.x, this->scale, &bottomRhw, &topRhw, + image, &quad, box, &quadColor, 0, 0, !drawOnTop + ); + if (this->pc->render.unknown_0130[0] == 1) { + quad.color = static_cast(static_cast(static_cast(static_cast(quad.color >> 24) * (70.0f / 255.0f)))) << 24 | + (quad.color & 0xFFFFFF); + } + + quad.image = image; + int blend = this->pc->blend; + this->pc->ApplyLayerEffects( + &quad, &cell, 0, box, this->scale, bottomRhw, bottomRhw, topRhw, this->x, this->y, sprite->palette, image, &blend, 0, 0 + ); + if (drawOnTop && g_session.IsTopLayerRobe(this->pc->unknown_049C)) { + SpriteLayerQuad entry; + entry.quad = quad; + entry.palette = sprite->palette; + entry.blend = blend; + this->quads.insert(std::map::value_type(400, entry)); + } else { + this->QueueQuad(0, &quad, sprite->palette, blend); + } + } +} + // OFFSET: 0x00640AD0 // FUNCTION: fn_04811 int SpriteLayerRenderer::DrawBodyOutline(int layer) { @@ -330,6 +592,120 @@ std::pair SpriteLayerRenderer::GetLayerSound(int layer, CActR return {true, name}; } +// OFFSET: 0x00641850 +// FUNCTION: fn_04817 +void SpriteLayerRenderer::DrawLayer( + int index, int layer, const ActionFrame* frame, CSprRes* sprite, CActRes* action, int animation, int frameIndex, bool replaced +) { + int cellIndex = GetSlotLayer(g_session.IsSpecialMonsterJob(this->layerViews[layer]) ? 1 : layer); + for (int i = 0; i < frame->cellCount; ++i) { + if (layer == 7) { + cellIndex = i; + } else if (cellIndex != i) { + continue; + } + + const SpriteFrameCell* cell = &frame->Cell(cellIndex); + if (cell->image == -1) { + continue; + } + + const SpriteRleImage* image = sprite->images[cell->imageType][cell->image]; + int offsetX = 0; + int offsetY = 0; + const std::pair itemOffset = this->GetItemOffset(layer); + offsetX += itemOffset.first; + offsetY += itemOffset.second; + const SpriteLayerCell resolved = this->ResolveCell(layer, cell, cellIndex, sprite, action, frame, image, animation, frameIndex, replaced); + offsetX += resolved.offsetX; + offsetY += resolved.offsetY; + this->pc->ApplySwing(layer, offsetX, offsetY, this->swingX, this->swingY); + + float bottomRhw = 0.0f; + float topRhw = 0.0f; + SpriteQuad quad; + int box[4]; + std::uint32_t quadColor; + if (!this->pc->Slot09( + index, this->unknown_0060, this->distanceScale, *resolved.cell, this->x, this->y, &this->position.x, this->scale, &bottomRhw, &topRhw, + resolved.image, &quad, box, &quadColor, offsetX, offsetY, 0 + )) { + continue; + } + + if (layer == 0) { + const float depthScale = (quad.bottomRhw - quad.topRhw) / (quad.bottom - quad.top); + this->depthScale = depthScale; + this->depthBias = ((quad.topRhw + quad.bottomRhw) - (quad.top + quad.bottom) * depthScale) * g_depthAverageHalf; + } + + if (this->pc->render.unknown_0130[0] == 1) { + quad.color = static_cast(static_cast(static_cast(static_cast(quad.color >> 24) * (70.0f / 255.0f)))) << 24 | + (quad.color & 0xFFFFFF); + } + + if (layer == 1) { + this->pc->unknown_04EC = static_cast(resolved.cell->x + this->swingX); + this->pc->unknown_04F0 = static_cast(resolved.cell->y + this->swingY); + if (this->unknown_006C == true) { + continue; + } + } + + quad.image = resolved.image; + const std::uint32_t* palette = this->GetPalette(layer, sprite, action); + int effect = 0xA6; + this->pc->SendMsg(nullptr, 0x78, 0, reinterpret_cast(&effect), reinterpret_cast(&effect) >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + int blend; + switch (layer) { + case 2: + case 3: + case 8: + blend = 1; + break; + case 4: + blend = this->pc->unknown_0458 == 0xB9 ? 0x11 : 1; + break; + default: + blend = 0x101; + if (quad.color >= 0xFF000000 && this->unknown_0030 == 1) { + switch (this->unknown_0034) { + case 1: + if (layer == 5) { + blend = layer; + } + break; + case 2: + if (layer == 0 || layer == 1) { + blend = 0x11; + } + break; + } + } + break; + } + + if ((layer == 0 || layer == 1) && this->pc->render.unknown_00A4Bytes[1] == 1) { + this->bounds.Include(&quad.top); + } + + this->unknown_0094 = true; + this->pc->ApplyLayerEffects( + &quad, resolved.cell, layer, box, this->scale, this->rhw, bottomRhw, topRhw, this->x, this->y, palette, resolved.image, &blend, offsetX, + offsetY + ); + this->QueueQuad(layer, &quad, palette, blend); + this->pc->DrawStatusOverlays(quad, palette); + if (layer == 0) { + this->pc->blend = blend; + this->pc->unknown_04A4 = resolved.cell->x; + this->pc->unknown_04A8 = resolved.cell->y; + this->DrawRobe(true); + } + } +} + // OFFSET: 0x00641E40 // FUNCTION: fn_04818 void SpriteLayerRenderer::LoadLayers() { diff --git a/Source/Contents/SpriteLayerDrawing.h b/Source/Contents/SpriteLayerDrawing.h index 3e6c4412..edd62c79 100644 --- a/Source/Contents/SpriteLayerDrawing.h +++ b/Source/Contents/SpriteLayerDrawing.h @@ -39,8 +39,10 @@ struct SpriteLayerQuad { class SpriteLayerRenderer { public: + void Render(const float* matrix, int unknown0030, char unknown0034); void QueueQuad(int layer, const SpriteQuad* quad, const std::uint32_t* palette, int blend); void DrawLayerOutlines(std::uint32_t color); + void DrawRobe(bool drawOnTop); int DrawBodyOutline(int layer); SpriteLayerCell ResolveCell( int layer, const SpriteFrameCell* cell, int cellIndex, CSprRes* sprite, CActRes* action, const ActionFrame* frame, @@ -48,13 +50,16 @@ public: ); __declspec(noinline) std::pair GetItemOffset(int layer); __declspec(noinline) const std::uint32_t* GetPalette(int layer, CSprRes* sprite, CActRes* action); - std::pair FindLayer(int layer); + __declspec(noinline) std::pair FindLayer(int layer); std::pair GetLayerSound(int layer, CActRes* action, int sound); + void DrawLayer( + int index, int layer, const ActionFrame* frame, CSprRes* sprite, CActRes* action, int animation, int frameIndex, bool replaced + ); void LoadLayers(); /* 0000 */ float matrix[12]; - /* 0030 */ float unknown_0030; - /* 0034 */ bool unknown_0034; + /* 0030 */ int unknown_0030; + /* 0034 */ char unknown_0034; /* 0038 */ CPc* pc; /* 003C */ vector3d position; /* 0048 */ float x;