//[NOTE] In addition to some Ogre setup, this function configures PagedGeometry in the scene. void World::load() { //-------------------------------------- LOAD TERRAIN -------------------------------------- //Setup the fog up to 500 units away sceneMgr->setFog(FOG_LINEAR, viewport->getBackgroundColour(), 0, 100, 700); //Load the terrain sceneMgr->setWorldGeometry("terrain.cfg"); //Start off with the camera at the center of the terrain camera->setPosition(700, 100, 700); //-------------------------------------- LOAD GRASS -------------------------------------- //Create and configure a new PagedGeometry instance for grass grass = new PagedGeometry(camera, 50); grass->addDetailLevel<GrassPage>(150); //Create a GrassLoader object grassLoader = new GrassLoader(grass); grass->setPageLoader(grassLoader); //Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance //Supply a height function to GrassLoader so it can calculate grass Y values HeightFunction::initialize(sceneMgr); grassLoader->setHeightFunction(&HeightFunction::getTerrainHeight); //Add some grass to the scene with GrassLoader::addLayer() GrassLayer *l = grassLoader->addLayer("grass"); //Configure the grass layer properties (size, density, animation properties, fade settings, etc.) l->setMinimumSize(2.0f, 2.0f); l->setMaximumSize(2.5f, 2.5f); l->setAnimationEnabled(true); //Enable animations l->setSwayDistribution(10.0f); //Sway fairly unsynchronized l->setSwayLength(0.5f); //Sway back and forth 0.5 units in length l->setSwaySpeed(0.5f); //Sway 1/2 a cycle every second l->setDensity(1.5f); //Relatively dense grass l->setFadeTechnique(FADETECH_GROW); //Distant grass should slowly raise out of the ground when coming in range l->setRenderTechnique(GRASSTECH_QUAD); //Draw grass as scattered quads //This sets a color map to be used when determining the color of each grass quad. setMapBounds() //is used to set the area which is affected by the color map. Here, "terrain_texture.jpg" is used //to color the grass to match the terrain under it. l->setColorMap("terrain_texture.jpg"); l->setMapBounds(TBounds(0, 0, 1500, 1500)); //(0,0)-(1500,1500) is the full boundaries of the terrain }
//[NOTE] In addition to some Ogre setup, this function configures PagedGeometry in the scene. void World::load() { //-------------------------------------- LOAD TERRAIN -------------------------------------- //Setup the fog up to 1500 units away sceneMgr->setFog(FOG_LINEAR, viewport->getBackgroundColour(), 0, 100, 900); //Load the terrain sceneMgr->setWorldGeometry("terrain2.cfg"); //Start off with the camera at the center of the terrain camera->setPosition(700, 100, 700); //Setup a skybox sceneMgr->setSkyBox(true, "3D-Diggers/SkyBox", 2000); //-------------------------------------- LOAD GRASS -------------------------------------- //Create and configure a new PagedGeometry instance for grass grass = new PagedGeometry(camera, 30); grass->addDetailLevel<GrassPage>(60); //Create a GrassLoader object grassLoader = new GrassLoader(grass); grass->setPageLoader(grassLoader); //Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance //Supply a height function to GrassLoader so it can calculate grass Y values HeightFunction::initialize(sceneMgr); grassLoader->setHeightFunction(&HeightFunction::getTerrainHeight); //Add some grass to the scene with GrassLoader::addLayer() GrassLayer *l = grassLoader->addLayer("3D-Diggers/plant1sprite"); //Configure the grass layer properties (size, density, animation properties, fade settings, etc.) l->setMinimumSize(0.7f, 0.7f); l->setMaximumSize(0.9f, 0.9f); l->setAnimationEnabled(true); //Enable animations l->setSwayDistribution(7.0f); //Sway fairly unsynchronized l->setSwayLength(0.1f); //Sway back and forth 0.5 units in length l->setSwaySpeed(0.4f); //Sway 1/2 a cycle every second l->setDensity(3.0f); //Relatively dense grass l->setRenderTechnique(GRASSTECH_SPRITE); l->setFadeTechnique(FADETECH_GROW); //Distant grass should slowly raise out of the ground when coming in range //[NOTE] This sets the color map, or lightmap to be used for grass. All grass will be colored according //to this texture. In this case, the colors of the terrain is used so grass will be shadowed/colored //just as the terrain is (this usually makes the grass fit in very well). l->setColorMap("terrain_texture2.jpg"); //This sets the density map that will be used to determine the density levels of grass all over the //terrain. This can be used to make grass grow anywhere you want to; in this case it's used to make //grass grow only on fairly level ground (see densitymap.png to see how this works). l->setDensityMap("densitymap.png"); //setMapBounds() must be called for the density and color maps to work (otherwise GrassLoader wouldn't //have any knowledge of where you want the maps to be applied). In this case, the maps are applied //to the same boundaries as the terrain. l->setMapBounds(TBounds(0, 0, 1500, 1500)); //(0,0)-(1500,1500) is the full boundaries of the terrain //-------------------------------------- LOAD TREES -------------------------------------- //Create and configure a new PagedGeometry instance trees = new PagedGeometry(); trees->setCamera(camera); //Set the camera so PagedGeometry knows how to calculate LODs trees->setPageSize(50); //Set the size of each page of geometry trees->setInfinite(); //Use infinite paging mode #ifdef WIND //WindBatchPage is a variation of BatchPage which includes a wind animation shader trees->addDetailLevel<WindBatchPage>(90, 30); //Use batches up to 150 units away, and fade for 30 more units #else trees->addDetailLevel<BatchPage>(90, 30); //Use batches up to 150 units away, and fade for 30 more units #endif trees->addDetailLevel<ImpostorPage>(700, 50); //Use impostors up to 400 units, and for for 50 more units //Create a new TreeLoader2D object TreeLoader2D *treeLoader = new TreeLoader2D(trees, TBounds(0, 0, 1500, 1500)); trees->setPageLoader(treeLoader); //Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance //Supply a height function to TreeLoader2D so it can calculate tree Y values HeightFunction::initialize(sceneMgr); treeLoader->setHeightFunction(&HeightFunction::getTerrainHeight); //[NOTE] This sets the color map, or lightmap to be used for trees. All trees will be colored according //to this texture. In this case, the shading of the terrain is used so trees will be shadowed //just as the terrain is (this should appear like the terrain is casting shadows on the trees). //You may notice that TreeLoader2D / TreeLoader3D doesn't have a setMapBounds() function as GrassLoader //does. This is because the bounds you specify in the TreeLoader2D constructor are used to apply //the color map. treeLoader->setColorMap("terrain_lightmap.jpg"); //Load a tree entity Entity *tree1 = sceneMgr->createEntity("Tree1", "fir05_30.mesh"); Entity *tree2 = sceneMgr->createEntity("Tree2", "fir14_25.mesh"); #ifdef WIND trees->setCustomParam(tree1->getName(), "windFactorX", 15); trees->setCustomParam(tree1->getName(), "windFactorY", 0.01); trees->setCustomParam(tree2->getName(), "windFactorX", 22); trees->setCustomParam(tree2->getName(), "windFactorY", 0.013); #endif //Randomly place 10000 copies of the tree on the terrain Ogre::Vector3 position = Ogre::Vector3::ZERO; Radian yaw; Real scale; for (int i = 0; i < 10000; i++){ yaw = Degree(Math::RangeRandom(0, 360)); position.x = Math::RangeRandom(0, 1500); position.z = Math::RangeRandom(0, 1500); scale = Math::RangeRandom(0.07f, 0.12f); float rnd = Math::UnitRandom(); if (rnd < 0.5f) { //[NOTE] Unlike TreeLoader3D, TreeLoader2D's addTree() function accepts a Vector2D position (x/z) //The Y value is calculated during runtime (to save memory) from the height function supplied (above) if (Math::UnitRandom() < 0.5f) treeLoader->addTree(tree1, position, yaw, scale); //else // treeLoader->addTree(tree2, position, yaw, scale); } else treeLoader->addTree(tree2, position, yaw, scale); } //-------------------------------------- LOAD BUSHES -------------------------------------- //Create and configure a new PagedGeometry instance for bushes bushes = new PagedGeometry(camera, 50); #ifdef WIND bushes->addDetailLevel<WindBatchPage>(80, 50); #else bushes->addDetailLevel<BatchPage>(80, 50); #endif //Create a new TreeLoader2D object for the bushes TreeLoader2D *bushLoader = new TreeLoader2D(bushes, TBounds(0, 0, 1500, 1500)); bushes->setPageLoader(bushLoader); //Supply the height function to TreeLoader2D so it can calculate tree Y values HeightFunction::initialize(sceneMgr); bushLoader->setHeightFunction(&HeightFunction::getTerrainHeight); bushLoader->setColorMap("terrain_lightmap.jpg"); //Load a bush entity Entity *fern = sceneMgr->createEntity("Fern", "farn1.mesh"); Entity *plant = sceneMgr->createEntity("Plant", "plant2.mesh"); Entity *mushroom = sceneMgr->createEntity("Mushroom", "shroom1_1.mesh"); #ifdef WIND bushes->setCustomParam(fern->getName(), "factorX", 1); bushes->setCustomParam(fern->getName(), "factorY", 0.01); bushes->setCustomParam(plant->getName(), "factorX", 0.6); bushes->setCustomParam(plant->getName(), "factorY", 0.02); #endif //Randomly place 20,000 bushes on the terrain for (int i = 0; i < 20000; i++){ yaw = Degree(Math::RangeRandom(0, 360)); position.x = Math::RangeRandom(0, 1500); position.z = Math::RangeRandom(0, 1500); float rnd = Math::UnitRandom(); if (rnd < 0.8f) { scale = Math::RangeRandom(0.3f, 0.4f); bushLoader->addTree(fern, position, yaw, scale); } else if (rnd < 0.9) { scale = Math::RangeRandom(0.2f, 0.6f); bushLoader->addTree(mushroom, position, yaw, scale); } else { scale = Math::RangeRandom(0.3f, 0.5f); bushLoader->addTree(plant, position, yaw, scale); } } }
//[NOTE] In addition to some Ogre setup, this function configures PagedGeometry in the scene. void World::load() { //-------------------------------------- LOAD TERRAIN -------------------------------------- //Setup the fog up to 500 units away sceneMgr->setFog(FOG_LINEAR, viewport->getBackgroundColour(), 0, 100, 700); //Load the terrain auto terrain = loadLegacyTerrain("terrain2.cfg", sceneMgr); //Start off with the camera at the center of the terrain cameraNode->setPosition(700, 100, 700); //-------------------------------------- LOAD GRASS -------------------------------------- //Create and configure a new PagedGeometry instance for grass grass = new PagedGeometry(camera, 50); grass->addDetailLevel<GrassPage>(100); //Create a GrassLoader object grassLoader = new GrassLoader(grass); grass->setPageLoader(grassLoader); //Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance //Supply a height function to GrassLoader so it can calculate grass Y values HeightFunction::initialize(terrain); grassLoader->setHeightFunction(&HeightFunction::getTerrainHeight); //Add some grass to the scene with GrassLoader::addLayer() GrassLayer *l = grassLoader->addLayer("grass"); //Configure the grass layer properties (size, density, animation properties, fade settings, etc.) l->setMinimumSize(2.0f, 1.5f); l->setMaximumSize(2.5f, 1.9f); l->setAnimationEnabled(true); //Enable animations l->setSwayDistribution(10.0f); //Sway fairly unsynchronized l->setSwayLength(0.5f); //Sway back and forth 0.5 units in length l->setSwaySpeed(0.5f); //Sway 1/2 a cycle every second l->setDensity(2.0f); //Relatively dense grass l->setFadeTechnique(FADETECH_GROW); //Distant grass should slowly raise out of the ground when coming in range //[NOTE] This sets the color map, or lightmap to be used for grass. All grass will be colored according //to this texture. In this case, the colors of the terrain is used so grass will be shadowed/colored //just as the terrain is (this usually makes the grass fit in very well). l->setColorMap("terrain_texture2.jpg"); //This sets the density map that will be used to determine the density levels of grass all over the //terrain. This can be used to make grass grow anywhere you want to; in this case it's used to make //grass grow only on fairly level ground (see densitymap.png to see how this works). l->setDensityMap("densitymap.png"); //setMapBounds() must be called for the density and color maps to work (otherwise GrassLoader wouldn't //have any knowledge of where you want the maps to be applied). In this case, the maps are applied //to the same boundaries as the terrain. l->setMapBounds(TBounds(0, 0, 1500, 1500)); //(0,0)-(1500,1500) is the full boundaries of the terrain //-------------------------------------- LOAD TREES -------------------------------------- //Create and configure a new PagedGeometry instance trees = new PagedGeometry(); trees->setCamera(camera); //Set the camera so PagedGeometry knows how to calculate LODs trees->setPageSize(80); //Set the size of each page of geometry trees->setInfinite(); //Use infinite paging mode trees->addDetailLevel<BatchPage>(150, 50); //Use batches up to 150 units away, and fade for 30 more units trees->addDetailLevel<ImpostorPage>(500, 50); //Use impostors up to 400 units, and for for 50 more units //Create a new TreeLoader2D object TreeLoader2D *treeLoader = new TreeLoader2D(trees, TBounds(0, 0, 1500, 1500)); trees->setPageLoader(treeLoader); //Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance //Supply a height function to TreeLoader2D so it can calculate tree Y values treeLoader->setHeightFunction(&HeightFunction::getTerrainHeight); //[NOTE] This sets the color map, or lightmap to be used for trees. All trees will be colored according //to this texture. In this case, the shading of the terrain is used so trees will be shadowed //just as the terrain is (this should appear like the terrain is casting shadows on the trees). //You may notice that TreeLoader2D / TreeLoader3D doesn't have a setMapBounds() function as GrassLoader //does. This is because the bounds you specify in the TreeLoader2D constructor are used to apply //the color map. treeLoader->setColorMap("terrain_lightmap.jpg"); //Load a tree entity Entity *myEntity = sceneMgr->createEntity("Tree", "tree2.mesh"); //Randomly place 20,000 copies of the tree on the terrain Ogre::Vector3 position = Ogre::Vector3::ZERO; Radian yaw; Real scale; for (int i = 0; i < 20000; i++){ yaw = Degree(Math::RangeRandom(0, 360)); position.x = Math::RangeRandom(0, 1500); position.z = Math::RangeRandom(0, 1500); scale = Math::RangeRandom(0.9f, 1.1f); //[NOTE] Unlike TreeLoader3D, TreeLoader2D's addTree() function accepts a Vector2D position (x/z) //The Y value is calculated during runtime (to save memory) from the height function supplied (above) treeLoader->addTree(myEntity, position, yaw, scale); } }
void TerrainObjectManager::loadObjectConfigFile(Ogre::String odefname) { proceduralManager = new ProceduralManager(); objcounter = 0; free_localizer = 0; ProceduralObject po; po.loadingState = -1; int r2oldmode = 0; int lastprogress = -1; bool proroad = false; DataStreamPtr ds; try { ds = ResourceGroupManager::getSingleton().openResource(odefname, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); } catch(...) { LOG("Error opening object configuration: " + odefname); return; } int mapsizex = terrainManager->getGeometryManager()->getMaxTerrainSize().x; int mapsizez = terrainManager->getGeometryManager()->getMaxTerrainSize().z; Vector3 r2lastpos=Vector3::ZERO; Quaternion r2lastrot=Quaternion::IDENTITY; int r2counter=0; //long line = 0; char line[4096] = ""; while (!ds->eof()) { int progress = ((float)(ds->tell()) / (float)(ds->size())) * 100.0f; if (progress-lastprogress > 20) { #ifdef USE_MYGUI LoadingWindow::getSingleton().setProgress(progress, _L("Loading Terrain Objects")); #endif //MYGUI lastprogress = progress; } char oname[1024] = {}; char type[256] = {}; char name[256] = {}; Vector3 pos(Vector3::ZERO); Vector3 rot(Vector3::ZERO); size_t ll = ds->readLine(line, 1023); if (line[0]=='/' || line[0]==';' || ll==0) continue; //comments if (!strcmp("end",line)) break; if (!strncmp(line,"collision-tris", 14)) { long amount = Collisions::MAX_COLLISION_TRIS; sscanf(line, "collision-tris %ld", &amount); gEnv->collisions->resizeMemory(amount); } if (!strncmp(line,"grid", 4)) { sscanf(line, "grid %f, %f, %f", &pos.x, &pos.y, &pos.z); Ogre::ColourValue BackgroundColour = Ogre::ColourValue::White;//Ogre::ColourValue(0.1337f, 0.1337f, 0.1337f, 1.0f); Ogre::ColourValue GridColour = Ogre::ColourValue(0.2f, 0.2f, 0.2f, 1.0f); Ogre::ManualObject *mReferenceObject = new Ogre::ManualObject("ReferenceGrid"); mReferenceObject->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_LIST); Ogre::Real step = 1.0f; unsigned int count = 50; unsigned int halfCount = count / 2; Ogre::Real full = (step * count); Ogre::Real half = full / 2; Ogre::Real y = 0; Ogre::ColourValue c; for (unsigned i=0;i < count+1;i++) { if (i == halfCount) c = Ogre::ColourValue(1,0,0,1.0f); else c = GridColour; mReferenceObject->position(-half,y,-half+(step*i)); mReferenceObject->colour(BackgroundColour); mReferenceObject->position(0,y,-half+(step*i)); mReferenceObject->colour(c); mReferenceObject->position(0,y,-half+(step*i)); mReferenceObject->colour(c); mReferenceObject->position(half,y,-half+(step*i)); mReferenceObject->colour(BackgroundColour); if (i == halfCount) c = Ogre::ColourValue(0,0,1,1.0f); else c = GridColour; mReferenceObject->position(-half+(step*i),y,-half); mReferenceObject->colour(BackgroundColour); mReferenceObject->position(-half+(step*i),y,0); mReferenceObject->colour(c); mReferenceObject->position(-half+(step*i),y,0); mReferenceObject->colour(c); mReferenceObject->position(-half+(step*i),y, half); mReferenceObject->colour(BackgroundColour); } mReferenceObject->end(); mReferenceObject->setCastShadows(false); SceneNode *n = gEnv->sceneManager->getRootSceneNode()->createChildSceneNode(); n->setPosition(pos); n->attachObject(mReferenceObject); n->setVisible(true); } #ifdef USE_PAGED //ugly stuff to parse trees :) if (!strncmp("trees", line, 5)) { if (terrainManager->getPagedMode() == 0) continue; char ColorMap[256] = {}; char DensityMap[256] = {}; char treemesh[256] = {}; char treeCollmesh[256] = {}; float gridspacing = 0.0f; float yawfrom = 0.0f, yawto = 0.0f; float scalefrom = 0.0f, scaleto = 0.0f; float highdens = 1.0f; int minDist = 90, maxDist = 700; sscanf(line, "trees %f, %f, %f, %f, %f, %d, %d, %s %s %s %f %s", &yawfrom, &yawto, &scalefrom, &scaleto, &highdens, &minDist, &maxDist, treemesh, ColorMap, DensityMap, &gridspacing, treeCollmesh); if (strnlen(ColorMap, 3) == 0) { LOG("tree ColorMap map zero!"); continue; } if (strnlen(DensityMap, 3) == 0) { LOG("tree DensityMap zero!"); continue; } Forests::DensityMap *densityMap = Forests::DensityMap::load(DensityMap, Forests::CHANNEL_COLOR); if (!densityMap) { LOG("could not load densityMap: "+String(DensityMap)); continue; } densityMap->setFilter(Forests::MAPFILTER_BILINEAR); //densityMap->setMapBounds(TRect(0, 0, mapsizex, mapsizez)); paged_geometry_t paged; paged.geom = new PagedGeometry(); paged.geom->setTempDir(SSETTING("User Path", "") + "cache" + SSETTING("dirsep", "\\")); paged.geom->setCamera(gEnv->mainCamera); paged.geom->setPageSize(50); paged.geom->setInfinite(); Ogre::TRect<Ogre::Real> bounds = TBounds(0, 0, mapsizex, mapsizez); paged.geom->setBounds(bounds); //Set up LODs //trees->addDetailLevel<EntityPage>(50); float min = minDist * terrainManager->getPagedDetailFactor(); if (min<10) min = 10; paged.geom->addDetailLevel<BatchPage>(min, min/2); float max = maxDist * terrainManager->getPagedDetailFactor(); if (max<10) max = 10; paged.geom->addDetailLevel<ImpostorPage>(max, max/10); TreeLoader2D *treeLoader = new TreeLoader2D(paged.geom, TBounds(0, 0, mapsizex, mapsizez)); paged.geom->setPageLoader(treeLoader); treeLoader->setHeightFunction(&getTerrainHeight); if (String(ColorMap) != "none") { treeLoader->setColorMap(ColorMap); } Entity *curTree = gEnv->sceneManager->createEntity(String("paged_")+treemesh+TOSTRING(pagedGeometry.size()), treemesh); if (gridspacing > 0) { // grid style for (float x=0; x < mapsizex; x += gridspacing) { for (float z=0; z < mapsizez; z += gridspacing) { float density = densityMap->_getDensityAt_Unfiltered(x, z, bounds); if (density < 0.8f) continue; float nx = x + gridspacing * 0.5f; float nz = z + gridspacing * 0.5f; float yaw = Math::RangeRandom(yawfrom, yawto); float scale = Math::RangeRandom(scalefrom, scaleto); Vector3 pos = Vector3(nx, 0, nz); treeLoader->addTree(curTree, pos, Degree(yaw), (Ogre::Real)scale); if (strlen(treeCollmesh)) { pos.y = gEnv->terrainManager->getHeightFinder()->getHeightAt(pos.x, pos.z); scale *= 0.1f; gEnv->collisions->addCollisionMesh(String(treeCollmesh), pos, Quaternion(Degree(yaw), Vector3::UNIT_Y), Vector3(scale, scale, scale)); } } } } else { float gridsize = 10; if (gridspacing < 0 && gridspacing != 0) { gridsize = -gridspacing; } float hd = highdens; // normal style, random for (float x=0; x < mapsizex; x += gridsize) { for (float z=0; z < mapsizez; z += gridsize) { if (highdens < 0) hd = Math::RangeRandom(0, -highdens); float density = densityMap->_getDensityAt_Unfiltered(x, z, bounds); int numTreesToPlace = (int)((float)(hd) * density * terrainManager->getPagedDetailFactor()); float nx=0, nz=0; while(numTreesToPlace-->0) { nx = Math::RangeRandom(x, x + gridsize); nz = Math::RangeRandom(z, z + gridsize); float yaw = Math::RangeRandom(yawfrom, yawto); float scale = Math::RangeRandom(scalefrom, scaleto); Vector3 pos = Vector3(nx, 0, nz); treeLoader->addTree(curTree, pos, Degree(yaw), (Ogre::Real)scale); if (strlen(treeCollmesh)) { pos.y = gEnv->terrainManager->getHeightFinder()->getHeightAt(pos.x, pos.z); gEnv->collisions->addCollisionMesh(String(treeCollmesh),pos, Quaternion(Degree(yaw), Vector3::UNIT_Y), Vector3(scale, scale, scale)); } } } } } paged.loader = (void*)treeLoader; pagedGeometry.push_back(paged); } //ugly stuff to parse grass :) if (!strncmp("grass", line, 5) || !strncmp("grass2", line, 6)) { // is paged geometry disabled by configuration? if (terrainManager->getPagedMode() == 0) continue; int range = 80; float SwaySpeed=0.5, SwayLength=0.05, SwayDistribution=10.0, minx=0.2, miny=0.2, maxx=1, maxy=0.6, Density=0.6, minH=-9999, maxH=9999; char grassmat[256]=""; char colorMapFilename[256]=""; char densityMapFilename[256]=""; int growtechnique = 0; int techn = GRASSTECH_CROSSQUADS; if (!strncmp("grass2", line, 6)) sscanf(line, "grass2 %d, %f, %f, %f, %f, %f, %f, %f, %f, %d, %f, %f, %d, %s %s %s", &range, &SwaySpeed, &SwayLength, &SwayDistribution, &Density, &minx, &miny, &maxx, &maxy, &growtechnique, &minH, &maxH, &techn, grassmat, colorMapFilename, densityMapFilename); else if (!strncmp("grass", line, 5)) sscanf(line, "grass %d, %f, %f, %f, %f, %f, %f, %f, %f, %d, %f, %f, %s %s %s", &range, &SwaySpeed, &SwayLength, &SwayDistribution, &Density, &minx, &miny, &maxx, &maxy, &growtechnique, &minH, &maxH, grassmat, colorMapFilename, densityMapFilename); //Initialize the PagedGeometry engine try { paged_geometry_t paged; PagedGeometry *grass = new PagedGeometry(gEnv->mainCamera, 30); //Set up LODs grass->addDetailLevel<GrassPage>(range * terrainManager->getPagedDetailFactor()); // original value: 80 //Set up a GrassLoader for easy use GrassLoader *grassLoader = new GrassLoader(grass); grass->setPageLoader(grassLoader); grassLoader->setHeightFunction(&getTerrainHeight); // render grass at first grassLoader->setRenderQueueGroup(RENDER_QUEUE_MAIN-1); GrassLayer* grassLayer = grassLoader->addLayer(grassmat); grassLayer->setHeightRange(minH, maxH); grassLayer->setLightingEnabled(true); grassLayer->setAnimationEnabled((SwaySpeed>0)); grassLayer->setSwaySpeed(SwaySpeed); grassLayer->setSwayLength(SwayLength); grassLayer->setSwayDistribution(SwayDistribution); //String grassdensityTextureFilename = String(DensityMap); grassLayer->setDensity(Density * terrainManager->getPagedDetailFactor()); if (techn>10) grassLayer->setRenderTechnique(static_cast<GrassTechnique>(techn-10), true); else grassLayer->setRenderTechnique(static_cast<GrassTechnique>(techn), false); grassLayer->setMapBounds(TBounds(0, 0, mapsizex, mapsizez)); if (strcmp(colorMapFilename,"none") != 0) { grassLayer->setColorMap(colorMapFilename); grassLayer->setColorMapFilter(MAPFILTER_BILINEAR); } if (strcmp(densityMapFilename,"none") != 0) { grassLayer->setDensityMap(densityMapFilename); grassLayer->setDensityMapFilter(MAPFILTER_BILINEAR); } //grassLayer->setMinimumSize(0.5,0.5); //grassLayer->setMaximumSize(1.0, 1.0); grassLayer->setMinimumSize(minx, miny); grassLayer->setMaximumSize(maxx, maxy); // growtechnique if (growtechnique == 0) grassLayer->setFadeTechnique(FADETECH_GROW); else if (growtechnique == 1) grassLayer->setFadeTechnique(FADETECH_ALPHAGROW); else if (growtechnique == 2) grassLayer->setFadeTechnique(FADETECH_ALPHA); paged.geom = grass; paged.loader = (void*)grassLoader; pagedGeometry.push_back(paged); } catch(...) { LOG("error loading grass!"); } continue; } #endif //USE_PAGED { // ugly stuff to parse procedural roads if (!strncmp("begin_procedural_roads", line, 22)) { po = ProceduralObject(); po.loadingState = 1; r2oldmode = 1; proroad = true; continue; } if (!strncmp("end_procedural_roads", line, 20)) { if (r2oldmode) { if (proceduralManager) proceduralManager->addObject(po); po = ProceduralObject(); } proroad = false; continue; } if (proroad) { float rwidth, bwidth, bheight; //position x,y,z rotation rx,ry,rz, width, border width, border height, type int r = sscanf(line, "%f, %f, %f, %f, %f, %f, %f, %f, %f, %s",&pos.x,&pos.y,&pos.z, &rot.x, &rot.y, &rot.z, &rwidth, &bwidth, &bheight, oname); Quaternion rotation = Quaternion(Degree(rot.x), Vector3::UNIT_X)*Quaternion(Degree(rot.y), Vector3::UNIT_Y)*Quaternion(Degree(rot.z), Vector3::UNIT_Z); int roadtype=Road2::ROAD_AUTOMATIC; int pillartype = 0; if (!strcmp(oname, "flat")) roadtype=Road2::ROAD_FLAT; if (!strcmp(oname, "left")) roadtype=Road2::ROAD_LEFT; if (!strcmp(oname, "right")) roadtype=Road2::ROAD_RIGHT; if (!strcmp(oname, "both")) roadtype=Road2::ROAD_BOTH; if (!strcmp(oname, "bridge")) {roadtype=Road2::ROAD_BRIDGE;pillartype=1;} if (!strcmp(oname, "monorail")) {roadtype=Road2::ROAD_MONORAIL;pillartype=2;} if (!strcmp(oname, "monorail2")) {roadtype=Road2::ROAD_MONORAIL;pillartype=0;} if (!strcmp(oname, "bridge_no_pillars")) {roadtype=Road2::ROAD_BRIDGE;pillartype=0;} if (r2oldmode) { //fill object ProceduralPoint pp; pp.bheight = bheight; pp.bwidth = bwidth; pp.pillartype = pillartype; pp.position = pos; pp.rotation = rotation; pp.type = roadtype; pp.width = rwidth; po.points.push_back(pp); } continue; } } //end of the ugly (somewhat) strcpy(name, "generic"); memset(oname, 0, 255); memset(type, 0, 255); memset(name, 0, 255); int r = sscanf(line, "%f, %f, %f, %f, %f, %f, %s %s %s",&pos.x,&pos.y,&pos.z, &rot.x, &rot.y, &rot.z, oname, type, name); if (r < 6) continue; if ((!strcmp(oname, "truck")) || (!strcmp(oname, "load") || (!strcmp(oname, "machine")) || (!strcmp(oname, "boat")) || (!strcmp(oname, "truck2")) )) { if (!strcmp(oname, "boat") && !terrainManager->getWater()) { // no water so do not load boats! continue; } String group = ""; String truckname(type); if (!RoR::Application::GetCacheSystem()->checkResourceLoaded(truckname, group)) { LOG("Error while loading Terrain: truck " + String(type) + " not found. ignoring."); continue; } truck_prepare_t tempTruckPreload; //this is a truck or load declaration tempTruckPreload.px = pos.x; tempTruckPreload.py = pos.y; tempTruckPreload.pz = pos.z; tempTruckPreload.freePosition = (!strcmp(oname, "truck2")); tempTruckPreload.ismachine = (!strcmp(oname, "machine")); tempTruckPreload.rotation = Quaternion(Degree(rot.x), Vector3::UNIT_X)*Quaternion(Degree(rot.y), Vector3::UNIT_Y)*Quaternion(Degree(rot.z), Vector3::UNIT_Z); strcpy(tempTruckPreload.name, truckname.c_str()); truck_preload.push_back(tempTruckPreload); continue; } if ( !strcmp(oname, "road") || !strcmp(oname, "roadborderleft") || !strcmp(oname, "roadborderright") || !strcmp(oname, "roadborderboth") || !strcmp(oname, "roadbridgenopillar") || !strcmp(oname, "roadbridge")) { int pillartype = !(strcmp(oname, "roadbridgenopillar") == 0); // okay, this is a job for roads2 int roadtype=Road2::ROAD_AUTOMATIC; if (!strcmp(oname, "road")) roadtype=Road2::ROAD_FLAT; Quaternion rotation; rotation = Quaternion(Degree(rot.x), Vector3::UNIT_X)*Quaternion(Degree(rot.y), Vector3::UNIT_Y)*Quaternion(Degree(rot.z), Vector3::UNIT_Z); if (pos.distance(r2lastpos) > 20.0f) { // break the road if (r2oldmode != 0) { // fill object ProceduralPoint pp; pp.bheight = 0.2; pp.bwidth = 1.4; pp.pillartype = pillartype; pp.position = r2lastpos + r2lastrot * Vector3(10.0f, 0.0f, 0.9f); pp.rotation = r2lastrot; pp.type = roadtype; pp.width = 8; po.points.push_back(pp); // finish it and start new object if (proceduralManager) proceduralManager->addObject(po); po = ProceduralObject(); r2oldmode = 1; } r2oldmode = 1; // beginning of new ProceduralPoint pp; pp.bheight = 0.2; pp.bwidth = 1.4; pp.pillartype = pillartype; pp.position = pos; pp.rotation = rotation; pp.type = roadtype; pp.width = 8; po.points.push_back(pp); } else { // fill object ProceduralPoint pp; pp.bheight = 0.2; pp.bwidth = 1.4; pp.pillartype = pillartype; pp.position = pos; pp.rotation = rotation; pp.type = roadtype; pp.width = 8; po.points.push_back(pp); } r2lastpos=pos; r2lastrot=rotation; continue; } loadObject(oname, pos, rot, bakeNode, name, type); } // ds closes automatically, so do not close it explicitly here: ds->close(); // finish the last road if (r2oldmode != 0) { // fill object ProceduralPoint pp; pp.bheight = 0.2; pp.bwidth = 1.4; pp.pillartype = 1; pp.position = r2lastpos+r2lastrot*Vector3(10.0,0,0); pp.rotation = r2lastrot; pp.type = Road2::ROAD_AUTOMATIC; pp.width = 8; po.points.push_back(pp); // finish it and start new object if (proceduralManager) proceduralManager->addObject(po); } }