From 7634660c2cc84c6aa4780fed058206d8264b4c49 Mon Sep 17 00:00:00 2001 From: Mathias Gottschlag Date: Sat, 21 Feb 2009 23:05:21 +0100 Subject: [PATCH] First part of terrain scene node --- src/eal/eal.hh | 13 ++++- src/eal/engine.cc | 13 ++++- src/eal/engine.hh | 9 ++++ src/eal/environment.cc | 48 +++++++++++++++++ src/eal/terrainscenenode.cc | 126 ++++++++++++++++++++++++++++++++++++++------ src/eal/terrainscenenode.hh | 11 ++-- src/map.cc | 2 + src/map.hh | 2 + 8 files changed, 202 insertions(+), 22 deletions(-) diff --git a/src/eal/eal.hh b/src/eal/eal.hh index 9029a30..77c1582 100644 --- a/src/eal/eal.hh +++ b/src/eal/eal.hh @@ -37,6 +37,8 @@ namespace irr namespace eal { + class TerrainSceneNode; + /* * This is the class representing the Graphical User Interface */ @@ -138,12 +140,14 @@ namespace eal * @param colormap Array with 24bit packed color data. * @param size Size of the square */ - void setColorMap (unsigned char *colormap, int size); + void + setColorMap (unsigned char *colormap, int size); /** * Sets the color map of the terrain using a texture file. * @param path Path to the color texture */ - void setColorMap (std::string path); + void + setColorMap (std::string path); /* * Planned methods: @@ -151,6 +155,11 @@ namespace eal * Change properties of light source * Change color of terrain on certain position */ + private: + void + createTerrain(); + + TerrainSceneNode *terrain; }; } diff --git a/src/eal/engine.cc b/src/eal/engine.cc index c5b965e..6d17d02 100644 --- a/src/eal/engine.cc +++ b/src/eal/engine.cc @@ -56,8 +56,10 @@ namespace eal irr::scene::ISceneManager* smgr = irrlicht->getSceneManager(); //irr::scene::ICameraSceneNode *camera = smgr->addCameraSceneNode (); - irr::scene::ICameraSceneNode *camera = smgr->addCameraSceneNodeFPS(); - this->camera.create (camera); + irr::scene::ICameraSceneNode *camera = smgr->addCameraSceneNodeFPS(); + camera->setPosition(irr::core::vector3df(0, 30, 0)); + camera->setTarget(irr::core::vector3df(0, 0, 0)); + this->camera.create(camera); return true; } @@ -99,4 +101,11 @@ namespace eal driver->endScene (); return true; } + + irr::scene::ISceneManager* + Engine::getSceneManager() + { + if (!irrlicht) return 0; + return irrlicht->getSceneManager(); + } } diff --git a/src/eal/engine.hh b/src/eal/engine.hh index 1e5d4e5..d21ea4e 100644 --- a/src/eal/engine.hh +++ b/src/eal/engine.hh @@ -27,6 +27,10 @@ namespace irr { class IrrlichtDevice; + namespace scene + { + class ISceneManager; + } } namespace eal @@ -77,6 +81,11 @@ namespace eal */ bool update (); + /** + * Returns a pointer to the Irrlicht scene manager + */ + irr::scene::ISceneManager *getSceneManager(); + private: Engine (); diff --git a/src/eal/environment.cc b/src/eal/environment.cc index a12b48c..1fe683f 100644 --- a/src/eal/environment.cc +++ b/src/eal/environment.cc @@ -1,16 +1,58 @@ +/* + * Interface for the scene functions (terrain, lighting) + * + * Copyright (C) 2009 Mathias Gottschlag + * + * This file is part of OpenStranded + * + * OpenStranded is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * OpenStranded is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenStranded. If not, see . + */ #include "eal/eal.hh" +#include "eal/terrainscenenode.hh" +#include "eal/engine.hh" + +#include +using namespace irr; namespace eal { Environment::Environment () { + terrain = 0; } Environment::~Environment () { } void + Environment::setSize(int size) + { + if (!terrain) + createTerrain(); + } + + int + Environment::getSize() + { + if (!terrain) + createTerrain(); + + return 0; + } + + void Environment::setHeight (const Vector2 &pos, double height) { } @@ -36,4 +78,10 @@ namespace eal void Environment::setColorMap (std::string path) { } + + void Environment::createTerrain() + { + scene::ISceneManager *smgr = Engine::get()->getSceneManager(); + terrain = new TerrainSceneNode(smgr->getRootSceneNode(), smgr, 0, 1024, 1024); + } } \ No newline at end of file diff --git a/src/eal/terrainscenenode.cc b/src/eal/terrainscenenode.cc index 98c6f1e..0143e7b 100644 --- a/src/eal/terrainscenenode.cc +++ b/src/eal/terrainscenenode.cc @@ -20,6 +20,7 @@ */ #include "eal/terrainscenenode.hh" +#include "eal/engine.hh" using namespace irr; @@ -38,11 +39,12 @@ namespace eal { heightdata[i] = 0; } - for (int i = 0; i < 64; i++) + for (int i = 0; i < TILE_COUNT; i++) { mesh[i] = 0; vertices[i] = 0; dirty[i] = true; + level[i] = 0; } // TODO: Create index buffers for (int i = 0; i < 5; i++) @@ -50,26 +52,34 @@ namespace eal lod[i] = 0; } - // Maximum detail - lod[0] = new scene::CIndexBuffer(video::EIT_16BIT); - lod[0]->reallocate(128 * 128 * 6);// + 128 * 4 * 6); - // Surface - for (int z = 0; z < 128; z++) + int size = TILE_SIZE; + for (int i = 0; i < 5; i++) { - for (int x = 0; x < 128; x++) + int factor = TILE_SIZE / size; + // Create buffer + lod[i] = new scene::CIndexBuffer(video::EIT_16BIT); + lod[i]->reallocate(size * size * 6);// + 128 * 4 * 6); + // Surface + for (int z = 0; z < size; z++) { - lod[0]->setValue((z * 128 + x) * 6 + 0, (z + 0) * 129 + x + 0); - lod[0]->setValue((z * 128 + x) * 6 + 1, (z + 0) * 129 + x + 1); - lod[0]->setValue((z * 128 + x) * 6 + 2, (z + 1) * 129 + x + 0); - lod[0]->setValue((z * 128 + x) * 6 + 3, (z + 0) * 129 + x + 1); - lod[0]->setValue((z * 128 + x) * 6 + 4, (z + 1) * 129 + x + 1); - lod[0]->setValue((z * 128 + x) * 6 + 5, (z + 1) * 129 + x + 0); + for (int x = 0; x < size; x++) + { + lod[i]->setValue((z * size + x) * 6 + 0, (z * factor + 0) * (TILE_SIZE + 1) + x * factor + 0); + lod[i]->setValue((z * size + x) * 6 + 2, (z * factor + 0) * (TILE_SIZE + 1) + x * factor + factor); + lod[i]->setValue((z * size + x) * 6 + 1, (z * factor + factor) * (TILE_SIZE + 1) + x * factor + 0); + lod[i]->setValue((z * size + x) * 6 + 3, (z * factor + 0) * (TILE_SIZE + 1) + x * factor + factor); + lod[i]->setValue((z * size + x) * 6 + 5, (z * factor + factor) * (TILE_SIZE + 1) + x * factor + factor); + lod[i]->setValue((z * size + x) * 6 + 4, (z * factor + factor) * (TILE_SIZE + 1) + x * factor + 0); + } } + lod[i]->set_used(size * size * 6); + lod[i]->setHardwareMappingHint(scene::EHM_DYNAMIC); + // TODO: Skirts + size /= 2; } - // TODO: Skirts // TODO: Culling - box = core::aabbox3d(-10000.0f, -10000.0f, -10000.0f, -10000.0f, -10000.0f, -10000.0f); + box = core::aabbox3d(-10000.0f, -10000.0f, -10000.0f, 10000.0f, 10000.0f, 10000.0f); // Create initial meshes rebuildMeshes(); @@ -83,11 +93,67 @@ namespace eal if (IsVisible) SceneManager->registerNodeForRendering(this); + scene::ICameraSceneNode *camera = SceneManager->getActiveCamera(); + ISceneNode::OnRegisterSceneNode(); + // Update LOD + for (int z = 0; z < EDGE_TILES; z++) + { + for (int x = 0; x < EDGE_TILES; x++) + { + if (!mesh[z * EDGE_TILES + x]) continue; + core::vector3df patchposition(x * TILE_SIZE + TILE_SIZE / 2, 0, z * TILE_SIZE + TILE_SIZE / 2); + float distance = (patchposition - camera->getPosition()).getLength(); + int newlevel = 0; + if (distance > 4 * TILE_SIZE) + { + newlevel = 4; + } + else if (distance > 3 * TILE_SIZE) + { + newlevel = 3; + } + else if (distance > 2 * TILE_SIZE) + { + newlevel = 2; + } + else if (distance > TILE_SIZE) + { + newlevel = 1; + } + else + { + newlevel = 0; + } + if (level[z * EDGE_TILES + x] != newlevel) + { + level[z * EDGE_TILES + x] = newlevel; + mesh[z * EDGE_TILES + x]->setIndexBuffer(lod[newlevel]); + mesh[z * EDGE_TILES + x]->setDirty(scene::EBT_VERTEX_AND_INDEX); + } + } + } } void TerrainSceneNode::render() { + if (!IsVisible || !SceneManager->getActiveCamera()) + return; + + scene::ISceneManager *smgr = Engine::get()->getSceneManager(); + + video::IVideoDriver* driver = smgr->getVideoDriver(); + + // Draw mesh + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + driver->setMaterial(material); + for (int i = 0; i < TILE_COUNT; i++) + { + if (mesh[i]) + { + driver->drawMeshBuffer(mesh[i]); + } + } } const core::aabbox3d& TerrainSceneNode::getBoundingBox() const { @@ -104,5 +170,35 @@ namespace eal void TerrainSceneNode::rebuildMeshes() { + int alignedx = ((sizex - 1) + TILE_SIZE) & ~(TILE_SIZE - 1); + int alignedz = ((sizez - 1) + TILE_SIZE) & ~(TILE_SIZE - 1); + + // Create flat vertex buffers + for (int z = 0; z < alignedz / TILE_SIZE; z++) + { + for (int x = 0; x < alignedx / TILE_SIZE; x++) + { + // Create and fill vertex buffer + vertices[x + z * EDGE_TILES] = new scene::CVertexBuffer(video::EVT_STANDARD); + scene::IVertexBuffer *buffer = vertices[x + z * EDGE_TILES]; + buffer->reallocate((TILE_SIZE + 1) * (TILE_SIZE + 1)); // + skirts + for (int z2 = 0; z2 < TILE_SIZE + 1; z2++) + { + for (int x2 = 0; x2 < TILE_SIZE + 1; x2++) + { + buffer->pointer()[z2 * (TILE_SIZE + 1) + x2].Pos = core::vector3df(x * TILE_SIZE + x2, 0, z * TILE_SIZE + z2); + buffer->pointer()[z2 * (TILE_SIZE + 1) + x2].Normal = core::vector3df(0, 1, 0); + //buffer->pointer()[z2 * (TILE_SIZE + 1) + x2].Color = video::SColor(255, 255, 255, 255); + } + } + buffer->set_used((TILE_SIZE + 1) * (TILE_SIZE + 1)); + buffer->setHardwareMappingHint(scene::EHM_STATIC); + // Create mesh + mesh[x + z * EDGE_TILES] = new scene::CDynamicMeshBuffer(video::EVT_STANDARD, video::EIT_16BIT); + mesh[x + z * EDGE_TILES]->setVertexBuffer(buffer); + mesh[x + z * EDGE_TILES]->setIndexBuffer(lod[0]); + mesh[x + z * EDGE_TILES]->setDirty(); + } + } } } diff --git a/src/eal/terrainscenenode.hh b/src/eal/terrainscenenode.hh index 7bb6fdd..68505d3 100644 --- a/src/eal/terrainscenenode.hh +++ b/src/eal/terrainscenenode.hh @@ -26,6 +26,10 @@ namespace eal { + static const int EDGE_TILES = 16; + static const int TILE_SIZE = 64; + static const int TILE_COUNT = 256; + class TerrainSceneNode : public irr::scene::ISceneNode { public: @@ -47,9 +51,10 @@ namespace eal int sizex; int sizez; float *heightdata; - irr::scene::IDynamicMeshBuffer *mesh[64]; - irr::scene::IVertexBuffer *vertices[64]; - bool dirty[64]; + irr::scene::IDynamicMeshBuffer *mesh[TILE_COUNT]; + irr::scene::IVertexBuffer *vertices[TILE_COUNT]; + bool dirty[TILE_COUNT]; + int level[TILE_COUNT]; irr::scene::IIndexBuffer *lod[5]; irr::video::SMaterial material; diff --git a/src/map.cc b/src/map.cc index 84bbcb5..8568bc1 100644 --- a/src/map.cc +++ b/src/map.cc @@ -21,6 +21,7 @@ #include "map.hh" #include "bbfile.hh" +#include "eal/eal.hh" #include @@ -96,6 +97,7 @@ Map::load (std::string path) mapfile.readData(grassmap, colormapsize * colormapsize); // Create terrain + environment.setSize(heightmapsize); // TODO // Entities diff --git a/src/map.hh b/src/map.hh index 3fe6946..44207a4 100644 --- a/src/map.hh +++ b/src/map.hh @@ -23,6 +23,7 @@ #define STRANDED_MAP_HH #include "entity.hh" +#include "eal/eal.hh" #include #include @@ -30,6 +31,7 @@ class Map { protected: std::list entities; + eal::Environment environment; public: Map (); ~Map (); -- 2.11.4.GIT