diff --git a/build/gamesource/textures/decal/decals.ini b/build/engine/config/decals/decals.cfg similarity index 87% rename from build/gamesource/textures/decal/decals.ini rename to build/engine/config/decals/decals.cfg index 438710c7aed537951bd0844fc34a9322d07eba3c..5054a8a4802bee12ac478bb04d96107770bbc8da 100644 --- a/build/gamesource/textures/decal/decals.ini +++ b/build/engine/config/decals/decals.cfg @@ -2,7 +2,7 @@ [decal_0] id=0 base_scale=2.0 -tex=decal_test.dds +tex=decal_test tex0=[0,0,64,64] tex1=[64,0,128,64] tex2=[0,64,64,128] @@ -12,7 +12,7 @@ tex3=[64,64,128,128] [decal_1] id=1 base_scale=2.0 -tex=decal_test.dds +tex=decal_test tex0=[128,0,192,64] tex1=[192,0,256,64] tex2=[128,64,192,128] @@ -20,9 +20,9 @@ tex3=[192,64,256,128] ;wood [decal_2] -id=2 +id=4 base_scale=2.0 -tex=decal_test.dds +tex=decal_test tex0=[256,0,320,64] tex1=[320,0,384,64] tex2=[256,64,320,128] @@ -31,9 +31,9 @@ tex4=[384,0,448,64] ;glass [decal_3] -id=3 +id=2 base_scale=2.0 -tex=decal_test.dds +tex=decal_test tex0=[0,128,128,256] tex1=[128,128,256,256] tex2=[256,128,384,256] @@ -44,7 +44,7 @@ tex4=[128,256,256,384] [decal_4] id=7 base_scale=8.0 -tex=decal_test.dds +tex=decal_test tex0=[256,256,384,384] tex1=[384,256,512,384] tex2=[384,128,512,256] diff --git a/build/gamesource/textures/decal/decal_test.dds b/build/engine/textures/decal/decal_test.dds similarity index 100% rename from build/gamesource/textures/decal/decal_test.dds rename to build/engine/textures/decal/decal_test.dds diff --git a/build/engine/textures/decal/decal_test2.dds b/build/engine/textures/decal/decal_test2.dds new file mode 100644 index 0000000000000000000000000000000000000000..497ec0a645bbe369790dd9d2d78db10214bb2d5e Binary files /dev/null and b/build/engine/textures/decal/decal_test2.dds differ diff --git a/build/engine/textures/decal/decal_test3.dds b/build/engine/textures/decal/decal_test3.dds new file mode 100644 index 0000000000000000000000000000000000000000..b068b6500463898c431ee6069992113c5d9bc5de Binary files /dev/null and b/build/engine/textures/decal/decal_test3.dds differ diff --git a/docs/gen-entity.js b/docs/gen-entity.js index 95ba19a9209b1a6bffd67fe2eb9df10021af47ee..6641926e08179d5d94270d297b48a0a3cea78f36 100644 --- a/docs/gen-entity.js +++ b/docs/gen-entity.js @@ -19,6 +19,7 @@ g_mFieldTypes = { "DEFINE_FIELD_STRING": "string", "DEFINE_FIELD_ANGLES": "angles", "DEFINE_FIELD_INT": "int", + "DEFINE_FIELD_UINT": "uint", "DEFINE_FIELD_ENUM": null, "DEFINE_FIELD_FLOAT": "float", "DEFINE_FIELD_BOOL": "bool", @@ -29,6 +30,7 @@ g_mFieldTypes = { g_mInputTypes = { "PDF_NONE": "none", "PDF_INT": "int", + "PDF_UINT": "uint", "PDF_FLOAT": "float", "PDF_VECTOR": "float3", "PDF_VECTOR4": "float4", diff --git a/proj/sxanim/vs2013/sxanim.vcxproj b/proj/sxanim/vs2013/sxanim.vcxproj index bd4a7d117b7fa96a3a354af493a33fc234c34eac..e20becf019bca210c7f7fcd838fbbad66df5363a 100644 --- a/proj/sxanim/vs2013/sxanim.vcxproj +++ b/proj/sxanim/vs2013/sxanim.vcxproj @@ -181,26 +181,36 @@ <ClCompile Include="..\..\..\source\anim\AnimatedModel.cpp" /> <ClCompile Include="..\..\..\source\anim\AnimatedModelProvider.cpp" /> <ClCompile Include="..\..\..\source\anim\AnimatedModelShared.cpp" /> + <ClCompile Include="..\..\..\source\anim\Decal.cpp" /> + <ClCompile Include="..\..\..\source\anim\DecalProvider.cpp" /> <ClCompile Include="..\..\..\source\anim\dllmain.cpp" /> <ClCompile Include="..\..\..\source\anim\DynamicModel.cpp" /> <ClCompile Include="..\..\..\source\anim\DynamicModelProvider.cpp" /> <ClCompile Include="..\..\..\source\anim\DynamicModelShared.cpp" /> + <ClCompile Include="..\..\..\source\anim\ModelOverlay.cpp" /> <ClCompile Include="..\..\..\source\anim\plugin_main.cpp" /> <ClCompile Include="..\..\..\source\anim\Renderable.cpp" /> <ClCompile Include="..\..\..\source\anim\RenderableVisibility.cpp" /> + <ClCompile Include="..\..\..\source\anim\StaticModelProvider.cpp" /> <ClCompile Include="..\..\..\source\anim\Updatable.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\anim\AnimatedModel.h" /> <ClInclude Include="..\..\..\source\anim\AnimatedModelProvider.h" /> <ClInclude Include="..\..\..\source\anim\AnimatedModelShared.h" /> + <ClInclude Include="..\..\..\source\anim\Decal.h" /> + <ClInclude Include="..\..\..\source\anim\DecalProvider.h" /> <ClInclude Include="..\..\..\source\anim\DynamicModel.h" /> <ClInclude Include="..\..\..\source\anim\DynamicModelProvider.h" /> <ClInclude Include="..\..\..\source\anim\DynamicModelShared.h" /> + <ClInclude Include="..\..\..\source\anim\ModelOverlay.h" /> <ClInclude Include="..\..\..\source\anim\Renderable.h" /> <ClInclude Include="..\..\..\source\anim\RenderableVisibility.h" /> + <ClInclude Include="..\..\..\source\anim\StaticModelProvider.h" /> <ClInclude Include="..\..\..\source\anim\Updatable.h" /> <ClInclude Include="..\..\..\source\xcommon\IXScene.h" /> + <ClInclude Include="..\..\..\source\xcommon\resource\IXDecal.h" /> + <ClInclude Include="..\..\..\source\xcommon\resource\IXDecalProvider.h" /> <ClInclude Include="..\..\..\source\xcommon\resource\IXModelProvider.h" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> diff --git a/proj/sxanim/vs2013/sxanim.vcxproj.filters b/proj/sxanim/vs2013/sxanim.vcxproj.filters index 1db63868b08793ae349c2374e6c93b2f85f5ed5b..e907c6c64e5b8546f8410d5adccef4efb1c75ec3 100644 --- a/proj/sxanim/vs2013/sxanim.vcxproj.filters +++ b/proj/sxanim/vs2013/sxanim.vcxproj.filters @@ -49,6 +49,18 @@ <ClCompile Include="..\..\..\source\anim\dllmain.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\anim\DecalProvider.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\source\anim\ModelOverlay.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\source\anim\Decal.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\source\anim\StaticModelProvider.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\anim\Renderable.h"> @@ -84,5 +96,23 @@ <ClInclude Include="..\..\..\source\xcommon\IXScene.h"> <Filter>Header Files\xcommon</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\xcommon\resource\IXDecalProvider.h"> + <Filter>Header Files\xcommon</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\xcommon\resource\IXDecal.h"> + <Filter>Header Files\xcommon</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\anim\DecalProvider.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\anim\ModelOverlay.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\anim\Decal.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\source\anim\StaticModelProvider.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> </Project> \ No newline at end of file diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj index 6b2bc8d735699766e886b7b69dfee7e44688adcd..8ab0fd8f3d070671bc27d0323b1e6e3104e4d851 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj +++ b/proj/sxgame/vs2013/sxgame.vcxproj @@ -210,6 +210,7 @@ <ClCompile Include="..\..\..\source\game\GUICraftController.cpp" /> <ClCompile Include="..\..\..\source\game\GUIInventoryController.cpp" /> <ClCompile Include="..\..\..\source\game\HUDcontroller.cpp" /> + <ClCompile Include="..\..\..\source\game\InfoOverlay.cpp" /> <ClCompile Include="..\..\..\source\game\InfoParticlePlayer.cpp" /> <ClCompile Include="..\..\..\source\game\LadderMovementController.cpp" /> <ClCompile Include="..\..\..\source\game\LightDirectional.cpp" /> @@ -297,6 +298,7 @@ <ClInclude Include="..\..\..\source\game\HUDcontroller.h" /> <ClInclude Include="..\..\..\source\game\IGameState.h" /> <ClInclude Include="..\..\..\source\game\IMovementController.h" /> + <ClInclude Include="..\..\..\source\game\InfoOverlay.h" /> <ClInclude Include="..\..\..\source\game\InfoParticlePlayer.h" /> <ClInclude Include="..\..\..\source\game\LadderMovementController.h" /> <ClInclude Include="..\..\..\source\game\LightSun.h" /> diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters index ad313030c273047139c37747e35db9ac6b354975..01a241c50c71b92e5a88a35df59b9daf88dae08e 100644 --- a/proj/sxgame/vs2013/sxgame.vcxproj.filters +++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters @@ -381,6 +381,9 @@ <ClCompile Include="..\..\..\source\game\NarrowPassageMovementController.cpp"> <Filter>Source Files\character_movement</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\game\InfoOverlay.cpp"> + <Filter>Source Files\ents\info</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\source\game\sxgame.h"> @@ -665,6 +668,9 @@ <ClInclude Include="..\..\..\source\game\NarrowPassageMovementController.h"> <Filter>Header Files\character_movement</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\game\InfoOverlay.h"> + <Filter>Header Files\ents\info</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\..\source\game\sxgame.rc"> diff --git a/proj/terrax/vs2013/terrax.vcxproj b/proj/terrax/vs2013/terrax.vcxproj index fad89107a72f7c7eefc68fbdd5884a7f2d5b1e37..461cd97712f84454376cb5f6e7a277ec2993bd4f 100644 --- a/proj/terrax/vs2013/terrax.vcxproj +++ b/proj/terrax/vs2013/terrax.vcxproj @@ -244,6 +244,7 @@ <ClCompile Include="..\..\..\source\terrax\MaterialEditor.cpp" /> <ClCompile Include="..\..\..\source\terrax\PropertyWindow.cpp" /> <ClCompile Include="..\..\..\source\terrax\ProxyObject.cpp" /> + <ClCompile Include="..\..\..\source\terrax\ResourceBrowser.cpp" /> <ClCompile Include="..\..\..\source\terrax\SceneTreeWindow.cpp" /> <ClCompile Include="..\..\..\source\terrax\ScrollBar.cpp" /> <ClCompile Include="..\..\..\source\terrax\terrax.cpp" /> @@ -303,6 +304,7 @@ <ClInclude Include="..\..\..\source\terrax\MaterialEditor.h" /> <ClInclude Include="..\..\..\source\terrax\PropertyWindow.h" /> <ClInclude Include="..\..\..\source\terrax\ProxyObject.h" /> + <ClInclude Include="..\..\..\source\terrax\ResourceBrowser.h" /> <ClInclude Include="..\..\..\source\terrax\SceneTreeWindow.h" /> <ClInclude Include="..\..\..\source\terrax\ScrollBar.h" /> <ClInclude Include="..\..\..\source\terrax\TextureViewGraphNode.h" /> diff --git a/proj/terrax/vs2013/terrax.vcxproj.filters b/proj/terrax/vs2013/terrax.vcxproj.filters index 919fa263ed4e46045b8d5715f2b3abe0c6500dfc..71fef577fe56b1114d70f818b5cdfa5b198c4d30 100644 --- a/proj/terrax/vs2013/terrax.vcxproj.filters +++ b/proj/terrax/vs2013/terrax.vcxproj.filters @@ -213,6 +213,9 @@ <ClCompile Include="..\..\..\source\terrax\CommandUngroup.cpp"> <Filter>Source Files\cmd</Filter> </ClCompile> + <ClCompile Include="..\..\..\source\terrax\ResourceBrowser.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\..\source\terrax\terrax.rc"> @@ -415,6 +418,9 @@ <ClInclude Include="..\..\..\source\terrax\CommandUngroup.h"> <Filter>Header Files\cmd</Filter> </ClInclude> + <ClInclude Include="..\..\..\source\terrax\ResourceBrowser.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <Image Include="..\..\..\source\terrax\resource\new.bmp"> diff --git a/source/anim/AnimatedModelProvider.cpp b/source/anim/AnimatedModelProvider.cpp index 7265f05afe21f7cc46a3741aacdbd90febda6034..9147e9e896e73633729ddec5f844894268343fb8 100644 --- a/source/anim/AnimatedModelProvider.cpp +++ b/source/anim/AnimatedModelProvider.cpp @@ -202,6 +202,11 @@ void CAnimatedModelProvider::bindVertexFormat() m_pMaterialSystem->bindVS(m_pVertexShaderHandler); } +bool CAnimatedModelProvider::hasPendingOps() +{ + return(!m_queueGPUinitModel.empty() || !m_queueGPUinitShared.empty()); +} + void CAnimatedModelProvider::render(CRenderableVisibility *pVisibility) { XPROFILE_FUNCTION(); diff --git a/source/anim/AnimatedModelProvider.h b/source/anim/AnimatedModelProvider.h index a9242e6352a19a3fd0edb65edaa17fee6974dfb9..4789f1b6483a20fd8d9f5ca619c67c5886ce0af3 100644 --- a/source/anim/AnimatedModelProvider.h +++ b/source/anim/AnimatedModelProvider.h @@ -37,6 +37,8 @@ public: void bindVertexFormat(); + bool hasPendingOps(); + protected: AssotiativeArray<IXResourceModelAnimated*, Array<CAnimatedModelShared*>> m_mModels; diff --git a/source/anim/Decal.cpp b/source/anim/Decal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18c808f591f1dc7419b80d62252a1c0d9c76d326 --- /dev/null +++ b/source/anim/Decal.cpp @@ -0,0 +1,657 @@ +#include "Decal.h" +#include "DynamicModel.h" +#include "DecalProvider.h" + +CDecal::CDecal(IXSceneQuery *pSceneQuery, IXRender *pRender, CDecalProvider *pProvider): + m_pSceneQuery(pSceneQuery), + m_pRender(pRender), + m_pProvider(pProvider) +{ +} + +CDecal::~CDecal() +{ + removeOverlays(); + mem_release(m_pMaterial); +} + +bool XMETHODCALLTYPE CDecal::isEnabled() const +{ + return(m_isEnabled); +} +void XMETHODCALLTYPE CDecal::enable(bool yesNo) +{ + m_isEnabled = yesNo; + TODO("Change state"); +} + +float3 XMETHODCALLTYPE CDecal::getPosition() const +{ + return(m_vPos); +} +void XMETHODCALLTYPE CDecal::setPosition(const float3 &vPos) +{ + m_vPos = vPos; + setDirty(); +} + +SMQuaternion XMETHODCALLTYPE CDecal::getOrientation() const +{ + return(m_qRot); +} +void XMETHODCALLTYPE CDecal::setOrientation(const SMQuaternion &qRot) +{ + m_qRot = qRot; + setDirty(); +} + +float3 XMETHODCALLTYPE CDecal::getLocalBoundMin() const +{ + float3 vBound; + for(UINT i = 0; i < DECAL_POINTS; ++i) + { + if(i == 0) + { + vBound = m_qRot * float3(m_avCorners[0], 0.0f); + } + else + { + vBound = SMVectorMin(vBound, m_qRot * float3(m_avCorners[0], 0.0f)); + } + vBound = SMVectorMin(vBound, m_qRot * float3(m_avCorners[0], m_fHeight)); + } + + return(vBound); +} +float3 XMETHODCALLTYPE CDecal::getLocalBoundMax() const +{ + float3 vBound; + for(UINT i = 0; i < DECAL_POINTS; ++i) + { + if(i == 0) + { + vBound = m_qRot * float3(m_avCorners[0], 0.0f); + } + else + { + vBound = SMVectorMax(vBound, m_qRot * float3(m_avCorners[0], 0.0f)); + } + vBound = SMVectorMax(vBound, m_qRot * float3(m_avCorners[0], m_fHeight)); + } + + return(vBound); +} +SMAABB XMETHODCALLTYPE CDecal::getLocalBound() const +{ + return(SMAABB(getLocalBoundMin(), getLocalBoundMax())); +} + +bool XMETHODCALLTYPE CDecal::rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal) +{ + fora(i, m_aOverlays) + { + const Overlay &overlay = m_aOverlays[i]; + const Array<XResourceModelStaticVertex> &aVertices = overlay.pOverlay->getVertices(); + + float3 vRayStart = vStart; + float3 vRayEnd = vEnd; + + if(!overlay.pModel->isStatic()) + { + // transform ray to local space + float3 vPos = overlay.pModel->getPosition(); + SMQuaternion qRot = overlay.pModel->getOrientation(); + + vRayStart = qRot.Conjugate() * vRayStart - vPos; + vRayEnd = qRot.Conjugate() * vRayEnd - vPos; + } + + for(UINT j = 0, jl = aVertices.size(); j < jl; j += 4) + { + // 012 213 + if(SMTriangleIntersectLine(aVertices[j].vPos, aVertices[j + 1].vPos, aVertices[j + 2].vPos, vRayStart, vRayEnd, pvOut)) + { + if(pvNormal) + { + *pvNormal = SMVector3Normalize(SMVector3Cross(aVertices[j + 1].vPos - aVertices[j].vPos, aVertices[j + 2].vPos - aVertices[j].vPos)); + } + return(true); + } + + if(!SMIsZero(SMVector3Length2(aVertices[j + 3].vPos - aVertices[j + 2].vPos)) && SMTriangleIntersectLine(aVertices[j + 2].vPos, aVertices[j + 1].vPos, aVertices[j + 3].vPos, vRayStart, vRayEnd, pvOut)) + { + if(pvNormal) + { + *pvNormal = SMVector3Normalize(SMVector3Cross(aVertices[j + 1].vPos - aVertices[j + 2].vPos, aVertices[j + 3].vPos - aVertices[j + 2].vPos)); + } + return(true); + } + } + } + return(false); +} + +void XMETHODCALLTYPE CDecal::setLayer(UINT uLayer) +{ + m_uLayer = uLayer; + setDirty(); +} +UINT XMETHODCALLTYPE CDecal::getLayer() +{ + return(m_uLayer); +} + +void XMETHODCALLTYPE CDecal::setHeight(float fHeight) +{ + m_fHeight = fHeight; + setDirty(); +} +float XMETHODCALLTYPE CDecal::getHeight() +{ + return(m_fHeight); +} + +void XMETHODCALLTYPE CDecal::setTextureRangeU(const float2_t &vRange) +{ + m_vTexRangeU = vRange; +} +float2_t XMETHODCALLTYPE CDecal::getTextureRangeU() +{ + return(m_vTexRangeU); +} + +void XMETHODCALLTYPE CDecal::setTextureRangeV(const float2_t &vRange) +{ + m_vTexRangeV = vRange; +} +float2_t XMETHODCALLTYPE CDecal::getTextureRangeV() +{ + return(m_vTexRangeV); +} + +void XMETHODCALLTYPE CDecal::setMaterial(const char *szMaterial) +{ + mem_release(m_pMaterial); + m_pProvider->getMaterialSystem()->loadMaterial(szMaterial, &m_pMaterial); + + setDirty(); +} + +void CDecal::setMaterial(IXMaterial *pMaterial) +{ + mem_release(m_pMaterial); + m_pMaterial = pMaterial; + add_ref(m_pMaterial); + + setDirty(); +} +void XMETHODCALLTYPE CDecal::setCorner(UINT uCorner, const float2_t &vCorner) +{ + assert(uCorner < DECAL_POINTS); + if(uCorner < DECAL_POINTS) + { + m_avCorners[uCorner] = vCorner; + setDirty(); + } +} + +void CDecal::update( +#ifdef DECAL_DEBUG_DRAW + IXGizmoRenderer *pDebugRenderer +#endif +) +{ + if(m_isDirty) + { + // cleanup old overlays + removeOverlays(); + + // query for objects + + SMPLANE aPlanes[] = { + SMPlaneNormalize(SMPLANE(float3(m_avCorners[0], 0.0f), float3(m_avCorners[1], 0.0f), float3(m_avCorners[1], m_fHeight))), + SMPlaneNormalize(SMPLANE(float3(m_avCorners[2], 0.0f), float3(m_avCorners[3], 0.0f), float3(m_avCorners[3], m_fHeight))), + + SMPlaneNormalize(SMPLANE(float3(m_avCorners[1], 0.0f), float3(m_avCorners[2], 0.0f), float3(m_avCorners[2], m_fHeight))), + SMPlaneNormalize(SMPLANE(float3(m_avCorners[3], 0.0f), float3(m_avCorners[0], 0.0f), float3(m_avCorners[0], m_fHeight))), + + SMPLANE(0.0f, 0.0f, 1.0f, m_fHeight), + SMPLANE(0.0f, 0.0f, -1.0f, m_fHeight), + }; + + //SMMATRIX mWorld = SMMatrixTranspose(m_qRot.GetMatrix() * SMMatrixTranslation(m_vPos)); + //SMMATRIX mWorld = m_qRot.GetMatrix(); + for(UINT i = 0; i < ARRAYSIZE(aPlanes); ++i) + { + //aPlanes[i] = SMPlaneTransformTI(aPlanes[i], mWorld); + aPlanes[i] = SMPLANE(m_qRot * float3(aPlanes[i]), aPlanes[i].w); + aPlanes[i].w -= SMVector3Dot(aPlanes[i], m_vPos); + } + + IXFrustum *pFrustum; + m_pRender->newFrustum(&pFrustum); + + pFrustum->update(aPlanes, false); + +#ifdef DECAL_DEBUG_DRAW + pDebugRenderer->setColor(float4(1.0f, 1.0f, 0.0f, 1.0f)); + for(UINT i = 0; i < 8; ++i) + { + pDebugRenderer->drawPoint(pFrustum->getPoint(i)); + } + pDebugRenderer->setColor(float4(1.0f, 1.0f, 0.0f, 0.2f)); +#endif + + CDynamicModel **ppObjects = NULL; + m_pSceneQuery->setLayerMask(1 << m_uLayer); + UINT uCount = m_pSceneQuery->execute(pFrustum, (void***)&ppObjects); + + SMPLANE aPlanesObjectSpace[ARRAYSIZE(aPlanes)]; + + // build overlays + for(UINT i = 0; i < uCount; ++i) + { + TODO("Check ppObjects[i]->receivingDecals()"); + + for(UINT j = 0; j < ARRAYSIZE(aPlanes); ++j) + { + aPlanesObjectSpace[j] = SMPLANE(ppObjects[i]->getOrientation().Conjugate() * float3(aPlanes[j]), aPlanes[j].w + SMVector3Dot(aPlanes[j], ppObjects[i]->getPosition())); + } + pFrustum->update(aPlanesObjectSpace, false); + + spawnOverlayForModel(ppObjects[i], pFrustum +#ifdef DECAL_DEBUG_DRAW + , pDebugRenderer +#endif + ); + } + + mem_release(pFrustum); + + m_isDirty = false; + } +} + +void CDecal::onOverlayRemoved(CModelOverlay *pOverlay) +{ + int idx = m_aOverlays.indexOf(pOverlay, [](const Overlay &a, CModelOverlay *pB){ + return(a.pOverlay == pB); + }); + assert(idx >= 0); + if(idx >= 0) + { + m_aOverlays.erase(idx); + m_pProvider->freeOverlay(pOverlay); + if(!m_aOverlays.size()) + { + m_pProvider->onDecalEmptied(this); + } + } +} + +template<typename T> +static T ArrGet(T *pArr, UINT uSize, UINT uIdx, int iStartOffset = 0) +{ + return(pArr[((int)uIdx + iStartOffset) % uSize]); +} + +template<typename T> +static void ArrDel(T *pArr, UINT &uSize, UINT uIdx, int &iStartOffset) +{ + UINT uStartIndex = ((int)uIdx + iStartOffset) % uSize; + --uSize; + if(uStartIndex != uSize) + { + for(UINT i = uStartIndex; i < uSize; ++i) + { + pArr[i] = pArr[i + 1]; + } + } + if(uStartIndex < iStartOffset) + { + --iStartOffset; + } +} + +template<typename T> +static void ArrIns(const T &val, T *pArr, UINT &uSize, UINT uIdx, int &iStartOffset) +{ + UINT uStartIndex = ((int)uIdx + iStartOffset) % uSize; + if(uStartIndex == 0) + { + uStartIndex = uSize; + } + else + { + for(UINT i = uSize; i > uStartIndex; --i) + { + pArr[i] = pArr[i - 1]; + } + } + assert(uStartIndex < 10); + pArr[uStartIndex] = val; + ++uSize; + + if(uStartIndex < iStartOffset) + { + ++iStartOffset; + } +} + +template<typename T> +static void ArrSet(const T &val, T *pArr, UINT &uSize, UINT uIdx, int iStartOffset = 0) +{ + pArr[((int)uIdx + iStartOffset) % uSize] = val; +} + +static bool IsInside(const SMPLANE &plane, const float3_t &vPos) +{ + return(SMVector4Dot(plane, float4(vPos, 1.0f)) > 0.0f); +} + +void XMETHODCALLTYPE CDecal::FinalRelease() +{ + m_pProvider->onDecalReleased(this); +} + +void CDecal::spawnOverlayForModel(CDynamicModel *pModel, IXFrustum *pFrustum +#ifdef DECAL_DEBUG_DRAW + , IXGizmoRenderer *pDebugRenderer +#endif +) +{ + const IXResourceModelStatic *pResource = pModel->getResource()->asStatic(); + if(!pResource) + { + return; + } + + if(pResource->getPrimitiveTopology() != XPT_TRIANGLELIST) + { + LogError("CDecal::spawnOverlayForModel(): Unsupported primitive topology"); + } + + SMQuaternion qDecalToModel = m_qRot * pModel->getOrientation().Conjugate(); + float3 vS = qDecalToModel * float3(1.0f, 0.0f, 0.0f); + float3 vT = qDecalToModel * float3(0.0f, 1.0f, 0.0f); + float3 vN = qDecalToModel * float3(0.0f, 0.0f, 1.0f); + + float2_t sBound; + float2_t tBound; + // center point + float3 vModelSpaceDecalCenter = pModel->getOrientation().Conjugate() * (m_vPos - pModel->getPosition()); + + for(UINT j = 0; j < DECAL_POINTS; ++j) + { + float s = m_avCorners[j].x; + float t = m_avCorners[j].y; + if(j == 0) + { + sBound.x = s; + sBound.y = s; + tBound.x = t; + tBound.y = t; + } + else + { + if(sBound.x > s) + { + sBound.x = s; + } + if(sBound.y < s) + { + sBound.y = s; + } + if(tBound.x > t) + { + tBound.x = t; + } + if(tBound.y < t) + { + tBound.y = t; + } + } + } + float2_t vInvBoundRange = float2(1.0f, 1.0f) / float2(sBound.y - sBound.x, tBound.y - tBound.x); + XResourceModelStaticVertex vtx; + vtx.vTangent = vS; + vtx.vBinorm = vT; + vtx.vNorm = vN; + + float3_t aTempVertices[10]; // 9 - max vertex count of clipped triangle + 1 temp vertex + UINT uVertexCount; + + Array<XResourceModelStaticVertex> aOverlayVertices; + + float fCosThreshold = m_isLeakAllowed ? -0.1f : 0.2f; + + UINT uSubsets = pResource->getSubsetCount(0); + for(UINT uSubset = 0; uSubset < uSubsets; ++uSubset) + { + TODO("Separate transparent subsets"); + const XResourceModelStaticSubset *pSubset = pResource->getSubset(0, uSubset); + for(UINT i = 0; i < pSubset->iIndexCount; i += 3) + { + float3_t &a = pSubset->pVertices[pSubset->pIndices[i]].vPos; + float3_t &b = pSubset->pVertices[pSubset->pIndices[i + 1]].vPos; + float3_t &c = pSubset->pVertices[pSubset->pIndices[i + 2]].vPos; + + float3 vTriN = SMVector3Normalize(SMVector3Cross(b - a, c - a)); + float fCos = SMVector3Dot(vN, vTriN); + + if(fCos > fCosThreshold && pFrustum->polyInFrustum(a, b, c)) + { + aTempVertices[0] = a; + aTempVertices[1] = b; + aTempVertices[2] = c; + uVertexCount = 3; + + //pDebugRenderer->drawPoly(a, b, c); + + // clip by frustum planes + for(UINT j = 0, jl = pFrustum->getPlaneCount(); j < jl && uVertexCount >= 3/* && j < 4*/; ++j) + { + const SMPLANE &plane = pFrustum->getPlaneAt(j); + int iInsideVertex = -1; + // - find inside vertex + for(UINT k = 0; k < uVertexCount; ++k) + { + if(IsInside(plane, aTempVertices[k])) + { + iInsideVertex = (int)k; + break; + } + } + + if(iInsideVertex < 0) + { + // all vertices outside clipping plane + uVertexCount = 0; + break; + } + // - rotate array to make inside vertex first + // - clip + + for(UINT k = 0; k < uVertexCount; ++k) + { + float3_t vCur = ArrGet(aTempVertices, uVertexCount, k, iInsideVertex); + float3_t vNext = ArrGet(aTempVertices, uVertexCount, k + 1, iInsideVertex); + bool bCurInside = IsInside(plane, vCur); + bool bNextInside = IsInside(plane, vNext); + if(bCurInside) + { + if(bNextInside) + { + continue; + } + else + { + // clip + float3 vPt; + bool b = plane.intersectLine(&vPt, vCur, vNext); + assert(b); + // insert after cur + ArrIns((float3_t)vPt, aTempVertices, uVertexCount, k + 1, iInsideVertex); + ++k; + } + } + else + { + if(bNextInside) + { + // clip + float3 vPt; + bool b = plane.intersectLine(&vPt, vCur, vNext); + assert(b); + // replace cur + ArrSet((float3_t)vPt, aTempVertices, uVertexCount, k, iInsideVertex); + } + else + { + // drop cur + ArrDel(aTempVertices, uVertexCount, k, iInsideVertex); + --k; + } + } + } + } + + // put into overlay + if(uVertexCount >= 3) + { + if(pModel->isStatic()) + { + // transform to world pos + float3 vPos = pModel->getPosition(); + SMQuaternion qRot = pModel->getOrientation(); + for(UINT j = 0; j < uVertexCount; ++j) + { + aTempVertices[j] = qRot * aTempVertices[j] + vPos; + } + } + + UINT uStartVtx = aOverlayVertices.size(); + for(UINT begin = 0, end = uVertexCount - 1; begin + 1 <= end - 1; ++begin, --end) + { + vtx.vPos = aTempVertices[end]; + aOverlayVertices.push_back(vtx); + + vtx.vPos = aTempVertices[begin]; + aOverlayVertices.push_back(vtx); + + vtx.vPos = aTempVertices[end - 1]; + aOverlayVertices.push_back(vtx); + + vtx.vPos = aTempVertices[begin + 1]; + aOverlayVertices.push_back(vtx); + } + + float3 vTriS = vS; + float3 vTriT = vT; + + if(fCos < 0.2f) + { + float3 vRotAxis = SMVector3Cross(vTriN, vN); + + float fTempS = SMVector3Dot(vRotAxis, vS); + float fTempT = SMVector3Dot(vRotAxis, vT); + + float fSign = max(fTempS, fTempT); + float fAngle = safe_acosf(fCos); + if(fSign < 0.0f) + { + fAngle = SM_2PI - fAngle; + } + + SMQuaternion q(vRotAxis, fAngle); + vTriS = q * vS; + vTriT = q * vT; + } + + for(UINT j = uStartVtx, jl = aOverlayVertices.size(); j < jl; ++j) + { + XResourceModelStaticVertex &vt = aOverlayVertices[j]; + + float3 vPos = vt.vPos - vModelSpaceDecalCenter; + float s = SMVector3Dot(vPos, vTriS); + float t = SMVector3Dot(vPos, vTriT); + vt.vPos = vt.vPos + vTriN * 0.0001f; + + vt.vTex.x = lerpf(m_vTexRangeU.x, m_vTexRangeU.y, clampf((s - sBound.x) * vInvBoundRange.x, 0.0f, 1.0f)); + vt.vTex.y = lerpf(m_vTexRangeV.x, m_vTexRangeV.y, clampf((t - tBound.x) * vInvBoundRange.y, 0.0f, 1.0f)); + } + } + } + } + } + + // aOverlayVertices + CModelOverlay *pOverlay = m_pProvider->allocOverlay(this, m_pMaterial, aOverlayVertices, vN); + m_aOverlays.push_back({pModel, pOverlay}); + + CModelOverlay *pLastOverlay = pModel->getOverlay(); + if(!pLastOverlay) + { + pModel->setOverlay(pOverlay); + } + else + { + while(pLastOverlay->getNextOverlay()) + { + pLastOverlay = pLastOverlay->getNextOverlay(); + } + pLastOverlay->setNextOverlay(pOverlay); + } +} + +void CDecal::removeOverlays() +{ + fora(i, m_aOverlays) + { + Overlay &ovl = m_aOverlays[i]; + + CModelOverlay *pPrev = NULL; + CModelOverlay *pCur = ovl.pModel->getOverlay(); + while(pCur) + { + if(pCur == ovl.pOverlay) + { + if(pPrev) + { + pPrev->setNextOverlay(pCur->getNextOverlay()); + } + else + { + ovl.pModel->setOverlay(pCur->getNextOverlay()); + } + + break; + } + + pPrev = pCur; + pCur = pCur->getNextOverlay(); + } + + m_pProvider->freeOverlay(ovl.pOverlay); + } + + m_aOverlays.clearFast(); +} + +void CDecal::setDirty() +{ + if(!m_isDirty) + { + m_isDirty = true; + m_pProvider->updateDecal(this); + } +} + +void XMETHODCALLTYPE CDecal::setLeakAllowed(bool yesNo) +{ + if(!!yesNo != !!m_isLeakAllowed) + { + m_isLeakAllowed = yesNo; + setDirty(); + } +} diff --git a/source/anim/Decal.h b/source/anim/Decal.h new file mode 100644 index 0000000000000000000000000000000000000000..da5016ff7958b6f6d8c081341235125a3d3e55eb --- /dev/null +++ b/source/anim/Decal.h @@ -0,0 +1,110 @@ +#ifndef __DECAL_H +#define __DECAL_H + +#include <xcommon/resource/IXDecal.h> +#include <xcommon/IXScene.h> +#include <xcommon/render/IXRender.h> +#include "ModelOverlay.h" + +#define DECAL_POINTS 4 + +// #define DECAL_DEBUG_DRAW + +class CDynamicModel; +class CDecalProvider; + +class CDecal final: public IXUnknownImplementation<IXDecal> +{ +public: + CDecal(IXSceneQuery *pSceneQuery, IXRender *pRender, CDecalProvider *pProvider); + ~CDecal(); + + bool XMETHODCALLTYPE isEnabled() const override; + void XMETHODCALLTYPE enable(bool yesNo) override; + + float3 XMETHODCALLTYPE getPosition() const override; + void XMETHODCALLTYPE setPosition(const float3 &vPos) override; + + SMQuaternion XMETHODCALLTYPE getOrientation() const override; + void XMETHODCALLTYPE setOrientation(const SMQuaternion &qRot) override; + + float3 XMETHODCALLTYPE getLocalBoundMin() const override; + float3 XMETHODCALLTYPE getLocalBoundMax() const override; + SMAABB XMETHODCALLTYPE getLocalBound() const override; + + bool XMETHODCALLTYPE rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut = NULL, float3 *pvNormal = NULL) override; + + void XMETHODCALLTYPE setLayer(UINT uLayer) override; + UINT XMETHODCALLTYPE getLayer() override; + + void XMETHODCALLTYPE setHeight(float fHeight) override; + float XMETHODCALLTYPE getHeight() override; + + void XMETHODCALLTYPE setTextureRangeU(const float2_t &vRange) override; + float2_t XMETHODCALLTYPE getTextureRangeU() override; + + void XMETHODCALLTYPE setTextureRangeV(const float2_t &vRange) override; + float2_t XMETHODCALLTYPE getTextureRangeV() override; + + void XMETHODCALLTYPE setMaterial(const char *szMaterial) override; + + void setMaterial(IXMaterial *pMaterial); + void XMETHODCALLTYPE setCorner(UINT uCorner, const float2_t &vCorner) override; + + void XMETHODCALLTYPE setLeakAllowed(bool yesNo) override; + + void update( +#ifdef DECAL_DEBUG_DRAW + IXGizmoRenderer *pDebugRenderer +#endif + ); + + // Must be called only for overlays removed with model + void onOverlayRemoved(CModelOverlay *pOverlay); + +private: + IXSceneQuery *m_pSceneQuery = NULL; + IXRender *m_pRender = NULL; + CDecalProvider *m_pProvider = NULL; + + IXMaterial *m_pMaterial = NULL; + + float2_t m_avCorners[4]; + + SMQuaternion m_qRot; + float3_t m_vPos; + + float m_fHeight = 0.1f; + + UINT m_uLayer = 0; + + float2_t m_vTexRangeU = float2_t(0.0f, 1.0f); + float2_t m_vTexRangeV = float2_t(0.0f, 1.0f); + + struct Overlay + { + CDynamicModel *pModel; + CModelOverlay *pOverlay; + }; + Array<Overlay> m_aOverlays; + + bool m_isEnabled = true; + + bool m_isDirty = false; + + bool m_isLeakAllowed = true; + +private: + void XMETHODCALLTYPE FinalRelease() override; + void spawnOverlayForModel(CDynamicModel *pModel, IXFrustum *pFrustum +#ifdef DECAL_DEBUG_DRAW + , IXGizmoRenderer *pDebugRenderer +#endif + ); + + void removeOverlays(); + + void setDirty(); +}; + +#endif diff --git a/source/anim/DecalProvider.cpp b/source/anim/DecalProvider.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1aaec25f9fe51e9aaccd002b98c58724e9f0e827 --- /dev/null +++ b/source/anim/DecalProvider.cpp @@ -0,0 +1,619 @@ +#include "DecalProvider.h" +//#include <xcommon/IPluginManager.h> +//#include <core/sxcore.h> +#include "ModelOverlay.h" +#include "DynamicModel.h" +#include "DynamicModelProvider.h" +#include <xcommon/IPluginManager.h> +#include "Decal.h" + +CDecalProvider::CDecalProvider(IXCore *pCore, CDynamicModelProvider *pProviderDynamic): + m_pCore(pCore), + m_pProviderDynamic(pProviderDynamic) +{ + m_pMaterialSystem = (IXMaterialSystem*)pCore->getPluginManager()->getInterface(IXMATERIALSYSTEM_GUID); + m_pRenderUtils = (IXRenderUtils*)pCore->getPluginManager()->getInterface(IXRENDERUTILS_GUID); + m_pRender = (IXRender*)pCore->getPluginManager()->getInterface(IXRENDER_GUID); + + IXScene *pScene = (IXScene*)pCore->getPluginManager()->getInterface(IXSCENE_GUID); + IXSceneObjectType *pType = pScene->getObjectType("xDynamic"); + m_pQuery = pType->newQuery(); + mem_release(pType); + + pCore->getConsole()->registerCVar("r_maxdecals", 300, "Max temp decals"); + //pCore->getConsole()->registerCVar("r_max_overlapped_decals", 4, "Max overlapped decals"); + +#ifdef DECAL_DEBUG_DRAW + m_pRenderUtils->newGizmoRenderer(&m_pDebugRenderer); +#endif + + m_pMaterialSystem->loadMaterial("dev_null", &m_pNullMaterial); + + loadDecals(); +} + +CDecalProvider::~CDecalProvider() +{ + mem_release(m_pNullMaterial); + fora(i, m_aTempDecals) + { + mem_release(m_aTempDecals[i]); + } + for(UINT i = 0; i < XDT__COUNT; ++i) + { + mem_release(m_aDecalTypes[i].pMaterial); + } + mem_release(m_pQuery); + mem_release(m_pBlendState); + mem_release(m_pDSState); + mem_release(m_pWorldBuffer); +#ifdef DECAL_DEBUG_DRAW + mem_release(m_pDebugRenderer); +#endif +} + +void CDecalProvider::render(CRenderableVisibility *pVisibility) +{ + XPROFILE_FUNCTION(); + + CRenderableVisibility::OverlayData &overlayData = pVisibility->getOverlayData(); + + UINT uVertexCount = overlayData.aVertices.size(); + + if(uVertexCount) + { + if(overlayData.uVertexBufferAllocSize < uVertexCount) + { + overlayData.uVertexBufferAllocSize = uVertexCount; + mem_release(overlayData.pRB); + mem_release(overlayData.pVB); + mem_release(overlayData.pIB); + + overlayData.pVB = m_pDevice->createVertexBuffer(sizeof(XResourceModelStaticVertexGPU) * uVertexCount, GXBUFFER_USAGE_STREAM); + overlayData.pRB = m_pDevice->createRenderBuffer(1, &overlayData.pVB, m_pProviderDynamic->getVertexDeclaration()); + m_pRenderUtils->getQuadIndexBuffer(uVertexCount / 4, &overlayData.pIB); + } + + XResourceModelStaticVertexGPU *pVertices; + if(overlayData.pVB->lock((void**)&pVertices, GXBL_WRITE)) + { + memcpy(pVertices, overlayData.aVertices, sizeof(XResourceModelStaticVertexGPU) * uVertexCount); + overlayData.pVB->unlock(); + } + + m_pProviderDynamic->bindVertexFormat(); + + IGXContext *pCtx = m_pDevice->getThreadContext(); + pCtx->setRenderBuffer(overlayData.pRB); + pCtx->setIndexBuffer(overlayData.pIB); + pCtx->setPrimitiveTopology(GXPT_TRIANGLELIST); + IGXBlendState *pOldBlendState = pCtx->getBlendState(); + pCtx->setBlendState(m_pBlendState); + m_pDevice->getThreadContext()->setVSConstant(m_pWorldBuffer, 1 /* SCR_OBJECT */); + IGXDepthStencilState *pOldDSState = pCtx->getDepthStencilState(); + pCtx->setDepthStencilState(m_pDSState); + + fora(i, overlayData.aSubsets) + { + auto &ss = overlayData.aSubsets[i]; + m_pMaterialSystem->bindMaterial(ss.pMaterial); + pCtx->drawIndexed(ss.uQuadCount * 4, ss.uQuadCount * 2, ss.uStartIndex); + } + + pCtx->setBlendState(pOldBlendState); + mem_release(pOldBlendState); + + pCtx->setDepthStencilState(pOldDSState); + mem_release(pOldDSState); + } + +#ifdef DECAL_DEBUG_DRAW + m_pDebugRenderer->render(false, false); +#endif +} + +bool XMETHODCALLTYPE CDecalProvider::newDecal(IXDecal **ppDecal) +{ + CDecal *pDecal = allocDecal(); + pDecal->setMaterial(m_pNullMaterial); + + *ppDecal = pDecal; + + return(true); +} + +void XMETHODCALLTYPE CDecalProvider::shootDecal(XDECAL_TYPE type, const float3 &vWorldPos, const float3 &vNormal, float fScale, const float3 *pvSAxis) +{ + //type = XDT_GLASS; + const DecalType *pType = getDecalType(type); + if(!pType || !pType->pMaterial) + { + return; + } + + fScale *= pType->fBaseScale * 0.0008f; + + IXTexture *pTex = pType->pMaterial->getTexture("txBase"); + if(!pTex) + { + IKeyIterator *pIter = pType->pMaterial->getTexturesIterator(); + if(pIter) + { + pTex = pType->pMaterial->getTexture(pIter->getCurrent()); + } + mem_release(pIter); + } + + UINT uTexWidth = pTex->getWidth(); + UINT uTexHeight = pTex->getHeight(); + + DecalTexRange texRange = {0, 0, uTexWidth, uTexHeight}; + if(pType->aTextures.size()) + { + texRange = pType->aTextures[rand() % pType->aTextures.size()]; + } + + float2_t vSize((float)(texRange.xmax - texRange.xmin) * fScale, (float)(texRange.ymax - texRange.ymin) * fScale); + + float2_t sBound(-vSize.x * 0.5f, vSize.x * 0.5f); + float2_t tBound(-vSize.y * 0.5f, vSize.y * 0.5f); + + //compute basis + SMMATRIX mBasis; + computeBasis(&mBasis, SMVector3Normalize(vNormal), pvSAxis); + + SMQuaternion qOrient = SMQuaternion(mBasis.r[0], mBasis.r[1], mBasis.r[2]).Normalize(); + + //vWorldPos; + //qOrient; + //pType->pMaterial; + float2_t avCorners[] = { + float2_t(sBound.x, tBound.x), + float2_t(sBound.x, tBound.y), + float2_t(sBound.y, tBound.y), + float2_t(sBound.y, tBound.x), + }; + float fHeight = min(vSize.x, vSize.y) * 0.5f + 0.1f; + +#ifdef DECAL_DEBUG_DRAW + m_pDebugRenderer->setPointSize(0.01f); + m_pDebugRenderer->setLineWidth(0.01f); + m_pDebugRenderer->setColor(float4(1.0f, 0.0f, 0.0f, 1.0f)); + m_pDebugRenderer->jumpTo(vWorldPos); + m_pDebugRenderer->lineTo(vWorldPos + mBasis.r[0]); + m_pDebugRenderer->setColor(float4(0.0f, 1.0f, 0.0f, 1.0f)); + m_pDebugRenderer->jumpTo(vWorldPos); + m_pDebugRenderer->lineTo(vWorldPos + mBasis.r[1]); + m_pDebugRenderer->setColor(float4(0.0f, 0.0f, 1.0f, 1.0f)); + m_pDebugRenderer->jumpTo(vWorldPos); + m_pDebugRenderer->lineTo(vWorldPos + mBasis.r[2]); + + m_pDebugRenderer->setColor(float4(1.0f, 1.0f, 1.0f, 1.0f)); + /*for(UINT i = 0; i < ARRAYSIZE(avCorners); ++i) + { + m_pDebugRenderer->drawPoint(qOrient * float3(avCorners[i], -fHeight) + vWorldPos); + m_pDebugRenderer->drawPoint(qOrient * float3(avCorners[i], fHeight) + vWorldPos); + }*/ +#endif + + // create CDecal + CDecal *pDecal = allocDecal(); + pDecal->setMaterial(pType->pMaterial); + for(UINT i = 0; i < DECAL_POINTS; ++i) + { + pDecal->setCorner(i, avCorners[i]); + } + pDecal->setPosition(vWorldPos); + pDecal->setOrientation(qOrient); + pDecal->setHeight(fHeight); + pDecal->setTextureRangeU(float2((float)texRange.xmin, (float)texRange.xmax) / (float)uTexWidth); + pDecal->setTextureRangeV(float2((float)texRange.ymin, (float)texRange.ymax) / (float)uTexHeight); + + addTempDecal(pDecal); +} + +void CDecalProvider::computeVisibility(const float3 &vHintDir, CRenderableVisibility *pVisibility) +{ + Array<CDynamicModel*> &aRenderList = pVisibility->getRenderList(); + + struct TmpOverlay + { + CDynamicModel *pModel; + CModelOverlay *pOverlay; + }; + + Array<TmpOverlay> aOverlays; + + bool useHintDir = !SMIsZero(SMVector3Length2(vHintDir)); + + UINT uVertices = 0; + fora(i, aRenderList) + { + CDynamicModel *pMdl = aRenderList[i]; + CModelOverlay *pOverlay = pMdl->getOverlay(); + while(pOverlay) + { + // skip backface overlays + bool bRender = !useHintDir || pOverlay->getMaterial()->isTwoSided(); + if(!bRender) + { + float3 vNormal = pOverlay->getNormal(); + if(!pMdl->isStatic()) + { + vNormal = pMdl->getOrientation() * vNormal; + } + bRender = SMVector3Dot(vNormal, vHintDir) < 0.0f; + } + if(bRender) + { + aOverlays.push_back({pMdl, pOverlay}); + + uVertices += pOverlay->getVertices().size(); + } + + pOverlay = pOverlay->getNextOverlay(); + } + } + + CRenderableVisibility::OverlayData &overlayData = pVisibility->getOverlayData(); + + Array<XResourceModelStaticVertexGPU> &aVertices = overlayData.aVertices; + aVertices.clearFast(); + aVertices.reserve(uVertices); + Array<CRenderableVisibility::OverlaySubset>& aSubsets = overlayData.aSubsets; + aSubsets.clearFast(); + + aOverlays.quickSort([](const TmpOverlay &a, const TmpOverlay &b){ + return(a.pOverlay->getMaterial() < b.pOverlay->getMaterial()); + }); + + XResourceModelStaticVertex tempVertex; + XResourceModelStaticVertexGPU tempGpuVertex; + CRenderableVisibility::OverlaySubset curSubset = {}; + fora(i, aOverlays) + { + TmpOverlay &overlay = aOverlays[i]; + + if(curSubset.pMaterial != overlay.pOverlay->getMaterial()) + { + if(curSubset.uStartVertex != aVertices.size()) + { + curSubset.uQuadCount = (aVertices.size() - curSubset.uStartVertex) / 4; + aSubsets.push_back(curSubset); + } + curSubset.pMaterial = overlay.pOverlay->getMaterial(); + + curSubset.uStartVertex = aVertices.size(); + curSubset.uStartIndex = aVertices.size() / 4 * 6; + } + + const Array<XResourceModelStaticVertex>& aOverlayVertices = overlay.pOverlay->getVertices(); + bool bNeedTransform = !overlay.pModel->isStatic(); + + float3 vPos = overlay.pModel->getPosition(); + SMQuaternion qRot = overlay.pModel->getOrientation(); + + fora(j, aOverlayVertices) + { + tempVertex = aOverlayVertices[j]; + if(bNeedTransform) + { + // transform vertices + tempVertex.vPos = qRot * tempVertex.vPos + vPos; + tempVertex.vNorm = qRot * tempVertex.vNorm; + tempVertex.vTangent = qRot * tempVertex.vTangent; + tempVertex.vBinorm = qRot * tempVertex.vBinorm; + } + +#define TO_SHORT(v) ((short)((v) * 32767.0f)) + auto &dst = tempGpuVertex; + auto &src = tempVertex; + dst.vPos = src.vPos; + dst.vTex = src.vTex; + dst.vNorm[0] = TO_SHORT(src.vNorm.x); + dst.vNorm[1] = TO_SHORT(src.vNorm.y); + dst.vNorm[2] = TO_SHORT(src.vNorm.z); + dst.vTangent[0] = TO_SHORT(src.vTangent.x); + dst.vTangent[1] = TO_SHORT(src.vTangent.y); + dst.vTangent[2] = TO_SHORT(src.vTangent.z); + dst.vBinorm[0] = TO_SHORT(src.vBinorm.x); + dst.vBinorm[1] = TO_SHORT(src.vBinorm.y); + dst.vBinorm[2] = TO_SHORT(src.vBinorm.z); +#undef TO_SHORT + + aVertices.push_back(tempGpuVertex); + } + } + + if(curSubset.uStartVertex != aVertices.size()) + { + curSubset.uQuadCount = (aVertices.size() - curSubset.uStartVertex) / 4; + aSubsets.push_back(curSubset); + } +} + +void CDecalProvider::setDevice(IGXDevice *pDevice) +{ + m_pDevice = pDevice; + + GXBlendDesc blendDesc; + memset(&blendDesc, 0, sizeof(blendDesc)); + blendDesc.renderTarget[0].u8RenderTargetWriteMask = GXCOLOR_WRITE_ENABLE_RED | GXCOLOR_WRITE_ENABLE_GREEN | GXCOLOR_WRITE_ENABLE_BLUE; + blendDesc.renderTarget[0].blendSrcColor = GXBLEND_DEST_COLOR; + blendDesc.renderTarget[0].blendDestColor = GXBLEND_SRC_COLOR; + blendDesc.renderTarget[0].blendSrcAlpha = GXBLEND_SRC_ALPHA; + blendDesc.renderTarget[0].blendDestAlpha = GXBLEND_INV_SRC_ALPHA; + blendDesc.renderTarget[0].blendOpColor = GXBLEND_OP_ADD; + blendDesc.renderTarget[0].blendOpAlpha = GXBLEND_OP_ADD; + + /*blendDesc.renderTarget[0].blendSrcColor = GXBLEND_DEST_COLOR; + blendDesc.renderTarget[0].blendDestColor = GXBLEND_SRC_COLOR; + blendDesc.renderTarget[0].blendSrcAlpha = GXBLEND_DEST_ALPHA; + blendDesc.renderTarget[0].blendDestAlpha = GXBLEND_SRC_ALPHA; + blendDesc.renderTarget[0].blendOpColor = GXBLEND_OP_ADD; + blendDesc.renderTarget[0].blendOpAlpha = GXBLEND_OP_ADD;*/ + + blendDesc.renderTarget[0].useBlend = TRUE; + + blendDesc.renderTarget[1].blendSrcColor = GXBLEND_ZERO; + blendDesc.renderTarget[1].blendDestColor = GXBLEND_ONE; + + blendDesc.renderTarget[2].blendSrcColor = GXBLEND_ONE; + blendDesc.renderTarget[2].blendDestColor = GXBLEND_ZERO; + + blendDesc.renderTarget[3].blendSrcColor = GXBLEND_ONE; + blendDesc.renderTarget[3].blendDestColor = GXBLEND_ZERO; + + blendDesc.renderTarget[1].useBlend = FALSE; + blendDesc.renderTarget[2].useBlend = FALSE; + blendDesc.renderTarget[3].useBlend = FALSE; + + blendDesc.useIndependentBlend = TRUE; + + m_pBlendState = pDevice->createBlendState(&blendDesc); + + + GXDepthStencilDesc dsDesc = {}; + dsDesc.cmpFuncDepth = GXCMP_GREATER_EQUAL; + dsDesc.useDepthWrite = FALSE; + m_pDSState = pDevice->createDepthStencilState(&dsDesc); + + + m_pWorldBuffer = pDevice->createConstantBuffer(sizeof(SMMATRIX)); + m_pWorldBuffer->update(&SMMatrixIdentity()); +} + +void CDecalProvider::onDecalReleased(CDecal *pDecal) +{ + ScopedSpinLock lock(m_slMemDecals); + m_memDecals.Delete(pDecal); +} + +void CDecalProvider::onDecalEmptied(CDecal *pDecal) +{ + int idx = -1; + { + ScopedSpinLock lock(m_slTempDecals); + + idx = m_aTempDecals.indexOf(pDecal); + if(idx >= 0) + { + m_aTempDecals.erase(idx); + } + } + + if(idx >= 0) + { + mem_release(pDecal); + } +} + +void CDecalProvider::updateDecal(CDecal *pDecal) +{ + add_ref(pDecal); + m_qDecalsForUpdate.push(pDecal); +} + +void CDecalProvider::update() +{ + if(!m_isEnabled) + { + return; + } + + CDecal *pDecal; + while(m_qDecalsForUpdate.pop(&pDecal)) + { + pDecal->update( +#ifdef DECAL_DEBUG_DRAW + m_pDebugRenderer +#endif + ); + mem_release(pDecal); + } +} + +CDecal* CDecalProvider::allocDecal() +{ + ScopedSpinLock lock(m_slMemDecals); + return(m_memDecals.Alloc(m_pQuery, m_pRender, this)); +} + +CModelOverlay* CDecalProvider::allocOverlay(CDecal *pDecal, IXMaterial *pMaterial, Array<XResourceModelStaticVertex> &aVertices, const float3_t &vNormal) +{ + ScopedSpinLock lock(m_slMemOverlays); + return(m_memOverlays.Alloc(pDecal, pMaterial, aVertices, vNormal)); +} +void CDecalProvider::freeOverlay(CModelOverlay *pOverlay) +{ + ScopedSpinLock lock(m_slMemOverlays); + m_memOverlays.Delete(pOverlay); +} + +IXMaterialSystem* CDecalProvider::getMaterialSystem() +{ + return(m_pMaterialSystem); +} + +void CDecalProvider::setEnabled(bool yesNo) +{ + m_isEnabled = yesNo; +} + +void CDecalProvider::loadDecals() +{ + IXConfig *pConfig = m_pCore->newConfig(); + if(pConfig->open("config/decals/decals.cfg")) + { + UINT uSections = pConfig->getSectionCount(); + for(UINT i = 0; i < uSections; ++i) + { + const char *szSection = pConfig->getSectionName(i); + + int id; + if(pConfig->keyExists(szSection, "id") && sscanf(pConfig->getKey(szSection, "id"), "%d", &id)) + { + if(id < 0 || id >= XDT__COUNT) + { + LogError("Incorrect decal type id '%s'\n", szSection); + continue; + } + } + else + { + LogError("Unable to read decal id '%s'\n", szSection); + continue; + } + + const char *szTex = pConfig->getKey(szSection, "tex"); + if(!szTex) + { + LogError("Unable to read decal tex '%s'\n", szSection); + continue; + } + + const char *szScale = pConfig->getKey(szSection, "base_scale"); + if(szScale) + { + sscanf(szScale, "%f", &m_aDecalTypes[id].fBaseScale); + } + + + int j = 0; + + DecalTexRange rng; + char key[64]; + while(sprintf(key, "tex%d", j) && pConfig->keyExists(szSection, key)) + { + if(sscanf(pConfig->getKey(szSection, key), "[%d,%d,%d,%d]", &rng.xmin, &rng.ymin, &rng.xmax, &rng.ymax) != 4) + { + LogError("Unable to read decal tex coords \"%s\" \"%s\"\n", pConfig->getKey(szSection, key), szSection); + } + else + { + m_aDecalTypes[id].aTextures.push_back(rng); + } + j++; + } + + m_pMaterialSystem->loadMaterial(szTex, &m_aDecalTypes[id].pMaterial); + } + } + + mem_release(pConfig); +} + +const CDecalProvider::DecalType* CDecalProvider::getDecalType(XDECAL_TYPE type) +{ + if(type < 0 || type >= XDT__COUNT) + { + LogError("Incorrect decal type %d\n", type); + return(NULL); + } + return(&m_aDecalTypes[type]); +} + +void CDecalProvider::computeBasis(SMMATRIX *pmOut, const float3_t &vSurfaceNormal, const float3 *pvSAxis) +{ + // s, t, textureSpaceNormal (S cross T = textureSpaceNormal(N)) + // + // +---->S + // /| + // / | + // N |T + // + // S = textureSpaceBasis[0] + // T = textureSpaceBasis[1] + // N = textureSpaceBasis[2] + + // Get the surface normal. + pmOut->r[2] = vSurfaceNormal; + + if(pvSAxis) + { + // T = N cross S + pmOut->r[1] = SMVector3Cross(pmOut->r[2], *pvSAxis); + + // Name sure they aren't parallel or antiparallel + // In that case, fall back to the normal algorithm. + if(SMVector3Dot(pmOut->r[1], pmOut->r[1]) > 1e-6) + { + // S = T cross N + pmOut->r[0] = SMVector3Cross(pmOut->r[1], pmOut->r[2]); + + pmOut->r[0] = SMVector3Normalize(pmOut->r[0]); + pmOut->r[1] = SMVector3Normalize(pmOut->r[1]); + return; + } + + // Fall through to the standard algorithm for parallel or antiparallel + } + + // floor/ceiling? + if(fabs(vSurfaceNormal.y) > SIN_45_DEGREES) + { + pmOut->r[0] = float4(1.0f, 0.0f, 0.0f, 0.0f); + + // T = N cross S + pmOut->r[1] = SMVector3Cross(pmOut->r[2], pmOut->r[0]); + + // S = T cross N + pmOut->r[0] = SMVector3Cross(pmOut->r[1], pmOut->r[2]); + } + // wall + else + { + pmOut->r[1] = float4(0.0f, -1.0f, 0.0f, 0.0f); + + // S = T cross N + pmOut->r[0] = SMVector3Cross(pmOut->r[1], pmOut->r[2]); + // T = N cross S + pmOut->r[1] = SMVector3Cross(pmOut->r[2], pmOut->r[0]); + } + + pmOut->r[0] = SMVector3Normalize(pmOut->r[0]); + pmOut->r[1] = SMVector3Normalize(pmOut->r[1]); +} + +void CDecalProvider::addTempDecal(CDecal *pDecal) +{ + ScopedSpinLock lock(m_slTempDecals); + + static const int *r_maxdecals = m_pCore->getConsole()->getPCVarInt("r_maxdecals"); + if(m_aTempDecals.size() > *r_maxdecals) + { + for(UINT i = (UINT)*r_maxdecals, l = m_aTempDecals.size(); i < l; ++i) + { + mem_release(m_aTempDecals[i]); + } + } + m_aTempDecals.reserve(*r_maxdecals); + + TODO("Use ring array for that"); + if(m_aTempDecals.size() == *r_maxdecals) + { + mem_release(m_aTempDecals[0]); + m_aTempDecals.erase(0); + } + m_aTempDecals.push_back(pDecal); +} diff --git a/source/anim/DecalProvider.h b/source/anim/DecalProvider.h new file mode 100644 index 0000000000000000000000000000000000000000..58580748fa70f2bdb7161c697fee0b133a41d625 --- /dev/null +++ b/source/anim/DecalProvider.h @@ -0,0 +1,114 @@ +#ifndef __DECALPROVIDER_H +#define __DECALPROVIDER_H + +#include <xcommon/resource/IXDecalProvider.h> +#include <xcommon/IXCore.h> +#include "RenderableVisibility.h" +//#include <mtrl/IXMaterialSystem.h> +//#include <common/ConcurrentQueue.h> +//#include <xcommon/XEvents.h> +#include <xcommon/IXScene.h> +#include <common/queue.h> +#include "Decal.h" + +#define SIN_45_DEGREES 0.70710678118654752440084436210485f + +class CDecalProvider: public IXUnknownImplementation<IXDecalProvider> +{ +public: + CDecalProvider(IXCore *pCore, CDynamicModelProvider *pProviderDynamic); + ~CDecalProvider(); + + void render(CRenderableVisibility *pVisibility); + + bool XMETHODCALLTYPE newDecal(IXDecal **ppDecal) override; + + void XMETHODCALLTYPE shootDecal(XDECAL_TYPE type, const float3 &vWorldPos, const float3 &vNormal, float fScale = 1.0f, const float3 *pvSAxis = NULL) override; + + void computeVisibility(const float3 &vHintDir, CRenderableVisibility *pVisibility); + + void setDevice(IGXDevice *pDevice); + + void onDecalReleased(CDecal *pDecal); + + void onDecalEmptied(CDecal *pDecal); + + void updateDecal(CDecal *pDecal); + + void update(); + + CModelOverlay* allocOverlay(CDecal *pDecal, IXMaterial *pMaterial, Array<XResourceModelStaticVertex> &aVertices, const float3_t &vNormal); + void freeOverlay(CModelOverlay *pOverlay); + + IXMaterialSystem* getMaterialSystem(); + + void setEnabled(bool yesNo); + +private: + struct DecalTexRange + { + int xmin; + int ymin; + int xmax; + int ymax; + }; + + struct DecalType + { + Array<DecalTexRange> aTextures; + float fBaseScale = 1.0f; + IXMaterial *pMaterial = NULL; + }; + + /*struct TempDecal + { + CDecal *pDecal; + };*/ + +private: + IXCore *m_pCore = NULL; + CDynamicModelProvider *m_pProviderDynamic = NULL; + IGXDevice *m_pDevice = NULL; + IXMaterialSystem *m_pMaterialSystem = NULL; + IXRender *m_pRender = NULL; + IXRenderUtils *m_pRenderUtils = NULL; + IXSceneQuery *m_pQuery = NULL; + + IXMaterial *m_pNullMaterial = NULL; + + IGXConstantBuffer *m_pWorldBuffer = NULL; + + IGXBlendState *m_pBlendState = NULL; + IGXDepthStencilState *m_pDSState = NULL; + + DecalType m_aDecalTypes[XDT__COUNT]; + +#ifdef DECAL_DEBUG_DRAW + IXGizmoRenderer *m_pDebugRenderer = NULL; +#endif + + MemAlloc<CDecal> m_memDecals; + MemAlloc<CModelOverlay> m_memOverlays; + SpinLock m_slMemDecals; + SpinLock m_slMemOverlays; + + Array<CDecal*> m_aTempDecals; + SpinLock m_slTempDecals; + + Queue<CDecal*> m_qDecalsForUpdate; + + bool m_isEnabled = true; + +private: + void loadDecals(); + + const DecalType* getDecalType(XDECAL_TYPE type); + + void computeBasis(SMMATRIX *pmOut, const float3_t &vSurfaceNormal, const float3 *pvSAxis = NULL); + + CDecal* allocDecal(); + + void addTempDecal(CDecal *pDecal); +}; + +#endif diff --git a/source/anim/DynamicModel.cpp b/source/anim/DynamicModel.cpp index 0a79dbe82ff68b47fe0a024e1a8761ada11a8a6d..85ad2e562d43aec535b0cc217b183e07db86198f 100644 --- a/source/anim/DynamicModel.cpp +++ b/source/anim/DynamicModel.cpp @@ -31,6 +31,8 @@ CDynamicModel::~CDynamicModel() mem_release(m_pWorldBuffer); mem_release(m_pColorBuffer); mem_release(m_pSceneObject); + + SAFE_CALL(m_pOverlay, onModelRemoved); } void CDynamicModel::initGPUresources() @@ -80,7 +82,7 @@ IXDynamicModel * XMETHODCALLTYPE CDynamicModel::asDynamicModel() } IXStaticModel * XMETHODCALLTYPE CDynamicModel::asStaticModel() { - return(NULL); + return(isStatic() ? this : NULL); } float3 XMETHODCALLTYPE CDynamicModel::getPosition() const @@ -209,11 +211,11 @@ void CDynamicModel::_updateAABB() const m_vLocalMin = (float3)SMVectorMin( SMVectorMin(SMVectorMin(vCurrent[0], vCurrent[1]), SMVectorMin(vCurrent[2], vCurrent[3])), SMVectorMin(SMVectorMin(vCurrent[4], vCurrent[5]), SMVectorMin(vCurrent[6], vCurrent[7])) - ); + ); m_vLocalMax = (float3)SMVectorMax( SMVectorMax(SMVectorMax(vCurrent[0], vCurrent[1]), SMVectorMax(vCurrent[2], vCurrent[3])), SMVectorMax(SMVectorMax(vCurrent[4], vCurrent[5]), SMVectorMax(vCurrent[6], vCurrent[7])) - ); + ); m_isLocalAABBvalid = true; } @@ -466,3 +468,23 @@ UINT XMETHODCALLTYPE CDynamicModel::getLayer() { return(m_uLayer); } + +CModelOverlay* CDynamicModel::getOverlay() +{ + return(m_pOverlay); +} + +void CDynamicModel::setOverlay(CModelOverlay *pOverlay) +{ + m_pOverlay = pOverlay; +} + +void CDynamicModel::setStatic(bool yesNo) +{ + m_isStatic = yesNo; +} + +bool CDynamicModel::isStatic() +{ + return(m_isStatic); +} diff --git a/source/anim/DynamicModel.h b/source/anim/DynamicModel.h index 836ebdda06dc00c7aafa6efa8f93dd7fe363cd42..97612f2543b3fec1422acfc786f337b60bd9aeea 100644 --- a/source/anim/DynamicModel.h +++ b/source/anim/DynamicModel.h @@ -4,6 +4,7 @@ #include <xcommon/resource/IXModel.h> #include <xcommon/IXScene.h> #include "DynamicModelShared.h" +#include "ModelOverlay.h" class CDynamicModel final: public IXUnknownImplementation<IXDynamicModel> { @@ -58,7 +59,14 @@ public: void XMETHODCALLTYPE setLayer(UINT uLayer) override; UINT XMETHODCALLTYPE getLayer() override; -protected: + + CModelOverlay* getOverlay(); + void setOverlay(CModelOverlay *pOverlay); + + void setStatic(bool yesNo); + bool isStatic(); + +private: CDynamicModelProvider *m_pProvider; CDynamicModelShared *m_pShared; IGXDevice *m_pDevice; @@ -75,17 +83,21 @@ protected: UINT m_uSkin = 0; float4_t m_vColor{1.0f, 1.0f, 1.0f, 1.0f}; bool m_isEnabled = true; + bool m_isStatic = false; float m_fScale = 1.0f; mutable bool m_isLocalAABBvalid = false; mutable float3_t m_vLocalMin; mutable float3_t m_vLocalMax; + UINT m_uLayer = 0; + + CModelOverlay *m_pOverlay = NULL; + +private: void _updateAABB() const; void XMETHODCALLTYPE FinalRelease() override; - - UINT m_uLayer = 0; }; #endif diff --git a/source/anim/DynamicModelProvider.cpp b/source/anim/DynamicModelProvider.cpp index 4ce0af11d6c8855f0963e177aa8165be14fbcbe7..36af3b00e4a7f2d4c05454888f9b305f7f49e4cf 100644 --- a/source/anim/DynamicModelProvider.cpp +++ b/source/anim/DynamicModelProvider.cpp @@ -541,6 +541,8 @@ void CDynamicModelProvider::computeVisibility(const IXFrustum *pFrustum, const f { XPROFILE_FUNCTION(); + TODO("Make some hints to not to compute stages is not required for render. eg selfillum stage for shadows"); + if(pCamera && pCamera->getProjectionMode() == XCPM_PERSPECTIVE) { FIXME("Use actual target width!"); @@ -806,3 +808,8 @@ void CDynamicModelProvider::enqueueModelDelete(CDynamicModel* pModel) { m_qModelDelete.push(pModel); } + +bool CDynamicModelProvider::hasPendingOps() +{ + return(!m_queueGPUinitModel.empty() || !m_queueGPUinitShared.empty()); +} diff --git a/source/anim/DynamicModelProvider.h b/source/anim/DynamicModelProvider.h index 3b126cae9b99e10c9e4de2f924fea8fa1b8af757..ce66cf3ea02d6d24e9fea5c88a0ffa2df4b4b933 100644 --- a/source/anim/DynamicModelProvider.h +++ b/source/anim/DynamicModelProvider.h @@ -70,6 +70,9 @@ public: IXSceneFeature* getFeature(XMODEL_FEATURE bmFeature); void enqueueModelDelete(CDynamicModel* pModel); + + bool hasPendingOps(); + protected: void onMaterialEmissivityChanged(const IXMaterial *pMaterial); void onMaterialTransparencyChanged(const IXMaterial *pMaterial); diff --git a/source/anim/ModelOverlay.cpp b/source/anim/ModelOverlay.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ead2048997a2aea32fff6996aa5b413880429bf5 --- /dev/null +++ b/source/anim/ModelOverlay.cpp @@ -0,0 +1,49 @@ +#include "ModelOverlay.h" +#include "Decal.h" + +CModelOverlay::CModelOverlay(CDecal *pDecal, IXMaterial *pMaterial, Array<XResourceModelStaticVertex> &aVertices, const float3_t &vNormal): + m_pDecal(pDecal), + m_pMaterial(pMaterial), + m_vNormal(vNormal) +{ + m_aVertices.swap(aVertices); + add_ref(m_pMaterial); +} + +CModelOverlay::~CModelOverlay() +{ + mem_release(m_pMaterial); +} + + +const Array<XResourceModelStaticVertex>& CModelOverlay::getVertices() +{ + return(m_aVertices); +} + +CModelOverlay* CModelOverlay::getNextOverlay() +{ + return(m_pNextOverlay); +} +void CModelOverlay::setNextOverlay(CModelOverlay *pOverlay) +{ + m_pNextOverlay = pOverlay; +} + +IXMaterial* CModelOverlay::getMaterial() +{ + return(m_pMaterial); +} + +const float3_t& CModelOverlay::getNormal() +{ + return(m_vNormal); +} + +void CModelOverlay::onModelRemoved() +{ + SAFE_CALL(m_pNextOverlay, onModelRemoved); + + //notify decal + m_pDecal->onOverlayRemoved(this); +} diff --git a/source/anim/ModelOverlay.h b/source/anim/ModelOverlay.h new file mode 100644 index 0000000000000000000000000000000000000000..4404a20c1a65f57d4472ef95f4bb4bf5efea15ef --- /dev/null +++ b/source/anim/ModelOverlay.h @@ -0,0 +1,43 @@ +#ifndef __MODELOVERLAY_H +#define __MODELOVERLAY_H + +#include <xcommon/resource/IXModel.h> +#include <graphix/graphix.h> +#include <mtrl/IXMaterial.h> + +class IXMaterialSystem; +class CDecal; + +class CModelOverlay final +{ +public: + CModelOverlay(CDecal *pDecal, IXMaterial *pMaterial, Array<XResourceModelStaticVertex> &aVertices, const float3_t &vNormal); + ~CModelOverlay(); + + const Array<XResourceModelStaticVertex>& getVertices(); + + CModelOverlay* getNextOverlay(); + void setNextOverlay(CModelOverlay *pOverlay); + + IXMaterial* getMaterial(); + + const float3_t& getNormal(); + + void onModelRemoved(); + +private: + // Model's overlays stored as linked list + CModelOverlay *m_pNextOverlay = NULL; + CDecal *m_pDecal; + + TODO("Use memory pool"); + Array<XResourceModelStaticVertex> m_aVertices; + + IXMaterial *m_pMaterial = NULL; + + float3_t m_vNormal; + + bool m_isTransparent = false; +}; + +#endif diff --git a/source/anim/Renderable.cpp b/source/anim/Renderable.cpp index 81ac9ab42dbb1d20f0597036e2df28da16bcfc76..52ad958bccb76178cbb80d6718cf70d4f22c2fed 100644 --- a/source/anim/Renderable.cpp +++ b/source/anim/Renderable.cpp @@ -1,10 +1,12 @@ #include "Renderable.h" #include "RenderableVisibility.h" +#include "DecalProvider.h" -CRenderable::CRenderable(ID idPlugin, CAnimatedModelProvider *pProviderAnimated, CDynamicModelProvider *pProviderDynamic): +CRenderable::CRenderable(ID idPlugin, CAnimatedModelProvider *pProviderAnimated, CDynamicModelProvider *pProviderDynamic, CDecalProvider *pProviderDecal): m_idPlugin(idPlugin), m_pAnimatedModelProvider(pProviderAnimated), - m_pDynamicModelProvider(pProviderDynamic) + m_pDynamicModelProvider(pProviderDynamic), + m_pDecalProvider(pProviderDecal) { } @@ -40,6 +42,7 @@ void XMETHODCALLTYPE CRenderable::renderStage(X_RENDER_STAGE stage, IXRenderable case XRS_GBUFFER: m_pAnimatedModelProvider->render(pVis); m_pDynamicModelProvider->render(false, pVis); + m_pDecalProvider->render(pVis); break; case XRS_SHADOWS: m_pAnimatedModelProvider->render(pVis); @@ -89,6 +92,7 @@ void XMETHODCALLTYPE CRenderable::startup(IXRender *pRender, IXMaterialSystem *p m_pAnimatedModelProvider->setDevice(m_pDevice); m_pDynamicModelProvider->setDevice(m_pDevice); + m_pDecalProvider->setDevice(m_pDevice); } void XMETHODCALLTYPE CRenderable::shutdown() { @@ -96,7 +100,7 @@ void XMETHODCALLTYPE CRenderable::shutdown() void XMETHODCALLTYPE CRenderable::newVisData(IXRenderableVisibility **ppVisibility) { - *ppVisibility = new CRenderableVisibility(m_idPlugin, m_pAnimatedModelProvider, m_pDynamicModelProvider); + *ppVisibility = new CRenderableVisibility(m_idPlugin, m_pAnimatedModelProvider, m_pDynamicModelProvider, m_pDecalProvider); } IXMaterialSystem* CRenderable::getMaterialSystem() diff --git a/source/anim/Renderable.h b/source/anim/Renderable.h index cafcc2fbfc260553f1c8f3cf5f857b0b7919a2e8..85f03cc5139e0e8d2d3a4b34f849466849376c73 100644 --- a/source/anim/Renderable.h +++ b/source/anim/Renderable.h @@ -9,7 +9,7 @@ class CRenderable: public IXUnknownImplementation<IXRenderable> { public: - CRenderable(ID idPlugin, CAnimatedModelProvider *pProviderAnimated, CDynamicModelProvider *pProviderDynamic); + CRenderable(ID idPlugin, CAnimatedModelProvider *pProviderAnimated, CDynamicModelProvider *pProviderDynamic, CDecalProvider *pProviderDecal); XIMPLEMENT_VERSION(IXRENDERABLE_VERSION); @@ -56,6 +56,7 @@ protected: CAnimatedModelProvider *m_pAnimatedModelProvider = NULL; CDynamicModelProvider *m_pDynamicModelProvider = NULL; + CDecalProvider *m_pDecalProvider = NULL; }; #endif diff --git a/source/anim/RenderableVisibility.cpp b/source/anim/RenderableVisibility.cpp index d37373b47f114ba2fe3b7f3101020a0965ec53a3..f012c9831787a31e0f85b2e09e058b7df230044b 100644 --- a/source/anim/RenderableVisibility.cpp +++ b/source/anim/RenderableVisibility.cpp @@ -1,11 +1,13 @@ #include "RenderableVisibility.h" #include "AnimatedModelProvider.h" #include "DynamicModelProvider.h" +#include "DecalProvider.h" -CRenderableVisibility::CRenderableVisibility(ID idPlugin, CAnimatedModelProvider *pProviderAnimated, CDynamicModelProvider *pProviderDynamic): +CRenderableVisibility::CRenderableVisibility(ID idPlugin, CAnimatedModelProvider *pProviderAnimated, CDynamicModelProvider *pProviderDynamic, CDecalProvider *pProviderDecal): m_idPlugin(idPlugin), m_pProviderAnimated(pProviderAnimated), - m_pProviderDynamic(pProviderDynamic) + m_pProviderDynamic(pProviderDynamic), + m_pProviderDecal(pProviderDecal) { } @@ -38,6 +40,7 @@ void CRenderableVisibility::updateForCamera(IXCamera *pCamera, const IXRenderabl IXFrustum *pFrustum = pCamera->getFrustum(); m_pProviderAnimated->computeVisibility(pFrustum, this, pCamera->getLayerMask(), pRef); m_pProviderDynamic->computeVisibility(pFrustum, pCamera->getLook(), this, pCamera->getLayerMask(), pRef, pCamera); + m_pProviderDecal->computeVisibility(pCamera->getLook(), this); mem_release(pFrustum); } @@ -52,6 +55,7 @@ void CRenderableVisibility::updateForFrustum(const IXFrustum *pFrustum, UINT bmL m_pProviderAnimated->computeVisibility(pFrustum, this, bmLayers, pRef); m_pProviderDynamic->computeVisibility(pFrustum, float3(), this, bmLayers, pRef); + m_pProviderDecal->computeVisibility(float3(), this); } static void SortRenderList(Array<CDynamicModel*> &aList) @@ -139,7 +143,8 @@ void CRenderableVisibility::append(const IXRenderableVisibility *pOther_) MergeArrays(m_aSelfillumList, pOther->m_aSelfillumList); SortRenderList(m_aSelfillumList); - //! @todo implement for transparency too! + TODO("Implement for transparency too!"); + TODO("Implement for decals too!"); } void CRenderableVisibility::substract(const IXRenderableVisibility *pOther_) @@ -159,7 +164,8 @@ void CRenderableVisibility::substract(const IXRenderableVisibility *pOther_) } } - //! @todo implement for transparency too! + TODO("Implement for transparency too!"); + TODO("Implement for decals too!"); } void CRenderableVisibility::setItemCount(UINT uCount) @@ -257,3 +263,8 @@ Array<CDynamicModel*>& CRenderableVisibility::getTransparentList() { return(m_aTransparentList); } + +CRenderableVisibility::OverlayData& CRenderableVisibility::getOverlayData() +{ + return(m_overlayData); +} diff --git a/source/anim/RenderableVisibility.h b/source/anim/RenderableVisibility.h index 6d96b4998ce3e48771a923a55da214e68c183b2e..8032e469b6fd1bdb59f61f1b95513719956feac8 100644 --- a/source/anim/RenderableVisibility.h +++ b/source/anim/RenderableVisibility.h @@ -2,14 +2,16 @@ #define __RENDERABLE_VISIBILITY_H #include <xcommon/IXRenderable.h> +#include <xcommon/resource/IXResourceModel.h> class CAnimatedModelProvider; class CDynamicModelProvider; +class CDecalProvider; class CDynamicModel; class CRenderableVisibility final: public IXUnknownImplementation<IXRenderableVisibility> { public: - CRenderableVisibility(ID idPlugin, CAnimatedModelProvider *m_pProviderAnimated, CDynamicModelProvider *m_pProviderDynamic); + CRenderableVisibility(ID idPlugin, CAnimatedModelProvider *pProviderAnimated, CDynamicModelProvider *pProviderDynamic, CDecalProvider *pProviderDecal); ~CRenderableVisibility(); ID getPluginId() const override; @@ -40,6 +42,24 @@ public: UINT uLod; IXMaterial *pMaterial; }; + + struct OverlaySubset + { + IXMaterial *pMaterial; + UINT uStartVertex; + UINT uStartIndex; + UINT uQuadCount; + }; + + struct OverlayData + { + Array<XResourceModelStaticVertexGPU> aVertices; + Array<OverlaySubset> aSubsets; + IGXVertexBuffer *pVB = NULL; + IGXRenderBuffer *pRB = NULL; + IGXIndexBuffer *pIB = NULL; + UINT uVertexBufferAllocSize = 0; + }; void setItemCount(UINT uCount); item_s* getItem(UINT uIndex); @@ -57,16 +77,18 @@ public: Array<CDynamicModel*>& getRenderList(); Array<CDynamicModel*>& getTransparentList(); Array<CDynamicModel*>& getSelfillumList(); + OverlayData& getOverlayData(); IXOcclusionCuller* getCuller() { return(m_pOcclusionCuller); } -protected: +private: ID m_idPlugin; CAnimatedModelProvider *m_pProviderAnimated; CDynamicModelProvider *m_pProviderDynamic; + CDecalProvider *m_pProviderDecal; IXOcclusionCuller *m_pOcclusionCuller = NULL; Array<item_s> m_aItems; @@ -75,6 +97,8 @@ protected: Array<CDynamicModel*> m_aRenderList; Array<CDynamicModel*> m_aTransparentList; Array<CDynamicModel*> m_aSelfillumList; + + OverlayData m_overlayData; }; #endif diff --git a/source/anim/StaticModelProvider.cpp b/source/anim/StaticModelProvider.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99cbb517abaa174b2d4e455bbe092bf52944648f --- /dev/null +++ b/source/anim/StaticModelProvider.cpp @@ -0,0 +1,20 @@ +#include "StaticModelProvider.h" + +CStaticModelProvider::CStaticModelProvider(CDynamicModelProvider *pDynamicModelProvider): + m_pDynamicModelProvider(pDynamicModelProvider) +{ +} + +bool XMETHODCALLTYPE CStaticModelProvider::createModel(IXResourceModelStatic *pResource, IXStaticModel **ppModel) +{ + IXDynamicModel *pModel; + if(m_pDynamicModelProvider->createModel(pResource, &pModel)) + { + ((CDynamicModel*)pModel)->setStatic(true); + + *ppModel = pModel; + return(true); + } + + return(false); +} diff --git a/source/anim/StaticModelProvider.h b/source/anim/StaticModelProvider.h new file mode 100644 index 0000000000000000000000000000000000000000..37fd0b31938fa825400c5cf9bb52e85f312e9d8d --- /dev/null +++ b/source/anim/StaticModelProvider.h @@ -0,0 +1,18 @@ +#ifndef __STATICMODELPROVIDER_H +#define __STATICMODELPROVIDER_H + +#include <xcommon/resource/IXModelProvider.h> +#include "DynamicModelProvider.h" + +class CStaticModelProvider final: public IXUnknownImplementation<IXStaticModelProvider> +{ +public: + CStaticModelProvider(CDynamicModelProvider *pDynamicModelProvider); + + bool XMETHODCALLTYPE createModel(IXResourceModelStatic *pResource, IXStaticModel **ppModel) override; + +private: + CDynamicModelProvider *m_pDynamicModelProvider; +}; + +#endif diff --git a/source/anim/Updatable.cpp b/source/anim/Updatable.cpp index d04c08cd13b194c8bac23e7493ff8084328d2471..2a48fd286fed63e6c019b14c508c3ed413305dd1 100644 --- a/source/anim/Updatable.cpp +++ b/source/anim/Updatable.cpp @@ -1,8 +1,9 @@ #include "Updatable.h" -CUpdatable::CUpdatable(CAnimatedModelProvider *pAnimatedModelProvider, CDynamicModelProvider *pDynamicModelProvider): +CUpdatable::CUpdatable(CAnimatedModelProvider *pAnimatedModelProvider, CDynamicModelProvider *pDynamicModelProvider, CDecalProvider *pDecalProvider): m_pAnimatedModelProvider(pAnimatedModelProvider), - m_pDynamicModelProvider(pDynamicModelProvider) + m_pDynamicModelProvider(pDynamicModelProvider), + m_pDecalProvider(pDecalProvider) { } @@ -23,6 +24,8 @@ ID CUpdatable::run(float fDelta) m_pDynamicModelProvider->update(); + m_pDecalProvider->update(); + return(-1); } @@ -30,4 +33,5 @@ void CUpdatable::sync() { m_pAnimatedModelProvider->sync(); m_pDynamicModelProvider->sync(); + //m_pDecalProvider->update(); } diff --git a/source/anim/Updatable.h b/source/anim/Updatable.h index 7123026acff06ca4a1edf9f3efeabeeec7ecc1e1..54089837a4775ebad5c966dc60b1d1c316b9545d 100644 --- a/source/anim/Updatable.h +++ b/source/anim/Updatable.h @@ -4,11 +4,12 @@ #include <xcommon/IXUpdatable.h> #include "AnimatedModelProvider.h" #include "DynamicModelProvider.h" +#include "DecalProvider.h" class CUpdatable: public IXUnknownImplementation<IXUpdatable> { public: - CUpdatable(CAnimatedModelProvider *pAnimatedModelProvider, CDynamicModelProvider *pDynamicModelProvider); + CUpdatable(CAnimatedModelProvider *pAnimatedModelProvider, CDynamicModelProvider *pDynamicModelProvider, CDecalProvider *pDecalProvider); UINT startup() override; void shutdown() override; @@ -19,6 +20,7 @@ public: protected: CAnimatedModelProvider *m_pAnimatedModelProvider; CDynamicModelProvider *m_pDynamicModelProvider; + CDecalProvider *m_pDecalProvider; }; #endif diff --git a/source/anim/plugin_main.cpp b/source/anim/plugin_main.cpp index 307928b5c6c0bcc1ad61feda2a988a7dda710a94..c0c068c21cb63c94a496f3b9c67af7987c57fcca 100644 --- a/source/anim/plugin_main.cpp +++ b/source/anim/plugin_main.cpp @@ -4,6 +4,8 @@ #include "Updatable.h" #include "AnimatedModelProvider.h" #include "DynamicModelProvider.h" +#include "StaticModelProvider.h" +#include "DecalProvider.h" class CLevelSizeEventListener final: public IEventListener<XEventLevelSize> { @@ -27,8 +29,11 @@ protected: class CLoadLevelEventListener final: public IEventListener<XEventLevel> { public: - CLoadLevelEventListener(CRenderable *pRenderable): - m_pRenderable(pRenderable) + CLoadLevelEventListener(CRenderable *pRenderable, CAnimatedModelProvider *pAnimatedModelProvider, CDynamicModelProvider *pDynamicModelProvider, CDecalProvider *pDecalProvider): + m_pRenderable(pRenderable), + m_pAnimatedModelProvider(pAnimatedModelProvider), + m_pDynamicModelProvider(pDynamicModelProvider), + m_pDecalProvider(pDecalProvider) {} void onEvent(const XEventLevel *pData) { @@ -36,9 +41,18 @@ public: { case XEventLevel::TYPE_LOAD_BEGIN: m_pRenderable->setEnabled(false); + m_pDecalProvider->setEnabled(false); break; case XEventLevel::TYPE_LOAD_END: m_pRenderable->setEnabled(true); + m_pDecalProvider->setEnabled(true); + break; + + case XEventLevel::TYPE_LOAD_WAIT_ASYNC_TASKS: + while(m_pAnimatedModelProvider->hasPendingOps() && m_pDynamicModelProvider->hasPendingOps()) + { + Sleep(100); + } break; default: @@ -48,6 +62,9 @@ public: protected: CRenderable *m_pRenderable; + CAnimatedModelProvider *m_pAnimatedModelProvider; + CDynamicModelProvider *m_pDynamicModelProvider; + CDecalProvider *m_pDecalProvider; }; class CDSEPlugin: public IXUnknownImplementation<IXPlugin> @@ -57,10 +74,12 @@ public: { m_pAnimatedModelProvider = new CAnimatedModelProvider(m_pCore); m_pDynamicModelProvider = new CDynamicModelProvider(m_pCore); - m_pRenderable = new CRenderable(getID(), m_pAnimatedModelProvider, m_pDynamicModelProvider); - m_pUpdatable = new CUpdatable(m_pAnimatedModelProvider, m_pDynamicModelProvider); + m_pStaticModelProvider = new CStaticModelProvider(m_pDynamicModelProvider); + m_pDecalProvider = new CDecalProvider(m_pCore, m_pDynamicModelProvider); + m_pRenderable = new CRenderable(getID(), m_pAnimatedModelProvider, m_pDynamicModelProvider, m_pDecalProvider); + m_pUpdatable = new CUpdatable(m_pAnimatedModelProvider, m_pDynamicModelProvider, m_pDecalProvider); m_pLevelSizeEventListener = new CLevelSizeEventListener(m_pAnimatedModelProvider, m_pDynamicModelProvider); - m_pLevelLoadEventListener = new CLoadLevelEventListener(m_pRenderable); + m_pLevelLoadEventListener = new CLoadLevelEventListener(m_pRenderable, m_pAnimatedModelProvider, m_pDynamicModelProvider, m_pDecalProvider); m_pCore->getEventChannel<XEventLevelSize>(EVENT_LEVEL_GET_SIZE_GUID)->addListener(m_pLevelSizeEventListener); m_pCore->getEventChannel<XEventLevel>(EVENT_LEVEL_GUID)->addListener(m_pLevelLoadEventListener); @@ -77,16 +96,22 @@ public: { m_pCore->getEventChannel<XEventLevelSize>(EVENT_LEVEL_GET_SIZE_GUID)->removeListener(m_pLevelSizeEventListener); } + if(m_pLevelLoadEventListener) + { + m_pCore->getEventChannel<XEventLevel>(EVENT_LEVEL_GUID)->removeListener(m_pLevelLoadEventListener); + } mem_delete(m_pLevelSizeEventListener); mem_delete(m_pRenderable); mem_delete(m_pUpdatable); mem_delete(m_pAnimatedModelProvider); + mem_delete(m_pStaticModelProvider); mem_delete(m_pDynamicModelProvider); +// mem_delete(m_pDecalProvider); } UINT XMETHODCALLTYPE getInterfaceCount() override { - return(4); + return(6); } const XGUID* XMETHODCALLTYPE getInterfaceGUID(UINT id) override { @@ -105,6 +130,12 @@ public: case 3: s_guid = IXDYNAMICMODELPROVIDER_GUID; break; + case 4: + s_guid = IXDECALPROVIDER_GUID; + break; + case 5: + s_guid = IXSTATICMODELPROVIDER_GUID; + break; default: return(NULL); } @@ -149,6 +180,24 @@ public: add_ref(m_pDynamicModelProvider); *ppOut = m_pDynamicModelProvider; break; + + case 4: + if(!m_pDecalProvider) + { + init(); + } + add_ref(m_pDecalProvider); + *ppOut = m_pDecalProvider; + break; + + case 5: + if(!m_pStaticModelProvider) + { + init(); + } + add_ref(m_pStaticModelProvider); + *ppOut = m_pStaticModelProvider; + break; default: *ppOut = NULL; @@ -161,6 +210,8 @@ protected: IXCore *m_pCore = NULL; CAnimatedModelProvider *m_pAnimatedModelProvider = NULL; CDynamicModelProvider *m_pDynamicModelProvider = NULL; + CStaticModelProvider *m_pStaticModelProvider = NULL; + CDecalProvider *m_pDecalProvider = NULL; CLevelSizeEventListener *m_pLevelSizeEventListener = NULL; CLoadLevelEventListener *m_pLevelLoadEventListener = NULL; }; diff --git a/source/common b/source/common index 8103fff484d6dd1f7006973af8bf581334d8ea1e..bcaae290724afea7b115514dd8e7b9e75bb67726 160000 --- a/source/common +++ b/source/common @@ -1 +1 @@ -Subproject commit 8103fff484d6dd1f7006973af8bf581334d8ea1e +Subproject commit bcaae290724afea7b115514dd8e7b9e75bb67726 diff --git a/source/core/Config.cpp b/source/core/Config.cpp index 2f336a6083ffe5365da016044463d7cbdb3594d6..d8a5b37a5d0e1ca78e52a7693f75eeacb31574e2 100644 --- a/source/core/Config.cpp +++ b/source/core/Config.cpp @@ -479,275 +479,243 @@ void CConfig::set(const char * sectionp, const char * key, const char * val) int CConfig::save() { - static const bool *s_pbDebug = GET_PCVAR_BOOL("dbg_config_save"); - if(*s_pbDebug) - { - printf(COLOR_GRAY "====== " COLOR_CYAN "CConfig::save() " COLOR_GRAY "======" COLOR_RESET "\n"); - } int terror = 0; for(AssotiativeArray<CConfigString, CSection>::Iterator i = m_mSections.begin(); i; ++i) { - if(*s_pbDebug) - { - printf("Testing section: " COLOR_LGREEN "%s" COLOR_RESET "...", i.first->c_str()); - } if(i.second->isModified) { - if(*s_pbDebug) - { - printf(COLOR_YELLOW " modified" COLOR_RESET "\n"); - } for(AssotiativeArray<CConfigString, CValue>::Iterator j = i.second->mValues.begin(); j; ++j) { - if(*s_pbDebug) - { - printf(" testing key: " COLOR_LGREEN "%s" COLOR_RESET "...", j.first->c_str()); - } if(j.second->isModified) { - if(*s_pbDebug) - { - printf(COLOR_YELLOW " modified" COLOR_RESET "\n"); - } if(i.second->native) // Write to BaseFile { - if(*s_pbDebug) - { - printf(" writing to base file " COLOR_CYAN "%s" COLOR_RESET "...\n", BaseFile.c_str()); - } terror = writeFile(BaseFile, *i.first, *j.first, j.second->val); if(terror != 0) goto end; } else // Write to i.second->Include { - if(*s_pbDebug) - { - printf(" writing to include file " COLOR_CYAN "%s" COLOR_RESET "...\n", i.second->Include.c_str()); - } terror = writeFile(i.second->Include, *i.first, *j.first, j.second->val); if(terror != 0) goto end; } } - else - { - if(*s_pbDebug) - { - printf(COLOR_GRAY " not modified" COLOR_RESET "\n"); - } - } - } - } - else - { - if(*s_pbDebug) - { - printf(COLOR_GRAY " not modified" COLOR_RESET "\n"); } } } + + terror = commitFiles(); end: - if(*s_pbDebug) - { - printf(COLOR_GRAY "=============================" COLOR_RESET "\n"); - } return(terror); } int CConfig::writeFile(const CConfigString & name, CConfigString section, CConfigString key, const CConfigString & val) { - static const bool *s_pbDebug = GET_PCVAR_BOOL("dbg_config_save"); - //printf("W: %s\t[%s]: %s = %s\n", name.c_str(), section.c_str(), key.c_str(), val.c_str()); - FILE * pF = fopen(name.c_str(), "rb"); - if(pF) + const AssotiativeArray<String, String>::Node *pUncommittedNode; + + if(!m_mapUncommitted.KeyExists(name, &pUncommittedNode)) { - if(*s_pbDebug) - { - printf(" file opened\n"); - } + pUncommittedNode = m_mapUncommitted.insert(name, ""); - fseek(pF, 0, SEEK_END); - UINT fl = ftell(pF); - fseek(pF, 0, SEEK_SET); - char * szData = new char[fl + 1]; - if(!szData) + // read file + IFile *pFile = m_pFS->openFile(name.c_str()); + if(pFile) { - printf(COLOR_LRED "Unable to allocate memory (%d) in CConfig::writeFile()" COLOR_RESET "\n", fl + 1); - fclose(pF); - return(-1); + size_t sizeFile = pFile->getSize(); + + pUncommittedNode->Val->resize(sizeFile); + char *szPtr = &((*(pUncommittedNode->Val))[0]); + pFile->readBin(szPtr, sizeFile); + szPtr[sizeFile] = 0; + + mem_release(pFile); } - fread(szData, 1, fl, pF); - szData[fl] = 0; - fclose(pF); - UINT sl = section.length(); - UINT kl = key.length(); - bool sf = false; - bool kf = false; - bool se = false; - UINT sp = 0; - for(UINT i = 0; i < fl; ++i) + } + + String &sFileData = *(pUncommittedNode->Val); + + + UINT fl = sFileData.length(); + UINT sl = section.length(); + UINT kl = key.length(); + bool sf = false; + bool kf = false; + bool se = false; + UINT sp = 0; + const char *szData = sFileData.c_str(); + for(UINT i = 0; i < fl; ++i) + { + if(szData[i] == '[' && ((i > 0 && (szData[i - 1] == '\r' || szData[i - 1] == '\n')) || i == 0)) { - if(szData[i] == '[' && ((i > 0 && (szData[i - 1] == '\r' || szData[i - 1] == '\n')) || i == 0)) + bool cmp = true; + UINT j; + for(j = i + 1; j < fl - 1 && j - i - 1 < sl; ++j) + { + if(szData[j] != section[j - i - 1]) + { + cmp = false; + break; + } + } + if(cmp && szData[j] == ']')//Section Found! { - bool cmp = true; - UINT j; - for(j = i + 1; j < fl - 1 && j - i - 1 < sl; ++j) + sf = true; + i = j; + for(; i < fl; ++i) { - if(szData[j] != section[j - i - 1]) + if(szData[i] == '\r' || szData[i] == '\n') { - cmp = false; break; } } - if(cmp && szData[j] == ']')//Section Found! + while(i < fl && (szData[i] == '\r' || szData[i] == '\n')) { - sf = true; - i = j; - for(; i < fl; ++i) + ++i; + } + sp = i; + //We are inside the section + //So, let's find the key + while(i < fl) + { + if(szData[i] == '[') // New section begin. There is no our key, so, add it! { - if(szData[i] == '\r' || szData[i] == '\n') - { - break; - } + kf = false; + se = true; + break; } - while(i < fl && (szData[i] == '\r' || szData[i] == '\n')) + while(i < fl && (szData[i] == ' ' || szData[i] == '\t')) { ++i; } - sp = i; - //We are inside the section - //So, let's find the key - while(i < fl) + bool f = true; + for(j = i; j < fl && j - i < kl; ++j) { - if(szData[i] == '[') // New section begin. There is no our key, so, add it! + if(szData[j] != key[j - i]) { - kf = false; - se = true; + f = false; break; } - while(i < fl && (szData[i] == ' ' || szData[i] == '\t')) - { - ++i; - } - bool f = true; - for(j = i; j < fl && j - i < kl; ++j) + } + if(f && (isspace((unsigned char)szData[j]) || szData[j] == '='))//KeyFound! + { + i = j; + kf = true; + for(j = i; j < fl; ++j) { - if(szData[j] != key[j - i]) + if(szData[j] == '\n' || szData[j] == '\r' || szData[j] == ';') { - f = false; + //f = false; break; } } - if(f && (isspace((unsigned char)szData[j]) || szData[j] == '='))//KeyFound! + //while(szData[j] == '\r' || szData[j] == '\n') + //{ + // ++j; + //} + //Let's write the file + + if(i != j) { - i = j; - kf = true; - for(j = i; j < fl; ++j) - { - if(szData[j] == '\n' || szData[j] == '\r' || szData[j] == ';') - { - //f = false; - break; - } - } - //while(szData[j] == '\r' || szData[j] == '\n') - //{ - // ++j; - //} - //Let's write the file - FILE * pF = fopen(name.c_str(), "wb"); - if(!pF) - { - ErrorFile = name; - mem_delete_a(szData); - return -1; - } - fwrite(szData, 1, i, pF); // First file part, including key - fwrite(" = ", 1, 3, pF); - fwrite(val.c_str(), 1, val.length(), pF); - //fwrite("\n", 1, 1, pF); - fwrite(&szData[j], 1, fl - j, pF); - fclose(pF); + sFileData.remove(i, j - i); + } + + sFileData.insert(i, String(" = ") + val); + + /* + FILE * pF = fopen(name.c_str(), "wb"); + if(!pF) + { + ErrorFile = name; mem_delete_a(szData); - return 0; + return -1; } - else // Skip current row + fwrite(szData, 1, i, pF); // First file part, including key + fwrite(" = ", 1, 3, pF); + fwrite(val.c_str(), 1, val.length(), pF); + //fwrite("\n", 1, 1, pF); + fwrite(&szData[j], 1, fl - j, pF); + fclose(pF); + mem_delete_a(szData);*/ + return 0; + } + else // Skip current row + { + for(; i < fl; ++i) { - for(; i < fl; ++i) - { - if(szData[i] == '\n' || szData[i] == '\r') - { - //f = false; - break; - } - } - while(i < fl && (szData[i] == '\r' || szData[i] == '\n')) + if(szData[i] == '\n' || szData[i] == '\r') { - ++i; + //f = false; + break; } } - } - // - if(se) - { - break; + while(i < fl && (szData[i] == '\r' || szData[i] == '\n')) + { + ++i; + } } } + // + if(se) + { + break; + } } } - if(sf && !kf) - { - if(*s_pbDebug) - { - printf(" adding key to section(sp=" COLOR_LCYAN "%d" COLOR_RESET ")\n", sp); - } - FILE * pF = fopen(name.c_str(), "wb"); - if(!pF) - { - ErrorFile = name; - mem_delete_a(szData); - return -1; - } - fwrite(szData, 1, sp, pF); // First file part - fwrite(key.c_str(), 1, key.length(), pF); - fwrite(" = ", 1, 3, pF); - fwrite(val.c_str(), 1, val.length(), pF); - fwrite("\n", 1, 1, pF); - fwrite(&szData[sp], 1, fl - sp, pF); - fclose(pF); - mem_delete_a(szData); - return 0; - } - if(!sf)//!(Section found) == Add new - { - FILE * pF = fopen(name.c_str(), "ab"); - if(!pF) - { - ErrorFile = name; - return -1; - } - fwrite((CConfigString("\n[") + section + "]\n" + key + " = " + val + "\n").c_str(), sizeof(char), section.length() + key.length() + val.length() + 8, pF); - fclose(pF); - mem_delete_a(szData); - return 0; - } } - else + if(sf && !kf) { - FILE * pF = fopen(name.c_str(), "wb"); - if(!pF) - { - ErrorFile = name; - return -1; - } - fwrite((CConfigString("[") + section + "]\n" + key + " = " + val + "\n").c_str(), sizeof(char), section.length() + key.length() + val.length() + 7, pF); - fclose(pF); + sFileData.insert(sp, key + " = " + val + '\n'); + + return 0; + } + if(!sf)//!(Section found) == Add new + { + sFileData += '\n'; + sFileData += '['; + sFileData += section; + sFileData += ']'; + sFileData += '\n'; + sFileData += key; + sFileData += " = "; + sFileData += val; + sFileData += '\n'; + return 0; } + return 0; } +int CConfig::commitFiles() +{ + for(AssotiativeArray<String, String>::Iterator i = m_mapUncommitted.begin(); i; ++i) + { + //String sTempName = (*i.first) + ".new"; + const String &sName = (*i.first); + IFile *pFile = m_pFS->openFile(sName.c_str(), FILE_MODE_WRITE); + if(!pFile) + { + ErrorFile = sName; + return(-1); + } + + if(i.second->length() != pFile->writeBin(i.second->c_str(), i.second->length())) + { + ErrorFile = sName; + pFile->close(); + return(-2); + } + pFile->close(); + + //m_pFS->rename + } + + m_mapUncommitted.clear(); + + return(0); +} + int CConfig::getSectionCount() { return(m_mSections.Size()); @@ -804,7 +772,6 @@ void CConfig::clear() for(int i = 0; i < size; ++i) { mem_release(m_vIncludes[i].pParser); - mem_delete(m_vIncludes[i].pParser); } m_vIncludes.clear(); m_mFinalValues.clear(); diff --git a/source/core/Config.h b/source/core/Config.h index a921ce2cac390b981e2ef30e75072363085586cc..a2455e8582c2d464e8a3d23a6672e757511c07be 100644 --- a/source/core/Config.h +++ b/source/core/Config.h @@ -37,6 +37,8 @@ public: } }; +//########################################################################## + class CConfig: public ISXConfig { public: @@ -117,8 +119,16 @@ protected: CConfigString baseName(CConfigString dir); void modify(AssotiativeArray<CConfigString, CSection> & sections, AssotiativeArray<CConfigString, CValue> & values, CConfigString IncName); + +private: + int commitFiles(); + +private: + AssotiativeArray<String, String> m_mapUncommitted; }; +//########################################################################## + class CXConfig: public IXUnknownImplementation<IXConfig> { public: diff --git a/source/core/Core.cpp b/source/core/Core.cpp index 701dbefd9fe74d6521b702d63a072f39c1fa7952..567a43d4b214155d1aee509d45d86f0e63e5694e 100644 --- a/source/core/Core.cpp +++ b/source/core/Core.cpp @@ -35,7 +35,6 @@ CCore::CCore(const char *szName) Core_0RegisterCVarBool("g_time_run", true, "Запущено ли игровое время?", FCVAR_NOTIFY_OLD); Core_0RegisterCVarFloat("g_time_speed", 1.f, "Скорость/соотношение течения игрового времени", FCVAR_NOTIFY_OLD); - Core_0RegisterCVarBool("dbg_config_save", false, "Отладочный вывод процесса сохранения конфига"); Core_0RegisterCVarInt("r_stats", 0, "Показывать ли статистику? 0 - нет, 1 - fps и игровое время, 2 - показать полностью"); Core_0RegisterConcmd("on_g_time_run_change", []() diff --git a/source/core/JSON.cpp b/source/core/JSON.cpp index 01cf57087512654df973e57ae71807a483decf4f..c25acd44e60fe9529a69ea96a0fa640453d535e7 100644 --- a/source/core/JSON.cpp +++ b/source/core/JSON.cpp @@ -1,5 +1,9 @@ #include "JSON.h" +MemAlloc<CJSONValue> CJSON::ms_memValues; +MemAlloc<CJSONArray> CJSON::ms_memArrays; +MemAlloc<CJSONObject> CJSON::ms_memObjects; +SpinLock CJSON::ms_slMem; bool XMETHODCALLTYPE CJSON::parse(const char *szString, IXJSONItem **ppOut, void *pReserved) const { @@ -25,7 +29,7 @@ bool CJSON::Parse(const char **str, IXJSONItem **ppOut) if(**str == '{') { - CJSONObject *o = new CJSONObject(); + CJSONObject *o = AllocObject(); if(!o->load(str)) { mem_release(o); @@ -35,7 +39,7 @@ bool CJSON::Parse(const char **str, IXJSONItem **ppOut) } else if(**str == '[') { - CJSONArray *o = new CJSONArray(); + CJSONArray *o = AllocArray(); if(!o->load(str)) { mem_release(o); @@ -45,7 +49,7 @@ bool CJSON::Parse(const char **str, IXJSONItem **ppOut) } else { - CJSONValue *o = new CJSONValue(); + CJSONValue *o = AllocValue(); if(!o->load(str)) { mem_release(o); @@ -56,16 +60,40 @@ bool CJSON::Parse(const char **str, IXJSONItem **ppOut) return(true); } -//########################################################################## +CJSONValue* CJSON::AllocValue() +{ + ScopedSpinLock lock(ms_slMem); + return(ms_memValues.Alloc()); +} +CJSONArray* CJSON::AllocArray() +{ + ScopedSpinLock lock(ms_slMem); + return(ms_memArrays.Alloc()); +} +CJSONObject* CJSON::AllocObject() +{ + ScopedSpinLock lock(ms_slMem); + return(ms_memObjects.Alloc()); +} -CJSONArray::~CJSONArray() +void CJSON::ReleaseItem(CJSONValue *pItem) { - for(UINT i = 0, l = m_aItems.size(); i < l; ++i) - { - mem_release(m_aItems[i]); - } + ScopedSpinLock lock(ms_slMem); + ms_memValues.Delete(pItem); +} +void CJSON::ReleaseItem(CJSONArray *pItem) +{ + ScopedSpinLock lock(ms_slMem); + ms_memArrays.Delete(pItem); +} +void CJSON::ReleaseItem(CJSONObject *pItem) +{ + ScopedSpinLock lock(ms_slMem); + ms_memObjects.Delete(pItem); } +//########################################################################## + UINT XMETHODCALLTYPE CJSONArray::size() const { return(m_aItems.size()); @@ -122,16 +150,18 @@ bool CJSONArray::loadArr(const char **str) return(true); } -//########################################################################## - -CJSONObject::~CJSONObject() +void XMETHODCALLTYPE CJSONArray::FinalRelease() { - for(UINT i = 0, l = m_aPairs.size(); i < l; ++i) + for(UINT i = 0, l = m_aItems.size(); i < l; ++i) { - mem_release(m_aPairs[i].pVal); + mem_release(m_aItems[i]); } + + CJSON::ReleaseItem(this); } +//########################################################################## + UINT XMETHODCALLTYPE CJSONObject::size() const { return(m_aPairs.size()); @@ -216,3 +246,21 @@ bool CJSONObject::loadObj(const char **str) ++*str; return(true); } + +void XMETHODCALLTYPE CJSONObject::FinalRelease() +{ + for(UINT i = 0, l = m_aPairs.size(); i < l; ++i) + { + mem_release(m_aPairs[i].pVal); + } + + CJSON::ReleaseItem(this); +} + +//########################################################################## + +void XMETHODCALLTYPE CJSONValue::FinalRelease() +{ + CJSON::ReleaseItem(this); +} + diff --git a/source/core/JSON.h b/source/core/JSON.h index 0e04ec2ec0c70dae94c7e44f710533160c6883a4..92b7d5f534b5ba6f9bf0e38091b4740cff9b80f0 100644 --- a/source/core/JSON.h +++ b/source/core/JSON.h @@ -195,8 +195,10 @@ public: private: bool loadString(const char **prm) { + m_sVal = ""; + m_type = XJI_STRING; - Array<char> tmp; + //Array<char> tmp; ++*prm; while(**prm && **prm != '"') { @@ -208,22 +210,22 @@ private: case L'"': case L'\\': case L'/': - tmp.push_back(**prm); + m_sVal += **prm; break; case L'b': - tmp.push_back('\b'); + m_sVal += '\b'; break; case L'f': - tmp.push_back('\f'); + m_sVal += '\f'; break; case L'n': - tmp.push_back('\n'); + m_sVal += '\n'; break; case L'r': - tmp.push_back('\r'); + m_sVal += '\r'; break; case L't': - tmp.push_back('\t'); + m_sVal += '\t'; break; case L'u': { @@ -249,7 +251,7 @@ private: return(false); } } - writeChar(code, &tmp); + writeChar(code); } break; default: @@ -258,7 +260,7 @@ private: } else { - tmp.push_back(**prm); + m_sVal += **prm; } ++*prm; } @@ -267,8 +269,6 @@ private: return(false); } ++*prm; - tmp.push_back(0); - m_sVal = tmp; return(true); } bool loadNum(const char **prm) @@ -399,7 +399,7 @@ private: return(false); } - void writeChar(UINT c, Array<char> *pOut) + void writeChar(UINT c) { UINT codepoint = 0; short *in = (short*)&c; @@ -422,28 +422,28 @@ private: if(codepoint <= 0x7f) { - pOut->push_back(codepoint); + m_sVal += (char)codepoint; break; } else if(codepoint <= 0x7ff) { - pOut->push_back(0xc0 | ((codepoint >> 6) & 0x1f)); - pOut->push_back(0x80 | (codepoint & 0x3f)); + m_sVal += (char)(0xc0 | ((codepoint >> 6) & 0x1f)); + m_sVal += (char)(0x80 | (codepoint & 0x3f)); break; } else if(codepoint <= 0xffff) { - pOut->push_back(0xe0 | ((codepoint >> 12) & 0x0f)); - pOut->push_back(0x80 | ((codepoint >> 6) & 0x3f)); - pOut->push_back(0x80 | (codepoint & 0x3f)); + m_sVal += (char)(0xe0 | ((codepoint >> 12) & 0x0f)); + m_sVal += (char)(0x80 | ((codepoint >> 6) & 0x3f)); + m_sVal += (char)(0x80 | (codepoint & 0x3f)); break; } else { - pOut->push_back(0xf0 | ((codepoint >> 18) & 0x07)); - pOut->push_back(0x80 | ((codepoint >> 12) & 0x3f)); - pOut->push_back(0x80 | ((codepoint >> 6) & 0x3f)); - pOut->push_back(0x80 | (codepoint & 0x3f)); + m_sVal += (char)(0xf0 | ((codepoint >> 18) & 0x07)); + m_sVal += (char)(0x80 | ((codepoint >> 12) & 0x3f)); + m_sVal += (char)(0x80 | ((codepoint >> 6) & 0x3f)); + m_sVal += (char)(0x80 | (codepoint & 0x3f)); break; } } @@ -458,15 +458,19 @@ protected: mutable String m_sVal; }; +//########################################################################## + class CJSONValue: public CJSONItem<IXJSONItem> { +private: + void XMETHODCALLTYPE FinalRelease() override; }; +//########################################################################## + class CJSONArray: public CJSONItem<IXJSONArray> { public: - ~CJSONArray(); - UINT XMETHODCALLTYPE size() const override; IXJSONItem* XMETHODCALLTYPE at(UINT idx) const override; @@ -481,16 +485,18 @@ public: private: bool loadArr(const char **str) override; + + void XMETHODCALLTYPE FinalRelease() override; private: Array<IXJSONItem*> m_aItems; }; +//########################################################################## + class CJSONObject: public CJSONItem<IXJSONObject> { public: - ~CJSONObject(); - UINT XMETHODCALLTYPE size() const override; IXJSONItem* XMETHODCALLTYPE at(UINT idx) const override; @@ -509,7 +515,10 @@ public: private: bool loadObj(const char **str) override; - + + void XMETHODCALLTYPE FinalRelease() override; + +private: struct KeyValue { String sKey; @@ -519,12 +528,30 @@ private: Array<KeyValue> m_aPairs; }; +//########################################################################## + class CJSON: public IXUnknownImplementation<IXJSON> { public: bool XMETHODCALLTYPE parse(const char *szString, IXJSONItem **ppOut, void *pReserved = NULL) const override; static bool Parse(const char **str, IXJSONItem **ppOut); + + static void ReleaseItem(CJSONValue *pItem); + static void ReleaseItem(CJSONArray *pItem); + static void ReleaseItem(CJSONObject *pItem); + +private: + static MemAlloc<CJSONValue> ms_memValues; + static MemAlloc<CJSONArray> ms_memArrays; + static MemAlloc<CJSONObject> ms_memObjects; + + static SpinLock ms_slMem; + +private: + static CJSONValue* AllocValue(); + static CJSONArray* AllocArray(); + static CJSONObject* AllocObject(); }; #endif diff --git a/source/game/BaseAmmo.cpp b/source/game/BaseAmmo.cpp index 8714102d3348320990b7f1ca63891f49ba742bac..35abac1eea8a590650ec7e3abe5d2d9420f35cb7 100644 --- a/source/game/BaseAmmo.cpp +++ b/source/game/BaseAmmo.cpp @@ -9,11 +9,10 @@ See the license in LICENSE #include "BaseTool.h" #include <particles/sxparticles.h> #include <mtrl/IXMaterial.h> -#include <decals/sxdecals.h> //#include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h> //! TODO Reimplement me! -#define SMtrl_MtlGetPhysicMaterial(id) MTLTYPE_PHYSIC_METAL +#define SMtrl_MtlGetPhysicMaterial(id) MTLTYPE_PHYSIC_CONCRETE #define SMtrl_MtlGetDurability(id) 1.0f #define SMtrl_MtlGetDensity(id) 1.0f #define SMtrl_MtlGetHitChance(id) 1.0f @@ -107,8 +106,7 @@ void CBaseAmmo::fire(const float3 &_vStart, const float3 &_vDir, CBaseCharacter }); for(int i = 0, l = aHitPoints.size(); i < l; ++i) { - - ID idMtl = -1; // SPhysics_GetMtlID(aHitPoints[i].pCollisionObject, &aHitPoints[i].shapeInfo); + ID idMtl = 0; // SPhysics_GetMtlID(aHitPoints[i].pCollisionObject, &aHitPoints[i].shapeInfo); if(ID_VALID(idMtl) && !aHitPoints[i].isExit) { float fHitChance = SMtrl_MtlGetHitChance(idMtl); @@ -184,6 +182,15 @@ void CBaseAmmo::fire(const float3 &_vStart, const float3 &_vDir, CBaseCharacter // restart fire with new dir and speed float3 vStart2 = aHitPoints[i].vPosition + SMVector3Normalize(vDir) * 0.001f; + for(int j = i + 1; j < l; ++j) + { + if(aHitPoints[j].isExit) + { + // restart at exit point + vStart2 = aHitPoints[i].vPosition + SMVector3Normalize(vDir) * 0.001f; + } + } + vDir = vNewDir; fSpeed = fNewSpeed; @@ -240,26 +247,26 @@ void CBaseAmmo::shootDecal(const float3 &vPos, const float3 &vNormal, ID idMtl) if(ID_VALID(idMtl)) { MTLTYPE_PHYSIC type = SMtrl_MtlGetPhysicMaterial(idMtl); - DECAL_TYPE decalType = DECAL_TYPE_CONCRETE; + XDECAL_TYPE decalType = XDT_CONCRETE; switch(type) { case MTLTYPE_PHYSIC_METAL: - decalType = DECAL_TYPE_METAL; + decalType = XDT_METAL; break; case MTLTYPE_PHYSIC_FLESH: - decalType = DECAL_TYPE_FLESH; + decalType = XDT_FLESH; break; case MTLTYPE_PHYSIC_GROUD_SAND: - decalType = DECAL_TYPE_EARTH; + decalType = XDT_EARTH; break; case MTLTYPE_PHYSIC_PLASTIC: - decalType = DECAL_TYPE_PLASTIC; + decalType = XDT_PLASTIC; break; case MTLTYPE_PHYSIC_TREE: - decalType = DECAL_TYPE_WOOD; + decalType = XDT_WOOD; break; } - SXDecals_ShootDecal(decalType, vPos, vNormal); + SAFE_CALL(GetDecalProvider(), shootDecal, decalType, vPos, vNormal); //SPE_EffectPlayByName("create_decal_test", &aHitPoints[i].vPosition, &aHitPoints[i].vNormal); } @@ -267,7 +274,7 @@ void CBaseAmmo::shootDecal(const float3 &vPos, const float3 &vNormal, ID idMtl) void CBaseAmmo::shootBlood(const float3 &vPos, const float3 &vNormal) { - SXDecals_ShootDecal(DECAL_TYPE_BLOOD_BIG, vPos, vNormal); + SAFE_CALL(GetDecalProvider(), shootDecal, XDT_BLOOD_BIG, vPos, vNormal); } bool CBaseAmmo::shouldRecochet(const float3 &vPos, const float3 &vNormal, const float3 &vDir, ID idMtl, float fSpeed, float3 *pvNewDir, float *pfNewSpeed) diff --git a/source/game/BaseEntity.h b/source/game/BaseEntity.h index 53ecd6de3f3eb3fbfd47e08a0069ab9b61f2c086..a6bee19631543f2b0abd55b67c9582dcbba2c7cb 100644 --- a/source/game/BaseEntity.h +++ b/source/game/BaseEntity.h @@ -36,11 +36,13 @@ See the license in LICENSE #include <light/IXLightSystem.h> +#include <xcommon/resource/IXDecalProvider.h> + #pragma pointers_to_members(full_generality, virtual_inheritance) IXRender* GetRender(); IXParticleSystem* GetParticleSystem(); - +IXDecalProvider* GetDecalProvider(); @@ -170,6 +172,10 @@ public: return(false); } + virtual void setSize(const float3_t &vSize) + { + } + private: void setClassName(const char *name); void setDefaults(); diff --git a/source/game/BaseMover.cpp b/source/game/BaseMover.cpp index d1eed1100fb19396ccf75ec46eaaea9469b83150..0008c78b676ec18bab8b1c443c1cfb37d3aaec24 100644 --- a/source/game/BaseMover.cpp +++ b/source/game/BaseMover.cpp @@ -31,7 +31,7 @@ BEGIN_PROPTABLE(CBaseMover) DEFINE_FLAG(MOVER_NO_AUTOMOUNT, "Disable automount") END_PROPTABLE() -REGISTER_ENTITY(CBaseMover, base_mover); +REGISTER_ENTITY_NOLISTING(CBaseMover, base_mover); IEventChannel<XEventPhysicsStep> *CBaseMover::m_pTickEventChannel = NULL; diff --git a/source/game/BaseTool.cpp b/source/game/BaseTool.cpp index 5d84a3a0fa5b3c5dfe5026fd5c4fe95d425a8bfb..ccc15248bd43e6211a5ace7862af189df0c4ef6a 100644 --- a/source/game/BaseTool.cpp +++ b/source/game/BaseTool.cpp @@ -7,7 +7,6 @@ See the license in LICENSE #include "BaseTool.h" #include <particles/sxparticles.h> -#include <decals/sxdecals.h> #include "Player.h" /*! \skydocent base_tool @@ -138,7 +137,8 @@ void CBaseTool::primaryAction(BOOL st) if(cb.hasHit()) { //shoot decal - SXDecals_ShootDecal(DECAL_TYPE_CONCRETE, BTVEC_F3(cb.m_hitPointWorld), BTVEC_F3(cb.m_hitNormalWorld)); + SAFE_CALL(GetDecalProvider(), shootDecal, XDT_CONCRETE, cb.m_result.vHitPoint, cb.m_result.vHitNormal); + //SXDecals_ShootDecal(DECAL_TYPE_CONCRETE, BTVEC_F3(cb.m_hitPointWorld), BTVEC_F3(cb.m_hitNormalWorld)); SPE_EffectPlayByName("fire", &BTVEC_F3(cb.m_hitPointWorld), &BTVEC_F3(cb.m_hitNormalWorld)); IXRigidBody *pRB = cb.m_result.pCollisionObject->asRigidBody(); diff --git a/source/game/Editable.cpp b/source/game/Editable.cpp index d9484c6714bbd3ddf3e66f29daa70a44428a01ba..dc3239c24b6876ba31a7ec1cd237fc0ba6c81dd1 100644 --- a/source/game/Editable.cpp +++ b/source/game/Editable.cpp @@ -110,14 +110,15 @@ void CEditable::onSelectionChanged(CEditorObject *pObject) bool XMETHODCALLTYPE CEditable::canUseModel(const char *szClass) { - IEntityFactory *pFactory = CEntityFactoryMap::GetInstance()->getFactory(szClass); + return(getClassKV(szClass, "model_field") != NULL); +} + +const char* XMETHODCALLTYPE CEditable::getClassKV(const char *szClassName, const char *szKey) +{ + IEntityFactory *pFactory = CEntityFactoryMap::GetInstance()->getFactory(szClassName); if(pFactory) { - const char *szModelField = pFactory->getKV("model_field"); - if(szModelField) - { - return(true); - } + return(pFactory->getKV(szKey)); } - return(false); + return(NULL); } diff --git a/source/game/Editable.h b/source/game/Editable.h index 3db86f3e571426fb60a88cd3b09ed1836d3342f3..b2f66e35549c4af59d1f7c199a496c3d6519261d 100644 --- a/source/game/Editable.h +++ b/source/game/Editable.h @@ -80,6 +80,8 @@ public: return(m_pDevice); } + const char* XMETHODCALLTYPE getClassKV(const char *szClassName, const char *szKey) override; + protected: IGXDevice *m_pDevice = NULL; IXCore *m_pCore = NULL; diff --git a/source/game/EditorObject.cpp b/source/game/EditorObject.cpp index 944656b71a186737cba9e37b9ab212f9c68ef0af..83da6cb47cfffe04f57985332e1ca7ddc2dd1e01 100644 --- a/source/game/EditorObject.cpp +++ b/source/game/EditorObject.cpp @@ -71,6 +71,8 @@ void CEditorObject::_iniFieldList() && pField->editor.type != PDE_NONE ) { + xField.pEditorData = NULL; + switch(pField->editor.type) { case PDE_COMBOBOX: @@ -79,27 +81,30 @@ void CEditorObject::_iniFieldList() break; case PDE_FILEFIELD: xField.editorType = XPET_FILE; - xField.pEditorData = NULL; { - editor_kv *pKV = (editor_kv*)pField->editor.pData; - if(pKV && pKV[0].value) + kv_t *pKV = (kv_t*)pField->editor.pData; + if(pKV && pKV[0].szValue) { - if(!fstrcmp(pKV[0].value, "dse")) + if(!fstrcmp(pKV[0].szValue, "dse")) { xField.pEditorData = "model"; } - else if(!fstrcmp(pKV[0].value, "ogg")) + else if(!fstrcmp(pKV[0].szValue, "ogg")) { xField.pEditorData = "sound"; } - else if(!fstrcmp(pKV[0].value, "dds")) + else if(!fstrcmp(pKV[0].szValue, "dds")) { xField.pEditorData = "texture"; } - else if(!fstrcmp(pKV[0].value, "eff")) + else if(!fstrcmp(pKV[0].szValue, "eff")) { xField.pEditorData = "effect"; } + else if(!fstrcmp(pKV[0].szValue, "mtl")) + { + xField.pEditorData = "material"; + } } //xField.pEditorData } @@ -119,6 +124,7 @@ void CEditorObject::_iniFieldList() break; case PDE_POINTCOORD: xField.editorType = XPET_POINTCOORD; + xField.pEditorData = pField->editor.pData; break; case PDE_RADIUS: xField.editorType = XPET_RADIUS; @@ -129,6 +135,9 @@ void CEditorObject::_iniFieldList() case PDE_HDRCOLOR: xField.editorType = XPET_HDRCOLOR; break; + case PDE_SIZE: + xField.editorType = XPET_SIZE; + break; } xField.szHelp = ""; xField.szKey = pField->szKey; @@ -218,8 +227,8 @@ void CEditorObject::setPos(const float3_t &pos, bool isSeparate) void XMETHODCALLTYPE CEditorObject::setSize(const float3_t &vSize) { - // TODO Implement me //m_vScale = vScale; + m_pEntity->setSize(vSize); } /*void CEditorObject::setScale(const float3_t &vScale, bool isSeparate) diff --git a/source/game/EntityFactory.h b/source/game/EntityFactory.h index 46ff5c91c3305bdbaa86b8b6eeeedd4507ae70c3..1ec3331aa9c0e3a792d98f708298c4b0b350f746 100644 --- a/source/game/EntityFactory.h +++ b/source/game/EntityFactory.h @@ -203,6 +203,9 @@ private: #define REC_ICON(s) REC_KV("icon", s) #define REC_MODEL(s) REC_KV("model", s) #define REC_MODEL_FIELD(s) REC_KV("model_field", s) +#define REC_NO_HEIGHT_ADJUST() REC_KV("no_height_adj", "1") +#define REC_ALIGN_WITH_NORMAL(axis) REC_KV("align_with_norm", axis) +#define REC_MATERIAL_FIELD(s) REC_KV("material_field", s) #define REGISTER_ENTITY(cls, name, ...) \ CEntityFactory<cls> ent_ ## name ## _factory(#name, {__VA_ARGS__}) diff --git a/source/game/EntityManager.cpp b/source/game/EntityManager.cpp index f7bdfed35d1ef3e3676bd0e6d9c6ab1ce8179b1f..f7a14bf636cc0f33f3d042888fdb676cea6dac76 100644 --- a/source/game/EntityManager.cpp +++ b/source/game/EntityManager.cpp @@ -400,14 +400,14 @@ bool CEntityManager::exportList(const char * file) int ic = 0; //if(m_isOldImported) - { + /*{ FILE *fp = fopen(file, "w"); if(fp) { fclose(fp); } m_isOldImported = false; - } + }*/ // conf->set("meta", "count", "0"); @@ -463,13 +463,7 @@ bool CEntityManager::import(const char * file, bool shouldSendProgress) CBaseEntity *pEnt = NULL; Array<CBaseEntity*> tmpList; - char szFullPath[1024]; - if(!Core_GetIXCore()->getFileSystem()->resolvePath(file, szFullPath, sizeof(szFullPath))) - { - goto err; - } - - if(conf->open(szFullPath)) + if(conf->open(file)) { goto err; } diff --git a/source/game/GameData.cpp b/source/game/GameData.cpp index a759bab3943e33f7e5b6181e9951d5975667c0d7..1f6d4ed04c74d4e943320d065d60fc55a9e820e5 100644 --- a/source/game/GameData.cpp +++ b/source/game/GameData.cpp @@ -81,6 +81,7 @@ static IXPhysics *g_pPhysics = NULL; static IXPhysicsWorld *g_pPhysWorld = NULL; static IXRender *g_pRender = NULL; static IXParticleSystem *g_pParticleSystem = NULL; +static IXDecalProvider *g_pDecalProvider = NULL; //########################################################################## @@ -114,6 +115,10 @@ IXParticleSystem* GetParticleSystem() { return(g_pParticleSystem); } +IXDecalProvider* GetDecalProvider() +{ + return(g_pDecalProvider); +} //########################################################################## @@ -342,9 +347,12 @@ void XMETHODCALLTYPE CLevelLoadTask::exec() evLevel.szLevelName = m_szLevelName; g_levelProgressListener.onLoadBegin(); - + evLevel.type = XEventLevel::TYPE_LOAD; g_pLevelChannel->broadcastEvent(&evLevel); + + evLevel.type = XEventLevel::TYPE_LOAD_WAIT_ASYNC_TASKS; + g_pLevelChannel->broadcastEvent(&evLevel); } void XMETHODCALLTYPE CLevelLoadTask::onFinished() @@ -489,6 +497,7 @@ GameData::GameData(HWND hWnd, bool isGame): g_pPhysics = (IXPhysics*)Core_GetIXCore()->getPluginManager()->getInterface(IXPHYSICS_GUID); g_pPhysWorld = g_pPhysics->getWorld(); g_pParticleSystem = (IXParticleSystem*)Core_GetIXCore()->getPluginManager()->getInterface(IXPARTICLESYSTEM_GUID); + g_pDecalProvider = (IXDecalProvider*)Core_GetIXCore()->getPluginManager()->getInterface(IXDECALPROVIDER_GUID); if(m_pLightSystem && false) { diff --git a/source/game/InfoOverlay.cpp b/source/game/InfoOverlay.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d534185547e5ba48ac82dacbb5350993b783db45 --- /dev/null +++ b/source/game/InfoOverlay.cpp @@ -0,0 +1,372 @@ +#include "InfoOverlay.h" + +BEGIN_PROPTABLE(CInfoOverlay) + //! Значение по умолчанию + DEFINE_FIELD_STRINGFN(m_szMaterial, PDFF_NONE, "material", "Overlay material", setMaterial, EDITOR_MATERIAL) + + //! Высота объема декали + DEFINE_FIELD_FLOATFN(m_fHeight, PDFF_NONE, "height", "Height", setHeight, EDITOR_TEXTFIELD) + + //! Угол 1 + DEFINE_FIELD_VECTORFN(m_vCorner0, PDFF_USE_GIZMO, "point0", "Point 1", setCorner0, EDITOR_POINTCOORDEX) + EDITOR_KV("lock", "plane") + EDITOR_KV("axis", "z") + EDITOR_KV("local", "1") + EDITOR_END() + //! Угол 2 + DEFINE_FIELD_VECTORFN(m_vCorner1, PDFF_USE_GIZMO, "point1", "Point 2", setCorner1, EDITOR_POINTCOORDEX) + EDITOR_KV("lock", "plane") + EDITOR_KV("axis", "z") + EDITOR_KV("local", "1") + EDITOR_END() + //! Угол 3 + DEFINE_FIELD_VECTORFN(m_vCorner2, PDFF_USE_GIZMO, "point2", "Point 3", setCorner2, EDITOR_POINTCOORDEX) + EDITOR_KV("lock", "plane") + EDITOR_KV("axis", "z") + EDITOR_KV("local", "1") + EDITOR_END() + //! Угол 4 + DEFINE_FIELD_VECTORFN(m_vCorner3, PDFF_USE_GIZMO, "point3", "Point 4", setCorner3, EDITOR_POINTCOORDEX) + EDITOR_KV("lock", "plane") + EDITOR_KV("axis", "z") + EDITOR_KV("local", "1") + EDITOR_END() + + //! Разрешить перетекание на перпендикулярные поверхности + DEFINE_FIELD_BOOLFN(m_isLeakAllowed, PDFF_NONE, "allow_leak", "Allow leak to perpendicular surface", setLeakAllowed, EDITOR_YESNO) + + //! Угол 4 + //DEFINE_FIELD_VECTORFN(m_vSize, PDFF_USE_GIZMO, "size", "Size", setSize, EDITOR_SIZE) + + //! Включает + //DEFINE_INPUT(turnOn, "turnOn", "Turn on", PDF_NONE) + //! Выключает + //DEFINE_INPUT(turnOff, "turnOff", "Turn off", PDF_NONE) + //! Переключает состояние + //DEFINE_INPUT(toggle, "toggle", "Toggle", PDF_NONE) + + + + //! Изначально выключена + //DEFINE_FLAG(MOVER_INITIALLY_DISABLED, "Start disabled") + //! Отключить автомонтирование (требуется нажать кнопку взаимодействия) + //DEFINE_FLAG(MOVER_NO_AUTOMOUNT, "Disable automount") +END_PROPTABLE() + +REGISTER_ENTITY(CInfoOverlay, info_overlay, REC_NO_HEIGHT_ADJUST(), REC_ALIGN_WITH_NORMAL("z"), REC_MATERIAL_FIELD("material")); + +CInfoOverlay::CInfoOverlay() +{ + float2_t vSize(1.0f, 1.0f); + + float2_t sBound(-vSize.x * 0.5f, vSize.x * 0.5f); + float2_t tBound(-vSize.y * 0.5f, vSize.y * 0.5f); + + m_vCorner0 = float3_t(sBound.x, tBound.x, 0.0f); + m_vCorner1 = float3_t(sBound.x, tBound.y, 0.0f); + m_vCorner2 = float3_t(sBound.y, tBound.y, 0.0f); + m_vCorner3 = float3_t(sBound.y, tBound.x, 0.0f); + + m_fHeight = min(vSize.x, vSize.y) * 0.25f; + + GetDecalProvider()->newDecal(&m_pDecal); + + m_pDecal->setHeight(m_fHeight); + + m_pDecal->setCorner(0, float2(m_vCorner0)); + m_pDecal->setCorner(1, float2(m_vCorner1)); + m_pDecal->setCorner(2, float2(m_vCorner2)); + m_pDecal->setCorner(3, float2(m_vCorner3)); + + updateSize(); +} + +CInfoOverlay::~CInfoOverlay() +{ + mem_release(m_pDecal); +} + +void CInfoOverlay::setCorner0(const float3 &v) +{ + m_vCorner0 = v; + m_pDecal->setCorner(0, float2(v)); + updateSize(); +} +void CInfoOverlay::setCorner1(const float3 &v) +{ + m_vCorner1 = v; + m_pDecal->setCorner(1, float2(v)); + updateSize(); +} +void CInfoOverlay::setCorner2(const float3 &v) +{ + m_vCorner2 = v; + m_pDecal->setCorner(2, float2(v)); + updateSize(); +} +void CInfoOverlay::setCorner3(const float3 &v) +{ + m_vCorner3 = v; + m_pDecal->setCorner(3, float2(v)); + updateSize(); +} + +void CInfoOverlay::setPos(const float3 &vPos) +{ + BaseClass::setPos(vPos); + + m_pDecal->setPosition(vPos); +} + +void CInfoOverlay::setOrient(const SMQuaternion &qRot) +{ + BaseClass::setOrient(qRot); + + m_pDecal->setOrientation(qRot); +} + +void CInfoOverlay::setMaterial(const char *szValue) +{ + _setStrVal(&m_szMaterial, szValue); + + m_pDecal->setMaterial(szValue); +} + +void CInfoOverlay::setHeight(float fHeight) +{ + m_fHeight = fHeight; + m_pDecal->setHeight(fHeight); +} + +void CInfoOverlay::renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) +{ + if(pRenderer) + { + pRenderer->setLineWidth(is3D ? 0.01f : 1.0f); + + pRenderer->setColor(float4(1.0f, 0.0f, 0.0f, 1.0f)); + pRenderer->jumpTo(getPos()); + pRenderer->lineTo(getPos() + getOrient() * float3(0.1f, 0.0f, 0.0f)); + + pRenderer->setColor(float4(0.0f, 1.0f, 0.0f, 1.0f)); + pRenderer->jumpTo(getPos()); + pRenderer->lineTo(getPos() + getOrient() * float3(0.0f, 0.1f, 0.0f)); + + pRenderer->setColor(float4(0.0f, 0.0f, 1.0f, 1.0f)); + pRenderer->jumpTo(getPos()); + pRenderer->lineTo(getPos() + getOrient() * float3(0.0f, 0.0f, 0.2f)); + + if(bRenderSelection || !is3D) + { + pRenderer->setLineWidth(is3D ? 0.005f : 1.0f); + const float4 c_vLineColor = bRenderSelection ? float4(1.0f, 0.0f, 0.0f, 1.0f) : float4(1.0f, 0.0f, 1.0f, 1.0f); + pRenderer->setColor(c_vLineColor); + + float3 vS = getOrient() * float3(1.0f, 0.0f, 0.0f); + float3 vT = getOrient() * float3(0.0f, 1.0f, 0.0f); + float3 vN = getOrient() * float3(0.0f, 0.0f, 1.0f); + + float3_t vPt0 = getPos() + m_vCorner0.x * vS + m_vCorner0.y * vT; + float3_t vPt1 = getPos() + m_vCorner1.x * vS + m_vCorner1.y * vT; + float3_t vPt2 = getPos() + m_vCorner2.x * vS + m_vCorner2.y * vT; + float3_t vPt3 = getPos() + m_vCorner3.x * vS + m_vCorner3.y * vT; + + float3 vTopOffset = vN * m_fHeight; + + pRenderer->jumpTo(vPt0 - vTopOffset); + pRenderer->lineTo(vPt1 - vTopOffset); + pRenderer->lineTo(vPt2 - vTopOffset); + pRenderer->lineTo(vPt3 - vTopOffset); + pRenderer->lineTo(vPt0 - vTopOffset); + pRenderer->lineTo(vPt0 + vTopOffset); + pRenderer->lineTo(vPt1 + vTopOffset); + pRenderer->lineTo(vPt2 + vTopOffset); + pRenderer->lineTo(vPt3 + vTopOffset); + pRenderer->lineTo(vPt0 + vTopOffset); + + pRenderer->jumpTo(vPt1 - vTopOffset); + pRenderer->lineTo(vPt1 + vTopOffset); + + pRenderer->jumpTo(vPt2 - vTopOffset); + pRenderer->lineTo(vPt2 + vTopOffset); + + pRenderer->jumpTo(vPt3 - vTopOffset); + pRenderer->lineTo(vPt3 + vTopOffset); + } + } +} + +void CInfoOverlay::getMinMax(float3 *min, float3 *max) +{ + float3 vS = getOrient() * float3(1.0f, 0.0f, 0.0f); + float3 vT = getOrient() * float3(0.0f, 1.0f, 0.0f); + float3 vN = getOrient() * float3(0.0f, 0.0f, 1.0f); + + float3 vTopOffset = vN * m_fHeight; + + float3_t vPt0 = m_vCorner0.x * vS + m_vCorner0.y * vT; + float3_t vPt1 = m_vCorner1.x * vS + m_vCorner1.y * vT; + float3_t vPt2 = m_vCorner2.x * vS + m_vCorner2.y * vT; + float3_t vPt3 = m_vCorner3.x * vS + m_vCorner3.y * vT; + + float3_t vPt10 = vPt0 + vTopOffset; + float3_t vPt11 = vPt1 + vTopOffset; + float3_t vPt12 = vPt2 + vTopOffset; + float3_t vPt13 = vPt3 + vTopOffset; + + vPt0 = vPt0 - vTopOffset; + vPt1 = vPt1 - vTopOffset; + vPt2 = vPt2 - vTopOffset; + vPt3 = vPt3 - vTopOffset; + + if(min) + { + *min = SMVectorMin( + SMVectorMin(SMVectorMin(vPt0, vPt1), SMVectorMin(vPt2, vPt3)), + SMVectorMin(SMVectorMin(vPt10, vPt11), SMVectorMin(vPt12, vPt13)) + ); + } + + if(max) + { + *max = SMVectorMax( + SMVectorMax(SMVectorMax(vPt0, vPt1), SMVectorMax(vPt2, vPt3)), + SMVectorMax(SMVectorMax(vPt10, vPt11), SMVectorMax(vPt12, vPt13)) + ); + } +} + +void CInfoOverlay::setSize(const float3_t &vSize) +{ + float3 vMin, vMax; + getMinMax(&vMin, &vMax); + BaseClass::setSize(vSize); + + float3 vRelativeSize = vSize / (vMax - vMin); + + float3 vS = getOrient() * float3(1.0f, 0.0f, 0.0f); + float3 vT = getOrient() * float3(0.0f, 1.0f, 0.0f); + float3 vN = getOrient() * float3(0.0f, 0.0f, 1.0f); + + float3_t vPt0 = (m_vCorner0.x * vS + m_vCorner0.y * vT) * vRelativeSize; + float3_t vPt1 = (m_vCorner1.x * vS + m_vCorner1.y * vT) * vRelativeSize; + float3_t vPt2 = (m_vCorner2.x * vS + m_vCorner2.y * vT) * vRelativeSize; + float3_t vPt3 = (m_vCorner3.x * vS + m_vCorner3.y * vT) * vRelativeSize; + + m_vCorner0 = float3_t(SMVector3Dot(vPt0, vS), SMVector3Dot(vPt0, vT), 0.0f); + m_vCorner1 = float3_t(SMVector3Dot(vPt1, vS), SMVector3Dot(vPt1, vT), 0.0f); + m_vCorner2 = float3_t(SMVector3Dot(vPt2, vS), SMVector3Dot(vPt2, vT), 0.0f); + m_vCorner3 = float3_t(SMVector3Dot(vPt3, vS), SMVector3Dot(vPt3, vT), 0.0f); + + m_pDecal->setCorner(0, float2(m_vCorner0)); + m_pDecal->setCorner(1, float2(m_vCorner1)); + m_pDecal->setCorner(2, float2(m_vCorner2)); + m_pDecal->setCorner(3, float2(m_vCorner3)); + + m_fHeight *= SMVector3Dot(vN, vRelativeSize); + m_pDecal->setHeight(m_fHeight); + + updateSize(); +} + +bool CInfoOverlay::rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut, float3 *pvNormal, bool isRayInWorldSpace, bool bReturnNearestPoint) +{ + if(!isRayInWorldSpace) + { + float3 vPos = getPos(); + SMQuaternion qRot = getOrient().Conjugate(); + + float3 vRayStart = qRot * vStart - vPos; + float3 vRayEnd = qRot * vEnd - vPos; + return(m_pDecal->rayTest(vRayStart, vRayEnd, pvOut, pvNormal)); + } + + return(m_pDecal->rayTest(vStart, vEnd, pvOut, pvNormal)); +} + +void CInfoOverlay::updateSize() +{ + float3 vMin = SMVectorMin(SMVectorMin(m_vCorner0, m_vCorner1), SMVectorMin(m_vCorner2, m_vCorner3)); + float3 vMax = SMVectorMax(SMVectorMax(m_vCorner0, m_vCorner1), SMVectorMax(m_vCorner2, m_vCorner3)); + + m_vSize = vMax - vMin; + m_vSize.z = m_fHeight * 2.0f; +} + +void CInfoOverlay::setSize(const float3 &v) +{ +} + +void CInfoOverlay::setLeakAllowed(bool yesNo) +{ + m_isLeakAllowed = yesNo; + m_pDecal->setLeakAllowed(yesNo); +} + +#if 0 + +void CInfoOverlay::updateFlags() +{ + BaseClass::updateFlags(); + + if(getFlags() & MOVER_INITIALLY_DISABLED) + { + disable(); + } + else + { + enable(); + } +} + +void CInfoOverlay::turnOn(inputdata_t *pInputdata) +{ + enable(); +} + +void CInfoOverlay::turnOff(inputdata_t *pInputdata) +{ + disable(); +} + +void CInfoOverlay::toggle(inputdata_t *pInputdata) +{ + if(m_isEnabled) + { + turnOff(pInputdata); + } + else + { + turnOn(pInputdata); + } +} + + + +void CInfoOverlay::enable() +{ + if(!m_isEnabled) + { + if(m_pGhostObject) + { + GetPhysWorld()->addCollisionObject(m_pGhostObject, CG_LADDER, CG_CHARACTER); + } + m_pTickEventChannel->addListener(&m_physicsTicker); + m_isEnabled = true; + } +} + +void CInfoOverlay::disable() +{ + if(m_isEnabled) + { + if(m_pGhostObject) + { + GetPhysWorld()->removeCollisionObject(m_pGhostObject); + } + m_pTickEventChannel->removeListener(&m_physicsTicker); + m_isEnabled = false; + } +} + +#endif diff --git a/source/game/InfoOverlay.h b/source/game/InfoOverlay.h new file mode 100644 index 0000000000000000000000000000000000000000..ca46e39c52d3ffeb2fe6891bd5113822b7fa8764 --- /dev/null +++ b/source/game/InfoOverlay.h @@ -0,0 +1,71 @@ +#ifndef __INFO_OVERLAY_H +#define __INFO_OVERLAY_H + +#include "PointEntity.h" + +//#define MOVER_INITIALLY_DISABLED ENT_FLAG_0 +//#define MOVER_NO_AUTOMOUNT ENT_FLAG_1 + +class CInfoOverlay: public CPointEntity +{ + DECLARE_CLASS(CInfoOverlay, CPointEntity); + DECLARE_PROPTABLE(); +public: + DECLARE_CONSTRUCTOR(); + ~CInfoOverlay(); + + void setPos(const float3 &vPos) override; + void setOrient(const SMQuaternion &qRot) override; + + void renderEditor(bool is3D, bool bRenderSelection, IXGizmoRenderer *pRenderer) override; + + void getMinMax(float3 *min, float3 *max) override; + + + + bool rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut = NULL, float3 *pvNormal = NULL, bool isRayInWorldSpace = true, bool bReturnNearestPoint = false) override; + + void setHeight(float fHeight); + void setMaterial(const char *szValue); + + void setSize(const float3_t &vSize) override; + + void setLeakAllowed(bool yesNo); + +private: + void setCorner0(const float3 &v); + void setCorner1(const float3 &v); + void setCorner2(const float3 &v); + void setCorner3(const float3 &v); + + void setSize(const float3 &v); + //void updateFlags() override; + + //void turnOn(inputdata_t *pInputdata); + //void turnOff(inputdata_t *pInputdata); + //void toggle(inputdata_t *pInputdata); + //void enable(); + //void disable(); + + //SMAABB getBound(); + void updateSize(); + +private: + IXDecal *m_pDecal = NULL; + const char *m_szMaterial = NULL; + + float3_t m_vCorner0; + float3_t m_vCorner1; + float3_t m_vCorner2; + float3_t m_vCorner3; + + float m_fHeight = 0.1f; + + float3_t m_vSize; + + bool m_isLeakAllowed = true; + + //bool m_isEnabled = false; +}; + +#endif diff --git a/source/game/ZombieHands.cpp b/source/game/ZombieHands.cpp index 19b7df3658635fc40ebad62f6021db8467b8a3ec..4e8e4f1887143866e16efce5465d843585c807ef 100644 --- a/source/game/ZombieHands.cpp +++ b/source/game/ZombieHands.cpp @@ -1,7 +1,6 @@ #include "ZombieHands.h" #include "BaseCharacter.h" -#include <decals/sxdecals.h> #include "Tracer.h" /*! \skydocent wpn_zombie_hands @@ -52,7 +51,7 @@ void CZombieHands::actualShoot(float dt) if(cb.hasHit()) { - SXDecals_ShootDecal(DECAL_TYPE_BLOOD_BIG, BTVEC_F3(cb.m_hitPointWorld), BTVEC_F3(cb.m_hitNormalWorld)); + SAFE_CALL(GetDecalProvider(), shootDecal, XDT_BLOOD_BIG, cb.m_result.vHitPoint, cb.m_result.vHitNormal); if(cb.m_result.pCollisionObject->getUserPointer() && cb.m_result.pCollisionObject->getUserTypeId() == 1) { diff --git a/source/game/proptable.cpp b/source/game/proptable.cpp index 619cba20ad883d8889af3b7296df202deaa73c98..57723b117e69977e564bfb0a58cf06182a0c2dec 100644 --- a/source/game/proptable.cpp +++ b/source/game/proptable.cpp @@ -11,14 +11,14 @@ See the license in LICENSE #include "BaseEntity.h" -prop_editor_t _GetEditorCombobox(int start, ...) +prop_editor_t _GetEditor(PDE_TYPE type, ...) { prop_editor_t out; - out.type = PDE_COMBOBOX; - editor_kv kvs[ED_COMBO_MAXELS]; + out.type = type; + kv_t kvs[ED_COMBO_MAXELS]; va_list va; - va_start(va, start); + va_start(va, type); const char * el; int i = 0; @@ -28,56 +28,21 @@ prop_editor_t _GetEditorCombobox(int start, ...) { break; } - kvs[i].key = el; + kvs[i].szKey = el; if(!(el = va_arg(va, const char *))) { break; } - kvs[i].value = el; + kvs[i].szValue = el; ++i; } - kvs[i].value = kvs[i].key = 0; + kvs[i].szValue = kvs[i].szKey = 0; ++i; va_end(va); - out.pData = new editor_kv[i]; - memcpy(out.pData, kvs, sizeof(editor_kv)* i); - return(out); -} - -prop_editor_t _GetEditorFilefield(int start, ...) -{ - prop_editor_t out; - out.type = PDE_FILEFIELD; - editor_kv kvs[ED_COMBO_MAXELS]; - - va_list va; - va_start(va, start); - - const char * el; - int i = 0; - while(i < ED_COMBO_MAXELS) - { - if(!(el = va_arg(va, const char *))) - { - break; - } - kvs[i].key = el; - if(!(el = va_arg(va, const char *))) - { - break; - } - kvs[i].value = el; - ++i; - } - kvs[i].value = kvs[i].key = 0; - ++i; - - va_end(va); - - out.pData = new editor_kv[i]; - memcpy(out.pData, kvs, sizeof(editor_kv)* i); + out.pData = new kv_t[i]; + memcpy(out.pData, kvs, sizeof(kv_t)* i); return(out); } diff --git a/source/game/proptable.h b/source/game/proptable.h index b73c430f918522042ca208b713ced369059cd7f1..3f97ecba76de87cf3078cd626635b3999668dc39 100644 --- a/source/game/proptable.h +++ b/source/game/proptable.h @@ -74,7 +74,8 @@ enum PDE_TYPE PDE_POINTCOORD, PDE_RADIUS, PDE_COLOR, - PDE_HDRCOLOR + PDE_HDRCOLOR, + PDE_SIZE }; enum PDF_FLAG @@ -170,12 +171,6 @@ union PFNFIELDSET int __; }; -struct editor_kv -{ - const char * key; - const char * value; -}; - struct prop_editor_t { PDE_TYPE type; @@ -367,8 +362,7 @@ struct proptable_t #define ED_COMBO_MAXELS 256 -prop_editor_t _GetEditorCombobox(int start, ...); -prop_editor_t _GetEditorFilefield(int start, ...); +prop_editor_t _GetEditor(PDE_TYPE type, ...); #define DECLARE_PROPTABLE() \ \ @@ -454,6 +448,10 @@ void cls::InitPropData() \ const char * GetEmptyString(); +#define EDITOR_BEGIN(type) _GetEditor(type +#define EDITOR_KV(name, value) , name, value +#define EDITOR_END() , NULL)} + #define EDITOR_NONE {PDE_NONE, NULL}} #define EDITOR_TEXTFIELD {PDE_TEXTFIELD, NULL}} #define EDITOR_TIMEFIELD {PDE_TIME, NULL}} @@ -463,19 +461,24 @@ const char * GetEmptyString(); #define EDITOR_FLAGS {PDE_FLAGS, NULL}} #define EDITOR_COLOR {PDE_COLOR, NULL}} #define EDITOR_HDRCOLOR {PDE_HDRCOLOR, NULL}} +#define EDITOR_SIZE {PDE_SIZE, NULL}} + +#define EDITOR_POINTCOORDEX EDITOR_BEGIN(PDE_POINTCOORD) + -#define EDITOR_COMBOBOX _GetEditorCombobox(0 -#define COMBO_OPTION(name, value) , name, value -#define EDITOR_COMBO_END() , NULL)} +#define EDITOR_COMBOBOX EDITOR_BEGIN(PDE_COMBOBOX) +#define COMBO_OPTION(name, value) EDITOR_KV(name, value) +#define EDITOR_COMBO_END() EDITOR_END() -#define EDITOR_FILEFIELD _GetEditorFilefield(0 -#define FILE_OPTION(name, value) , name, value -#define EDITOR_FILE_END() , NULL)} +#define EDITOR_FILEFIELD EDITOR_BEGIN(PDE_FILEFIELD) +#define FILE_OPTION(name, value) EDITOR_KV(name, value) +#define EDITOR_FILE_END() EDITOR_END() #define EDITOR_YESNO EDITOR_COMBOBOX COMBO_OPTION("Yes", "1") COMBO_OPTION("No", "0") EDITOR_COMBO_END() #define EDITOR_MODEL EDITOR_FILEFIELD FILE_OPTION("Select model", "dse") EDITOR_FILE_END() #define EDITOR_SOUND EDITOR_FILEFIELD FILE_OPTION("Select sound", "ogg") EDITOR_FILE_END() #define EDITOR_TEXTURE EDITOR_FILEFIELD FILE_OPTION("Select texture", "dds") EDITOR_FILE_END() +#define EDITOR_MATERIAL EDITOR_FILEFIELD FILE_OPTION("Select material", "mtl") EDITOR_FILE_END() #define EDITOR_EFFECT EDITOR_FILEFIELD FILE_OPTION("Select effect", "eff") EDITOR_FILE_END() #define DEFINE_FIELD_STRING(field, flags, keyname, edname, editor) , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field), PDF_STRING, flags, keyname, edname, editor diff --git a/source/gdefines.h b/source/gdefines.h index 30f4bac0d425986a774eff01ce5cf0072086fefc..bc8b37e1f5df43181052d80037318ab599bb27cd 100644 --- a/source/gdefines.h +++ b/source/gdefines.h @@ -221,6 +221,12 @@ typedef void(*report_func) (int iLevel, const char *szLibName, const char *szMes #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) #endif +struct kv_t +{ + const char *szKey; + const char *szValue; +}; + /** \name Уровни критичности сообщений для функции репортов */ //! @{ #define REPORT_MSG_LEVEL_NOTICE 0 /*!< заметка */ diff --git a/source/physics/PhyWorld.cpp b/source/physics/PhyWorld.cpp index 0dd249c57282fc0b1fd30fa45d528f3a1bc7590a..c4eb6d186be5e804983271a66b263e81adc9e567 100644 --- a/source/physics/PhyWorld.cpp +++ b/source/physics/PhyWorld.cpp @@ -56,7 +56,7 @@ struct XRayResultCallback: public btCollisionWorld::RayResultCallback m_hitPointWorld.setInterpolate3(m_rayFromWorld, m_rayToWorld, rayResult.m_hitFraction); m_result.vHitPoint = BTVEC_F3(m_hitPointWorld); - m_result.vHitNormal = BTVEC_F3(m_hitPointWorld); + m_result.vHitNormal = BTVEC_F3(m_hitNormalWorld); m_result.pCollisionObject = m_collisionObject->getUserIndex() == 2 ? (IXCollisionObject*)m_collisionObject->getUserPointer() : NULL; m_result.fHitFraction = rayResult.m_hitFraction; diff --git a/source/render/Scene.cpp b/source/render/Scene.cpp index 42e5ad8a8b557b67fe6cb19cc90f7b3a5803fc4e..46d10cb9cc88b4586996f9a5299367e1b7c2cb09 100644 --- a/source/render/Scene.cpp +++ b/source/render/Scene.cpp @@ -1287,6 +1287,11 @@ public: return(m_pEditorExt->getRenderer()); } + const char* XMETHODCALLTYPE getClassKV(const char *szClassName, const char *szKey) override + { + return(NULL); + } + private: CEditorExt *m_pEditorExt = NULL; }; @@ -1696,3 +1701,8 @@ void CScene::print() m_pRootNode->print(0, &uNodesCount, &uObjectsCount, &uMaxDepth); printf("Total objects: %u, Total nodes: %u, Max depth: %u, avg objects per node: %f\n", uObjectsCount, uNodesCount, uMaxDepth, (float)uObjectsCount / (float)uNodesCount); } + +bool CScene::hasPendingOps() +{ + return(!m_qUpdate.empty()); +} diff --git a/source/render/Scene.h b/source/render/Scene.h index 4d810b09aaf95bef82711d954347bdc953ae975b..7b42aeff747a16a0e22954db3f3ce7b83bcc62d2 100644 --- a/source/render/Scene.h +++ b/source/render/Scene.h @@ -275,6 +275,8 @@ public: bool validate(); void print(); + bool hasPendingOps(); + protected: void addObject(CSceneObject *pObject); void removeObject(CSceneObject *pObject); diff --git a/source/render/plugin_main.cpp b/source/render/plugin_main.cpp index 0e510908d5fba6132a52ba7642596c3f96e1a97a..01d6d674333e70fb40f671902f51f54515d336df 100644 --- a/source/render/plugin_main.cpp +++ b/source/render/plugin_main.cpp @@ -15,6 +15,33 @@ #pragma comment(lib, "sxgame.lib") #endif +class CLoadLevelEventListener final: public IEventListener<XEventLevel> +{ +public: + CLoadLevelEventListener(CScene *pScene): + m_pScene(pScene) + { + } + void onEvent(const XEventLevel *pData) + { + switch(pData->type) + { + case XEventLevel::TYPE_LOAD_WAIT_ASYNC_TASKS: + while(m_pScene->hasPendingOps()) + { + Sleep(100); + } + break; + + default: + break; + } + } + +protected: + CScene *m_pScene; +}; + class CRenderPlugin: public IXUnknownImplementation<IXPlugin> { public: @@ -25,6 +52,10 @@ public: void XMETHODCALLTYPE shutdown() override { + if(m_pLevelLoadEventListener) + { + m_pCore->getEventChannel<XEventLevel>(EVENT_LEVEL_GUID)->removeListener(m_pLevelLoadEventListener); + } } UINT XMETHODCALLTYPE getInterfaceCount() override @@ -68,6 +99,9 @@ public: if(!m_pScene) { m_pScene = new CScene(m_pCore); + m_pLevelLoadEventListener = new CLoadLevelEventListener(m_pScene); + + m_pCore->getEventChannel<XEventLevel>(EVENT_LEVEL_GUID)->addListener(m_pLevelLoadEventListener); } *ppOut = m_pScene; break; @@ -144,6 +178,7 @@ protected: CScene *m_pScene = NULL; CUpdatable *m_pUpdatable = NULL; CRender *m_pRender = NULL; + CLoadLevelEventListener *m_pLevelLoadEventListener = NULL; }; DECLARE_XPLUGIN(CRenderPlugin); diff --git a/source/terrax/CommandBuildModel.cpp b/source/terrax/CommandBuildModel.cpp index f3ff59d42f8b94b22cca96ca04f36814cf8e700e..30484344f531eb76436cf3aa900bb4d877df50d1 100644 --- a/source/terrax/CommandBuildModel.cpp +++ b/source/terrax/CommandBuildModel.cpp @@ -5,7 +5,7 @@ extern AssotiativeArray<AAString, IXEditable*> g_mEditableSystems; CCommandBuildModel::CCommandBuildModel(const char *szTypeName, const char *szClassName) { - m_pCommandCreate = new CCommandCreate(float3_t(), szTypeName, szClassName); + m_pCommandCreate = new CCommandCreate(float3_t(), float3_t(), szTypeName, szClassName); } CCommandBuildModel::~CCommandBuildModel() diff --git a/source/terrax/CommandCreate.cpp b/source/terrax/CommandCreate.cpp index 7dac8882c0c4ba1f15c956157d58bd30376f6040..df0279c186a20a1bd50bb06be8390cf9023337ec 100644 --- a/source/terrax/CommandCreate.cpp +++ b/source/terrax/CommandCreate.cpp @@ -3,15 +3,15 @@ extern AssotiativeArray<AAString, IXEditable*> g_mEditableSystems; -CCommandCreate::CCommandCreate(const float3_t &vPos, const char *szTypeName, const char *szClassName, bool useRandomScaleYaw) +CCommandCreate::CCommandCreate(const float3_t &vPos, const float3_t &vNorm, const char *szTypeName, const char *szClassName, bool useRandomScaleYaw): + m_vPos(vPos), + m_vNorm(vNorm), + m_sClassName(szClassName) { - m_vPos = vPos; - m_sClassName = szClassName; - if(useRandomScaleYaw) { m_fScale = randf(0.7, 1.3); - m_qOrient = SMQuaternion(randf(0, SM_2PI), 'y'); + m_fRotAngle = randf(0, SM_2PI); } const AssotiativeArray<AAString, IXEditable*>::Node *pNode; @@ -42,10 +42,82 @@ bool XMETHODCALLTYPE CCommandCreate::exec() m_pObject->setPos(m_vPos); //! @TODO Implement random scale? //m_pObject->setScale(float3(m_fScale)); - m_pObject->setOrient(m_qOrient); + const char *szNormalAlign = m_pEditable->getClassKV(m_sClassName.c_str(), "align_with_norm"); + if(!SMIsZero(SMVector3Length2(m_vNorm)) && szNormalAlign) + { + char cAxis = szNormalAlign[0]; + float fVal = 1.0f; + if(cAxis == '-') + { + cAxis = szNormalAlign[1]; + float fVal = -1.0f; + } + float3_t vFrom; + switch(tolower(cAxis)) + { + case 'x': + vFrom.x = fVal; + break; + case 'y': + vFrom.y = fVal; + break; + case 'z': + vFrom.z = fVal; + break; + } + SMQuaternion qRot(vFrom, m_vNorm); + m_pObject->setOrient(qRot * SMQuaternion(m_vNorm, m_fRotAngle)); + } + else + { + m_pObject->setOrient(SMQuaternion(m_fRotAngle, 'y')); + } m_pObject->setSelected(true); m_pObject->create(); + if(!SMIsZero(SMVector3Length2(m_vNorm)) && !m_pEditable->getClassKV(m_sClassName.c_str(), "no_height_adj")) + { + float3 vMin, vMax; + m_pObject->getBound(&vMin, &vMax); + + float3 avPoints[] = { + float3(vMin), + float3(vMin.x, vMin.y, vMax.z), + float3(vMin.x, vMax.y, vMin.z), + float3(vMin.x, vMax.y, vMax.z), + float3(vMax.x, vMin.y, vMin.z), + float3(vMax.x, vMin.y, vMax.z), + float3(vMax.x, vMax.y, vMin.z), + float3(vMax), + }; + //printf("%.2f, %.2f, %.2f\n", vNorm.x, vNorm.y, vNorm.z); + + float fProj = FLT_MAX; + for(UINT i = 0, l = ARRAYSIZE(avPoints); i < l; ++i) + { + float fTmp = SMVector3Dot(avPoints[i], m_vNorm); + //printf("%.2f\n", fTmp); + if(fTmp < fProj) + { + fProj = fTmp; + } + } + + fProj = SMVector3Dot(m_vPos, m_vNorm) - fProj; + //printf("%.2f, %.2f, %.2f\n%.2f, %.2f, %.2f\n%.2f, %.2f, %.2f\n%f\n\n", vPos.x, vPos.y, vPos.z, vMin.x, vMin.y, vMin.z, vMax.x, vMax.y, vMax.z, fProj); + if(fProj > 0) + { + m_pObject->setPos((float3)(m_vPos + m_vNorm * fProj)); + } + } + + const char *szMaterialField = m_pEditable->getClassKV(m_sClassName.c_str(), "material_field"); + if(szMaterialField) + { + m_sMaterial = g_pEditor->getMaterialBrowser()->getCurrentMaterial(); + m_pObject->setKV(szMaterialField, m_sMaterial.c_str()); + } + g_pEditor->addObject(m_pObject); XUpdatePropWindow(); diff --git a/source/terrax/CommandCreate.h b/source/terrax/CommandCreate.h index 7b72e90d6951e71d3c9341e4bf8d7b3caa57e828..ba0b86dee61cb72cf1a9bb2e7985b64f7ac614f0 100644 --- a/source/terrax/CommandCreate.h +++ b/source/terrax/CommandCreate.h @@ -11,7 +11,7 @@ class CCommandCreate final: public IXUnknownImplementation<IXEditorCommand> { public: - CCommandCreate(const float3_t &vPos, const char *szTypeName, const char *szClassName, bool useRandomScaleYaw=false); + CCommandCreate(const float3_t &vPos, const float3_t &vNorm, const char *szTypeName, const char *szClassName, bool useRandomScaleYaw = false); ~CCommandCreate(); bool XMETHODCALLTYPE exec() override; @@ -34,11 +34,13 @@ public: protected: float3_t m_vPos; - SMQuaternion m_qOrient; + float3_t m_vNorm; + float m_fRotAngle = 0.0f; float m_fScale = 1.0f; String m_sClassName; IXEditable *m_pEditable = NULL; IXEditorObject *m_pObject = NULL; + String m_sMaterial; }; #endif diff --git a/source/terrax/Editor.cpp b/source/terrax/Editor.cpp index e17b7ce2adc3b572aa9e263cca13c1cfda303392..51185b8270e370ecc459640a978b514bc7400f05 100644 --- a/source/terrax/Editor.cpp +++ b/source/terrax/Editor.cpp @@ -38,6 +38,8 @@ CEditor::CEditor(IXCore *pCore): pCore->getPluginManager()->registerInterface(IXCOLORPICKER_GUID, &m_colorPicker); m_pSceneTreeWindow = new CSceneTreeWindow(this, pCore); + + registerResourceBrowser(new CResourceBrowser()); } CEditor::~CEditor() diff --git a/source/terrax/Editor.h b/source/terrax/Editor.h index fb18b38d0b571fa69c8fce49d0453603c580b7ce..3f15126b872c664856d8b2da1629f4a8945e3cf8 100644 --- a/source/terrax/Editor.h +++ b/source/terrax/Editor.h @@ -15,6 +15,7 @@ #include "ColorGradientEditorDialog.h" #include "ColorPicker.h" #include "SceneTreeWindow.h" +#include "ResourceBrowser.h" #define GIZMO_TYPES() \ GTO(Handle)\ diff --git a/source/terrax/GroupObject.cpp b/source/terrax/GroupObject.cpp index 5beb78e13a37a1a825bd2c00fd5406de316446e1..5fa1a1aa1a60ef5e00e2cd63c3326ec7ac12e930 100644 --- a/source/terrax/GroupObject.cpp +++ b/source/terrax/GroupObject.cpp @@ -303,7 +303,7 @@ void CGroupObject::addChildObject(IXEditorObject *pObject) ICompoundObject *pOldContainer = XTakeObject(pObject, this); assert(pOldContainer == NULL); - //add_ref(pObject); + add_ref(pObject); m_aObjects.push_back({pObject, m_qOrient.Conjugate() * (pObject->getPos() - m_vPos), pObject->getOrient() * m_qOrient.Conjugate()}); g_pEditor->onObjectAdded(pObject); @@ -323,7 +323,7 @@ void CGroupObject::removeChildObject(IXEditorObject *pObject) g_pEditor->onObjectRemoved(pObject); - //mem_release(pObject); + mem_release(pObject); if(!m_aObjects.size()) { diff --git a/source/terrax/PropertyWindow.cpp b/source/terrax/PropertyWindow.cpp index 75896547e181e0092e1bd2b93c0af00c23960e1b..475f2471c523e876fa3eba1e55e7639d3c323cc2 100644 --- a/source/terrax/PropertyWindow.cpp +++ b/source/terrax/PropertyWindow.cpp @@ -63,6 +63,7 @@ static UINT g_uEditorDlgIds[] = { IDD_PROPEDIT_TEXT, IDD_PROPEDIT_TEXT, IDD_PROPEDIT_TEXT, + IDD_PROPEDIT_TEXT, }; static_assert(ARRAYSIZE(g_uEditorDlgIds) == XPET__LAST, "g_uEditorDlgIds must match X_PROP_EDITOR_TYPE"); @@ -819,7 +820,7 @@ void CPropertyWindow::initEditor(X_PROP_EDITOR_TYPE type, const void *pData, con { HWND hCombo = GetDlgItem(hEditorDlg, IDC_OPE_COMBO); ComboBox_ResetContent(hCombo); - edt_kv *pKV = (edt_kv*)pData; + kv_t *pKV = (kv_t*)pData; while(pKV->szKey) { ComboBox_AddString(hCombo, pKV->szKey); diff --git a/source/terrax/PropertyWindow.h b/source/terrax/PropertyWindow.h index 9047f29ce296a1cbb3b513e0ef1095741b25f932..2f8db9f8154cb4f20569f33891098f0abba36205 100644 --- a/source/terrax/PropertyWindow.h +++ b/source/terrax/PropertyWindow.h @@ -105,13 +105,7 @@ protected: X_PROP_FIELD field; String sValue; }; - - struct edt_kv - { - const char *szKey; - const char *szValue; - }; - + AssotiativeArray<AAString, prop_s> m_aPropFields; X_PROP_EDITOR_TYPE m_editorActive = XPET__LAST; diff --git a/source/terrax/ResourceBrowser.cpp b/source/terrax/ResourceBrowser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f0be58de59bbfd1f595898efd1bd4e7537348d6 --- /dev/null +++ b/source/terrax/ResourceBrowser.cpp @@ -0,0 +1,26 @@ +#include "ResourceBrowser.h" +#include "terrax.h" + +UINT XMETHODCALLTYPE CResourceBrowser::getResourceTypeCount() +{ + return(1); +} +const char* XMETHODCALLTYPE CResourceBrowser::getResourceType(UINT uId) +{ + if(uId == 0) + { + return("material"); + } + + return(NULL); +} + +void XMETHODCALLTYPE CResourceBrowser::browse(const char *szType, const char *szOldValue, IXEditorResourceBrowserCallback *pCallback) +{ + m_callback.init(pCallback); + g_pMaterialBrowser->browse(&m_callback); +} +void XMETHODCALLTYPE CResourceBrowser::cancel() +{ + g_pMaterialBrowser->abort(); +} diff --git a/source/terrax/ResourceBrowser.h b/source/terrax/ResourceBrowser.h new file mode 100644 index 0000000000000000000000000000000000000000..04b530571e612b34d2ab3904d5d6de3979039b22 --- /dev/null +++ b/source/terrax/ResourceBrowser.h @@ -0,0 +1,46 @@ +#ifndef __RESOURCEBROWSER_H +#define __RESOURCEBROWSER_H + +#include <xcommon/editor/IXEditorExtension.h> +#include "MaterialBrowser.h" + +class CResourceMaterialBrowserCallback: public IMaterialBrowserCallback +{ +public: + void init(IXEditorResourceBrowserCallback *pCallback) + { + SAFE_CALL(m_pCallback, onCancelled); + m_pCallback = pCallback; + } + void onSelected(const char *szName) override + { + SAFE_CALL(m_pCallback, onSelected, szName); + m_pCallback = NULL; + } + void onCancel() override + { + SAFE_CALL(m_pCallback, onCancelled); + m_pCallback = NULL; + } + + +private: + IXEditorResourceBrowserCallback *m_pCallback = NULL; +}; + +//############################################################################# + +class CResourceBrowser: public IXUnknownImplementation<IXEditorResourceBrowser> +{ +public: + UINT XMETHODCALLTYPE getResourceTypeCount() override; + const char* XMETHODCALLTYPE getResourceType(UINT uId) override; + + void XMETHODCALLTYPE browse(const char *szType, const char *szOldValue, IXEditorResourceBrowserCallback *pCallback) override; + void XMETHODCALLTYPE cancel() override; + +private: + CResourceMaterialBrowserCallback m_callback; +}; + +#endif diff --git a/source/terrax/mainWindow.cpp b/source/terrax/mainWindow.cpp index ab6b568737a1f8b14722bf9d522b926ad95de81d..763ed59dfcc6e89cb97f7dec07fc4299f6543749 100644 --- a/source/terrax/mainWindow.cpp +++ b/source/terrax/mainWindow.cpp @@ -972,7 +972,7 @@ guid = {9D7D2E62-24C7-42B7-8D83-8448FC4604F0} mem_release(pConfig); } -static CCommandCreate* CreateObjectAtPosition(const float3 &vPos, bool bDeselectAll) +static CCommandCreate* CreateObjectAtPosition(const float3 &vPos, const float3 &vNorm, bool bDeselectAll) { int iSel1 = ComboBox_GetCurSel(g_hComboTypesWnd); int iLen1 = ComboBox_GetLBTextLen(g_hComboTypesWnd, iSel1); @@ -989,7 +989,7 @@ static CCommandCreate* CreateObjectAtPosition(const float3 &vPos, bool bDeselect SendMessage(g_hWndMain, WM_COMMAND, MAKEWPARAM(ID_EDIT_CLEARSELECTION, 0), (LPARAM)0); } - CCommandCreate *pCmd = new CCommandCreate(vPos, szTypeName, szClassName, Button_GetCheck(g_hCheckboxRandomScaleYawWnd)); + CCommandCreate *pCmd = new CCommandCreate(vPos, vNorm, szTypeName, szClassName, Button_GetCheck(g_hCheckboxRandomScaleYawWnd)); g_pUndoManager->execCommand(pCmd); return(pCmd); @@ -1947,7 +1947,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case IDC_CTRL_RETURN: if(g_xState.bCreateMode) { - CreateObjectAtPosition(g_xState.vCreateOrigin, GetKeyState(VK_CONTROL) >= 0); + CreateObjectAtPosition(g_xState.vCreateOrigin, float3(0.0f), GetKeyState(VK_CONTROL) >= 0); g_xState.bCreateMode = false; } @@ -3285,40 +3285,8 @@ LRESULT CALLBACK RenderWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP vPos = s_aRaytracedItems[0].vPos; vNorm = SMVector3Normalize(s_aRaytracedItems[0].vNorm); - IXEditorObject *pObj = CreateObjectAtPosition(vPos, GetKeyState(VK_CONTROL) >= 0)->getObject(); - float3 vMin, vMax; - pObj->getBound(&vMin, &vMax); - - float3 avPoints[] = { - float3(vMin), - float3(vMin.x, vMin.y, vMax.z), - float3(vMin.x, vMax.y, vMin.z), - float3(vMin.x, vMax.y, vMax.z), - float3(vMax.x, vMin.y, vMin.z), - float3(vMax.x, vMin.y, vMax.z), - float3(vMax.x, vMax.y, vMin.z), - float3(vMax), - }; - //printf("%.2f, %.2f, %.2f\n", vNorm.x, vNorm.y, vNorm.z); - - float fProj = FLT_MAX; - for(UINT i = 0, l = ARRAYSIZE(avPoints); i < l; ++i) - { - float fTmp = SMVector3Dot(avPoints[i], vNorm); - //printf("%.2f\n", fTmp); - if(fTmp < fProj) - { - fProj = fTmp; - } - } - - fProj = SMVector3Dot(vPos, vNorm) - fProj; - //printf("%.2f, %.2f, %.2f\n%.2f, %.2f, %.2f\n%.2f, %.2f, %.2f\n%f\n\n", vPos.x, vPos.y, vPos.z, vMin.x, vMin.y, vMin.z, vMax.x, vMax.y, vMax.z, fProj); - if(fProj > 0) - { - pObj->setPos((float3)(vPos + vNorm * fProj)); - } - + IXEditorObject *pObj = CreateObjectAtPosition(vPos, vNorm, GetKeyState(VK_CONTROL) >= 0)->getObject(); + s_aRaytracedItems.clearFast(); } } @@ -4499,7 +4467,7 @@ case editor_type: if(pItem->m_pObj == pObj && !fstrcmp(pItem->m_field.szKey, pField->szKey)) \ { \ pItem->m_uUpdateRevision = g_uPropGizmoUpdateRevision; \ - pItem->init(); \ + pItem->init(pField->pEditorData); \ return; \ } \ } \ @@ -4508,7 +4476,7 @@ case editor_type: pCb->m_pObj = pObj; \ pCb->m_field = *pField; \ pCb->m_uUpdateRevision = g_uPropGizmoUpdateRevision; \ - pCb->init(); \ + pCb->init(pField->pEditorData); \ g_aPropGizmo##gizmo##Items.push_back(pCb); \ } \ break @@ -4531,7 +4499,7 @@ XDECLARE_PROP_GIZMO(Radius, void XMETHODCALLTYPE onChange(float fNewRadius, IXEd char tmp[16]; sprintf(tmp, "%f", fNewRadius); m_pCommand->setKV(m_field.szKey, tmp); -}, void init() +}, void init(const void *pEditorData) { m_pGizmo->setPos(m_pObj->getPos()); float fRadius; @@ -4548,13 +4516,69 @@ XDECLARE_PROP_GIZMO(Handle, void XMETHODCALLTYPE moveTo(const float3 &vNewPos, I char tmp[64]; sprintf(tmp, "%f %f %f", vTmp.x, vTmp.y, vTmp.z); m_pCommand->setKV(m_field.szKey, tmp); -}, void init() +}, void init(const void *pEditorData) { float3_t vec; if(sscanf(m_pObj->getKV(m_field.szKey), "%f %f %f", &vec.x, &vec.y, &vec.z)) { m_pGizmo->setPos(m_pObj->getOrient() * vec + m_pObj->getPos()); } + + if(pEditorData) + { + kv_t *pKV = (kv_t*)pEditorData; + bool bLockPlane = false; + bool bLockAxis = false; + bool bLockLocal = true; + char axis = 0; + while(pKV->szKey) + { + if(!strcmp(pKV->szKey, "lock")) + { + if(!strcmp(pKV->szValue, "plane")) + { + bLockPlane = true; + } + else if(!strcmp(pKV->szValue, "axis")) + { + bLockAxis = true; + } + } + else if(!strcmp(pKV->szKey, "axis")) + { + axis = pKV->szValue[0]; + } + else if(!strcmp(pKV->szKey, "local")) + { + if(pKV->szValue[0] != '0') + { + bLockLocal = true; + } + } + ++pKV; + } + + if((bLockPlane || bLockAxis) && axis) + { + float3_t vAxis(axis == 'x' ? 1.0f : 0.0, axis == 'y' ? 1.0f : 0.0, axis == 'z' ? 1.0f : 0.0); + if(bLockLocal) + { + vAxis = m_pObj->getOrient() * vAxis; + } + if(bLockPlane) + { + m_pGizmo->lockInPlane(vAxis); + } + else + { + m_pGizmo->lockInDir(vAxis); + } + } + else + { + m_pGizmo->unLock(); + } + } }); UINT g_uPropGizmoUpdateRevision = 0; diff --git a/source/terrax/terrax.cpp b/source/terrax/terrax.cpp index fe5e84feea376064c905a7c4a976e976873275ab..3a73567ac904ab6f2d5fc1e6b3a97cc438d8095a 100644 --- a/source/terrax/terrax.cpp +++ b/source/terrax/terrax.cpp @@ -827,7 +827,7 @@ int main(int argc, char **argv) g_pEditor->registerResourceBrowser(pResourceBrowser); mem_release(pResourceBrowser); // XInitTool(pResourceBrowser, pEditable); - } + } } } diff --git a/source/xParticles/Editable.h b/source/xParticles/Editable.h index af162845fe61a18fbfdc016fd118a546abdc6f4c..bbfe486f44d41ad889888c5f3b0df3289089b280 100644 --- a/source/xParticles/Editable.h +++ b/source/xParticles/Editable.h @@ -79,6 +79,11 @@ public: return(false); } + const char* XMETHODCALLTYPE getClassKV(const char *szClassName, const char *szKey) override + { + return(NULL); + } + private: CEditorObject* getObjectByGUID(const XGUID &guid); diff --git a/source/xUI/UIViewport.cpp b/source/xUI/UIViewport.cpp index 989921e9b303b116db11a8f351c3a6adaac8ec87..495b9560f381daa598a714ad30deb99776ff3455 100644 --- a/source/xUI/UIViewport.cpp +++ b/source/xUI/UIViewport.cpp @@ -46,5 +46,5 @@ void XMETHODCALLTYPE CUIViewport::setSize(float fSizeX, float fSizeY) { BaseClass::setSize(fSizeX, fSizeY); - m_pRenderTarget->resize((UINT)fSizeX, (UINT)fSizeY); + m_pRenderTarget->resize(fSizeX > 1.0f ? (UINT)fSizeX : 1, fSizeY > 1.0f ? (UINT)fSizeY : 1); } diff --git a/source/xUI/UIWindow.cpp b/source/xUI/UIWindow.cpp index 4fa6863ed70af72eb8a495facfa4295db91fd1cb..a6ae35a5e2741262a33708894ba7c31cc7700207 100644 --- a/source/xUI/UIWindow.cpp +++ b/source/xUI/UIWindow.cpp @@ -108,9 +108,22 @@ CUIWindow::CUIWindow(CXUI *pXUI, const XWINDOW_DESC *pWindowDesc, IUIWindow *pPa m_pXWindowCallback = new CWindowCallback(this, m_pDesktopStack); m_pXWindow = pXUI->getWindowSystem()->createWindow(pWindowDesc, m_pXWindowCallback, pXParent); - createSwapChain((UINT)pWindowDesc->iSizeX, (UINT)pWindowDesc->iSizeY); + float fScale = m_pXWindow->getScale(); + + if(fScale != 1.0f) + { + XWINDOW_DESC newDesc = *pWindowDesc; + newDesc.iSizeX *= fScale; + newDesc.iSizeY *= fScale; + m_pXWindow->update(&newDesc); + createSwapChain((UINT)newDesc.iSizeX, (UINT)newDesc.iSizeY); + } + else + { + createSwapChain((UINT)pWindowDesc->iSizeX, (UINT)pWindowDesc->iSizeY); + } - m_pDesktopStack->setScale(m_pXWindow->getScale()); + m_pDesktopStack->setScale(fScale); m_pControl = new CUIWindowControl(this, 0); } diff --git a/source/xcommon/XEvents.h b/source/xcommon/XEvents.h index fc73870971bcc377ed16e646b9d90a5a76425af9..09b2ae9f8172df10d57b6dccef02e38c1f14e9b7 100644 --- a/source/xcommon/XEvents.h +++ b/source/xcommon/XEvents.h @@ -95,6 +95,8 @@ struct XEventLevel TYPE_LOAD_END, //!< Уровень полностью загружен TYPE_UNLOAD_BEGIN, //!< До начала выгрузки уровня TYPE_UNLOAD_END, //!< Уровень полностью выгружен + + TYPE_LOAD_WAIT_ASYNC_TASKS, //!< Ожидание завершения асинхронных задач } type; const char *szLevelName; }; diff --git a/source/xcommon/editor/IXEditable.h b/source/xcommon/editor/IXEditable.h index 17cd062da54204939f4feff6707b9018f3f4d3db..abcd208faa589896dfe7271dd0a4bff7d7c60398 100644 --- a/source/xcommon/editor/IXEditable.h +++ b/source/xcommon/editor/IXEditable.h @@ -58,7 +58,7 @@ public: virtual const char* XMETHODCALLTYPE getName() = 0; virtual UINT XMETHODCALLTYPE getClassCount() = 0; virtual const char* XMETHODCALLTYPE getClass(UINT id) = 0; - + virtual void XMETHODCALLTYPE startup(IGXDevice *pDevice) = 0; virtual void XMETHODCALLTYPE shutdown() = 0; @@ -72,6 +72,7 @@ public: virtual bool XMETHODCALLTYPE canUseModel(const char *szClass) = 0; + virtual const char* XMETHODCALLTYPE getClassKV(const char *szClassName, const char *szKey) = 0; }; diff --git a/source/xcommon/editor/IXEditorObject.h b/source/xcommon/editor/IXEditorObject.h index b1643d970bec41590c397ed6122c0340bdf92191..156c7e2dd35d6a65ba9c4f4ed9564369ea539b15 100644 --- a/source/xcommon/editor/IXEditorObject.h +++ b/source/xcommon/editor/IXEditorObject.h @@ -16,6 +16,7 @@ enum X_PROP_EDITOR_TYPE XPET_RADIUS, XPET_COLOR, XPET_HDRCOLOR, + XPET_SIZE, //XPET_YESNO, XPET__LAST diff --git a/source/xcommon/resource/IXDecal.h b/source/xcommon/resource/IXDecal.h new file mode 100644 index 0000000000000000000000000000000000000000..67038ed8f4d4febb2d62e7248b1459d922034050 --- /dev/null +++ b/source/xcommon/resource/IXDecal.h @@ -0,0 +1,44 @@ +#ifndef __IXDECAL_H +#define __IXDECAL_H + +#include <gdefines.h> +#include "IXResourceModel.h" + +class IXDecal: public IXUnknown +{ +public: + virtual float3 XMETHODCALLTYPE getPosition() const = 0; + virtual void XMETHODCALLTYPE setPosition(const float3 &vPos) = 0; + + virtual SMQuaternion XMETHODCALLTYPE getOrientation() const = 0; + virtual void XMETHODCALLTYPE setOrientation(const SMQuaternion &qRot) = 0; + + virtual float3 XMETHODCALLTYPE getLocalBoundMin() const = 0; + virtual float3 XMETHODCALLTYPE getLocalBoundMax() const = 0; + virtual SMAABB XMETHODCALLTYPE getLocalBound() const = 0; + + virtual bool XMETHODCALLTYPE isEnabled() const = 0; + virtual void XMETHODCALLTYPE enable(bool yesNo) = 0; + + virtual bool XMETHODCALLTYPE rayTest(const float3 &vStart, const float3 &vEnd, float3 *pvOut = NULL, float3 *pvNormal = NULL) = 0; + + virtual void XMETHODCALLTYPE setLayer(UINT uLayer) = 0; + virtual UINT XMETHODCALLTYPE getLayer() = 0; + + virtual void XMETHODCALLTYPE setHeight(float fHeight) = 0; + virtual float XMETHODCALLTYPE getHeight() = 0; + + virtual void XMETHODCALLTYPE setTextureRangeU(const float2_t &vRange) = 0; + virtual float2_t XMETHODCALLTYPE getTextureRangeU() = 0; + + virtual void XMETHODCALLTYPE setTextureRangeV(const float2_t &vRange) = 0; + virtual float2_t XMETHODCALLTYPE getTextureRangeV() = 0; + + virtual void XMETHODCALLTYPE setMaterial(const char *szMaterial) = 0; + + virtual void XMETHODCALLTYPE setCorner(UINT uCorner, const float2_t &vCorner) = 0; + + virtual void XMETHODCALLTYPE setLeakAllowed(bool yesNo) = 0; +}; + +#endif diff --git a/source/xcommon/resource/IXDecalProvider.h b/source/xcommon/resource/IXDecalProvider.h new file mode 100644 index 0000000000000000000000000000000000000000..38420258815f8383c1d60823f6254c6a031263da --- /dev/null +++ b/source/xcommon/resource/IXDecalProvider.h @@ -0,0 +1,34 @@ +#ifndef __IXDECALPROVIDER_H +#define __IXDECALPROVIDER_H + +#include "IXDecal.h" + +// {878E7A1E-86D4-4967-9A6D-6054B4363119} +#define IXDECALPROVIDER_GUID DEFINE_XGUID(0x878e7a1e, 0x86d4, 0x4967, 0x9a, 0x6d, 0x60, 0x54, 0xb4, 0x36, 0x31, 0x19) + +enum XDECAL_TYPE +{ + XDT_CONCRETE = 0, + XDT_METAL, + XDT_GLASS, + XDT_PLASTIC, + XDT_WOOD, + XDT_FLESH, + XDT_EARTH, + XDT_BLOOD_BIG, + + XDT__COUNT +}; + +// Implemented in anim plugin +class IXDecalProvider: public IXUnknown +{ +public: + // create custom decal + virtual bool XMETHODCALLTYPE newDecal(IXDecal **ppDecal) = 0; + + // create temporal standard decal at point/normal + virtual void XMETHODCALLTYPE shootDecal(XDECAL_TYPE type, const float3 &vWorldPos, const float3 &vNormal, float fScale = 1.0f, const float3 *pvSAxis = NULL) = 0; +}; + +#endif diff --git a/source/xcsg/Editable.h b/source/xcsg/Editable.h index 8d88c2d9b081b928410d7b1bd7868b17cde75ba1..6df39e2befc5f1b11dd02eb6d368ad5be5c9cddf 100644 --- a/source/xcsg/Editable.h +++ b/source/xcsg/Editable.h @@ -103,6 +103,11 @@ public: void onModelDestroy(CEditorModel *pModel); void onModelRestored(CEditorModel *pModel); + const char* XMETHODCALLTYPE getClassKV(const char *szClassName, const char *szKey) override + { + return(NULL); + } + SX_ALIGNED_OP_MEM(); CVertexTool* getVertexTool(); diff --git a/source/xcsg/EditorObject.cpp b/source/xcsg/EditorObject.cpp index e168c533cfc99678ed213f1ca686c5f2cfd59edc..1ff89234361bfa37c2bc648d36d39f0b4de0bf33 100644 --- a/source/xcsg/EditorObject.cpp +++ b/source/xcsg/EditorObject.cpp @@ -144,7 +144,7 @@ bool XMETHODCALLTYPE CEditorObject::rayTest(const float3 &vStart, const float3 & if(bReturnNearestPoint) { float3 vOut, vMinOut, vNormal, *pNormal = NULL; - if(pNormal) + if(pvNormal) { pNormal = &vNormal; }