Updated almost all stuff
This commit is contained in:
432
src/terrain/terrain.cpp
Normal file
432
src/terrain/terrain.cpp
Normal file
@@ -0,0 +1,432 @@
|
||||
#define ENDLESS_PAGING
|
||||
|
||||
// max range for a int16
|
||||
#define ENDLESS_PAGE_MIN_X (-0x7FFF)
|
||||
#define ENDLESS_PAGE_MIN_Y (-0x7FFF)
|
||||
#define ENDLESS_PAGE_MAX_X 0x7FFF
|
||||
#define ENDLESS_PAGE_MAX_Y 0x7FFF
|
||||
|
||||
#include <Ogre.h>
|
||||
#include <OgrePageManager.h>
|
||||
#include <OgreTerrainMaterialGeneratorA.h>
|
||||
#include <OgreTerrainQuadTreeNode.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreTerrainAutoUpdateLod.h>
|
||||
#include <OgreTerrainPagedWorldSection.h>
|
||||
#include "terrain.h"
|
||||
|
||||
#define ENDLESS_TERRAIN_FILE_PREFIX Ogre::String("EndlessWorldTerrain")
|
||||
#define ENDLESS_TERRAIN_FILE_SUFFIX Ogre::String("dat")
|
||||
#define TERRAIN_WORLD_SIZE 12000.0f
|
||||
#define TERRAIN_SIZE 513
|
||||
#define HOLD_LOD_DISTANCE 3000.0
|
||||
#define USE_PERLIN_DEFINER 0
|
||||
class FlatTerrainDefiner
|
||||
: public Ogre::TerrainPagedWorldSection::TerrainDefiner {
|
||||
public:
|
||||
void define(Ogre::TerrainGroup *terrainGroup, long x, long y) override
|
||||
{
|
||||
#if 0
|
||||
Ogre::Image img;
|
||||
img.load(
|
||||
"terrain.png",
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
int terrainSize = terrainGroup->getTerrainSize();
|
||||
float *heightMap = OGRE_ALLOC_T(float, terrainSize *terrainSize,
|
||||
MEMCATEGORY_GEOMETRY);
|
||||
|
||||
Ogre::Vector2 worldOffset(Ogre::Real(x * (terrainSize - 1)),
|
||||
Ogre::Real(y * (terrainSize - 1)));
|
||||
float mCycle = 1.0f;
|
||||
// worldOffset += mOriginPoint;
|
||||
|
||||
Ogre::Vector2 revisedValuePoint;
|
||||
for (int i = 0; i < terrainSize; i++)
|
||||
for (int j = 0; j < terrainSize; j++) {
|
||||
revisedValuePoint =
|
||||
(worldOffset + Ogre::Vector2(j, i)) /
|
||||
mCycle;
|
||||
heightMap[i * terrainSize + j] =
|
||||
img.getColourAt(j * img.getWidth() /
|
||||
terrainSize,
|
||||
i * img.getHeight() /
|
||||
terrainSize,
|
||||
0)
|
||||
.r *
|
||||
0.2f -
|
||||
0.1f;
|
||||
}
|
||||
terrainGroup->defineTerrain(x, y, heightMap);
|
||||
OGRE_FREE(heightMap, MEMCATEGORY_GEOMETRY);
|
||||
#endif
|
||||
terrainGroup->defineTerrain(x, y, -0.2f);
|
||||
}
|
||||
};
|
||||
|
||||
void TerrainSetup::setupTerrain(Ogre::Camera *camera, Ogre::Light *sun,
|
||||
Ogre::Bullet::DynamicsWorld *dynamicsWorld,
|
||||
Ogre::Bullet::DebugDrawer *dbgDraw)
|
||||
{
|
||||
mDynWorld.reset(dynamicsWorld);
|
||||
mDbgDraw.reset(dbgDraw);
|
||||
mScnMgr = camera->getSceneManager();
|
||||
mTerrainGlobals = OGRE_NEW Ogre::TerrainGlobalOptions();
|
||||
|
||||
#if 0
|
||||
mCameraMan->setTopSpeed(100);
|
||||
|
||||
setDragLook(true);
|
||||
|
||||
#endif
|
||||
#if 0
|
||||
#if OGRE_PLATFORM != OGRE_PLATFORM_ANDROID
|
||||
Ogre::MaterialManager::getSingleton().setDefaultTextureFiltering(
|
||||
Ogre::TFO_ANISOTROPIC);
|
||||
Ogre::MaterialManager::getSingleton().setDefaultAnisotropy(8);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// mScnMgr->setFog(Ogre::FOG_LINEAR, Ogre::ColourValue(0.7, 0.7, 0.8), 0,
|
||||
// 4000, 10000);
|
||||
|
||||
Ogre::LogManager::getSingleton().setMinLogLevel(Ogre::LML_TRIVIAL);
|
||||
|
||||
#if 0
|
||||
Ogre::Light *l = mScnMgr->createLight("tstLight");
|
||||
l->setType(Ogre::Light::LT_DIRECTIONAL);
|
||||
l->setDiffuseColour(ColourValue::White);
|
||||
l->setSpecularColour(ColourValue(0.4, 0.4, 0.4));
|
||||
|
||||
auto ln = mSceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
ln->setDirection(Vector3(0.55, -0.3, 0.75).normalisedCopy());
|
||||
ln->attachObject(l);
|
||||
|
||||
mScnMgr->setAmbientLight(Ogre::ColourValue(0.2, 0.2, 0.2));
|
||||
#endif
|
||||
|
||||
mTerrainGroup =
|
||||
OGRE_NEW Ogre::TerrainGroup(mScnMgr, Ogre::Terrain::ALIGN_X_Z,
|
||||
TERRAIN_SIZE, TERRAIN_WORLD_SIZE);
|
||||
mTerrainGroup->setFilenameConvention(ENDLESS_TERRAIN_FILE_PREFIX,
|
||||
ENDLESS_TERRAIN_FILE_SUFFIX);
|
||||
mTerrainGroup->setOrigin(mTerrainPos);
|
||||
// mTerrainGroup->setAutoUpdateLod(
|
||||
// Ogre::TerrainAutoUpdateLodFactory::getAutoUpdateLod(
|
||||
// Ogre::BY_DISTANCE));
|
||||
|
||||
configureTerrainDefaults(sun);
|
||||
|
||||
// Paging setup
|
||||
mPageManager = OGRE_NEW Ogre::PageManager();
|
||||
// Since we're not loading any pages from .page files, we need a way just
|
||||
// to say we've loaded them without them actually being loaded
|
||||
mPageManager->setPageProvider(&mDummyPageProvider);
|
||||
mPageManager->addCamera(camera);
|
||||
mPageManager->setDebugDisplayLevel(0);
|
||||
mTerrainPaging = OGRE_NEW Ogre::TerrainPaging(mPageManager);
|
||||
mPagedWorld = mPageManager->createWorld();
|
||||
mTerrainPagedWorldSection = mTerrainPaging->createWorldSection(
|
||||
mPagedWorld, mTerrainGroup, 300, 500, ENDLESS_PAGE_MIN_X,
|
||||
ENDLESS_PAGE_MIN_Y, ENDLESS_PAGE_MAX_X, ENDLESS_PAGE_MAX_Y);
|
||||
|
||||
#if USE_PERLIN_DEFINER == 1
|
||||
mPerlinNoiseTerrainGenerator = OGRE_NEW PerlinNoiseTerrainGenerator;
|
||||
mTerrainPagedWorldSection->setDefiner(mPerlinNoiseTerrainGenerator);
|
||||
#else
|
||||
mTerrainPagedWorldSection->setDefiner(OGRE_NEW FlatTerrainDefiner);
|
||||
#endif
|
||||
|
||||
mTerrainGroup->freeTemporaryResources();
|
||||
|
||||
// mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
|
||||
|
||||
// setup LOD info overlay
|
||||
// mLodInfoOverlay =
|
||||
// OverlayManager::getSingleton().create("LODInfoOverlay");
|
||||
|
||||
// mLodInfoOverlay->setZOrder(10);
|
||||
// mLodInfoOverlayContainer =
|
||||
// (OverlayContainer *)OverlayManager::getSingleton()
|
||||
// .createOverlayElement("Panel", "LODInfoOverlayPanel");
|
||||
// mLodInfoOverlayContainer->setDimensions(1.0, 1.0);
|
||||
// mLodInfoOverlayContainer->setPosition(0.0, 0.0);
|
||||
|
||||
// mLodInfoOverlay->add2D(mLodInfoOverlayContainer);
|
||||
// mLodInfoOverlay->show();
|
||||
|
||||
// setupControls();
|
||||
}
|
||||
#if 0
|
||||
void TerrainSetup::setupTerrain(Ogre::Camera *camera)
|
||||
{
|
||||
//! [global_opts]
|
||||
mTerrainGlobals = new Ogre::TerrainGlobalOptions();
|
||||
//! [global_opts]
|
||||
mScnMgr = camera->getSceneManager();
|
||||
#if 0
|
||||
mEditMarker = m_app->getSceneManager()->createEntity("editMarker",
|
||||
"sphere.mesh");
|
||||
#endif
|
||||
mEditNode = mScnMgr->getRootSceneNode()->createChildSceneNode(
|
||||
"TerrainEditNode");
|
||||
// mEditNode->attachObject(mEditMarker);
|
||||
mEditNode->setScale(0.05, 0.05, 0.05);
|
||||
|
||||
#if 0
|
||||
setupControls();
|
||||
#endif
|
||||
|
||||
// mCameraMan->setTopSpeed(50);
|
||||
|
||||
// setDragLook(true);
|
||||
|
||||
#if OGRE_PLATFORM != OGRE_PLATFORM_ANDROID
|
||||
Ogre::MaterialManager::getSingleton().setDefaultTextureFiltering(
|
||||
Ogre::TFO_ANISOTROPIC);
|
||||
Ogre::MaterialManager::getSingleton().setDefaultAnisotropy(8);
|
||||
#endif
|
||||
|
||||
Ogre::ColourValue fadeColour(0.7, 0.7, 0.8);
|
||||
//! [linear_fog]
|
||||
mScnMgr->setFog(Ogre::FOG_LINEAR, fadeColour, 0, 2000, 10000);
|
||||
//! [linear_fog]
|
||||
|
||||
Ogre::LogManager::getSingleton().setMinLogLevel(Ogre::LML_TRIVIAL);
|
||||
|
||||
//! [light]
|
||||
Ogre::Light *l = mScnMgr->createLight();
|
||||
l->setType(Ogre::Light::LT_DIRECTIONAL);
|
||||
l->setDiffuseColour(Ogre::ColourValue::White);
|
||||
l->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
|
||||
|
||||
Ogre::SceneNode *ln =
|
||||
mScnMgr->getRootSceneNode()->createChildSceneNode();
|
||||
ln->setDirection(Ogre::Vector3(0.55, -0.3, 0.75).normalisedCopy());
|
||||
ln->attachObject(l);
|
||||
//! [light]
|
||||
mScnMgr->setAmbientLight(Ogre::ColourValue(0.2, 0.2, 0.2));
|
||||
|
||||
//! [terrain_create]
|
||||
mTerrainGroup =
|
||||
new Ogre::TerrainGroup(mScnMgr, Ogre::Terrain::ALIGN_X_Z,
|
||||
TERRAIN_SIZE, TERRAIN_WORLD_SIZE);
|
||||
mTerrainGroup->setOrigin(mTerrainPos);
|
||||
//! [terrain_create]
|
||||
|
||||
#if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
|
||||
//! [terrain_save_config]
|
||||
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
|
||||
".", "FileSystem", mTerrainGroup->getResourceGroup(), false,
|
||||
true);
|
||||
mTerrainGroup->setFilenameConvention("TerrainSample", "bin");
|
||||
//! [terrain_save_config]
|
||||
#endif
|
||||
|
||||
configureTerrainDefaults(l);
|
||||
#ifdef PAGING
|
||||
// Paging setup
|
||||
mPageManager = OGRE_NEW Ogre::PageManager();
|
||||
// Since we're not loading any pages from .page files, we need a way just
|
||||
// to say we've loaded them without them actually being loaded
|
||||
mPageManager->setPageProvider(&mDummyPageProvider);
|
||||
mPageManager->addCamera(camera);
|
||||
mTerrainPaging = OGRE_NEW Ogre::TerrainPaging(mPageManager);
|
||||
Ogre::PagedWorld *world = mPageManager->createWorld();
|
||||
mTerrainPaging->createWorldSection(
|
||||
world, mTerrainGroup, 2000, 3000, TERRAIN_PAGE_MIN_X,
|
||||
TERRAIN_PAGE_MIN_Y, TERRAIN_PAGE_MAX_X, TERRAIN_PAGE_MAX_Y);
|
||||
#else
|
||||
//! [define_loop]
|
||||
for (long x = TERRAIN_PAGE_MIN_X; x <= TERRAIN_PAGE_MAX_X; ++x)
|
||||
for (long y = TERRAIN_PAGE_MIN_Y; y <= TERRAIN_PAGE_MAX_Y; ++y)
|
||||
defineTerrain(x, y);
|
||||
// sync load since we want everything in place when we start
|
||||
mTerrainGroup->loadAllTerrains(true);
|
||||
//! [define_loop]
|
||||
#endif
|
||||
|
||||
//! [init_blend]
|
||||
if (mTerrainsImported) {
|
||||
for (const auto &ti : mTerrainGroup->getTerrainSlots()) {
|
||||
initBlendMaps(ti.second->instance);
|
||||
}
|
||||
}
|
||||
|
||||
mTerrainGroup->freeTemporaryResources();
|
||||
//! [init_blend]
|
||||
|
||||
#if 0
|
||||
// create a few entities on the terrain
|
||||
Entity *e = mSceneMgr->createEntity("tudorhouse.mesh");
|
||||
Vector3 entPos(mTerrainPos.x + 2043, 0, mTerrainPos.z + 1715);
|
||||
Quaternion rot;
|
||||
entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) +
|
||||
65.5 + mTerrainPos.y;
|
||||
rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)),
|
||||
Vector3::UNIT_Y);
|
||||
SceneNode *sn =
|
||||
mSceneMgr->getRootSceneNode()->createChildSceneNode(
|
||||
entPos, rot);
|
||||
sn->setScale(Vector3(0.12, 0.12, 0.12));
|
||||
sn->attachObject(e);
|
||||
mHouseList.push_back(e);
|
||||
|
||||
e = mSceneMgr->createEntity("tudorhouse.mesh");
|
||||
entPos = Vector3(mTerrainPos.x + 1850, 0, mTerrainPos.z + 1478);
|
||||
entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) +
|
||||
65.5 + mTerrainPos.y;
|
||||
rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)),
|
||||
Vector3::UNIT_Y);
|
||||
sn = mSceneMgr->getRootSceneNode()->createChildSceneNode(entPos,
|
||||
rot);
|
||||
sn->setScale(Vector3(0.12, 0.12, 0.12));
|
||||
sn->attachObject(e);
|
||||
mHouseList.push_back(e);
|
||||
|
||||
e = mSceneMgr->createEntity("tudorhouse.mesh");
|
||||
entPos = Vector3(mTerrainPos.x + 1970, 0, mTerrainPos.z + 2180);
|
||||
entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) +
|
||||
65.5 + mTerrainPos.y;
|
||||
rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)),
|
||||
Vector3::UNIT_Y);
|
||||
sn = mSceneMgr->getRootSceneNode()->createChildSceneNode(entPos,
|
||||
rot);
|
||||
sn->setScale(Vector3(0.12, 0.12, 0.12));
|
||||
sn->attachObject(e);
|
||||
mHouseList.push_back(e);
|
||||
|
||||
//! [skybox]
|
||||
mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
|
||||
//! [skybox]
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void TerrainSetup::configureTerrainDefaults(Ogre::Light *l)
|
||||
{
|
||||
//! [configure_lod]
|
||||
mTerrainGlobals->setMaxPixelError(8);
|
||||
mTerrainGlobals->setCompositeMapDistance(3000);
|
||||
//! [configure_lod]
|
||||
|
||||
// mTerrainGlobals->setUseRayBoxDistanceCalculation(true);
|
||||
// mTerrainGlobals->getDefaultMaterialGenerator()->setDebugLevel(1);
|
||||
// mTerrainGlobals->setLightMapSize(256);
|
||||
|
||||
Ogre::TerrainMaterialGeneratorA::SM2Profile *matProfile =
|
||||
static_cast<Ogre::TerrainMaterialGeneratorA::SM2Profile *>(
|
||||
mTerrainGlobals->getDefaultMaterialGenerator()
|
||||
->getActiveProfile());
|
||||
|
||||
// Disable the lightmap for OpenGL ES 2.0. The minimum number of samplers allowed is 8(as opposed to 16 on
|
||||
// desktop). Otherwise we will run over the limit by just one. The minimum was raised to 16 in GL ES 3.0.
|
||||
if (Ogre::Root::getSingletonPtr()
|
||||
->getRenderSystem()
|
||||
->getCapabilities()
|
||||
->getNumTextureUnits() < 9) {
|
||||
matProfile->setLightmapEnabled(false);
|
||||
}
|
||||
|
||||
// Disable steep parallax by default
|
||||
matProfile->setLayerParallaxOcclusionMappingEnabled(false);
|
||||
|
||||
//! [composite_lighting]
|
||||
// Important to set these so that the terrain knows what to use for baked (non-realtime) data
|
||||
mTerrainGlobals->setLightMapDirection(l->getDerivedDirection());
|
||||
mTerrainGlobals->setCompositeMapAmbient(mScnMgr->getAmbientLight());
|
||||
mTerrainGlobals->setCompositeMapDiffuse(l->getDiffuseColour());
|
||||
//! [composite_lighting]
|
||||
// mTerrainGlobals->setCompositeMapAmbient(ColourValue::Red);
|
||||
|
||||
// Configure default import settings for if we use imported image
|
||||
//! [import_settings]
|
||||
Ogre::Terrain::ImportData &defaultimp =
|
||||
mTerrainGroup->getDefaultImportSettings();
|
||||
defaultimp.inputScale = 600;
|
||||
defaultimp.minBatchSize = 33;
|
||||
defaultimp.maxBatchSize = 65;
|
||||
//! [import_settings]
|
||||
|
||||
//! [tex_from_src]
|
||||
Ogre::Image combined;
|
||||
combined.loadTwoImagesAsRGBA("Ground23_col.jpg", "Ground23_spec.png",
|
||||
"General");
|
||||
Ogre::TextureManager::getSingleton().loadImage("Ground23_diffspec",
|
||||
"General", combined);
|
||||
//! [tex_from_src]
|
||||
|
||||
//! [textures]
|
||||
defaultimp.layerList.resize(3);
|
||||
defaultimp.layerList[0].worldSize = 200;
|
||||
defaultimp.layerList[0].textureNames.push_back("Ground37_diffspec.dds");
|
||||
defaultimp.layerList[0].textureNames.push_back(
|
||||
"Ground37_normheight.dds");
|
||||
defaultimp.layerList[1].worldSize = 200;
|
||||
defaultimp.layerList[1].textureNames.push_back(
|
||||
"Ground23_diffspec"); // loaded from memory
|
||||
defaultimp.layerList[1].textureNames.push_back(
|
||||
"Ground23_normheight.dds");
|
||||
defaultimp.layerList[2].worldSize = 400;
|
||||
defaultimp.layerList[2].textureNames.push_back("Rock20_diffspec.dds");
|
||||
defaultimp.layerList[2].textureNames.push_back("Rock20_normheight.dds");
|
||||
//! [textures]
|
||||
}
|
||||
#endif
|
||||
void TerrainSetup::configureTerrainDefaults(Ogre::Light *l)
|
||||
{
|
||||
// Configure global
|
||||
mTerrainGlobals->setMaxPixelError(1);
|
||||
// testing composite map
|
||||
mTerrainGlobals->setCompositeMapDistance(30);
|
||||
//mTerrainGlobals->setUseRayBoxDistanceCalculation(true);
|
||||
mTerrainGlobals->getDefaultMaterialGenerator()->setLightmapEnabled(
|
||||
false);
|
||||
|
||||
mTerrainGlobals->setCompositeMapAmbient(mScnMgr->getAmbientLight());
|
||||
mTerrainGlobals->setCompositeMapDiffuse(l->getDiffuseColour());
|
||||
mTerrainGlobals->setLightMapDirection(l->getDerivedDirection());
|
||||
|
||||
// Configure default import settings for if we use imported image
|
||||
Ogre::Terrain::ImportData &defaultimp =
|
||||
mTerrainGroup->getDefaultImportSettings();
|
||||
defaultimp.terrainSize = TERRAIN_SIZE;
|
||||
defaultimp.worldSize = TERRAIN_WORLD_SIZE;
|
||||
defaultimp.inputScale = 600;
|
||||
defaultimp.minBatchSize = 33;
|
||||
defaultimp.maxBatchSize = 65;
|
||||
#if 0
|
||||
// textures
|
||||
defaultimp.layerList.resize(1);
|
||||
defaultimp.layerList[0].worldSize = 200;
|
||||
defaultimp.layerList[0].textureNames.push_back("Ground37_diffspec.dds");
|
||||
defaultimp.layerList[0].textureNames.push_back(
|
||||
"Ground37_normheight.dds");
|
||||
#endif
|
||||
Ogre::Image combined;
|
||||
combined.loadTwoImagesAsRGBA("Ground23_col.jpg", "Ground23_spec.png",
|
||||
"General");
|
||||
Ogre::TextureManager::getSingleton().loadImage("Ground23_diffspec",
|
||||
"General", combined);
|
||||
//! [tex_from_src]
|
||||
|
||||
//! [textures]
|
||||
defaultimp.layerList.resize(1);
|
||||
#if 0
|
||||
defaultimp.layerList[0].worldSize = 200;
|
||||
defaultimp.layerList[0].textureNames.push_back("Ground37_diffspec.dds");
|
||||
defaultimp.layerList[0].textureNames.push_back(
|
||||
"Ground37_normheight.dds");
|
||||
#endif
|
||||
#if 0
|
||||
defaultimp.layerList[0].worldSize = 200;
|
||||
defaultimp.layerList[0].textureNames.push_back(
|
||||
"Ground23_diffspec"); // loaded from memory
|
||||
defaultimp.layerList[0].textureNames.push_back(
|
||||
"Ground23_normheight.dds");
|
||||
#endif
|
||||
defaultimp.layerList[0].worldSize = 60;
|
||||
defaultimp.layerList[0].textureNames.push_back("Ground23_diffspec");
|
||||
// defaultimp.layerList[0].textureNames.push_back("Rock20_normheight.png");
|
||||
//! [textures]
|
||||
}
|
||||
541
src/terrain/terrain.h
Normal file
541
src/terrain/terrain.h
Normal file
@@ -0,0 +1,541 @@
|
||||
|
||||
#ifndef X_TERRAIN_H_
|
||||
#define X_TARRAIN_H_
|
||||
#include <unordered_set>
|
||||
#include <iostream>
|
||||
#include <Ogre.h>
|
||||
#include <OgreBullet.h>
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
#include <OgreTerrain.h>
|
||||
#include <OgreTerrainGroup.h>
|
||||
#include <OgrePageManager.h>
|
||||
#include <OgreTerrainPagedWorldSection.h>
|
||||
#include <OgrePage.h>
|
||||
#include <OgreTerrainPaging.h>
|
||||
|
||||
class TerrainSetup {
|
||||
Ogre::SceneManager *mScnMgr;
|
||||
|
||||
std::unique_ptr<Ogre::Bullet::DynamicsWorld> mDynWorld;
|
||||
std::unique_ptr<Ogre::Bullet::DebugDrawer> mDbgDraw;
|
||||
Ogre::TerrainGlobalOptions *mTerrainGlobals;
|
||||
Ogre::TerrainGroup *mTerrainGroup;
|
||||
Ogre::TerrainPaging *mTerrainPaging;
|
||||
Ogre::PageManager *mPageManager;
|
||||
Ogre::PagedWorld *mPagedWorld;
|
||||
Ogre::TerrainPagedWorldSection *mTerrainPagedWorldSection;
|
||||
bool mLodStatus;
|
||||
|
||||
class DummyPageProvider : public Ogre::PageProvider {
|
||||
public:
|
||||
DummyPageProvider(btDynamicsWorld *world)
|
||||
: Ogre::PageProvider()
|
||||
, mBtWorld(world)
|
||||
{
|
||||
}
|
||||
std::unordered_map<Ogre::PageID, btRigidBody *> body;
|
||||
btDynamicsWorld *mBtWorld;
|
||||
bool prepareProceduralPage(Ogre::Page *page,
|
||||
Ogre::PagedWorldSection *section)
|
||||
{
|
||||
Ogre::TerrainGroup *pGroup =
|
||||
((Ogre::TerrainPagedWorldSection *)section)
|
||||
->getTerrainGroup();
|
||||
long x, y;
|
||||
pGroup->unpackIndex(page->getID(), &x, &y);
|
||||
Ogre::Terrain *pTerrain = pGroup->getTerrain(x, y);
|
||||
if (!pTerrain)
|
||||
return true;
|
||||
float *terrainHeightData = pTerrain->getHeightData();
|
||||
Ogre::Vector3 terrainPosition = pTerrain->getPosition();
|
||||
|
||||
float *pDataConvert = new float[pTerrain->getSize() *
|
||||
pTerrain->getSize()];
|
||||
for (int i = 0; i < pTerrain->getSize(); i++)
|
||||
memcpy(pDataConvert + pTerrain->getSize() *
|
||||
i, // source
|
||||
terrainHeightData +
|
||||
pTerrain->getSize() *
|
||||
(pTerrain->getSize() -
|
||||
i - 1), // target
|
||||
sizeof(float) *
|
||||
(pTerrain->getSize()) // size
|
||||
);
|
||||
|
||||
float metersBetweenVertices =
|
||||
pTerrain->getWorldSize() /
|
||||
(pTerrain->getSize() -
|
||||
1); //edit: fixed 0 -> 1 on 2010-08-13
|
||||
btVector3 localScaling(metersBetweenVertices, 1,
|
||||
metersBetweenVertices);
|
||||
|
||||
btHeightfieldTerrainShape *groundShape =
|
||||
new btHeightfieldTerrainShape(
|
||||
pTerrain->getSize(),
|
||||
pTerrain->getSize(), pDataConvert,
|
||||
1 /*ignore*/, pTerrain->getMinHeight(),
|
||||
pTerrain->getMaxHeight(), 1, PHY_FLOAT,
|
||||
true);
|
||||
|
||||
groundShape->setUseDiamondSubdivision(true);
|
||||
groundShape->setLocalScaling(localScaling);
|
||||
|
||||
btRigidBody *groundBody = new btRigidBody(
|
||||
0, new btDefaultMotionState(), groundShape);
|
||||
|
||||
groundBody->getWorldTransform().setOrigin(btVector3(
|
||||
terrainPosition.x,
|
||||
terrainPosition.y + (pTerrain->getMaxHeight() -
|
||||
pTerrain->getMinHeight()) /
|
||||
2,
|
||||
terrainPosition.z));
|
||||
|
||||
groundBody->getWorldTransform().setRotation(
|
||||
btQuaternion(Ogre::Quaternion::IDENTITY.x,
|
||||
Ogre::Quaternion::IDENTITY.y,
|
||||
Ogre::Quaternion::IDENTITY.z,
|
||||
Ogre::Quaternion::IDENTITY.w));
|
||||
|
||||
mBtWorld->addRigidBody(groundBody);
|
||||
body[page->getID()] = groundBody;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool loadProceduralPage(Ogre::Page *page,
|
||||
Ogre::PagedWorldSection *section)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool unloadProceduralPage(Ogre::Page *page,
|
||||
Ogre::PagedWorldSection *section)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool unprepareProceduralPage(Ogre::Page *page,
|
||||
Ogre::PagedWorldSection *section)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
DummyPageProvider mDummyPageProvider;
|
||||
|
||||
bool mFly;
|
||||
bool mParallaxOcclusion;
|
||||
Ogre::Real mFallVelocity;
|
||||
enum Mode {
|
||||
MODE_NORMAL = 0,
|
||||
MODE_EDIT_HEIGHT = 1,
|
||||
MODE_EDIT_BLEND = 2,
|
||||
MODE_COUNT = 3
|
||||
};
|
||||
enum ShadowMode {
|
||||
SHADOWS_NONE = 0,
|
||||
SHADOWS_COLOUR = 1,
|
||||
SHADOWS_DEPTH = 2,
|
||||
SHADOWS_COUNT = 3
|
||||
};
|
||||
Mode mMode;
|
||||
ShadowMode mShadowMode;
|
||||
Ogre::uint8 mLayerEdit;
|
||||
Ogre::Real mBrushSizeTerrainSpace;
|
||||
Ogre::SceneNode *mEditNode;
|
||||
Ogre::Entity *mEditMarker;
|
||||
Ogre::Real mHeightUpdateCountDown;
|
||||
Ogre::Real mHeightUpdateRate;
|
||||
Ogre::Vector3 mTerrainPos;
|
||||
/*
|
||||
OgreBites::SelectMenu *mEditMenu;
|
||||
OgreBites::SelectMenu *mShadowsMenu;
|
||||
OgreBites::CheckBox *mFlyBox;
|
||||
OgreBites::CheckBox *mParallaxOcclusionBox;
|
||||
OgreBites::Label *mInfoLabel = nullptr;
|
||||
*/
|
||||
bool mTerrainsImported;
|
||||
Ogre::ShadowCameraSetupPtr mPSSMSetup;
|
||||
|
||||
typedef std::list<Ogre::Entity *> EntityList;
|
||||
EntityList mHouseList;
|
||||
|
||||
public:
|
||||
TerrainSetup(btDynamicsWorld *world)
|
||||
: mScnMgr(nullptr)
|
||||
, mTerrainPos(Ogre::Vector3(0, 0, 0))
|
||||
, mDummyPageProvider(world)
|
||||
{
|
||||
}
|
||||
void defineTerrain(long x, long y, bool flat = false)
|
||||
{
|
||||
// if a file is available, use it
|
||||
// if not, generate file from import
|
||||
|
||||
// Usually in a real project you'll know whether the compact terrain data is
|
||||
// available or not; I'm doing it this way to save distribution size
|
||||
|
||||
if (flat) {
|
||||
mTerrainGroup->defineTerrain(x, y, 0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
//! [define]
|
||||
Ogre::String filename = mTerrainGroup->generateFilename(x, y);
|
||||
if (Ogre::ResourceGroupManager::getSingleton().resourceExists(
|
||||
mTerrainGroup->getResourceGroup(), filename)) {
|
||||
mTerrainGroup->defineTerrain(x, y, filename);
|
||||
} else {
|
||||
Ogre::Image img;
|
||||
getTerrainImage(x % 2 != 0, y % 2 != 0, img);
|
||||
mTerrainGroup->defineTerrain(x, y, &img);
|
||||
mTerrainsImported = true;
|
||||
}
|
||||
//! [define]
|
||||
}
|
||||
|
||||
void getTerrainImage(bool flipX, bool flipY, Ogre::Image &img)
|
||||
{
|
||||
//! [heightmap]
|
||||
img.load("terrain.png", mTerrainGroup->getResourceGroup());
|
||||
if (flipX)
|
||||
img.flipAroundY();
|
||||
if (flipY)
|
||||
img.flipAroundX();
|
||||
//! [heightmap]
|
||||
}
|
||||
|
||||
void initBlendMaps(Ogre::Terrain *terrain)
|
||||
{
|
||||
//! [blendmap]
|
||||
using namespace Ogre;
|
||||
TerrainLayerBlendMap *blendMap0 = terrain->getLayerBlendMap(1);
|
||||
TerrainLayerBlendMap *blendMap1 = terrain->getLayerBlendMap(2);
|
||||
float minHeight0 = 20;
|
||||
float fadeDist0 = 15;
|
||||
float minHeight1 = 70;
|
||||
float fadeDist1 = 15;
|
||||
float *pBlend0 = blendMap0->getBlendPointer();
|
||||
float *pBlend1 = blendMap1->getBlendPointer();
|
||||
for (uint16 y = 0; y < terrain->getLayerBlendMapSize(); ++y) {
|
||||
for (uint16 x = 0; x < terrain->getLayerBlendMapSize();
|
||||
++x) {
|
||||
Real tx, ty;
|
||||
|
||||
blendMap0->convertImageToTerrainSpace(x, y, &tx,
|
||||
&ty);
|
||||
float height =
|
||||
terrain->getHeightAtTerrainPosition(tx,
|
||||
ty);
|
||||
|
||||
*pBlend0++ = Math::saturate(
|
||||
(height - minHeight0) / fadeDist0);
|
||||
*pBlend1++ = Math::saturate(
|
||||
(height - minHeight1) / fadeDist1);
|
||||
}
|
||||
}
|
||||
blendMap0->dirty();
|
||||
blendMap1->dirty();
|
||||
blendMap0->update();
|
||||
blendMap1->update();
|
||||
//! [blendmap]
|
||||
// set up a colour map
|
||||
/*
|
||||
if (!terrain->getGlobalColourMapEnabled())
|
||||
{
|
||||
terrain->setGlobalColourMapEnabled(true);
|
||||
Image colourMap;
|
||||
colourMap.load("testcolourmap.jpg", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
terrain->getGlobalColourMap()->loadImage(colourMap);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void configureTerrainDefaults(Ogre::Light *l);
|
||||
#if 0
|
||||
void addTextureShadowDebugOverlay(Ogre::TrayLocation loc, size_t num)
|
||||
{
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
Ogre::TexturePtr shadowTex = m_app->getSceneManager()->getShadowTexture(i);
|
||||
addTextureDebugOverlay(loc, shadowTex, i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void changeShadows()
|
||||
{
|
||||
configureShadows(mShadowMode != SHADOWS_NONE,
|
||||
mShadowMode == SHADOWS_DEPTH);
|
||||
}
|
||||
|
||||
|
||||
void configureShadows(bool enabled, bool depthShadows)
|
||||
{
|
||||
auto matProfile =
|
||||
static_cast<Ogre::TerrainMaterialGeneratorA::SM2Profile *>(
|
||||
mTerrainGlobals->getDefaultMaterialGenerator()
|
||||
->getActiveProfile());
|
||||
matProfile->setReceiveDynamicShadowsEnabled(
|
||||
false); // force regen if colour/ depth shadows change
|
||||
matProfile->setReceiveDynamicShadowsEnabled(enabled);
|
||||
matProfile->setReceiveDynamicShadowsLowLod(
|
||||
SHADOWS_IN_LOW_LOD_MATERIAL);
|
||||
|
||||
Ogre::RTShader::RenderState *schemRenderState =
|
||||
mShaderGenerator->getRenderState(MSN_SHADERGEN);
|
||||
if (auto srs = schemRenderState->getSubRenderState(
|
||||
RTShader::SRS_SHADOW_MAPPING)) {
|
||||
schemRenderState->removeSubRenderState(srs);
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
// General scene setup
|
||||
mSceneMgr->setShadowTechnique(
|
||||
SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED);
|
||||
mSceneMgr->setShadowFarDistance(3000);
|
||||
|
||||
// 3 textures per directional light (PSSM)
|
||||
mSceneMgr->setShadowTextureCountPerLightType(
|
||||
Ogre::Light::LT_DIRECTIONAL, 3);
|
||||
|
||||
if (!mPSSMSetup) {
|
||||
// shadow camera setup
|
||||
PSSMShadowCameraSetup *pssmSetup =
|
||||
new PSSMShadowCameraSetup();
|
||||
pssmSetup->setSplitPadding(
|
||||
mCamera->getNearClipDistance() * 2);
|
||||
pssmSetup->calculateSplitPoints(
|
||||
3, mCamera->getNearClipDistance(),
|
||||
mSceneMgr->getShadowFarDistance());
|
||||
pssmSetup->setOptimalAdjustFactor(0, 2);
|
||||
pssmSetup->setOptimalAdjustFactor(1, 1);
|
||||
pssmSetup->setOptimalAdjustFactor(2, 0.5);
|
||||
|
||||
mPSSMSetup.reset(pssmSetup);
|
||||
}
|
||||
mSceneMgr->setShadowCameraSetup(mPSSMSetup);
|
||||
|
||||
if (depthShadows) {
|
||||
mSceneMgr->setShadowTextureCount(3);
|
||||
mSceneMgr->setShadowTextureConfig(0, 2048, 2048,
|
||||
PF_DEPTH16);
|
||||
mSceneMgr->setShadowTextureConfig(1, 1024, 1024,
|
||||
PF_DEPTH16);
|
||||
mSceneMgr->setShadowTextureConfig(2, 1024, 1024,
|
||||
PF_DEPTH16);
|
||||
mSceneMgr->setShadowTextureSelfShadow(true);
|
||||
mSceneMgr->setShadowCasterRenderBackFaces(true);
|
||||
|
||||
auto subRenderState =
|
||||
mShaderGenerator->createSubRenderState(
|
||||
RTShader::SRS_SHADOW_MAPPING);
|
||||
subRenderState->setParameter(
|
||||
"split_points",
|
||||
static_cast<PSSMShadowCameraSetup *>(
|
||||
mPSSMSetup.get())
|
||||
->getSplitPoints());
|
||||
schemRenderState->addTemplateSubRenderState(
|
||||
subRenderState);
|
||||
} else {
|
||||
mSceneMgr->setShadowTextureCount(3);
|
||||
mSceneMgr->setShadowTextureConfig(0, 2048, 2048,
|
||||
PF_X8B8G8R8);
|
||||
mSceneMgr->setShadowTextureConfig(1, 1024, 1024,
|
||||
PF_X8B8G8R8);
|
||||
mSceneMgr->setShadowTextureConfig(2, 1024, 1024,
|
||||
PF_X8B8G8R8);
|
||||
mSceneMgr->setShadowTextureSelfShadow(false);
|
||||
mSceneMgr->setShadowCasterRenderBackFaces(
|
||||
false);
|
||||
}
|
||||
|
||||
matProfile->setReceiveDynamicShadowsPSSM(
|
||||
static_cast<PSSMShadowCameraSetup *>(
|
||||
mPSSMSetup.get()));
|
||||
|
||||
// addTextureShadowDebugOverlay(TL_RIGHT, 3);
|
||||
} else {
|
||||
mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE);
|
||||
}
|
||||
|
||||
// Update parallax occlusion
|
||||
matProfile->setLayerParallaxOcclusionMappingEnabled(
|
||||
mParallaxOcclusion);
|
||||
|
||||
mShaderGenerator->invalidateScheme(MSN_SHADERGEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
||||
void setupControls()
|
||||
{
|
||||
mTrayMgr->showCursor();
|
||||
|
||||
// make room for the controls
|
||||
mTrayMgr->showLogo(TL_TOPRIGHT);
|
||||
mTrayMgr->showFrameStats(TL_TOPRIGHT);
|
||||
mTrayMgr->toggleAdvancedFrameStats();
|
||||
|
||||
//! [infolabel_create]
|
||||
mInfoLabel = mTrayMgr->createLabel(TL_TOP, "TInfo", "", 350);
|
||||
//! [infolabel_create]
|
||||
|
||||
mEditMenu = mTrayMgr->createLongSelectMenu(
|
||||
TL_BOTTOM, "EditMode", "Edit Mode", 370, 250, 3);
|
||||
mEditMenu->addItem("None");
|
||||
mEditMenu->addItem("Elevation");
|
||||
mEditMenu->addItem("Blend");
|
||||
mEditMenu->selectItem(0); // no edit mode
|
||||
|
||||
mFlyBox = mTrayMgr->createCheckBox(TL_BOTTOM, "Fly", "Fly");
|
||||
mFlyBox->setChecked(false, false);
|
||||
|
||||
mParallaxOcclusionBox =
|
||||
mTrayMgr->createCheckBox(TL_BOTTOM, "ParallaxOcclusion",
|
||||
"Parallax Occlusion Mapping");
|
||||
mParallaxOcclusionBox->setChecked(false, false);
|
||||
|
||||
mShadowsMenu = mTrayMgr->createLongSelectMenu(
|
||||
TL_BOTTOM, "Shadows", "Shadows", 370, 250, 3);
|
||||
mShadowsMenu->addItem("None");
|
||||
mShadowsMenu->addItem("Colour Shadows");
|
||||
mShadowsMenu->addItem("Depth Shadows");
|
||||
mShadowsMenu->selectItem(0); // no edit mode
|
||||
|
||||
// a friendly reminder
|
||||
StringVector names;
|
||||
names.push_back("Help");
|
||||
mTrayMgr->createParamsPanel(TL_TOPLEFT, "Help", 100, names)
|
||||
->setParamValue(0, "H/F1");
|
||||
}
|
||||
#endif
|
||||
|
||||
void setupTerrain(Ogre::Camera *camera, Ogre::Light *sun,
|
||||
Ogre::Bullet::DynamicsWorld *dynamicsWorld,
|
||||
Ogre::Bullet::DebugDrawer *dbgDraw);
|
||||
float get_height(const Ogre::Vector3 &pos)
|
||||
{
|
||||
return mTerrainGroup->getHeightAtWorldPosition(pos);
|
||||
}
|
||||
std::unordered_set<long> col_terrains;
|
||||
std::unordered_map<long, btRigidBody *> col_bodies;
|
||||
void create_colliders()
|
||||
{
|
||||
btDynamicsWorld *world = mDynWorld->getBtWorld();
|
||||
std::unordered_set<long> new_terrains;
|
||||
Ogre::TerrainGroup::TerrainSlotMap slots =
|
||||
mTerrainGroup->getTerrainSlots();
|
||||
auto slot_it = slots.begin();
|
||||
while (slot_it != slots.end()) {
|
||||
Ogre::Terrain *terrain = slot_it->second->instance;
|
||||
long x = slot_it->second->x;
|
||||
long y = slot_it->second->y;
|
||||
long key = y * 1024 + y;
|
||||
std::cout << "x: " << x << "\n";
|
||||
std::cout << "y: " << y << "\n";
|
||||
if (!terrain) {
|
||||
slot_it++;
|
||||
continue;
|
||||
}
|
||||
if (new_terrains.find(key) != new_terrains.end()) {
|
||||
slot_it++;
|
||||
continue;
|
||||
}
|
||||
if (col_terrains.find(key) != col_terrains.end()) {
|
||||
slot_it++;
|
||||
continue;
|
||||
}
|
||||
new_terrains.insert(key);
|
||||
col_terrains.insert(key);
|
||||
btRigidBody *body = createHeightfieldShape(
|
||||
terrain->getSize(), terrain->getHeightData(),
|
||||
terrain->getMinHeight(),
|
||||
terrain->getMaxHeight(), terrain->getPosition(),
|
||||
terrain->getWorldSize() /
|
||||
(terrain->getSize() - 1),
|
||||
world);
|
||||
OgreAssert(body, "Could not allocate body");
|
||||
col_bodies[key] = body;
|
||||
std::cout << "adding terrain body: " << terrain << " "
|
||||
<< col_bodies[key] << "\n";
|
||||
slot_it++;
|
||||
}
|
||||
auto col_it = col_terrains.begin();
|
||||
std::list<long> rm_bodies;
|
||||
while (col_it != col_terrains.end()) {
|
||||
std::cout
|
||||
<< "checking: terrain still exists: " << *col_it
|
||||
<< "\n";
|
||||
/* no terrain */
|
||||
if (new_terrains.find(*col_it) == new_terrains.end()) {
|
||||
std::cout << "was removed: "
|
||||
<< col_bodies[*col_it] << " "
|
||||
<< *col_it << "\n";
|
||||
rm_bodies.push_back(*col_it);
|
||||
/* free shapes and bodies */
|
||||
}
|
||||
col_it++;
|
||||
}
|
||||
#if 0
|
||||
while (!rm_bodies.empty()) {
|
||||
long key = rm_bodies.front();
|
||||
rm_bodies.pop_front();
|
||||
btRigidBody *body = col_bodies[key];
|
||||
OgreAssert(body, "No body :(");
|
||||
btCollisionShape *shape = body->getCollisionShape();
|
||||
col_terrains.erase(key);
|
||||
mDynWorld->getBtWorld()->removeRigidBody(body);
|
||||
delete shape;
|
||||
delete body;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
btRigidBody *createHeightfieldShape(int size, float *data,
|
||||
const Ogre::Real &minHeight,
|
||||
const Ogre::Real &maxHeight,
|
||||
const Ogre::Vector3 &position,
|
||||
const Ogre::Real &scale,
|
||||
btDynamicsWorld *world)
|
||||
{
|
||||
Ogre::SceneNode *terrainNode =
|
||||
mScnMgr->getRootSceneNode()->createChildSceneNode(
|
||||
position, Ogre::Quaternion::IDENTITY);
|
||||
// Convert height data in a format suitable for the physics engine
|
||||
float *terrainHeights = new float[size * size];
|
||||
assert(terrainHeights != 0);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
memcpy(terrainHeights + size * i,
|
||||
data + size * (size - i - 1),
|
||||
sizeof(float) * size);
|
||||
}
|
||||
|
||||
btScalar heightScale = 1.f;
|
||||
|
||||
btVector3 localScaling(scale, heightScale, scale);
|
||||
|
||||
btHeightfieldTerrainShape *terrainShape =
|
||||
new btHeightfieldTerrainShape(
|
||||
size, size, terrainHeights, 1 /*ignore*/,
|
||||
minHeight, maxHeight, 1, PHY_FLOAT, true);
|
||||
terrainShape->setUseDiamondSubdivision(true);
|
||||
terrainShape->setLocalScaling(localScaling);
|
||||
|
||||
//Create Rigid Body using 0 mass so it is static
|
||||
btRigidBody *body = new btRigidBody(
|
||||
0, new Ogre::Bullet::RigidBodyState(terrainNode),
|
||||
terrainShape);
|
||||
body->setFriction(0.8f);
|
||||
body->setHitFraction(0.8f);
|
||||
body->setRestitution(0.6f);
|
||||
body->getWorldTransform().setOrigin(btVector3(
|
||||
position.x, position.y + (maxHeight - minHeight) / 2,
|
||||
position.z));
|
||||
body->getWorldTransform().setRotation(
|
||||
Ogre::Bullet::convert(Ogre::Quaternion::IDENTITY));
|
||||
body->setCollisionFlags(body->getCollisionFlags() |
|
||||
btCollisionObject::CF_STATIC_OBJECT);
|
||||
|
||||
world->addRigidBody(body);
|
||||
return body;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
Reference in New Issue
Block a user