Ogre::String GameBuildingSystem::BuildBuildings( Ogre::SceneManager *sceneMan, GameRoadGraphAreaTreeNode *roadRoot )
{
  Ogre::ManualObject *manObject = NULL;
  Ogre::String manObjectName    = "Buildings";
  manObject = sceneMan->createManualObject( manObjectName );
  manObject->setDynamic( false );
  
  BuildToArea( roadRoot, manObject );

  manObject->setCastShadows( true );

  sceneMan->getRootSceneNode()->createChildSceneNode()->attachObject( manObject );
  return manObjectName;
}
int DecalManager::addTerrainDecal(Ogre::Vector3 position, Ogre::Vector2 size, Ogre::Vector2 numSeg, Ogre::Real rotation, Ogre::String materialname, Ogre::String normalname)
{
#if 0
	Ogre::ManualObject *mo = gEnv->ogreSceneManager->createManualObject();
	String oname = mo->getName();
	SceneNode *mo_node = terrain_decals_snode->createChildSceneNode();

	mo->begin(materialname, Ogre::RenderOperation::OT_TRIANGLE_LIST);
	AxisAlignedBox *aab=new AxisAlignedBox();
	float uTile = 1, vTile = 1;

	Vector3 normal = Vector3(0,1,0); // UP
	
	int offset = 0;
	float ground_dist = 0.001f;

	Ogre::Vector3 vX = normal.perpendicular();
	Ogre::Vector3 vY = normal.crossProduct(vX);
	Ogre::Vector3 delta1 = size.x / numSeg.x * vX;
	Ogre::Vector3 delta2 = size.y / numSeg.y * vY;
	// build one corner of the square
	Ogre::Vector3 orig = -0.5*size.x*vX - 0.5*size.y*vY;

	for (int i1 = 0; i1<=numSeg.x; i1++)
		for (int i2 = 0; i2<=numSeg.y; i2++)
		{
			Vector3 pos = orig+i1*delta1+i2*delta2 + position;
			pos.y = hfinder->getHeightAt(pos.x, pos.z) + ground_dist;
			mo->position(pos);
			aab->merge(pos);
			mo->textureCoord(i1/(Ogre::Real)numSeg.x*uTile, i2/(Ogre::Real)numSeg.y*vTile);
			mo->normal(normal);
		}

	bool reverse = false;
	if (delta1.crossProduct(delta2).dotProduct(normal)>0)
		reverse= true;
	for (int n1 = 0; n1<numSeg.x; n1++)
	{
		for (int n2 = 0; n2<numSeg.y; n2++)
		{
			if (reverse)
			{
				mo->index(offset+0);
				mo->index(offset+(numSeg.y+1));
				mo->index(offset+1);
				mo->index(offset+1);
				mo->index(offset+(numSeg.y+1));
				mo->index(offset+(numSeg.y+1)+1);
			}
			else
			{
				mo->index(offset+0);
				mo->index(offset+1);
				mo->index(offset+(numSeg.y+1));
				mo->index(offset+1);
				mo->index(offset+(numSeg.y+1)+1);
				mo->index(offset+(numSeg.y+1));
			}
			offset++;
		}
		offset++;
	}
	offset+=numSeg.y+1;

	mo->end();
	mo->setBoundingBox(*aab);
	// some optimizations
	mo->setCastShadows(false);
	mo->setDynamic(false);
	delete(aab);

	MeshPtr mesh = mo->convertToMesh(oname+"_mesh");

	// build edgelist
	mesh->buildEdgeList();

	// remove the manualobject again, since we dont need it anymore
	gEnv->ogreSceneManager->destroyManualObject(mo);

	unsigned short src, dest;
	if (!mesh->suggestTangentVectorBuildParams(VES_TANGENT, src, dest))
	{
		mesh->buildTangentVectors(VES_TANGENT, src, dest);
	}
	
	Entity *ent = gEnv->ogreSceneManager->createEntity(oname+"_ent", oname+"_mesh");
	mo_node->attachObject(ent);

	mo_node->setVisible(true);
	//mo_node->showBoundingBox(true);
	mo_node->setPosition(Vector3::ZERO); //(position.x, 0, position.z));


	// RTSS
	//Ogre::RTShader::ShaderGenerator::getSingleton().createShaderBasedTechnique(materialname, Ogre::MaterialManager::DEFAULT_SCHEME_NAME, Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
	//Ogre::RTShader::ShaderGenerator::getSingleton().invalidateMaterial(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME, materialname);
	RTSSgenerateShadersForMaterial(materialname, normalname);

#endif
	return 0;
}
int DecalManager::addTerrainSplineDecal(Ogre::SimpleSpline *spline, float width, Ogre::Vector2 numSeg, Ogre::Vector2 uvSeg, Ogre::String materialname, float ground_offset, Ogre::String export_fn, bool debug)
{
#if 0
	Ogre::ManualObject *mo = gEnv->ogreSceneManager->createManualObject();
	String oname = mo->getName();
	SceneNode *mo_node = terrain_decals_snode->createChildSceneNode();

	mo->begin(materialname, Ogre::RenderOperation::OT_TRIANGLE_LIST);
	AxisAlignedBox *aab=new AxisAlignedBox();

	int offset = 0;

	// how width is the road?
	float delta_width = width / numSeg.x;

	float steps_len = 1.0f / numSeg.x;

	for (int l = 0; l<=numSeg.x; l++)
	{
		// get current position on that spline
		Vector3 pos_cur  = spline->interpolate(steps_len * (float)l);
		Vector3 pos_next = spline->interpolate(steps_len * (float)(l + 1));
        Ogre::Vector3 direction = (pos_next - pos_cur);
		if (l == numSeg.x)
		{
			// last segment uses previous position
			pos_next = spline->interpolate(steps_len * (float)(l - 1));
			direction = (pos_cur - pos_next);
		}


		for (int w = 0; w<=numSeg.y; w++)
		{
			// build vector for the width
			Vector3 wn = direction.normalisedCopy().crossProduct(Vector3::UNIT_Y);
			
			// calculate the offset, spline in the middle
			Vector3 offset = (-0.5 * wn * width) + (w/numSeg.y) * wn * width;

			// push everything together
			Ogre::Vector3 pos = pos_cur + offset;
			// get ground height there
			pos.y = hfinder->getHeightAt(pos.x, pos.z) + ground_offset;

			// add the position to the mesh
			mo->position(pos);
			aab->merge(pos);
			mo->textureCoord(l/(Ogre::Real)numSeg.x*uvSeg.x, w/(Ogre::Real)numSeg.y*uvSeg.y);
			mo->normal(Vector3::UNIT_Y);
		}
	}

	bool reverse = false;
	for (int n1 = 0; n1<numSeg.x; n1++)
	{
		for (int n2 = 0; n2<numSeg.y; n2++)
		{
			if (reverse)
			{
				mo->index(offset+0);
				mo->index(offset+(numSeg.y+1));
				mo->index(offset+1);
				mo->index(offset+1);
				mo->index(offset+(numSeg.y+1));
				mo->index(offset+(numSeg.y+1)+1);
			}
			else
			{
				mo->index(offset+0);
				mo->index(offset+1);
				mo->index(offset+(numSeg.y+1));
				mo->index(offset+1);
				mo->index(offset+(numSeg.y+1)+1);
				mo->index(offset+(numSeg.y+1));
			}
			offset++;
		}
		offset++;
	}
	offset+=numSeg.y+1;

	mo->end();
	mo->setBoundingBox(*aab);
	// some optimizations
	mo->setCastShadows(false);
	mo->setDynamic(false);
	delete(aab);

	MeshPtr mesh = mo->convertToMesh(oname+"_mesh");

	// build edgelist
	mesh->buildEdgeList();

	// remove the manualobject again, since we dont need it anymore
	gEnv->ogreSceneManager->destroyManualObject(mo);

	unsigned short src, dest;
	if (!mesh->suggestTangentVectorBuildParams(VES_TANGENT, src, dest))
	{
		mesh->buildTangentVectors(VES_TANGENT, src, dest);
	}
	
	Entity *ent = gEnv->ogreSceneManager->createEntity(oname+"_ent", oname+"_mesh");
	mo_node->attachObject(ent);

	mo_node->setVisible(true);
	//mo_node->showBoundingBox(true);
	mo_node->setPosition(Vector3::ZERO); //(position.x, 0, position.z));


	if (!export_fn.empty())
	{
		MeshSerializer *ms = new MeshSerializer();
		ms->exportMesh(mesh.get(), export_fn);
		LOG("spline mesh exported as " + export_fn);
		delete(ms);
	}

	// TBD: RTSS
	//Ogre::RTShader::ShaderGenerator::getSingleton().createShaderBasedTechnique(materialname, Ogre::MaterialManager::DEFAULT_SCHEME_NAME, Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
	//Ogre::RTShader::ShaderGenerator::getSingleton().invalidateMaterial(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME, materialname);
	RTSSgenerateShadersForMaterial(materialname, "");

#endif
	return 0;
}
Exemple #4
0
void Map::generateMeshObstacles(std::string materialName)
{
    Ogre::ManualObject* obstacles = new Ogre::ManualObject("obstacles");
    obstacles->estimateIndexCount(m_length * m_width * 8);
    obstacles->estimateVertexCount(m_length * m_width * 8);
    obstacles->clear();
    obstacles->begin(materialName);

    Ogre::Vector3 pos = Ogre::Vector3(0, 0, 0);
    Ogre::Quaternion quat;
    Ogre::Quaternion quatNext;
    unsigned long planeNum = 0;

    m_obstaclePositions.clear();

    for (unsigned int i = 0; i < m_length; i++) {
        quat = m_rotationalSpline.getPoint(i);
        quatNext = m_rotationalSpline.getPoint(i + 1);

        for (int x = -100 * (m_width / (double) 2), j = 0; (unsigned) j < m_width; j++, x += 100) {
            int back = -100;
            int left = x;
            int right = x + 100;
            int up = 100;

            Ogre::Vector3 nextPos =             pos + quat * Ogre::Vector3(0, 0, back);
            Ogre::Vector3 posMinus50 =          pos + quat * Ogre::Vector3(left, 0, 0);
            Ogre::Vector3 posPlus50 =           pos + quat * Ogre::Vector3(right, 0, 0);
            Ogre::Vector3 nextPosMinus50 =      nextPos + quatNext * Ogre::Vector3(left, 0, 0);
            Ogre::Vector3 nextPosPlus50 =       nextPos + quatNext * Ogre::Vector3(right, 0, 0);

            //TODO: fix normals
            obstacles->position(posMinus50);
            obstacles->normal((quat * Vector3(0, 1, 0)).normalisedCopy());
            obstacles->textureCoord(1, 1);
            obstacles->position(nextPosMinus50);
            obstacles->normal((quat * Vector3(0, 1, 0)).normalisedCopy());
            obstacles->textureCoord(1, 0);
            obstacles->position(posPlus50);
            obstacles->normal((quat * Vector3(0, 1, 0)).normalisedCopy());
            obstacles->textureCoord(0, 1);
            obstacles->position(nextPosPlus50);
            obstacles->normal((quat * Vector3(0, 1, 0)).normalisedCopy());
            obstacles->textureCoord(0, 0);

            Ogre::Vector3 nextPosUp =           nextPos + quat * Ogre::Vector3(0, up, 0);
            Ogre::Vector3 posMinus50Up =        posMinus50 + quat * Ogre::Vector3(0, up, 0);
            Ogre::Vector3 posPlus50Up =         posPlus50 + quat * Ogre::Vector3(0, up, 0);
            Ogre::Vector3 nextPosMinus50Up =    nextPosMinus50 + quatNext * Ogre::Vector3(0, up, 0);
            Ogre::Vector3 nextPosPlus50Up =     nextPosPlus50 + quatNext * Ogre::Vector3(0, up, 0);

            //TODO: fix normals
            obstacles->position(posMinus50Up);
            obstacles->normal((quat * Vector3(-1, 1, 1)).normalisedCopy());
            obstacles->textureCoord(0, 0);
            obstacles->position(nextPosMinus50Up);
            obstacles->normal((quat * Vector3(-1, 1, -1)).normalisedCopy());
            obstacles->textureCoord(0, 1);
            obstacles->position(posPlus50Up);
            obstacles->normal((quat * Vector3(1, 1, 1)).normalisedCopy());
            obstacles->textureCoord(1, 0);
            obstacles->position(nextPosPlus50Up);
            obstacles->normal((quat * Vector3(1, 1, -1)).normalisedCopy());
            obstacles->textureCoord(1, 1);

            if (m_cubes[planeNum / (double) m_width][planeNum % m_width] == OBSTACLE) {

                //TODO: check if this hack works..
                m_obstaclePositions.push_back(posMinus50);

                //top
                obstacles->triangle(4 + planeNum * 8, 5 + planeNum * 8, 6 + planeNum * 8);
                obstacles->triangle(6 + planeNum * 8, 5 + planeNum * 8, 4 + planeNum * 8);
                obstacles->triangle(5 + planeNum * 8, 7 + planeNum * 8, 6 + planeNum * 8);
                obstacles->triangle(6 + planeNum * 8, 7 + planeNum * 8, 5 + planeNum * 8);

                if (planeNum % m_width == 0 || m_cubes[planeNum / (double) m_width][(planeNum - 1) % m_width] != OBSTACLE) {
                    //left
                    obstacles->triangle(0 + planeNum * 8, 4 + planeNum * 8, 5 + planeNum * 8);
                    obstacles->triangle(5 + planeNum * 8, 4 + planeNum * 8, 0 + planeNum * 8);
                    obstacles->triangle(0 + planeNum * 8, 1 + planeNum * 8, 5 + planeNum * 8);
                    obstacles->triangle(5 + planeNum * 8, 1 + planeNum * 8, 0 + planeNum * 8);
                }

                if (planeNum % m_width == m_width - 1 || m_cubes[planeNum / (double) m_width][(planeNum + 1) % m_width] != OBSTACLE) {
                    //right
                    obstacles->triangle(2 + planeNum * 8, 6 + planeNum * 8, 7 + planeNum * 8);
                    obstacles->triangle(7 + planeNum * 8, 6 + planeNum * 8, 2 + planeNum * 8);
                    obstacles->triangle(2 + planeNum * 8, 3 + planeNum * 8, 7 + planeNum * 8);
                    obstacles->triangle(7 + planeNum * 8, 3 + planeNum * 8, 2 + planeNum * 8);
                }

                if (planeNum / (double) m_width >= m_length - 1 || m_cubes[(planeNum + m_width) / (double) m_width][planeNum % m_width] != OBSTACLE) {
                    //back
                    obstacles->triangle(5 + planeNum * 8, 7 + planeNum * 8, 1 + planeNum * 8);
                    obstacles->triangle(1 + planeNum * 8, 7 + planeNum * 8, 5 + planeNum * 8);
                    obstacles->triangle(1 + planeNum * 8, 3 + planeNum * 8, 7 + planeNum * 8);
                    obstacles->triangle(7 + planeNum * 8, 3 + planeNum * 8, 1 + planeNum * 8);
                }

                if (planeNum / (double) m_width <= m_width || m_cubes[(planeNum - m_width) / (double) m_width][planeNum % m_width] != OBSTACLE) {
                    //front
                    obstacles->triangle(2 + planeNum * 8, 6 + planeNum * 8, 4 + planeNum * 8);
                    obstacles->triangle(4 + planeNum * 8, 6 + planeNum * 8, 2 + planeNum * 8);
                    obstacles->triangle(0 + planeNum * 8, 4 + planeNum * 8, 2 + planeNum * 8);
                    obstacles->triangle(2 + planeNum * 8, 4 + planeNum * 8, 0 + planeNum * 8);
                }
            }

            planeNum++;
        }

        pos = pos + quat * Ogre::Vector3(0, 0, -100);
    }

    obstacles->end();
    obstacles->setCastShadows(true);

    //TODO: fix graphics bug when no obstacles
    /*if (m_obstaclePositions.size() <= 0)
    {
        return;
    }*/

    m_mapMainNode->attachObject(obstacles);

    MeshPtr ptr = obstacles->convertToMesh("obstaclesMesh");
    Entity* obstaclesEntity = m_pSceneMgr->createEntity("obstaclesEntity", "obstaclesMesh");
}
Exemple #5
0
void Map::generateMesh(std::string materialName)
{
    Ogre::ManualObject* plane = new Ogre::ManualObject("plane");
    plane->estimateIndexCount(m_length * m_width * 8);
    plane->estimateVertexCount(m_length * m_width * 8);
    plane->clear();
    plane->begin(materialName);

    Ogre::Vector3 pos = Ogre::Vector3(0, 0, 0);
    Ogre::Quaternion quat;
    Ogre::Quaternion quatNext;
    unsigned long planeNum = 0;

    for (unsigned int i = 0; i < m_length; i++) {
        quat = m_rotationalSpline.getPoint(i);
        quatNext = m_rotationalSpline.getPoint(i + 1);

        for (int x = -100 * (m_width / (double) 2), j = 0; (unsigned) j < m_width; j++, x += 100) {
            int back = -100;
            int left = x;
            int right = x + 100;
            int down = -20 ;

            Ogre::Vector3 nextPos =             pos + quat * Ogre::Vector3(0, 0, back);
            Ogre::Vector3 posMinus50 =          pos + quat * Ogre::Vector3(left, 0, 0);
            Ogre::Vector3 posPlus50 =           pos + quat * Ogre::Vector3(right, 0, 0);
            Ogre::Vector3 nextPosMinus50 =      nextPos + quatNext * Ogre::Vector3(left, 0, 0);
            Ogre::Vector3 nextPosPlus50 =       nextPos + quatNext * Ogre::Vector3(right, 0, 0);

            //TODO: fix normals?
            plane->position(posMinus50);
            plane->normal((quat * Vector3(0, 1, 0)).normalisedCopy());
            plane->textureCoord(1, 1);
            plane->position(nextPosMinus50);
            plane->normal((quat * Vector3(0, 1, 0)).normalisedCopy());
            plane->textureCoord(1, 0);
            plane->position(posPlus50);
            plane->normal((quat * Vector3(0, 1, 0)).normalisedCopy());
            plane->textureCoord(0, 1);
            plane->position(nextPosPlus50);
            plane->normal((quat * Vector3(0, 1, 0)).normalisedCopy());
            plane->textureCoord(0, 0);

            Ogre::Vector3 nextPosDown =         nextPos + quat * Ogre::Vector3(0, down, 0);
            Ogre::Vector3 posMinus50Down =      posMinus50 + quat * Ogre::Vector3(0, down, 0);
            Ogre::Vector3 posPlus50Down =       posPlus50 + quat * Ogre::Vector3(0, down, 0);
            Ogre::Vector3 nextPosMinus50Down =  nextPosMinus50 + quatNext * Ogre::Vector3(0, down, 0);
            Ogre::Vector3 nextPosPlus50Down =   nextPosPlus50 + quatNext * Ogre::Vector3(0, down, 0);

            //TODO: fix normals?
            plane->position(posMinus50Down);
            plane->normal((quat * Vector3(-1, -1, 1)).normalisedCopy());
            plane->textureCoord(0, 0);
            plane->position(nextPosMinus50Down);
            plane->normal((quat * Vector3(-1, -1, -1)).normalisedCopy());
            plane->textureCoord(0, 1);
            plane->position(posPlus50Down);
            plane->normal((quat * Vector3(1, -1, 1)).normalisedCopy());
            plane->textureCoord(1, 0);
            plane->position(nextPosPlus50Down);
            plane->normal((quat * Vector3(1, -1, -1)).normalisedCopy());
            plane->textureCoord(1, 1);

            if (m_cubes[planeNum / (double) m_width][planeNum % m_width] != HOLE) {
                //if (m_cubes[planeNum / (double) m_width][planeNum % m_width] == NORMAL)
                //{
                //top
                plane->triangle(0 + planeNum * 8, 1 + planeNum * 8, 2 + planeNum * 8);
                plane->triangle(2 + planeNum * 8, 1 + planeNum * 8, 0 + planeNum * 8);
                plane->triangle(1 + planeNum * 8, 3 + planeNum * 8, 2 + planeNum * 8);
                plane->triangle(2 + planeNum * 8, 3 + planeNum * 8, 1 + planeNum * 8);
                //}

                //bottom
                plane->triangle(4 + planeNum * 8, 5 + planeNum * 8, 6 + planeNum * 8);
                plane->triangle(6 + planeNum * 8, 5 + planeNum * 8, 4 + planeNum * 8);
                plane->triangle(5 + planeNum * 8, 7 + planeNum * 8, 6 + planeNum * 8);
                plane->triangle(6 + planeNum * 8, 7 + planeNum * 8, 5 + planeNum * 8);

                if (planeNum % m_width == 0 || m_cubes[planeNum / (double) m_width][(planeNum - 1) % m_width] == HOLE) {
                    //left
                    plane->triangle(0 + planeNum * 8, 4 + planeNum * 8, 5 + planeNum * 8);
                    plane->triangle(5 + planeNum * 8, 4 + planeNum * 8, 0 + planeNum * 8);
                    plane->triangle(0 + planeNum * 8, 1 + planeNum * 8, 5 + planeNum * 8);
                    plane->triangle(5 + planeNum * 8, 1 + planeNum * 8, 0 + planeNum * 8);
                }

                if (planeNum % m_width == m_width - 1 || m_cubes[planeNum / (double) m_width][(planeNum + 1) % m_width] == HOLE) {
                    //right
                    plane->triangle(2 + planeNum * 8, 6 + planeNum * 8, 7 + planeNum * 8);
                    plane->triangle(7 + planeNum * 8, 6 + planeNum * 8, 2 + planeNum * 8);
                    plane->triangle(2 + planeNum * 8, 3 + planeNum * 8, 7 + planeNum * 8);
                    plane->triangle(7 + planeNum * 8, 3 + planeNum * 8, 2 + planeNum * 8);
                }

                if (planeNum / (double) m_width >= m_length - 1 || m_cubes[(planeNum + m_width) / (double) m_width][planeNum % m_width] == HOLE) {
                    //back
                    plane->triangle(5 + planeNum * 8, 7 + planeNum * 8, 1 + planeNum * 8);
                    plane->triangle(1 + planeNum * 8, 7 + planeNum * 8, 5 + planeNum * 8);
                    plane->triangle(1 + planeNum * 8, 3 + planeNum * 8, 7 + planeNum * 8);
                    plane->triangle(7 + planeNum * 8, 3 + planeNum * 8, 1 + planeNum * 8);
                }

                if (planeNum / (double) m_width <= m_width || m_cubes[(planeNum - m_width) / (double) m_width][planeNum % m_width] == HOLE) {
                    //front
                    plane->triangle(2 + planeNum * 8, 6 + planeNum * 8, 4 + planeNum * 8);
                    plane->triangle(4 + planeNum * 8, 6 + planeNum * 8, 2 + planeNum * 8);
                    plane->triangle(0 + planeNum * 8, 4 + planeNum * 8, 2 + planeNum * 8);
                    plane->triangle(2 + planeNum * 8, 4 + planeNum * 8, 0 + planeNum * 8);
                }

            }

            planeNum++;
        }

        pos = pos + quat * Ogre::Vector3(0, 0, -100);
    }

    plane->end();
    plane->setCastShadows(false);
    m_mapMainNode->attachObject(plane);
    MeshPtr ptr = plane->convertToMesh("planeMesh");
    Entity* planeEntity = m_pSceneMgr->createEntity("planeEntity", "planeMesh");
}
// Given a scene node for a terrain, find the manual object on that scene node and
// update the manual object with the heightmap passed. If  there is no manual object on
// the scene node, remove all it's attachments and add the manual object.
// The heightmap is passed in a 1D array ordered by width rows (for(width) {for(length) {hm[w,l]}})
// This must be called between frames since it touches the scene graph
// BETWEEN FRAME OPERATION
void Region::UpdateTerrain(const int hmWidth, const int hmLength, const float* hm) {
	Ogre::SceneNode* node = this->TerrainSceneNode;
	LG::Log("Region::UpdateTerrain: updating terrain for region %s", this->Name.c_str());

	if (node == NULL) {
		LG::Log("Region::UpdateTerrain: terrain scene node doesn't exist. Not updating terrain.");
		return;
	}

	// Find the movable object attached to the scene node. If not found remove all.
	if (node->numAttachedObjects() > 0) {
		Ogre::MovableObject* attached = node->getAttachedObject(0);
		if (attached->getMovableType() != "ManualObject") {
            // don't know why this would ever happen but clean out the odd stuff
            LG::Log("Found extra stuff on terrain scene node");
			node->detachAllObjects();
		}
	}
	// if there is not a manual object on the node, create a new one
	if (node->numAttachedObjects() == 0) {
		LG::Log("Region::UpdateTerrain: creating terrain ManualObject for region %s", this->Name.c_str());
        // if no attached objects, we add our dynamic ManualObject
		Ogre::ManualObject* mob = LG::RendererOgre::Instance()->m_sceneMgr->createManualObject("ManualObject/" + node->getName());
		mob->addQueryFlags(Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK);
		mob->setDynamic(true);
		mob->setCastShadows(true);
		mob->setVisible(true);
		node->attachObject(mob);
		// m_visCalc->RecalculateVisibility();
	}

	Ogre::ManualObject* mo = (Ogre::ManualObject*)node->getAttachedObject(0);

	// stuff our heightmap information into the dynamic manual object
	mo->estimateVertexCount(hmWidth * hmLength);
	mo->estimateIndexCount(hmWidth * hmLength * 6);

	if (mo->getNumSections() == 0) {
		// if first time
		mo->begin(LG::GetParameter("Renderer.Ogre.DefaultTerrainMaterial"));
	}
	else {
		mo->beginUpdate(0);					// we've been here before
	}

	int loc = 0;
	for (int xx = 0; xx < hmWidth; xx++) {
		for (int yy = 0; yy < hmLength; yy++) {
			mo->position((Ogre::Real)xx, (Ogre::Real)yy, hm[loc++]);
			mo->textureCoord((float)xx / (float)hmWidth, (float)yy / (float)hmLength);
			mo->normal(0.0, 1.0, 0.0);	// always up (for the moment)
		}
	}

	for (int px = 0; px < hmLength-1; px++) {
		for (int py = 0; py < hmWidth-1; py++) {
			mo->quad(px      + py       * hmWidth,
					 px      + (py + 1) * hmWidth,
					(px + 1) + (py + 1) * hmWidth,
					(px + 1) + py       * hmWidth
					 );
		}
	}

	mo->end();

	return;
}
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);
	}
}