diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 13fb717147..4f45c9bee2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,7 +23,7 @@ add_openmw_dir (mwrender creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover - postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass navmeshmode + postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass navmeshmode debugdraw ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 40aa628f01..7120ab8e31 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -27,6 +27,9 @@ #include "../mwbase/statemanager.hpp" #include "../mwbase/luamanager.hpp" +#include "../mwrender/renderingmanager.hpp" +#include "../mwrender/debugdraw.hpp" + #include "../mwmechanics/aibreathe.hpp" #include "../mwrender/vismask.hpp" @@ -1607,9 +1610,14 @@ namespace MWMechanics continue; } + world->setActorActive(actor.getPtr(), true); const bool isDead = actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead(); + + world->getRenderingManager()->getDebugDrawer().drawCube(actor.getPtr().getRefData().getPosition().asVec3(), osg::Vec3(50.,50.,50.), isDead ? MWRenderDebug::colorRed:MWRenderDebug::colorGreen); + + if (!isDead && (!godmode || !isPlayer) && actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isParalyzed()) ctrl.skipAnim(); diff --git a/apps/openmw/mwrender/debugdraw.cpp b/apps/openmw/mwrender/debugdraw.cpp new file mode 100644 index 0000000000..42eb2a0ce9 --- /dev/null +++ b/apps/openmw/mwrender/debugdraw.cpp @@ -0,0 +1,152 @@ +#include "debugdraw.h" +#include "debugdraw.hpp" +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + +namespace MWRenderDebug +{ + void CubeCustomDraw::drawImplementation(osg::RenderInfo& renderInfo) const + { + auto state = renderInfo.getState(); + osg::GLExtensions* ext = osg::GLExtensions::Get( state->getContextID(), true ); + + const osg::StateSet* stateSet = this->getStateSet(); + + auto program = static_cast( stateSet->getAttribute(osg::StateAttribute::PROGRAM)); + const osg::Program::PerContextProgram* pcp = program->getPCP(*state); + if (!pcp) + { + return; + } + std::lock_guard lock(mDrawCallMutex); + + osg::Uniform* uTrans = const_cast( stateSet->getUniform("trans")); + osg::Uniform* uCol = const_cast( stateSet->getUniform("passColor")); + + auto transLocation = pcp->getUniformLocation(uTrans->getNameID() ); + auto colLocation = pcp->getUniformLocation(uCol->getNameID() ); + + for (int i = 0; i < mCubesToDraw.size(); i++) + { + osg::Vec3f translation = mCubesToDraw[i].mPosition; + osg::Vec3f color = mCubesToDraw[i].mColor; + + if (uTrans) + ext->glUniform3f(transLocation, translation.x(), translation.y(), translation.z()); + if (uCol) + { + ext->glUniform3f(colLocation, color.x(), color.y(), color.z()); + } + this->mCubeGeometry->drawImplementation(renderInfo); + } + + + + } +} + +static void generateCube(osg::Geometry& geom, float dim) +{ + + osg::ref_ptr vertices = new osg::Vec3Array; + osg::ref_ptr normals = new osg::Vec3Array; + osg::ref_ptr indices = new osg::DrawElementsUShort(osg::DrawElementsUShort::TRIANGLES, 0); + + for (int i_face = 0; i_face < 6; i_face++) + { + osg::Vec3f normale(0., 0., 0.); + osg::Vec3f u(0., 0., 0.); + osg::Vec3f v(0., 0., 0.); + int axis = i_face / 2; + //if (axis != 2) + // continue; + int dir = i_face % 2 == 0 ? -1 : 1; + float float_dir = dir; + normale[axis] = float_dir; + u[(axis + 1) % 3] = 1.0; + v[(axis + 2) % 3] = 1.0; + + + for (int i_point = 0; i_point < 4; i_point++) + { + float iu = i_point % 2 == 1 ? float_dir : -float_dir;//This is to get the right triangle orientation when the normal changes* + float iv = i_point / 2 == 1 ? 1.0 : -1.0; + osg::Vec3f point = (u * iu) + (v * iv); + point = (point + normale); + point = point * (dim * 0.5f); + vertices->push_back(point); + normals->push_back(normale); + } + int start_vertex(i_face * 4); + int newFace1[] = { start_vertex,start_vertex + 1,start_vertex + 2 }; + for (int i = 0; i < 3; i++) + { + indices->push_back(newFace1[i]); + } + int newFace2[] = { start_vertex + 2,start_vertex + 1,start_vertex + 3 }; + for (int i = 0; i < 3; i++) + { + indices->push_back(newFace2[i]); + } + } + geom.setVertexAttribArray(0, vertices, osg::Array::BIND_PER_VERTEX); + geom.setVertexAttribArray(1, normals, osg::Array::BIND_PER_VERTEX); + geom.addPrimitiveSet(indices); + +} + + +MWRenderDebug::DebugDrawer::DebugDrawer(MWRender::RenderingManager& renderingManager,osg::ref_ptr parentNode) +{ + auto& shaderManager = renderingManager.getResourceSystem()->getSceneManager()->getShaderManager(); + auto vertexShader = shaderManager.getShader("debugDraw_vertex.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::Type::VERTEX); + auto fragmentShader = shaderManager.getShader("debugDraw_fragment.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::Type::FRAGMENT); + + auto program = shaderManager.getProgram(vertexShader, fragmentShader); + program->addBindAttribLocation("aPos", 0); + program->addBindAttribLocation("aNormal", 1); + mCubeGeometry = new osg::Geometry; + mcustomCubesDrawer = new CubeCustomDraw(mCubeGeometry, mCubesToDrawRead, mDrawCallMutex); + osg::StateSet* stateset = mcustomCubesDrawer->getOrCreateStateSet(); + + stateset->addUniform(new osg::Uniform("passColor", osg::Vec3f(1., 1., 1.))); + stateset->addUniform(new osg::Uniform("trans", osg::Vec3f(1., 1., 1.))); + + stateset->setAttributeAndModes(program, osg::StateAttribute::ON); + stateset->setMode(GL_DEPTH_TEST, GL_TRUE); + stateset->setMode(GL_CULL_FACE, GL_TRUE); + mCubeGeometry->setCullingActive(false); + mCubeGeometry->setSupportsDisplayList(false); + mCubeGeometry->setUseVertexBufferObjects(true); + + generateCube(*mCubeGeometry,50.); + + mCubeGeometry->setStateSet(stateset->clone(osg::CopyOp::DEEP_COPY_ALL)->asStateSet()); + + parentNode->addChild(mcustomCubesDrawer); +} + +void MWRenderDebug::DebugDrawer::update() +{ + { + std::lock_guard lock(mDrawCallMutex); + mCubesToDrawRead.swap(mCubesToDrawWrite); + } + mCubesToDrawWrite.clear(); + + +} + +void MWRenderDebug::DebugDrawer::drawCube(osg::Vec3f mPosition, osg::Vec3f mDims, osg::Vec3f mColor) +{ + mCubesToDrawWrite.push_back({ mDims, mColor, mPosition }); +} diff --git a/apps/openmw/mwrender/debugdraw.hpp b/apps/openmw/mwrender/debugdraw.hpp new file mode 100644 index 0000000000..0b79282751 --- /dev/null +++ b/apps/openmw/mwrender/debugdraw.hpp @@ -0,0 +1,66 @@ +#pragma once +#include +#include +#include +#include "renderingmanager.hpp" + +namespace osg +{ + class Group; + class Geometry; +} + +namespace MWRenderDebug +{ + static const osg::Vec3f colorWhite = osg::Vec3(1., 1., 1.); + static const osg::Vec3f colorRed = osg::Vec3(1., 0., 0.); + static const osg::Vec3f colorBlue = osg::Vec3(0., 0., 1.); + static const osg::Vec3f colorGreen = osg::Vec3(0., 1., 0.); + static const osg::Vec3f colorBlack = osg::Vec3(0., 0., 0.); + static const osg::Vec3f colorDarkGrey= osg::Vec3(0.25, 0.25, 0.25); + + + struct CubeDraw + { + osg::Vec3f mDims; + osg::Vec3f mColor; + + osg::Vec3f mPosition; + }; + + class CubeCustomDraw : public osg::Drawable + { + public: + CubeCustomDraw(osg::ref_ptr& CubeGeometry, std::vector& cubesToDraw,std::mutex& mutex) : mCubeGeometry( CubeGeometry), mCubesToDraw(cubesToDraw),mDrawCallMutex(mutex) {} + + std::vector& mCubesToDraw; + + std::mutex& mDrawCallMutex; + + osg::ref_ptr mCubeGeometry; + virtual osg::BoundingSphere computeBound() const + { + return osg::BoundingSphere(); + } + + virtual void drawImplementation(osg::RenderInfo&) const; + + }; + + struct DebugDrawer + { + DebugDrawer(MWRender::RenderingManager& manager,osg::ref_ptr parentNode); + + void update(); + + + + std::vector mCubesToDrawRead; + std::vector mCubesToDrawWrite; + std::mutex mDrawCallMutex; + + osg::ref_ptr mcustomCubesDrawer; + osg::ref_ptr mCubeGeometry; + void drawCube(osg::Vec3f mPosition, osg::Vec3f mDims = osg::Vec3(50.,50.,50.), osg::Vec3f mColor = osg::Vec3(1.,1.,1.)); + }; +} diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1385147c4c..6903a33723 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -82,6 +82,7 @@ #include "screenshotmanager.hpp" #include "groundcover.hpp" #include "postprocessor.hpp" +#include "debugdraw.hpp" namespace MWRender { @@ -489,6 +490,7 @@ namespace MWRender mViewer->getIncrementalCompileOperation()->setTargetFrameRate(Settings::Manager::getFloat("target framerate", "Cells")); } + mDebugDraw = std::make_unique(*this, mRootNode); mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); mEffectManager = std::make_unique(sceneRoot, mResourceSystem); @@ -904,7 +906,7 @@ namespace MWRender reportStats(); mResourceSystem->getSceneManager()->getShaderManager().update(*mViewer); - + mDebugDraw->update(); float rainIntensity = mSky->getPrecipitationAlpha(); mWater->setRainIntensity(rainIntensity); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 83dfd32287..6edad3d2d0 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -74,7 +74,10 @@ namespace MWWorld { class GroundcoverStore; } - +namespace MWRenderDebug +{ + struct DebugDrawer; +} namespace MWRender { class StateUpdater; @@ -234,6 +237,8 @@ namespace MWRender void exportSceneGraph(const MWWorld::Ptr& ptr, const std::string& filename, const std::string& format); + MWRenderDebug::DebugDrawer& getDebugDrawer() const { return *mDebugDraw; } + LandManager* getLandManager() const; bool toggleBorders(); @@ -306,6 +311,7 @@ namespace MWRender osg::ref_ptr mPlayerAnimation; osg::ref_ptr mPlayerNode; std::unique_ptr mCamera; + std::unique_ptr mDebugDraw; osg::ref_ptr mStateUpdater; osg::ref_ptr mSharedUniformStateUpdater; diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index d688f9e7d9..c171834e82 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -46,6 +46,8 @@ set(SHADER_FILES gui_fragment.glsl debug_vertex.glsl debug_fragment.glsl + debugDraw_vertex.glsl + debugDraw_fragment.glsl sky_vertex.glsl sky_fragment.glsl skypasses.glsl diff --git a/files/shaders/debugDraw_fragment.glsl b/files/shaders/debugDraw_fragment.glsl new file mode 100644 index 0000000000..d7e6a6c801 --- /dev/null +++ b/files/shaders/debugDraw_fragment.glsl @@ -0,0 +1,15 @@ +#version 330 compatibility + +in vec3 vertexColor; +in vec3 vertexNormal; + +out vec4 fragColor; + +void main() +{ + vec3 lightDir = normalize(vec3(-1.,-2.,-0.5)); + + float lightAttenuation = dot(-lightDir, vertexNormal) * 0.5 + 0.5; + + fragColor = vec4(vertexColor * lightAttenuation, 1.); +} diff --git a/files/shaders/debugDraw_vertex.glsl b/files/shaders/debugDraw_vertex.glsl new file mode 100644 index 0000000000..a248e7900a --- /dev/null +++ b/files/shaders/debugDraw_vertex.glsl @@ -0,0 +1,26 @@ +#version 330 compatibility + + +uniform mat4 projectionMatrix; + + +// vec4 mw_modelToClip(vec4 pos); +// vec4 mw_modelToView(vec4 pos); +// vec4 mw_viewToClip(vec4 pos); + +uniform vec3 passColor; +uniform vec3 trans; + +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; + +out vec3 vertexColor; +out vec3 vertexNormal; + +void main() +{ + gl_Position = projectionMatrix * gl_ModelViewMatrix * vec4(aPos + trans, 1.); + + vertexNormal = aNormal; + vertexColor = passColor.xyz; +}