From c72b1cf35e22ddbd6221348c15063d9478727644 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Sat, 5 Jul 2025 06:19:03 +0300 Subject: [PATCH] Added separate game file --- CMakeLists.txt | 4 + Game.cpp | 901 ++++++++++++++++++++++++++++++++++++++++++++++++ water/water.cpp | 54 +-- 3 files changed, 911 insertions(+), 48 deletions(-) create mode 100644 Game.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1dc6d8a..9e6ed34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,10 @@ add_executable(Editor Editor.cpp ${TERRAIN_SRC} ${WATER_SRC}) target_link_libraries(Editor OgreBites OgreBullet OgrePaging OgreTerrain OgreMeshLodGenerator ${OgreProcedural_LIBRARIES} ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY}) target_include_directories(Editor PUBLIC OgreBites OgrePaging OgreBullet OgreTerrain OgreMeshLodGenerator ${OgreProcedural_INCLUDE_DIRS}) add_dependencies(Editor stage_files import_buildings) +add_executable(Game Game.cpp ${TERRAIN_SRC} ${WATER_SRC}) +target_link_libraries(Game OgreBites OgreBullet OgrePaging OgreTerrain OgreMeshLodGenerator ${OgreProcedural_LIBRARIES} ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY}) +target_include_directories(Game PUBLIC OgreBites OgrePaging OgreBullet OgreTerrain OgreMeshLodGenerator ${OgreProcedural_INCLUDE_DIRS}) +add_dependencies(Game stage_files import_buildings) add_executable(Procedural Procedural.cpp ${TERRAIN_SRC}) target_link_libraries(Procedural OgreBites OgreBullet OgrePaging OgreTerrain OgreProcedural::OgreProcedural ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY}) diff --git a/Game.cpp b/Game.cpp new file mode 100644 index 0000000..e60ca4a --- /dev/null +++ b/Game.cpp @@ -0,0 +1,901 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/terrain/terrain.h" +#include "water/water.h" +class App; +class SkyRenderer : public Ogre::SceneManager::Listener { +protected: + Ogre::SceneManager *mSceneManager; + virtual void _updateRenderQueue(Ogre::RenderQueue *queue) = 0; + +public: + enum BoxPlane { + BP_FRONT = 0, + BP_BACK = 1, + BP_LEFT = 2, + BP_RIGHT = 3, + BP_UP = 4, + BP_DOWN = 5 + }; + + SkyRenderer(Ogre::SceneManager *owner) + : mSceneManager(owner) + , mSceneNode(0) + , mEnabled(false) + { + } + + virtual ~SkyRenderer() + { + setEnabled(false); + if (mSceneNode) + mSceneManager->destroySceneNode(mSceneNode); + } + + Ogre::SceneNode *mSceneNode; + bool mEnabled; + + void setEnabled(bool enable) + { + if (enable == mEnabled) + return; + mEnabled = enable; + enable ? mSceneManager->addListener(this) : + mSceneManager->removeListener(this); + } + void + postFindVisibleObjects(Ogre::SceneManager *source, + Ogre::SceneManager::IlluminationRenderStage irs, + Ogre::Viewport *vp) override + { + // Queue skies, if viewport seems it + if (!vp->getSkiesEnabled() || + irs == Ogre::SceneManager::IRS_RENDER_TO_TEXTURE) + return; + + if (!mEnabled || !mSceneNode) + return; + + // Update nodes + // Translate the box by the camera position (constant distance) + mSceneNode->setPosition(vp->getCamera()->getDerivedPosition()); + _updateRenderQueue(source->getRenderQueue()); + } +}; +class SkyBoxRenderer : public SkyRenderer { + std::unique_ptr mSkyBoxObj; + + Ogre::Quaternion mSkyBoxOrientation; + void _updateRenderQueue(Ogre::RenderQueue *queue) override + { + if (mSkyBoxObj->isVisible()) { + mSkyBoxObj->_updateRenderQueue(queue); + } + } + +public: + SkyBoxRenderer(Ogre::SceneManager *owner) + : SkyRenderer(owner) + { + } + Ogre::SceneManager::SkyBoxGenParameters mSkyBoxGenParameters; + void create(const Ogre::String &materialName, Ogre::Real distance, + uint8_t renderQueue, const Ogre::Quaternion &orientation, + const Ogre::String &groupName) + { + Ogre::MaterialPtr m = + Ogre::MaterialManager::getSingleton().getByName( + materialName, groupName); + OgreAssert(m, "Sky box material '" + materialName + + "' not found."); + // Ensure loaded + m->load(); + + bool valid = m->getBestTechnique() && + m->getBestTechnique()->getNumPasses(); +#if 0 + if (valid) { + Pass *pass = m->getBestTechnique()->getPass(0); + valid = valid && pass->getNumTextureUnitStates() && + pass->getTextureUnitState(0)->getTextureType() == + TEX_TYPE_CUBE_MAP; + } + + if (!valid) { + LogManager::getSingleton().logWarning( + "skybox material " + materialName + + " is not supported, defaulting"); + m = MaterialManager::getSingleton().getDefaultSettings(); + } +#endif + OgreAssert(valid, "Bad material" + materialName); + + // Create node + mSceneNode = mSceneManager->createSceneNode(); + + // Create object + mSkyBoxObj = std::make_unique("SkyBox"); + mSkyBoxObj->setCastShadows(false); + mSceneNode->attachObject(mSkyBoxObj.get()); + + mSkyBoxObj->setRenderQueueGroup(renderQueue); + mSkyBoxObj->begin(materialName, + Ogre::RenderOperation::OT_TRIANGLE_STRIP, + groupName); + + // rendering cube, only using 14 vertices + const Ogre::Vector3 cube_strip[14] = { + { -1.f, 1.f, 1.f }, // Front-top-left + { 1.f, 1.f, 1.f }, // Front-top-right + { -1.f, -1.f, 1.f }, // Front-bottom-left + { 1.f, -1.f, 1.f }, // Front-bottom-right + { 1.f, -1.f, -1.f }, // Back-bottom-right + { 1.f, 1.f, 1.f }, // Front-top-right + { 1.f, 1.f, -1.f }, // Back-top-right + { -1.f, 1.f, 1.f }, // Front-top-left + { -1.f, 1.f, -1.f }, // Back-top-left + { -1.f, -1.f, 1.f }, // Front-bottom-left + { -1.f, -1.f, -1.f }, // Back-bottom-left + { 1.f, -1.f, -1.f }, // Back-bottom-right + { -1.f, 1.f, -1.f }, // Back-top-left + { 1.f, 1.f, -1.f } // Back-top-right + }; + + for (const auto &vtx : cube_strip) { + mSkyBoxObj->position(orientation * (vtx * distance)); + // Note UVs mirrored front/back + mSkyBoxObj->textureCoord(vtx.normalisedCopy() * + Ogre::Vector3(1, 1, -1)); + } + + mSkyBoxObj->end(); + mSkyBoxGenParameters.skyBoxDistance = distance; + } +}; + +class EditUI : public Ogre::RenderTargetListener { + App *m_app; + Ogre::SceneManager *mScnMgr; + Ogre::ImGuiOverlay *mGuiOverlay; + OgreBites::ImGuiInputListener *mGuiListener; + void + preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt) override + { + preview(evt); + } + +public: + EditUI(App *app) + : Ogre::RenderTargetListener() + , m_app(app) + { + } + + void position_editor(Ogre::SceneNode *node) + { + Ogre::Vector3 position = node->getPosition(); + float v[3] = { position.x, position.y, position.z }; + ImGui::InputFloat3("position", v); + position.x = v[0]; + position.y = v[1]; + position.z = v[2]; + node->setPosition(position); + } + void orientation_editor(Ogre::SceneNode *node) + { + Ogre::Quaternion q = node->getOrientation(); + float yaw = Ogre::Radian(q.getYaw()).valueDegrees(); + float pitch = Ogre::Radian(q.getPitch()).valueDegrees(); + float roll = Ogre::Radian(q.getRoll()).valueDegrees(); + bool m1 = ImGui::InputFloat("yaw", &yaw); + bool m2 = ImGui::InputFloat("pitch", &pitch); + bool m3 = ImGui::InputFloat("roll", &roll); + if (m1 || m2 || m3) { + Ogre::Quaternion q1(Ogre::Radian(Ogre::Degree(yaw)), + Ogre::Vector3::UNIT_Y); + Ogre::Quaternion q2(Ogre::Degree(pitch), + Ogre::Vector3::UNIT_X); + Ogre::Quaternion q3(Ogre::Degree(roll), + Ogre::Vector3::UNIT_Z); + node->setOrientation(q1 * q2 * q3); + } + } + void attachments_editor(Ogre::SceneNode *node) + { + const Ogre::SceneNode::ObjectMap &pmap = + node->getAttachedObjects(); + int i; + for (i = 0; i < pmap.size(); i++) { + const Ogre::MovableObject *mobj = pmap[i]; + const Ogre::String &pname = mobj->getName(); + ImGui::Text("Name: %s", pname.c_str()); + } + } + std::vector glb_names; + void init_glb_list() + { + int i; + + const std::vector &groups = + Ogre::ResourceGroupManager::getSingleton() + .getResourceGroups(); + for (i = 0; i < groups.size(); i++) { + std::vector names = + *Ogre::ResourceGroupManager::getSingleton() + .findResourceNames(groups[i], "*.glb"); + glb_names.insert(glb_names.end(), names.begin(), + names.end()); + } + } + void buildings_editor(); + void buttons_panel(); + void preview(const Ogre::RenderTargetViewportEvent &evt); + float panel_width; + void initGui(); +}; +class App : public OgreBites::ApplicationContext { + std::unique_ptr mDynWorld; + std::unique_ptr mDbgDraw; + Ogre::SceneNode *mCameraNode, *mCameraPivot, *mCameraGoal; + Ogre::Camera *mCamera; + Ogre::Real mPivotPitch; + Ogre::SceneManager *mScnMgr; + OgreBites::InputListenerChain mInput; + Ogre::Viewport *mViewport; + EditUI m_edit_ui; + TerrainSetup m_terrain; + Ogre::Light *mSun; + SkyBoxRenderer *sky; + Water m_water; + // OgreBites::TrayManager *mTrayMgr; + class KeyboardListener : public OgreBites::InputListener, + public Ogre::FrameListener { + App *mApp; + + public: + Ogre::Vector3 motion; + bool gui_active; + Ogre::Timer fps_timer; + bool fast; + KeyboardListener(App *app) + : OgreBites::InputListener() + , Ogre::FrameListener() + , mApp(app) + , gui_active(false) + , fast(false) + { + } + bool keyPressed(const OgreBites::KeyboardEvent &evt) override + { + if (gui_active) + return false; + if (evt.keysym.sym == OgreBites::SDLK_ESCAPE) { + gui_active = true; + // std::cout << "Escape!\n"; + // Ogre::Root::getSingleton().queueEndRendering(); + mApp->setWindowGrab(false); + } + if (evt.keysym.sym == OgreBites::SDLK_SPACE) + mApp->dump_water(); + if (evt.keysym.sym == 'w') + motion.z = -1.0f; + if (evt.keysym.sym == 's') + motion.z = 1.0f; + if (evt.keysym.sym == 'a') + motion.x = -1.0f; + if (evt.keysym.sym == 'd') + motion.x = 1.0f; + if (evt.keysym.sym == OgreBites::SDLK_LSHIFT) + fast = true; + // std::cout << "motion: " << motion << "\n"; + return true; + } + bool keyReleased(const OgreBites::KeyboardEvent &evt) override + { + if (gui_active) + return false; + if (evt.keysym.sym == 'w' && motion.z < 0.0f) + motion.z = 0.0f; + if (evt.keysym.sym == 's' && motion.z > 0.0f) + motion.z = 0.0f; + if (evt.keysym.sym == 'a' && motion.x < 0.0f) + motion.x = 0.0f; + if (evt.keysym.sym == 'd' && motion.x > 0.0f) + motion.x = 0.0f; + if (evt.keysym.sym == OgreBites::SDLK_LSHIFT) + fast = false; + return true; + } + bool mouseMoved(const OgreBites::MouseMotionEvent &evt) + { + if (gui_active) + return false; + // update camera goal based on mouse movement + mApp->updateCameraGoal(-0.18f * evt.xrel, + -0.12f * evt.yrel, 0); + return true; + } + bool mouseWheelRolled(const OgreBites::MouseWheelEvent &evt) + { + if (gui_active) + return false; + // update camera goal based on mouse movement + mApp->updateCameraGoal(0, 0, -0.15f * evt.y); + return true; + } + void update(float delta) + { + return; + // float fade = (1.0f - delta) * 0.98f; + // motion *= fade; + } + void frameRendered(const Ogre::FrameEvent &evt) override + { + if (fps_timer.getMilliseconds() > 1000.0f) { + std::cout << "FPS: " + << mApp->getRenderWindow() + ->getStatistics() + .lastFPS + << " "; + std::cout << "Draw calls: " + << mApp->getRenderWindow() + ->getStatistics() + .batchCount + << " "; + fps_timer.reset(); + std::cout << "Drops: " + << mApp->getRenderWindow() + ->getStatistics() + .vBlankMissCount + << "\n"; + fps_timer.reset(); + } + update(evt.timeSinceLastFrame); + if (!gui_active) { + mApp->updateMotion(evt.timeSinceLastFrame); + mApp->updateCamera(evt.timeSinceLastFrame); + mApp->updateSun(evt.timeSinceLastFrame); + mApp->updateTerrain(evt.timeSinceLastFrame); + mApp->updateWater(evt.timeSinceLastFrame); + } + } + }; + KeyboardListener mKbd; + +public: + App() + : OgreBites::ApplicationContext("GuiTest") + , mKbd(this) + , m_edit_ui(this) + , mDynWorld(new Ogre::Bullet::DynamicsWorld( + Ogre::Vector3(0, -9.8, 0))) + , m_terrain(mDynWorld->getBtWorld()) + { + } + virtual ~App() + { + } + void setup() + { + OgreBites::ApplicationContext::setup(); + Ogre::Root *root = getRoot(); + Ogre::SceneManager *scnMgr = root->createSceneManager(); + mScnMgr = scnMgr; + Ogre::OverlaySystem *pOverlaySystem = getOverlaySystem(); + mScnMgr->addRenderQueueListener(pOverlaySystem); + // mTrayMgr = new OgreBites::TrayManager("AppTrays", + // getRenderWindow()); + mDbgDraw.reset(new Ogre::Bullet::DebugDrawer( + mScnMgr->getRootSceneNode(), mDynWorld->getBtWorld())); + } + void locateResources() override + { + OgreBites::ApplicationContext::locateResources(); + } + void loadResources() override + { + } + void dump_water() + { + m_water.dump_textures(); + } + + void initCamera() + { + mCameraNode = mScnMgr->getRootSceneNode()->createChildSceneNode( + "CameraNode"); + mCameraNode->setPosition(0, 2, 3); + mCameraNode->lookAt(Ogre::Vector3(0, 1, -1), + Ogre::Node::TS_PARENT); + + // create the camera + mCamera = mScnMgr->createCamera("fps_camera"); + mCamera->setNearClipDistance(0.05f); + mCamera->setAutoAspectRatio(true); + mCameraNode->attachObject(mCamera); + + // and tell it to render into the main window + mViewport = getRenderWindow()->addViewport(mCamera); + mCameraPivot = + mScnMgr->getRootSceneNode()->createChildSceneNode( + "FPSCameraPivot"); + mCameraGoal = mCameraPivot->createChildSceneNode( + "FPSCameraGoal", Ogre::Vector3(0, 2, 3)); + mCameraNode->setPosition(mCameraPivot->getPosition() + + mCameraGoal->getPosition()); + mCameraPivot->setFixedYawAxis(true); + mCameraGoal->setFixedYawAxis(true); + mCameraNode->setFixedYawAxis(true); + // our model is quite small, so reduce the clipping planes + mCamera->setNearClipDistance(0.1f); + mCamera->setFarClipDistance(800); + mPivotPitch = 0; + } + void configure() + { + std::cout << "Startup" << "\n"; + initApp(); + std::cout << "Set up RTSS" << "\n"; + Ogre::Root *root = getRoot(); + Ogre::SceneManager *scnMgr = getSceneManager(); + + // register our scene with the RTSS + Ogre::RTShader::ShaderGenerator *shadergen = + Ogre::RTShader::ShaderGenerator::getSingletonPtr(); + shadergen->addSceneManager(scnMgr); + setWindowGrab(true); + std::cout << "Init camera" << "\n"; + initCamera(); + std::cout << "Set up water" << "\n"; + m_water.createWater(getRenderWindow(), mCamera); + std::cout << "Set up cursor" << "\n"; + Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); + // OgreBites::ApplicationContext::loadResources(); + setupCursor(); + std::cout << "Create content" << "\n"; + createContent(); + std::cout << "Setup terrain" << "\n"; + setupTerrain(); + m_water.init(); + } + void setupCursor() + { + + // mKeyDirection = Ogre::Vector3::ZERO; + // mVerticalVelocity = 0; + Ogre::ManualObject *mobj = + mScnMgr->createManualObject("cursorGen"); + +#if 0 + Ogre::MaterialPtr mat = + Ogre::static_pointer_cast( + Ogre::MaterialManager::getSingleton() + .createOrRetrieve("Debug/Red2", + "General") + .first); + mat->removeAllTechniques(); + Ogre::Technique *tech = mat->createTechnique(); + tech->setDiffuse(Ogre::ColourValue(1, 0, 0, 1)); + tech->setName("Debug/S"); + tech->setDepthCheckEnabled(false); + tech->setLightingEnabled(false); + mobj->begin(mat, Ogre::RenderOperation::OT_LINE_LIST); +#endif + mobj->begin("Debug/Red", Ogre::RenderOperation::OT_LINE_LIST); + mobj->position(0, 0, 0); + mobj->colour(Ogre::ColourValue(1, 0, 0)); + mobj->position(0, 2, 0); + mobj->colour(Ogre::ColourValue(1, 0, 0)); + mobj->position(-1, 1, 0); + mobj->colour(Ogre::ColourValue(1, 0, 0)); + mobj->position(1, 1, 0); + mobj->colour(Ogre::ColourValue(1, 0, 0)); + mobj->index(0); + mobj->index(1); + mobj->index(2); + mobj->index(3); + mobj->end(); + mCameraPivot->attachObject(mobj); + } + Ogre::SceneManager *getSceneManager() + { + return mScnMgr; + } + void updateMotion(float delta) + { + if (delta == 0.0f) + return; + Ogre::Vector3 move(mCameraNode->getOrientation().zAxis() * + mKbd.motion.z); + move += Ogre::Vector3(mCameraNode->getOrientation().xAxis() * + mKbd.motion.x); + move.y = 0.0f; + float speed = 15.0f; + if (mKbd.fast) + speed = 40.0f; + Ogre::Vector3 opos = mCameraPivot->getPosition(); + Ogre::Vector3 pos = + mCameraPivot->getPosition() + move * speed * delta; + float y = m_terrain.get_height(pos); + if (y < 0) + y = 0.0f; + pos.y = y; + + mCameraPivot->translate(pos - opos); + // mKbd.motion = Ogre::Vector3(0, 0, 0); + // if (move.squaredLength() > 0) + // std::cout << move << "\n"; + } + void updateCamera(Ogre::Real delta) + { + if (delta == 0.0f) + return; + // place the camera pivot roughly at the character's shoulder + // mCameraPivot->setPosition(mBodyNode->getPosition() + + // Ogre::Vector3::UNIT_Y * CAM_HEIGHT); + // move the camera smoothly to the goal + Ogre::Vector3 goalOffset = mCameraGoal->_getDerivedPosition() - + mCameraNode->getPosition(); + float l = goalOffset.squaredLength(); + Ogre::Vector3 v = goalOffset * 10.0 * delta; + if (v.squaredLength() > l * 0.5f - delta) + v = goalOffset * delta; + mCameraNode->translate(v); + // mCameraNode->translate(goalOffset); + // always look at the pivot + mCameraNode->lookAt(mCameraPivot->_getDerivedPosition(), + Ogre::Node::TS_PARENT); + } + void updateCameraGoal(Ogre::Real deltaYaw, Ogre::Real deltaPitch, + Ogre::Real deltaZoom) + { + mCameraPivot->yaw(Ogre::Degree(deltaYaw), + Ogre::Node::TS_PARENT); + if (!(mPivotPitch + deltaPitch > 25 && deltaPitch > 0) && + !(mPivotPitch + deltaPitch < -60 && deltaPitch < 0)) { + mCameraPivot->pitch(Ogre::Degree(deltaPitch), + Ogre::Node::TS_LOCAL); + mPivotPitch += deltaPitch; + } + Ogre::Real dist = mCameraGoal->_getDerivedPosition().distance( + mCameraPivot->_getDerivedPosition()); + Ogre::Real distChange = deltaZoom * dist * 0.5f; + if (distChange > 0 && dist + distChange > 30) + distChange *= 0.3f; + if (distChange < 0 && dist + distChange < 5) + distChange *= 0.2f; + + // bound the zoom + if (!(dist + distChange < 3 && distChange < 0) && + !(dist + distChange > 60 && distChange > 0)) + mCameraGoal->translate(0, 0, distChange, + Ogre::Node::TS_LOCAL); + Ogre::Vector3 mh = mCameraGoal->_getDerivedPosition(); + float h = m_terrain.get_height(mh); + if (h + 10 > mh.y) + mCameraGoal->translate(0, 10.0f * deltaZoom, distChange, + Ogre::Node::TS_LOCAL); + } + Ogre::SceneNode *mSunGoal; + Ogre::SceneNode *mSunNode; + Ogre::SceneNode *mSunTarget; + Ogre::Timer mSunUpdate; + void createSun() + { + Ogre::Light *light = mScnMgr->createLight("Sun"); + mSunNode = mScnMgr->getRootSceneNode()->createChildSceneNode( + "SunPivot"); + mSunGoal = mScnMgr->getRootSceneNode()->createChildSceneNode( + "SunGoal"); + mSunTarget = mSunGoal->createChildSceneNode( + "SunGoalTarget", + Ogre::Vector3(100.0f, -400.0f, -400.0f), + Ogre::Quaternion::IDENTITY); + // mSunNode->setAutoTracking(true, sun_target); + // lightNode->setPosition(0, 10, 15); + mSunNode->attachObject(light); + light->setType(Ogre::Light::LT_DIRECTIONAL); + light->setDiffuseColour(Ogre::ColourValue::White); + light->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4)); + mSunNode->setDirection(Ogre::Vector3(100.0f, -400.0f, -400.f)); + mSun = light; + } + void updateSun(float delta) + { + static const float sun_speed = 1.0f; + float uangle = M_PI * 2.0f / 24.0f / 60.0f; + mSunNode->pitch(Ogre::Radian(uangle) * sun_speed * delta); + if (mSunUpdate.getMilliseconds() > 1000) { + Ogre::TerrainGlobalOptions::getSingleton() + .setCompositeMapAmbient( + mScnMgr->getAmbientLight()); + Ogre::TerrainGlobalOptions::getSingleton() + .setCompositeMapDiffuse( + mSun->getDiffuseColour()); + Ogre::TerrainGlobalOptions::getSingleton() + .setLightMapDirection( + mSun->getDerivedDirection()); + std::cout << "sun pitch: " + << mSunNode->getOrientation().getPitch() + << "\n"; + mSunUpdate.reset(); + } + if (mSunNode->getOrientation().getPitch().valueRadians() > 0) + mScnMgr->setAmbientLight( + Ogre::ColourValue(0.1f, 0.1f, 0.4f, 1.0f)); + else + mScnMgr->setAmbientLight( + Ogre::ColourValue(0.2f, 0.2f, 0.2f, 1.0f)); + } + Ogre::Timer mTerrainUpd; + void updateTerrain(float delta) + { + // mDbgDraw->update(); +#if 0 + if (mTerrainUpd.getMilliseconds() > 1000) { + m_terrain.create_colliders(); + mTerrainUpd.reset(); + } +#endif + } + void updateWater(float delta) + { + m_water.updateWater(delta); + } + void createContent() + { + int i; + m_edit_ui.init_glb_list(); + m_edit_ui.initGui(); + createSun(); + mInput = OgreBites::InputListenerChain( + { getImGuiInputListener(), &mKbd }); + addInputListener(&mInput); + getRoot()->addFrameListener(&mKbd); + // mTrayMgr->showCursor(); + + // OgreBites::TrayManager *mTrayMgr = new OgreBites::TrayManager( + // "InterfaceName", getRenderWindow()); + // mScnMgr->setSkyBox(true, "Skybox/Dynamic", 490); + // /* mCamera->getCameraToViewportRay(left, top); */ +#if 1 + sky = new SkyBoxRenderer(getSceneManager()); + bool drawFirst = true; + uint8_t renderQueue = drawFirst ? + Ogre::RENDER_QUEUE_SKIES_EARLY : + Ogre::RENDER_QUEUE_SKIES_LATE; + sky->create("Skybox/Dynamic", 450, renderQueue, + Ogre::Quaternion::IDENTITY, + Ogre::ResourceGroupManager:: + AUTODETECT_RESOURCE_GROUP_NAME); + sky->setEnabled(true); + + Ogre::MaterialPtr m = + Ogre::MaterialManager::getSingleton().getByName( + "Skybox/Dynamic", "General"); + OgreAssert(m, "Sky box material not found."); + m->load(); +#endif + } + void create_entity_node(const Ogre::String &name, int key) + { + Ogre::Entity *ent = mScnMgr->createEntity(name); + Ogre::SceneNode *pnode = + mScnMgr->getRootSceneNode()->createChildSceneNode( + "ent:" + name + + Ogre::StringConverter::toString(key), + mCameraPivot->getPosition(), + mCameraPivot->getOrientation()); + pnode->attachObject(ent); + Ogre::Quaternion q = pnode->getOrientation(); + Ogre::Radian yaw = q.getYaw(); + Ogre::Quaternion nq(yaw, Ogre::Vector3(0, 1, 0)); + pnode->setOrientation(nq); + mKbd.gui_active = false; + setWindowGrab(true); + } + bool get_gui_active() + { + return mKbd.gui_active; + } + void set_gui_active(bool active) + { + mKbd.gui_active = active; + } + Ogre::Camera *getCamera() + { + return mCamera; + } + void setupTerrain() + { + m_terrain.setupTerrain(mCamera, mSun, mDynWorld.get(), + mDbgDraw.get()); + } +}; + +void EditUI::buildings_editor() +{ + int i; + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5 - 20; + ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, window_height), + ImGuiCond_Always); + ImGui::Begin("Droppings..."); + for (i = 0; i < glb_names.size(); i++) { + Ogre::String id_button = "Create entity: " + glb_names[i] + + "##ent:" + glb_names[i]; + if (ImGui::Button(id_button.c_str())) { + m_app->create_entity_node(glb_names[i], i); + } + } + ImGui::End(); +} +void EditUI::buttons_panel() +{ + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5f - 20; + ImGui::SetNextWindowPos(ImVec2(0, size.y * 0.5f + 20), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, window_height), + ImGuiCond_Always); + ImGui::Begin("Dumb and Stupid"); + if (!m_app->get_gui_active()) + m_app->setWindowGrab(true); + if (ImGui::Button("Shitty Quit button")) + Ogre::Root::getSingleton().queueEndRendering(); + if (ImGui::Button("Chick-chick")) { + m_app->set_gui_active(false); + m_app->setWindowGrab(true); + } + ImGui::Text("We do stoopid..."); + ImGui::End(); +} +void EditUI::preview(const Ogre::RenderTargetViewportEvent &evt) +{ + int i; + Ogre::ImGuiOverlay::NewFrame(); + if (m_app->get_gui_active()) { + buttons_panel(); + buildings_editor(); + ImVec2 size = ImGui::GetMainViewport()->Size; + float window_width = size.x * 0.2f; + if (window_width > panel_width) + window_width = panel_width; + float window_height = size.y * 0.5f - 20; + ImGui::SetNextWindowPos(ImVec2(size.x - window_width, + size.y * 0.5f + 20), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(window_width, window_height), + ImGuiCond_Always); + // ImGui::Begin("Dumb and Stupid", &mKbd.gui_active); + ImGui::Begin("Panel..."); + std::deque tree_input_queue, + tree_output_queue; + std::vector tree_list; + tree_input_queue.push_back(mScnMgr->getRootSceneNode()); + tree_input_queue.push_back(nullptr); + std::set visited; + while (true) { + int new_nodes_count = 0; + while (!tree_input_queue.empty()) { + int child; + Ogre::SceneNode *item = + tree_input_queue.front(); + tree_input_queue.pop_front(); + if (item && visited.find(item) == + visited.end()) { // new node + new_nodes_count++; + tree_output_queue.push_back(item); + visited.insert(item); + const Ogre::Node::ChildNodeMap + &children = item->getChildren(); + for (child = 0; child < children.size(); + child++) { + tree_output_queue.push_back( + static_cast( + children[child])); + tree_output_queue.push_back( + nullptr); + } + } else + tree_output_queue.push_back(item); + } + if (new_nodes_count == 0) + break; + tree_input_queue = tree_output_queue; + tree_output_queue.clear(); + } + tree_list.insert(tree_list.begin(), tree_output_queue.begin(), + tree_output_queue.end()); + int count = 0; + int depth = 0; + std::vector check_depth; + int max_depth = 0; + check_depth.push_back(0); + for (count = 0; count < tree_list.size(); count++) { + int t; + + Ogre::SceneNode *node = tree_list[count]; + if (node && max_depth >= depth) { + Ogre::String name = node->getName(); + if (name.length() == 0) { + name = "Node #" + + Ogre::StringConverter::toString( + count); + } + if (ImGui::TreeNode(name.c_str())) { + check_depth.push_back(max_depth); + max_depth++; + ImGui::Text( + "%s", + (name + "##caption").c_str()); + position_editor(node); + ImGui::Separator(); + orientation_editor(node); + ImGui::Separator(); + ImGui::Text("Attachments"); + attachments_editor(node); + } + } else if (!node && max_depth >= depth) { + max_depth = check_depth.back(); + check_depth.pop_back(); + ImGui::TreePop(); + } + if (tree_list[count]) + depth++; + else + depth--; + } + ImGui::Spacing(); + ImGui::End(); + } +} +void EditUI::initGui() +{ + mScnMgr = m_app->getSceneManager(); + float vpScale = m_app->getDisplayDPI() / 96 * + (float)m_app->getRenderWindow()->getWidth() / 1280; + panel_width = + 380.0f * (float)m_app->getRenderWindow()->getWidth() / 1280; + Ogre::OverlayManager::getSingleton().setPixelRatio(vpScale); + mGuiOverlay = m_app->initialiseImGui(); + // float vpScale = + // Ogre::OverlayManager::getSingleton().getPixelRatio(); + ImGui::GetIO().FontGlobalScale = std::round(vpScale); + mGuiOverlay->setZOrder(300); + mGuiOverlay->show(); + m_app->getRenderWindow()->addListener(this); +} +int main() +{ + App ctx; + ctx.configure(); + // ctx.runRenderingSettingsDialog(); + // get a pointer to the already created root + // register for input events + // KeyHandler keyHandler; + // ctx.addInputListener(&keyHandler); + + ctx.getRoot()->startRendering(); + ctx.setWindowGrab(false); + ctx.closeApp(); + return 0; +} diff --git a/water/water.cpp b/water/water.cpp index 05f795b..bc71f07 100644 --- a/water/water.cpp +++ b/water/water.cpp @@ -5,6 +5,11 @@ #include #include "water.h" +/* TODO: use blender glb model for water shape. + * TODO: Finish main shader + * TODO: Add caustics + * TODO: Add below shader */ + static const uint32_t SUBMERGED_MASK = 0x0F0; static const uint32_t SURFACE_MASK = 0x00F; static const uint32_t WATER_MASK = 0xF00; @@ -30,10 +35,6 @@ Water::~Water() mScnMgr->destroySceneNode(mWaterNode); if(mReflectionTexture) mReflectionTexture->removeAllListeners(); -#if 0 - if(mRefractionTexture) - mRefractionTexture->removeAllListeners(); -#endif } void Water::create_cameras() @@ -55,8 +56,6 @@ void Water::create_cameras() reflectionViewport->setAutoUpdated(false); mViewports.push_back(reflectionViewport); - // mRefractionTexture->addListener(this); -#if 1 mRefractionCamera = mScnMgr->createCamera("RefractionCamera"); mCamera->getParentSceneNode()->attachObject(mRefractionCamera); mRefractionCamera->setAspectRatio(mCamera->getAspectRatio()); @@ -71,7 +70,6 @@ void Water::create_cameras() refractionViewport->setSkiesEnabled(false); refractionViewport->setAutoUpdated(false); mViewports.push_back(refractionViewport); -#endif } void Water::create_textures() @@ -86,17 +84,6 @@ void Water::create_textures() mReflectionTexture = reflectionTexture->getBuffer()->getRenderTarget(); mReflectionTexture->setAutoUpdated(false); -#if 0 - Ogre::TexturePtr refractionTexture = Ogre::TextureManager::getSingleton().createManual( - "RefractionTexture", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, 512, 512, - 0, - Ogre::PF_R8G8B8A8, - Ogre::TU_RENDERTARGET); - - mRefractionTexture = refractionTexture->getBuffer()->getRenderTarget(); -#endif } void Water::init() @@ -127,21 +114,9 @@ void Water::init() auto mat = Ogre::MaterialManager::getSingleton().getByName("Water/Above"); mat->load(); mat->setReceiveShadows(false); -#if 0 - mat->getTechnique(0) - ->getPass(0) - ->getTextureUnitState(0) - ->setProjectiveTexturing(true, mCamera); -#endif auto mat2 = Ogre::MaterialManager::getSingleton().getByName("Water/Below"); mat2->load(); mat2->setReceiveShadows(false); -#if 0 - mat2->getTechnique(0) - ->getPass(0) - ->getTextureUnitState(0) - ->setProjectiveTexturing(true, mCamera); -#endif for (i = 0; i < (int)sizeof(positions) / (int)sizeof(positions[0]); i++) { @@ -158,9 +133,6 @@ void Water::init() water_lod1->setVisibilityFlags(WATER_MASK); mWaterMeshes.push_back(water_lod1); } - /* - Ogre::Root::getSingleton().addFrameListener(this); - */ } void Water::createWater(Ogre::RenderWindow * window, Ogre::Camera *camera) @@ -202,27 +174,14 @@ void Water::updateWater(float delta) mWaterMeshes[i]->setVisible(false); for (i = 0; i < mViewports.size(); i++) mViewports[i]->update(); -// mReflectionTexture->update(); for (i = 0; i < mWaterMeshes.size(); i++) mWaterMeshes[i]->setVisible(true); } -/* -bool Water::frameEnded(const Ogre::FrameEvent &evt) -{ - updateWater(evt.timeSinceLastFrame); - return true; -} -bool Water::frameRenderingQueued(const Ogre::FrameEvent &evt) -{ - return FrameListener::frameRenderingQueued(evt); -} -*/ - void Water::preRenderTargetUpdate(const Ogre::RenderTargetEvent &evt) { int i; - if (evt.source == mReflectionTexture /*|| evt.source == mRefractionTexture */) { + if (evt.source == mReflectionTexture) { for (i = 0; i < mWaterMeshes.size(); i++) mWaterMeshes[i]->setVisible(false); if (evt.source == mReflectionTexture) @@ -254,5 +213,4 @@ void Water::add_surface_entity(Ogre::Entity *ent) void Water::dump_textures() { mReflectionTexture->writeContentsToFile("Reflection.png"); - // mRefractionTexture->writeContentsToFile("Refraction.png"); }