From d620bda934ae547ba4b199c76cb48f6dc67060ad Mon Sep 17 00:00:00 2001 From: Tahsin Date: Wed, 1 Oct 2025 11:47:45 +0200 Subject: [PATCH] N3ME FXB WIP step 1 PR This block belongs to Twostars (Credits). char szEffectFN[MAX_PATH] = ""; // TCHAR szEffectFN[_MAX_PATH + 1] = {}; Credits to Twostars anyway.. Vector3 vEffectPos(0, 0, 0); float fEffectScale = 0; __Quaternion qtEffectRot; qtEffectRot.Identity(); szEffectFN,&vEffectPos.x, &vEffectPos.y, &vEffectPos.z, &fEffectScale,&qtEffectRot.x, &qtEffectRot.y, &qtEffectRot.z, &qtEffectRot.w); &pPart->m_Mtl.nRenderFlags, &pPart->m_Mtl.dwSrcBlend, &pPart->m_Mtl.dwDestBlend, &pPart->m_Mtl.dwColorOp, &pPart->m_Mtl.dwColorArg1, &pPart->m_Mtl.dwColorArg2 Looked like one of his early implementations that I used as a cheat sheet. It would be unfair to claim I did the MapMng.cpp totally on my part. What I have added is double checks to see if the line has enough arguments to fit the criteria and show a messagebox this might be too intrusive.. Andwe might want to change the loadfxb to return a false or true changing it to a boolean function for error checking... Also saving or moving an object and updating its position. Also adding a dialog box for FXB implementation would be neat. But first things first... AI was involved in n3scene/shape files, could have been cleaner but its a step in the right direction. Co-Authored-By: twostars --- Client/N3Base/N3Scene.cpp | 8 +++++ Client/N3Base/N3Shape.cpp | 68 +++++++++++++++++++++++++++++++++++++-- Client/N3Base/N3Shape.h | 11 ++++++- N3ME/MapMng.cpp | 58 ++++++++++++++++++++++++++++++--- 4 files changed, 137 insertions(+), 8 deletions(-) diff --git a/Client/N3Base/N3Scene.cpp b/Client/N3Base/N3Scene.cpp index ffdf565e4..56796c2bb 100644 --- a/Client/N3Base/N3Scene.cpp +++ b/Client/N3Base/N3Scene.cpp @@ -3,6 +3,7 @@ ////////////////////////////////////////////////////////////////////// #include "StdAfxBase.h" #include "N3Scene.h" +#include "N3Base\N3Shape.h" #ifdef _DEBUG #undef THIS_FILE @@ -241,7 +242,10 @@ void CN3Scene::Render() s_lpD3DDev->SetRenderState(D3DRS_AMBIENT, m_AmbientLightColor); for (CN3Shape* shape : m_Shapes) + { shape->Render(); + shape->RenderFX(); + } for (CN3Chr* chr : m_Chrs) chr->Render(); @@ -265,6 +269,10 @@ void CN3Scene::Tick(float fFrm) TickCameras(m_fFrmCur); TickLights(m_fFrmCur); TickShapes(m_fFrmCur); + for (CN3Shape* shape : m_Shapes) + { + shape->TickFX(); + } TickChrs(m_fFrmCur); } diff --git a/Client/N3Base/N3Shape.cpp b/Client/N3Base/N3Shape.cpp index 1e99cd349..3c08f7940 100644 --- a/Client/N3Base/N3Shape.cpp +++ b/Client/N3Base/N3Shape.cpp @@ -514,10 +514,13 @@ CN3Shape::CN3Shape() m_iEventType = 0; // Event Type m_iNPC_ID = 0; // NPC 로 쓰는 오브젝트일 경우 NPC ID m_iNPC_Status = 0; // NPC 로 쓰는 오브젝트일 경우 NPC Status + m_pFXB = nullptr; + m_fFXBScale = 1.0f; } CN3Shape::~CN3Shape() { + delete m_pFXB; int iPC = m_Parts.size(); for(int i = 0; i < iPC; i++) delete m_Parts[i]; m_Parts.clear(); @@ -525,6 +528,8 @@ CN3Shape::~CN3Shape() void CN3Shape::Release() { + delete m_pFXB; + m_pFXB = nullptr; m_bDontRender = false; m_bVisible = true; @@ -1033,7 +1038,7 @@ bool CN3Shape::SaveToSameFolder(const std::string& szFullPath) int i; for(i = szFullPath.size() - 1; i >= 0; i--) { - if('\\' == szPath[i] || '/' == szPath[i]) + if ('\\' == szPath[i] || '/' == szPath[i]) { szPath = szPath.substr(0, i+1); break; @@ -1114,7 +1119,7 @@ bool CN3Shape::SaveToSameFolderAndMore(const std::string& szFullPath, const std: int i; for(i = szFullPath.size() - 1; i >= 0; i--) { - if('\\' == szPath[i] || '/' == szPath[i]) + if ('\\' == szPath[i] || '/' == szPath[i]) { szPath = szPath.substr(0, i+1); break; @@ -1174,7 +1179,7 @@ bool CN3Shape::SaveToSameFolderAndMore(const std::string& szFullPath, const std: // void CN3Shape::SetMaxLOD() { - m_bDontRender = false; + m_bDontRender = false; for (auto itr = m_Parts.begin(); itr != m_Parts.end(); ++itr) { @@ -1250,3 +1255,60 @@ void CN3Shape::PartialGetCollision(int iIndex, __Vector3& vec) // ~(By Ecli666 On 2002-08-06 오후 4:33:32 ) +// FX Bundle... N3TOOL N3ME +void CN3Shape::SetFXB(const std::string& strFN, const __Vector3& vOffsetPos, const __Quaternion& qRot, float fScale) +{ + if (m_pFXB) + { + delete m_pFXB; + m_pFXB = nullptr; + } + + if (strFN.empty()) + { + return; + } + + m_pFXB = new CN3FXBundle(); + if (false == m_pFXB->LoadFromFile(strFN.c_str())) + { + delete m_pFXB; + m_pFXB = nullptr; + return; + } + + m_vFXBOffsetPos = vOffsetPos; + m_qFXBRot = qRot; + m_fFXBScale = fScale; + + m_pFXB->Init(); + m_pFXB->Trigger(); +} + +void CN3Shape::TickFX() +{ + if (m_pFXB) + { + __Matrix44 mtxWorld; + mtxWorld.Scale(m_fFXBScale, m_fFXBScale, m_fFXBScale); + mtxWorld *= m_Matrix; + + __Matrix44 mtxRot; + mtxRot.Rotation(m_qFXBRot.x, m_qFXBRot.y, m_qFXBRot.z); + + __Matrix44 mtxFinal = mtxRot * mtxWorld; + mtxFinal.PosSet(mtxWorld.Pos() + m_vFXBOffsetPos); + + m_pFXB->m_vPos = mtxFinal.Pos(); + m_pFXB->Tick(); + } +} + +void CN3Shape::RenderFX() +{ + if (m_pFXB) + { + m_pFXB->Render(); + } +} +// FX Bundle... N3TOOL N3ME diff --git a/Client/N3Base/N3Shape.h b/Client/N3Base/N3Shape.h index 5d009b9b3..70ea6e08d 100644 --- a/Client/N3Base/N3Shape.h +++ b/Client/N3Base/N3Shape.h @@ -14,7 +14,7 @@ #include "N3TransformCollision.h" #include "N3PMeshInstance.h" #include "N3Texture.h" - +#include "N3FXBundle.h" #include typedef std::vector it_pTex; @@ -125,6 +125,11 @@ class CN3Shape : public CN3TransformCollision std::vector m_Parts; // Part Data Pointer Linked List + CN3FXBundle* m_pFXB; + __Vector3 m_vFXBOffsetPos; + float m_fFXBScale; + __Quaternion m_qFXBRot; + public: #ifdef _N3TOOL bool SaveToSameFolderAndMore(const std::string& szFullPath, const std::string& szRelativePath); @@ -137,6 +142,10 @@ class CN3Shape : public CN3TransformCollision bool MakeCollisionMeshByParts(); // 충돌 메시를 박스 형태로 다시 만든다... bool MakeCollisionMeshByPartsDetail(); // 현재 모습 그대로... 충돌 메시를 만든다... + void SetFXB(const std::string& strFN, const __Vector3& vOffsetPos, const __Quaternion& qRot, float fScale); + void TickFX(); + void RenderFX(); + void FindMinMax(); virtual void ReCalcMatrix(); void ReCalcPartMatrix(); diff --git a/N3ME/MapMng.cpp b/N3ME/MapMng.cpp index 181cffc1b..c4efc0f72 100644 --- a/N3ME/MapMng.cpp +++ b/N3ME/MapMng.cpp @@ -32,6 +32,7 @@ #include "ProgressBar.h" #include "SoundMgr.h" #include "LightObjMgr.h" +#include "N3Base/N3FXBundle.h" #ifdef _DEBUG #undef THIS_FILE @@ -2215,12 +2216,50 @@ void CMapMng::LoadObjectPostData(LPCTSTR lpszFileName) __Quaternion qtRot; qtRot.Identity(); fgets(szLine, 1024, stream); - sscanf(szLine, "FileName[ %s ] PartCount[ %d ] Position[ %f %f %f] Rotation[ %f %f %f %f ] Scale[ %f %f %f ] Belong [ %d ] Attribute [ %d %d %d %d ]\n", + int n = sscanf(szLine, "FileName[ %s ] PartCount[ %d ] Position[ %f %f %f] Rotation[ %f %f %f %f ] Scale[ %f %f %f ] Belong [ %d ] Attribute [ %d %d %d %d ]\n", szSFN, &iSPC, &(vPos.x), &(vPos.y), &(vPos.z), &(qtRot.x), &(qtRot.y), &(qtRot.z), &(qtRot.w), &(vScale.x), &(vScale.y), &(vScale.z), &(iBelong), &(iEventID), &(iEventType), &(iNPC_ID), &(iNPC_Status) ); + + if (n != 17) + { + char msg[1024]; + sprintf(msg, "Failed to parse line (got %d/15):\n%s", n, szLine); + MessageBoxA(nullptr, msg, "Parse Error", MB_ICONERROR | MB_OK); + } + + char szEffectFN[MAX_PATH] = ""; // TCHAR szEffectFN[_MAX_PATH + 1] = {}; Credits to Twostars anyway.. + __Vector3 vEffectPos(0, 0, 0); + float fEffectScale = 0; + __Quaternion qtEffectRot; qtEffectRot.Identity(); + + fgets(szLine, 1024, stream); + + n = sscanf(szLine, "FXB FileName[ %s ] Offset Position[ %f %f %f ] Scale[ %f ] Rotation[ %f %f %f %f ]\n", + szEffectFN, + &vEffectPos.x, &vEffectPos.y, &vEffectPos.z, + &fEffectScale, + &qtEffectRot.x, &qtEffectRot.y, &qtEffectRot.z, &qtEffectRot.w); + + if (n != 9) + { + char msg[1024]; + sprintf(msg, "Failed to parse line (got %d/9):\n%s", n, szLine); + MessageBoxA(nullptr, "Failed to parse FXB line", "Parse Error", MB_ICONERROR | MB_OK); + } + + if (_strnicmp(szEffectFN, "empty", 5) == 0) + { + // Do nothing + } + else + { + pShape->SetFXB(szEffectFN, vEffectPos, qtEffectRot, fEffectScale); + // FXB 파일에서 읽고.. FXB Set and Read File… + } + // 텍스트에 Shape 파일 이름을 쓴다.. wsprintf(szSFN2, "Object\\%s", szSFN); pShape->LoadFromFile(szSFN2); // 파일에서 읽고.. @@ -2231,9 +2270,20 @@ void CMapMng::LoadObjectPostData(LPCTSTR lpszFileName) CN3SPart* pPart = pShape->Part(j); if(pPart) { - sscanf(szLine, "\tPart - DiffuseARGB[ %f %f %f %f ] AmbientARGB[ %f %f %f %f ]\n", - &(pPart->m_Mtl.Diffuse.a), &(pPart->m_Mtl.Diffuse.r), &(pPart->m_Mtl.Diffuse.g), &(pPart->m_Mtl.Diffuse.b), - &(pPart->m_Mtl.Ambient.a), &(pPart->m_Mtl.Ambient.r), &(pPart->m_Mtl.Ambient.g), &(pPart->m_Mtl.Ambient.b) ); + n = sscanf(szLine, + "\tOB1Part - DiffuseARGB[ %f %f %f %f ] AmbientARGB[ %f %f %f %f ] RenderState[ %d %d %d %d %d %d ]\n", + &pPart->m_Mtl.Diffuse.a, &pPart->m_Mtl.Diffuse.r, &pPart->m_Mtl.Diffuse.g, &pPart->m_Mtl.Diffuse.b, + &pPart->m_Mtl.Ambient.a, &pPart->m_Mtl.Ambient.r, &pPart->m_Mtl.Ambient.g, &pPart->m_Mtl.Ambient.b, + &pPart->m_Mtl.nRenderFlags, &pPart->m_Mtl.dwSrcBlend, &pPart->m_Mtl.dwDestBlend, + &pPart->m_Mtl.dwColorOp, &pPart->m_Mtl.dwColorArg1, &pPart->m_Mtl.dwColorArg2 + ); + + if (n != 14) + { + char msg[512]; + sprintf(msg, "Failed to parse OB1Part line (got %d/14):\n%s", n, szLine); + MessageBoxA(nullptr, msg, "Parse Error", MB_ICONERROR | MB_OK); + } } }