VertexType getHeightMap(const glm::vec2 position)
{
    const glm::vec2 dx(1.0,0.0);
    const glm::vec2 dy(0.0,1.0);

    VertexType v;
    float h = heightMap(position);
    float hx = 100.f * (heightMap(position + 0.01f*dx) - h );
    float hy = 100.f * (heightMap(position + 0.01f*dy) - h );

    v.position = glm::vec3(position,h);
    v.normal = glm::normalize(glm::vec3(-hx,-hy,1.0));

    float c = sin(h*5.f)*0.5+0.5;
    v.color = glm::vec4(c,1.0-c,1.0,1.0);
    return v;
}
helsing::HeightMap Continuous2DSignalTerrain::generateHeightMap(
		unsigned int gridPoints, float gridSpacing) {
	helsing::HeightMap heightMap(gridPoints);

	if(signal == NULL){
		return heightMap; //if there's no signal, simply return a flat HeightMap
	}

	for(unsigned int i=0; i<gridPoints; ++i){
		for(unsigned int j=0; j<gridPoints; ++j){
			heightMap.setHeight(i,j, signal->get(i/gridSpacing, j/gridSpacing)*gridSpacing*amplitude); //TODO GRIDSPACING?
		}
	}
	return heightMap;
}
Esempio n. 3
0
void GridMesh::AddNoise(vector<PositionTexCoordVertex>& vertices) 
{
	uint numVerticies = rows * columns;
	vector<float> heightMap(numVerticies);

	for (uint row = 0; row < rows; row++)
	{
		for (uint column = 0; column < columns; column++)
		{
			vertices[row * column].position.y = heightMap[row * column];
		}
	}

	int width = 128;
	int height = 128;

	auto xRange = 1.0;
	auto yRange = 1.0;
	auto xFactor = yRange / width;
	auto yFactor = yRange / height;

	for (uint i = 0; i < width; i++)
	{
		for (uint j = 0; j < height; j++)
		{
			float x = xFactor * i;
			float y = yFactor * j;
			float z = 0.0;

			auto value = glm::perlin(vec3(x, y, z));

			value = (value + 1.0f) * 0.5f;

			value = glm::min(value, 1.0f);
			value = glm::max(value, 0.0f);

			heightMap[i * j] = value;
		}
	}


}
Esempio n. 4
0
// loads a BMP file as the height map for the terrain. If the data
// from filename is valid the world is reset and new terrain is created.
int terrain::terrainLoadFile()
{
    QImage heightMap(m_terrainFilename);
    if(heightMap.isNull()){
        m_parent->printText("Terrain File could not open");
        return 0; // if the file does not open return
    }

    QStringList keyList = heightMap.textKeys();
    if(keyList.contains("sizex")) m_terrainSize.setX(heightMap.text("sizex").toFloat());	// import the size of the terrain from the image
    if(keyList.contains("sizey")) m_terrainSize.setY(heightMap.text("sizey").toFloat());
    if(keyList.contains("sizez")) m_terrainSize.setZ(heightMap.text("sizez").toFloat());
	
	tTool->setSize(m_terrainSize);															// write the new size to the tool
	
    m_pixelSize = heightMap.size();															// set the pixel size of the map

    int imgSize = m_pixelSize.width()*m_pixelSize.height();									// get the number of pixels

    unsigned int *imgData = new unsigned int[imgSize+1];									// create a new array to hold all the height data from the image
    if(imgData == NULL) {
        m_parent->printText("Memory error");
        return 0;
    }

    imgData[imgSize] = 0; 																	// the last element in the array contains the maximum height
	
    for(int j=0; j<m_pixelSize.height(); j++){													// load all the height data from the gray scale part of the height image
        for(int i=0; i<m_pixelSize.width(); i++){
            int k = i + j * m_pixelSize.width();
            imgData[k] = qGray(heightMap.pixel(i,j));										// get the height of the pixel
            if(imgData[k] > imgData[imgSize]) 
				imgData[imgSize] = imgData[k];												// save the highest height as the last element
        }
    }

	terrainCreateMesh(imgData); 															// create the new terrain mesh
	
    delete imgData;																			// free the temporary height data
    return 1;
}
void TerrainTessellationScene::initialise()
{
    m_material = MaterialPtr( new Material );
    m_material->setShaders( ":/shaders/terraintessellation.vert",
                            ":/shaders/terraintessellation.tcs",
                            ":/shaders/terraintessellation.tes",
                            ":/shaders/terraintessellation.geom",
                            ":/shaders/terraintessellation.frag" );

    QImage heightMapImage( "../../../opengl/assets/textures/heightmap-1024x1024.png" );
    TexturePtr heightMap( new Texture );
    heightMap->create();
    heightMap->bind();
    heightMap->setImage( heightMapImage );

    SamplerPtr sampler( new Sampler );
    sampler->create();
    sampler->setMinificationFilter( GL_LINEAR );
    sampler->setMagnificationFilter( GL_LINEAR );
    sampler->setWrapMode( Sampler::DirectionS, GL_CLAMP_TO_EDGE );
    sampler->setWrapMode( Sampler::DirectionT, GL_CLAMP_TO_EDGE );

    m_material->setTextureUnitConfiguration( 0, heightMap, sampler, QByteArrayLiteral( "heightMap" ) );


    // Create a renderable object
    prepareVertexBuffers( heightMapImage.size() );
    prepareVertexArrayObject();

    // Enable depth testing
    glEnable( GL_DEPTH_TEST );

    m_funcs = m_context->versionFunctions<QOpenGLFunctions_4_0_Core>();
    if ( !m_funcs )
        qFatal( "Could not obtain required OpenGL context version" );
    m_funcs->initializeOpenGLFunctions();
}
Esempio n. 6
0
Terrain::Terrain(const SystemBody *body) :
	m_seed(body->GetSeed()),
	m_rand(body->GetSeed()),
	m_heightScaling(0),
	m_minh(0),
	m_minBody(body)
{

	// load the heightmap
	if (!body->GetHeightMapFilename().empty()) {
		RefCountedPtr<FileSystem::FileData> fdata = FileSystem::gameDataFiles.ReadFile(body->GetHeightMapFilename());
		if (!fdata) {
			Output("Error: could not open file '%s'\n", body->GetHeightMapFilename().c_str());
			abort();
		}

		ByteRange databuf = fdata->AsByteRange();

		Sint16 minHMap = INT16_MAX, maxHMap = INT16_MIN;
		Uint16 minHMapScld = UINT16_MAX, maxHMapScld = 0;

		// XXX unify heightmap types
		switch (body->GetHeightMapFractal()) {
		case 0: {
			Uint16 v;
			bufread_or_die(&v, 2, 1, databuf);
			m_heightMapSizeX = v;
			bufread_or_die(&v, 2, 1, databuf);
			m_heightMapSizeY = v;
			const Uint32 heightmapPixelArea = (m_heightMapSizeX * m_heightMapSizeY);

			std::unique_ptr<Sint16[]> heightMap(new Sint16[heightmapPixelArea]);
			bufread_or_die(heightMap.get(), sizeof(Sint16), heightmapPixelArea, databuf);
			m_heightMap.reset(new double[heightmapPixelArea]);
			double *pHeightMap = m_heightMap.get();
			for (Uint32 i = 0; i < heightmapPixelArea; i++) {
				const Sint16 val = heightMap.get()[i];
				minHMap = std::min(minHMap, val);
				maxHMap = std::max(maxHMap, val);
				// store then increment pointer
				(*pHeightMap) = val;
				++pHeightMap;
			}
			assert(pHeightMap == &m_heightMap[heightmapPixelArea]);
			//Output("minHMap = (%hd), maxHMap = (%hd)\n", minHMap, maxHMap);
			break;
		}

		case 1: {
			Uint16 v;
			// XXX x and y reversed from above *sigh*
			bufread_or_die(&v, 2, 1, databuf);
			m_heightMapSizeY = v;
			bufread_or_die(&v, 2, 1, databuf);
			m_heightMapSizeX = v;
			const Uint32 heightmapPixelArea = (m_heightMapSizeX * m_heightMapSizeY);

			// read height scaling and min height which are doubles
			double te;
			bufread_or_die(&te, 8, 1, databuf);
			m_heightScaling = te;
			bufread_or_die(&te, 8, 1, databuf);
			m_minh = te;

			std::unique_ptr<Uint16[]> heightMapScaled(new Uint16[heightmapPixelArea]);
			bufread_or_die(heightMapScaled.get(), sizeof(Uint16), heightmapPixelArea, databuf);
			m_heightMap.reset(new double[heightmapPixelArea]);
			double *pHeightMap = m_heightMap.get();
			for (Uint32 i = 0; i < heightmapPixelArea; i++) {
				const Uint16 val = heightMapScaled[i];
				minHMapScld = std::min(minHMapScld, val);
				maxHMapScld = std::max(maxHMapScld, val);
				// store then increment pointer
				(*pHeightMap) = val;
				++pHeightMap;
			}
			assert(pHeightMap == &m_heightMap[heightmapPixelArea]);
			//Output("minHMapScld = (%hu), maxHMapScld = (%hu)\n", minHMapScld, maxHMapScld);
			break;
		}

		default:
			assert(0);
		}
	}

	switch (Pi::detail.textures) {
	case 0:
		textures = false;
		m_fracnum = 2;
		break;
	default:
	case 1:
		textures = true;
		m_fracnum = 0;
		break;
	}

	switch (Pi::detail.fracmult) {
	case 0: m_fracmult = 100; break;
	case 1: m_fracmult = 10; break;
	case 2: m_fracmult = 1; break;
	case 3: m_fracmult = 0.5; break;
	default:
	case 4: m_fracmult = 0.1; break;
	}

	m_sealevel = Clamp(body->GetVolatileLiquid(), 0.0, 1.0);
	m_icyness = Clamp(body->GetVolatileIces(), 0.0, 1.0);
	m_volcanic = Clamp(body->GetVolcanicity(), 0.0, 1.0); // height scales with volcanicity as well
	m_surfaceEffects = 0;

	const double rad = m_minBody.m_radius;

	// calculate max height
	if (!body->GetHeightMapFilename().empty() && body->GetHeightMapFractal() > 1) { // if scaled heightmap
		m_maxHeightInMeters = 1.1 * pow(2.0, 16.0) * m_heightScaling; // no min height required as it's added to radius in lua
	} else {
		// max mountain height for earth-like planet (same mass, radius)
		m_maxHeightInMeters = std::max(100.0, (9000.0 * rad * rad * (m_volcanic + 0.5)) / (body->GetMass() * 6.64e-12));
		m_maxHeightInMeters = std::min(rad, m_maxHeightInMeters); // small asteroid case
	}
	// and then in sphere normalized j**z
	m_maxHeight = m_maxHeightInMeters / rad;
	//Output("%s: max terrain height: %fm [%f]\n", m_minBody.name.c_str(), m_maxHeightInMeters, m_maxHeight);
	m_invMaxHeight = 1.0 / m_maxHeight;
	m_planetRadius = rad;
	m_planetEarthRadii = rad / EARTH_RADIUS;

	// Pick some colors, mainly reds and greens
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_rockColor)); i++) {
		double r, g, b;
		r = m_rand.Double(0.3, 1.0);
		g = m_rand.Double(0.3, r);
		b = m_rand.Double(0.3, g);
		r = std::max(b, r * body->GetMetallicity());
		g = std::max(b, g * body->GetMetallicity());
		m_rockColor[i] = vector3d(r, g, b);
	}

	// Pick some darker colours mainly reds and greens
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_darkrockColor)); i++) {
		double r, g, b;
		r = m_rand.Double(0.05, 0.3);
		g = m_rand.Double(0.05, r);
		b = m_rand.Double(0.05, g);
		r = std::max(b, r * body->GetMetallicity());
		g = std::max(b, g * body->GetMetallicity());
		m_darkrockColor[i] = vector3d(r, g, b);
	}

	// grey colours, in case you simply must have a grey colour on a world with high metallicity
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_greyrockColor)); i++) {
		double g;
		g = m_rand.Double(0.3, 0.9);
		m_greyrockColor[i] = vector3d(g, g, g);
	}

	// Pick some plant colours, mainly greens
	// TODO take star class into account
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_plantColor)); i++) {
		double r, g, b;
		g = m_rand.Double(0.3, 1.0);
		r = m_rand.Double(0.3, g);
		b = m_rand.Double(0.2, r);
		g = std::max(r, g * body->GetLife());
		b *= (1.0 - body->GetLife());
		m_plantColor[i] = vector3d(r, g, b);
	}

	// Pick some darker plant colours mainly greens
	// TODO take star class into account
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_darkplantColor)); i++) {
		double r, g, b;
		g = m_rand.Double(0.05, 0.3);
		r = m_rand.Double(0.00, g);
		b = m_rand.Double(0.00, r);
		g = std::max(r, g * body->GetLife());
		b *= (1.0 - body->GetLife());
		m_darkplantColor[i] = vector3d(r, g, b);
	}

	// Pick some sand colours, mainly yellow
	// TODO let some planetary value scale this colour
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_sandColor)); i++) {
		double r, g, b;
		r = m_rand.Double(0.6, 1.0);
		g = m_rand.Double(0.6, r);
		//b = m_rand.Double(0.0, g/2.0);
		b = 0;
		m_sandColor[i] = vector3d(r, g, b);
	}

	// Pick some darker sand colours mainly yellow
	// TODO let some planetary value scale this colour
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_darksandColor)); i++) {
		double r, g, b;
		r = m_rand.Double(0.05, 0.6);
		g = m_rand.Double(0.00, r);
		//b = m_rand.Double(0.00, g/2.0);
		b = 0;
		m_darksandColor[i] = vector3d(r, g, b);
	}

	// Pick some dirt colours, mainly red/brown
	// TODO let some planetary value scale this colour
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_dirtColor)); i++) {
		double r, g, b;
		r = m_rand.Double(0.3, 0.7);
		g = m_rand.Double(r - 0.1, 0.75);
		b = m_rand.Double(0.0, r / 2.0);
		m_dirtColor[i] = vector3d(r, g, b);
	}

	// Pick some darker dirt colours mainly red/brown
	// TODO let some planetary value scale this colour
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_darkdirtColor)); i++) {
		double r, g, b;
		r = m_rand.Double(0.05, 0.3);
		g = m_rand.Double(r - 0.05, 0.35);
		b = m_rand.Double(0.0, r / 2.0);
		m_darkdirtColor[i] = vector3d(r, g, b);
	}

	// These are used for gas giant colours, they are more m_random and *should* really use volatileGasses - TODO
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_gglightColor)); i++) {
		double r, g, b;
		r = m_rand.Double(0.0, 0.5);
		g = m_rand.Double(0.0, 0.5);
		b = m_rand.Double(0.0, 0.5);
		m_gglightColor[i] = vector3d(r, g, b);
	}
	//darker gas giant colours, more reds and greens
	for (int i = 0; i < int(COUNTOF(m_entropy)); i++)
		m_entropy[i] = m_rand.Double();
	for (int i = 0; i < int(COUNTOF(m_ggdarkColor)); i++) {
		double r, g, b;
		r = m_rand.Double(0.0, 0.3);
		g = m_rand.Double(0.0, r);
		b = m_rand.Double(0.0, std::min(r, g));
		m_ggdarkColor[i] = vector3d(r, g, b);
	}
}
Esempio n. 7
0
//------------------------------------------------------------------------------
void CTerrain::updateVirtual()
{
  const uint32 stepX = 1 << terrain.stepX; // edges count (vertices: step + 1)
  const uint32 stepZ = 1 << terrain.stepZ;
  const uint32 divStepX = 1 << terrain.divStepX; // count of chunks
  const uint32 divStepZ = 1 << terrain.divStepZ;
  const uint32 stepMeshX = stepX / divStepX; // number of edges in chunk
  const uint32 stepMeshZ = stepZ / divStepZ;

  QVector<SVertex> vx((stepX + 1) * (stepZ + 1));
  QVector<float> heightMap((stepX + 1) * (stepZ + 1), 0.0f);
  QVector<bool> usedHeightMap((stepX + 1) * (stepZ + 1), false);
  QVector<int32> heightMapLayer((stepX + 1) * (stepZ + 1), -1);
  float depth = 1.0f;

  srand(terrain.seed);

  // compute heightmap
  if(!terrain.landBorder)
  {
    heightMap[0] = rndHeight();
    heightMap[stepX] = rndHeight();
    heightMap[(stepX + 1) * stepZ] = rndHeight();
    heightMap[(stepX + 1) * stepZ + stepX] = rndHeight();
  }
  usedHeightMap[0] = true;
  usedHeightMap[stepX] = true;
  usedHeightMap[(stepX + 1) * stepZ] = true;
  usedHeightMap[(stepX + 1) * stepZ + stepX] = true;

  fractalGrid(&heightMap[0], &usedHeightMap[0], stepX, stepZ, stepX, stepZ, 0, depth);

  // compute positions
  float x = 0.0f;
  float z = 0.0f;
  const float xInc = 1.0f / stepX;
  const float zInc = 1.0f / stepZ;

  for(uint32 i = 0; i <= stepX; i++, x += xInc)
  {
    for(uint32 j = 0; j <= stepZ; j++, z += zInc)
    {
      const uint32 k = ((stepX + 1) * i + j);
      vx[k].position = QVector3D(x - 0.5f, heightMap[k] * terrain.heightMultiplier, z - 0.5f);
      vx[k].normal = QVector3D(0.0, 1.0, 0.0);
      vx[k].texCoord = QVector2D(-x * 10, z * 10);
      vx[k].color = QVector3D(1.0, 0.0, 0.0);
      vx[k].color2 = QVector3D(0.0, 0.0, 0.0);
    }
    z = 0.0f;
  }

  // compute normals, tangents, bitangents
  for(int32 v = 0; v < vx.size(); v++)
  {
    uint32 x = v % (stepX + 1);
    uint32 z = v / (stepX + 1);

    if((x > 0) && (x < stepX) && (z > 0) && (z < stepZ))
    {
      QVector3D &vC = vx[v].position;
      QVector3D &vL = vx[v - 1].position;
      QVector3D &vR = vx[v + 1].position;
      QVector3D &vT = vx[v - stepX - 1].position;
      QVector3D &vB = vx[v + stepX + 1].position;
      vx[v].normal  = QVector3D::normal(vC, vL, vT);
      vx[v].normal += QVector3D::normal(vC, vT, vR);
      vx[v].normal += QVector3D::normal(vC, vR, vB);
      vx[v].normal += QVector3D::normal(vC, vB, vL);
      vx[v].normal.normalize();
      vx[v].normalTangent = QVector3D(vx[v].normal.y(), -vx[v].normal.x(), -vx[v].normal.z());
      vx[v].normalBitangent = QVector3D(-vx[v].normal.x(), -vx[v].normal.z(), vx[v].normal.y());
    }
  }

  // compute colors by layers
  for(int32 v = 0; v < vx.size(); v++)
  {
    for(int32 l = 0; l != terrain.layers.size(); l++)
    {
      const SMaterialLayer *layer = &terrain.layers[l];
      if(!(((layer->useHeightLimit) && ((vx[v].position.y() < layer->minHeight) || (vx[v].position.y() > layer->maxHeight))) ||
         ((layer->useSlopeLimit) && (((1.0f - vx[v].normal.y()) < layer->minSlope) || ((1.0f - vx[v].normal.y()) > layer->maxSlope)))))
      {
        vx[v].color = layer->color.toVector3D() * layer->color.w();
        heightMapLayer[v] = l;
      }
    }
  }

  /*for(int32 v = 0; v < vx.size(); v++)
    qDebug(QString("y %1, x %2: %3").arg(v / (stepX + 1)).arg(v % (stepX + 1)).arg(heightMapLayer[v]).toStdString().c_str());*/

  // divide to meshes, fill model meshes
  /*model.materials.clear();
  model.materials.push_back(SMaterial(context->getShaders()->getShaderProgram(NShader::PROGRAM_TERRAIN),
    context->getMaps()->addMap(SMap(":/maps/data/maps/rocks00n.png")),
    context->getMaps()->addMap(SMap(":/maps/data/maps/rocks00n.png")),
    context->getMaps()->addMap(SMap(":/maps/data/maps/rocks00n.png"))));*/

  /*model.meshes.clear();
  for(uint32 m = 0; m < (divStepX * divStepZ); m++)
  {
    model.meshes.push_back(SMesh());
    SMesh *mesh = &model.meshes.back();

    mesh->transformation = SMatrix::composeTransformation(mesh->position, mesh->rotation, mesh->scale);

    mesh->faces.push_back(SFaces());
    SFaces *faces = &mesh->faces.back();

    mesh->vertices.resize((stepMeshX + 1) * (stepMeshZ + 1));
    faces->faces.resize(stepMeshX * stepMeshZ * NTerrain::FACE_BLOCK_SIZE);

    uint32 offset = (m / divStepZ) * stepMeshZ * (stepX + 1) + (m % divStepX) * stepMeshX;

    uint32 mCol2 = 0;
    for(uint32 mRow = 0; mRow <= stepMeshZ; mRow++, offset += (stepX + 1))
    {
      for(uint32 mCol = 0; mCol <= stepMeshX; mCol++, mCol2++)
      {
        mesh->vertices[mCol2] = vx[offset + mCol];
        if((mRow == stepMeshZ) || (mCol == stepMeshX))
          mesh->vertices[mCol2].color = QVector3D(0.8, 0.2, 0.2);
      }
    }

    for(uint32 i = 0; i < stepMeshX; i++)
    {
      for(uint32 j = 0; j < stepMeshZ; j++)
      {
        const uint32 k = (stepMeshX * i + j) * NTerrain::FACE_BLOCK_SIZE;
        const uint32 l0 = (stepMeshX + 1) * i + j + 0;
        const uint32 l1 = (stepMeshX + 1) * i + j + 1;
        const uint32 l2 = (stepMeshX + 1) * (i + 1) + j + 0;
        const uint32 l3 = (stepMeshX + 1) * (i + 1) + j + 1;
        faces->faces[k + 0] = SFace(l0, l1, l2);
        faces->faces[k + 1] = SFace(l2, l1, l3);
      }
    }
  }*/

  model.materials.clear();
  const CMap *noMap = context->getMaps()->getMap(NMap::DEFAULT_NORMAL); // default map
  model.meshes.clear();
  for(uint32 gz = 0; gz < divStepZ; gz++)
  {
    for(uint32 gx = 0; gx < divStepX; gx++)
    { // sub mesh
      //const uint32 groupBase = gz * divStepZ + gx;
      const uint32 vxGroupBase = gz * stepMeshZ * (stepX + 1) + gx * stepMeshX;

      //qDebug("new mesh");
      model.meshes.push_back(SMesh());
      SMesh *mesh = &model.meshes.back();
      mesh->transformation = SMatrix::composeTransformation(mesh->position, mesh->rotation, mesh->scale);

      for(uint32 ez = 0; ez < stepMeshZ; ez++)
      {
        for(uint32 ex = 0; ex < stepMeshX; ex++)
        { // two faces block
          const uint32 vx0 = vxGroupBase + ez * (stepX + 1) + ex;
          const uint32 vx1 = vx0 + 1;
          const uint32 vx2 = vx0 + (stepX + 1);
          const uint32 vx3 = vx2 + 1;

          for(uint8 v = 0; v < NTerrain::FACE_BLOCK_SIZE; v++)
          { // one face
            const uint32 face[NModel::FACE_SIZE] = { (!v) ? vx0 : vx2, (!v) ? vx1 : vx1, (!v) ? vx2 : vx3 };

            // material signature
            QSet<int32> faceSet;
            faceSet.insert(heightMapLayer[face[0]]);
            faceSet.insert(heightMapLayer[face[1]]);
            faceSet.insert(heightMapLayer[face[2]]);
            QVector<int32> faceMats = faceSet.toList().toVector();
            qSort(faceMats.begin(), faceMats.end());
            //qDebug(QString("%1 %2 %3 : %4 %5 %6 : %7").arg(face[0]).arg(face[1]).arg(face[2]).arg(heightMapLayer[face[0]]).arg(heightMapLayer[face[1]]).arg(heightMapLayer[face[2]]).arg(faceMats.size()).toStdString().c_str());
            /*for(int32 i : faceMats)
              qDebug(QString("%1").arg(i).toStdString().c_str());*/

            SFaces *faces = NULL;
            for(auto f = mesh->faces.begin(); f != mesh->faces.end(); f++)
            { // find faces group by material signature
              if(!f->material)
              {
                //qDebug("chyba mat chybi");
                break;
              }
              else if(f->material->layerVx == faceMats)
              {
                //qDebug("nasel");
                faces = &(*f);
                break;
              }
            }

            if(!faces)
            {
              SMaterial *material = NULL;
              for(auto m = model.materials.begin(); m != model.materials.end(); m++)
              { // find previous used material
                if(m->layerVx == faceMats)
                {
                  //qDebug("nenasel, ale predchozí mat ano");
                  material = &(*m);
                  break;
                }
              }
              if(!material)
              {
                //qDebug("nenasel");
                const CMap *maps[NModel::FACE_SIZE];
                for(int32 i = 0; static_cast<uint32>(i) < NModel::FACE_SIZE; i++)
                {
                  maps[i] = (faceMats.size() > i) ? ((faceMats[i] != -1) ? terrain.layers[faceMats[i]].detailTexture : noMap) : NULL;
                  /*if(maps[i])
                    qDebug(maps[i]->getMap()->file.toStdString().c_str());
                  else
                    qDebug("no map");*/
                }

                model.materials.push_back(SMaterial(context->getShaders()->getShaderProgram(NShader::PROGRAM_TERRAIN), NULL, NULL, NULL, maps[0], NULL, NULL, NULL, NULL, NULL, maps[1], maps[2], faceMats));
                material = &model.materials.back();
              }
              mesh->faces.push_back(SFaces(material));
              faces = &mesh->faces.back();
            }

            uint16 newFace[NModel::FACE_SIZE];
            SVertex newVx[NModel::FACE_SIZE] = { vx[face[0]], vx[face[1]], vx[face[2]] };

            for(uint32 i = 0; i < NModel::FACE_SIZE; i++)
            { // set texture using multiplier
              if(heightMapLayer[face[i]] == faceMats[0])
                newVx[i].color2.setX(1.0f);
              else if(heightMapLayer[face[i]] == faceMats[1])
                newVx[i].color2.setY(1.0f);
              else if(heightMapLayer[face[i]] == faceMats[2])
                newVx[i].color2.setZ(1.0f);
              //qDebug(QString("face %1: %2 %3 %4").arg(i).arg(newVx[i].color2.x()).arg(newVx[i].color2.y()).arg(newVx[i].color2.z()).toStdString().c_str());

              bool found = false;
              for(int32 v = 0; v < mesh->vertices.size(); v++)
              { // find same vertex
                if((mesh->vertices[v].position == newVx[i].position) && (mesh->vertices[v].color2 == newVx[i].color2))
                {
                  //qDebug("same vx found");
                  found = true;
                  newFace[i] = v;
                  break;
                }
              }
              if(!found)
              {
                //qDebug("same vx not found");
                newFace[i] = mesh->vertices.size();
                mesh->vertices.push_back(newVx[i]);
              }
            }
            faces->faces.push_back(SFace(newFace[0], newFace[1], newFace[2]));
          }
        }
      }
      //qDebug(QString("-------- face groups: %1").arg(mesh->faces.size()).toStdString().c_str());
    }
  }
  //qDebug(QString("-------- meshes: %1").arg(model.meshes.size()).toStdString().c_str());
}
Esempio n. 8
0
void MapGenerator::GenerateMap(const int width, const int height, const float resource, const float obstacle)
{
	std::vector<int>& mHeightMap			= pSceneGame->mHeightMap;
	std::vector<int>& mGameMap				= pSceneGame->mGameMap;
	std::vector<Scene_Game::LightMapData>& mLightMap	= pSceneGame->mLightMap;

	std::vector<double> heightMap(width);
	mHeightMap.resize(width);

	pSceneGame->iMapWidth = width;
	pSceneGame->iMapHeight = height;
	pSceneGame->iMapWidthPixel = width*BLOCK_SIZE;
	pSceneGame->iMapHeightPixel = height*BLOCK_SIZE;

	for (int i=0; i<width; i++)
	{
		heightMap[i] = (height*0.6+rand.NextDouble()*2);
	}

	// 당기기
	for (int i=0; i<width/20; i++)
	{
		int max_height = rand.Next()%41-20;
		double power = rand.NextDouble()*0.5+0.4;
		int seed_x = rand.Next()%width;
		while (max_height-->0)
		{
			double uplift = (max_height>0)? 1:-1;
			int offset = 0;
			while (abs(uplift)>0.1)
			{
				if (offset > 0)
					heightMap[(seed_x-offset+width)%width] += uplift;
				heightMap[(seed_x+offset)%width] += uplift;
				uplift *= power;
				offset++;
			}
		}
	}

	// 스무스
	for (int i=0; i<width; i++)
	{
		double h = 0;
		mHeightMap[i] = (int)((heightMap[(i-1+width)%width]
					+ heightMap[i]
					+ heightMap[(i+1)%width])/3);
	}

	// 생성
	mGameMap.resize(width*height);
	for (int i=0; i<width; i++)
	{
		int dirt = 6+rand.Next()%2;
		for (int j=0; j<height; j++)
		{
			if (j<height-mHeightMap[i])
				mGameMap[i+j*width] = BLOCK_AIR;
			else if (j >= (int)(height*0.7f)-1 && j<= (int)(height*0.7f)+1)
				mGameMap[i+j*width] = BLOCK_OBSIDIAN;
			else if (j >= height-2)
				mGameMap[i+j*width] = BLOCK_BEDROCK;
			else if(dirt)
			{
				mGameMap[i+j*width] = BLOCK_DIRT;
				dirt--;
			}
			else
				mGameMap[i+j*width] = BLOCK_ROCK;
		}
	}

	// 호수를 만든다.
	for (int i=0; i<width/40; i++) {
		int seed_x = rand.Next()%width;
		int seed_y = 0;
		bool retry = false;
		// 씨드를 뿌린다.
		while (true) {
			bool stop = true;
			while (mGameMap[seed_x+seed_y*width] == 0)
				seed_y++;
			if (mGameMap[seed_x+seed_y*width] == BLOCK_WATER) {
				retry = true;
				break;
			}
			for (int j=-5; j<=5; j++)
			{
				if (mGameMap[(seed_x+j+width)%width+seed_y*width] == 0) {
					stop = false;
					seed_x = (seed_x+j+width)%width;
					seed_y += 1;
					break;
				}
			}
			if (stop)
				break;
		}
		if (retry)
		{
			i--;
			continue;
		}
		// 그 자리에서부터 땅을 파고 들어간다.
		// 위에 있는 땅을 제거한다.
		double w = 3+rand.Next()%7;
		for (int k = seed_y; k>=seed_y-3; k--)
		{
			for (int j = (int)floor(-w/2); j < w/2; j++)
			{
				mGameMap[(seed_x+j+width)%width+k*width] = 0;
			}
		}
		while (w >= 1.5)
		{
			for (int j = (int)floor(-w/2); j < w/2; j++)
			{
				mGameMap[(seed_x+j+width)%width+seed_y*width] = BLOCK_WATER;
			}
			w *= 0.75;
			seed_y += 1;
			if (w >= 2)
				seed_x += rand.Next()%3-1;
		}
	}

	// 본부를 만든다.
	while (true)
	{
		int seed_x = rand.Next()%(width-30)+15;
		int seed_y = 0;
		bool retry = false;
		// 씨드를 뿌린다.
		while (true) {
			bool stop = true;
			while (mGameMap[seed_x+seed_y*width] == 0)
				seed_y++;
			if (mGameMap[seed_x+seed_y*width] == BLOCK_WATER) {
				retry = true;
				break;
			}
			for (int j=-10; j<=10; j++)
			{
				if (mGameMap[(seed_x+j+width)%width+seed_y*width] == 0) {
					stop = false;
					seed_x = (seed_x+j+width)%width;
					seed_y += 1;
					break;
				}
			}
			if (stop)
				break;
		}
		if (retry) continue;
		// 그 자리에 공간을 만든다.
		// 6X4
		for (int k = seed_y-1; k>=0; k--)
		{
			for (int j = -4; j <= 4; j++)
			{
				mGameMap[(seed_x+j+width)%width+k*width] = 0;
			}
		}
		for (int j = -4; j <= 4; j++)
		{
			mGameMap[(seed_x+j+width)%width+(seed_y+1)*width] = 
				mGameMap[(seed_x+j+width)%width+seed_y*width] = BLOCK_BEDROCK;
		}

		pSceneGame->mBaseCamp.SetBasePos(seed_x, seed_y-1);
		pSceneGame->SetPlayerPos(seed_x, seed_y-1);

		break;
	}

	int size = width*height;
	MakeMine(BLOCK_WATER, (int)(size*0.0013f*resource), 3, 0);	// 40
	MakeMine(BLOCK_MAGMA, (int)(size*0.0012f*obstacle), 3, (int)(height*0.6f));	// 35
	MakeMine(BLOCK_OBSIDIAN, (int)(size*0.001f*obstacle), 3, (int)(height*0.7f));				// 30
	MakeMine(BLOCK_MINERAL, (int)(size*0.0025f*resource), 5, 0);		// 75
	MakeMine(BLOCK_COAL, (int)(size*0.0017f*resource), 4, 0);		// 50
	MakeMine(BLOCK_OIL, (int)(size*0.001f*resource), 5, pSceneGame->mBaseCamp.iY+30);		// 30
	MakeMine(BLOCK_URANIUM, (int)(size*0.0007f*resource), 2, pSceneGame->mBaseCamp.iY+(height-pSceneGame->mBaseCamp.iY)/2);	// 20
	MakeMine(BLOCK_UNOBTAINIUM, (int)(size*0.0001f*resource), 5, height-20);	// 3
	MakeMine(BLOCK_COOKIE, 1, 2, height-4);	// 1

	// 라이트맵을 초기화한다.
	mLightMap.resize(width*height);
	for (int i=0; i<height; i++)
	{
		for (int j=0; j<width; j++)
		{
			if (mGameMap[j+i*width] == BLOCK_AIR)
			{
				mLightMap[j+i*width].light = mLightMap[j+i*width].base_light = 255;
				mLightMap[j+i*width].lighted = true;
// 				for (int k=0; k<5;k++)
// 				{
// 					if (i+k >= height) break;
// 					mLightMap[j+(i+k)*width].light += 10;
// 				}
			}
			else
			{
				mLightMap[j+i*width].light = mLightMap[j+i*width].base_light = min(max(255-(i-pSceneGame->mBaseCamp.iY)*10, 0), 255);
				mLightMap[j+i*width].lighted = mLightMap[j+i*width].base_light>64;
			}
		}
	}
}
Esempio n. 9
0
Chunk::Chunk(int x, int z, unsigned int seed)
: m_x(x), m_z(z)
{
	PerlinNoise heightMap(seed);
	PerlinNoise noise(seed + 1);
	PerlinNoise caves(seed + 2);

	// Lower means more mountains and valleys
	const float SMOOTHNESS = 25.0;

	// Larger means flatter
	const float DETAIL = 1 / 16.0;

	// Larger means more overhangs and caves
	const float CARVING = 2.0;

	// Larger means more caves
	const float CAVES = 3.0;

	for (int i = 0; i < SIZE; ++i)
	{
		for (int j = 0; j < SIZE; ++j)
		{
			float heightSample = heightMap.sample(SMOOTHNESS * (x * SIZE + i), 0.0, SMOOTHNESS * (z * SIZE + j));
			float height = (DEPTH / 2) + SCALE * heightSample; //(0.5 + 0.25 * heightSample);

			for (int k = 0; k < DEPTH; ++k)
			{
				float sample = noise.sample(DETAIL * (x * SIZE + i), CARVING * DETAIL * k, DETAIL * (z * SIZE + j));
				sample += (height - k) / (SCALE / 4.0);

				// Ground threshold
				if (sample > 0.0f)
				{
					// Stone threshold
					if (sample > 0.5f)
						newBlock(x * SIZE + i, k, z * SIZE + j, BlockLibrary::STONE);
					else
						newBlock(x * SIZE + i, k, z * SIZE + j, BlockLibrary::DIRT);
				}
			}
		}
	}

	// Convert top-level dirt to grass
	for (int i = 0; i < SIZE; ++i)
	{
		for (int j = 0; j < SIZE; ++j)
		{
			// Fill any gap below sea level with water
			for (int k = 0; k < 0.45 * DEPTH; ++k)
			{
				Coordinate location(x * SIZE + i, k, z * SIZE + j);
				if (!get(location))
				{
					newBlock(location.x, location.y, location.z, BlockLibrary::WATER);
				}
			}
		}
	}

	// Cut out some caves
	for (int i = 0; i < SIZE; ++i)
	{
		for (int j = 0; j < SIZE; ++j)
		{
			for (int k = 0; k < DEPTH; ++k)
			{
				Coordinate location(x * SIZE + i, k, z * SIZE + j);
				if (m_blocks.find(location) == m_blocks.end())
					continue;

				float caveSample = caves.sample(DETAIL * (x * SIZE + i), CAVES * DETAIL * k, DETAIL * (z * SIZE + j));
				caveSample = pow(caveSample, 3.0);

				// Ground threshold
				if (caveSample <= -0.1)
				{
					removeBlock(location);
				}
			}

			// Convert top-level dirt to grass
			for (int k = DEPTH - 1; k >= 0; --k)
			{
				Coordinate location(x * SIZE + i, k, z * SIZE + j);

				if (get(location))
				{
					auto& block = m_blocks[location];
					if (block->blockType == BlockLibrary::DIRT)
						block->blockType = BlockLibrary::GRASS;

					// We only work on the top-most block in a column.
					break;
				}
			}
		}
	}
}
Esempio n. 10
0
void terrain(Mesh *mesh) {
    QImage heightMap("clouds2.png");
    heightMap = heightMap.convertToFormat(QImage::Format_ARGB32);
    int height = heightMap.height();
    int width = heightMap.width();
    int verticesCount = height * width;
    int indicesCount = 2 * 3 * (height - 1) * (width - 1);
    vec3f *vertices = (vec3f *) malloc(verticesCount * sizeof(vec3f));
    int i = 0;
    int h = height >> 1;
    int w = width >> 1;
    for (int y = 0; y < height; ++y) {
        int *p = (int *) heightMap.scanLine(y);
        for (int x = 0; x < width; ++x) {
            vertices[i].x = -w + x;
            vertices[i].y = (GLfloat) (p[x] & 0xff) / 5.0f;
            vertices[i].z = -h + y;
            ++i;
        }
    }
    for (int i = 0; i < verticesCount; ++i) {
        vertices[i].x *= 2.0f;
        vertices[i].z *= 2.0f;
    }
    uint *indices = (uint *) malloc(indicesCount * sizeof(uint));
    i = 0;
    for (int y = 0; y < height - 1; ++y) {
        for (int x = 0; x < width - 1; ++x) {
            indices[i++] = (y + 1) * width + x;
            indices[i++] = (y + 1) * width + x + 1;
            indices[i++] = y * width + x + 1;
            indices[i++] = (y + 1) * width + x;
            indices[i++] = y * width + x + 1;
            indices[i++] = y * width + x;
        }
    }
    vec3f *normals = (vec3f *) malloc(verticesCount * sizeof(vec3f));
    memset(normals, 0, verticesCount * sizeof(vec3f));
    for (int i = 0; i < indicesCount; i += 3) {
        vec3f a = vertices[indices[i + 1]] - vertices[indices[i]];
        vec3f b = vertices[indices[i + 2]] - vertices[indices[i + 1]];
        vec3f c = normalize(cross(a, b));
        normals[indices[i]] = normals[indices[i]] + c;
        normals[indices[i + 1]] = normals[indices[i + 1]] + c;
        normals[indices[i + 2]] = normals[indices[i + 2]] + c;
    }
    for (int i = 0; i < verticesCount; ++i) {
        normals[i] = normalize(normals[i]);
    }
    float *fogCoordinates = (float *) malloc(verticesCount * sizeof(float));
    for (int i = 0; i < verticesCount; ++i) {
        fogCoordinates[i] = 255.0f - vertices[i].y;
    }
    float *textureCoordinates = (float *) malloc(2 * verticesCount * sizeof(float));
    i = 0;
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            float s = (float) x / (float) (width - 1);
            float t = (float) y / (float) (height - 1);
            textureCoordinates[i++] = s;
            textureCoordinates[i++] = t;
        }
    }
    mesh->loadVertices(vertices, verticesCount * sizeof(vec3f));
    mesh->loadNormals(normals, verticesCount * sizeof(vec3f));
    mesh->loadFogCoordinates(fogCoordinates, verticesCount * sizeof(float));
    mesh->loadTexture2DCoordinates(textureCoordinates, 2 * verticesCount * sizeof(float));
    mesh->loadIndices(indices, indicesCount * sizeof(uint));
    free(vertices);
    free(normals);
    free(fogCoordinates);
    free(textureCoordinates);
    free(indices);
}
graphics::Model *TerrainGenerator::simplexTerrain2(float xRange, float zRange, float vertexDensity, float octaves[], float yScales[], int nOctaves)
{
    graphics::Model* model = new graphics::Model;
    graphics::ModelGroup group;
    cv::Mat heightMap(xRange*vertexDensity, zRange*vertexDensity, CV_32FC1);
    cv::Mat heightMapThresh(xRange*vertexDensity, zRange*vertexDensity, CV_32FC1);
    int step = heightMap.cols;

    qDebug() << "Number of octaves: " << nOctaves;

    float y = 0;

    // find max scale to scale correctly when saved to cv::Mat
    float maxScale = 0;
    for (int i = 0; i < nOctaves; i++){
        if (yScales[i] > maxScale){
            maxScale = yScales[i];
        }
    }

    qDebug() << "MaxScale: " << maxScale;

    // Generate height map and texture coordinates
    for (int x = 0; x < xRange*vertexDensity; x++){
        for (int z = 0; z < zRange*vertexDensity; z++){

            y = 0;
            for(int i = 0; i < nOctaves; i++){
                y += SimplexNoise1234::noise(x/octaves[i], z/octaves[i]) * yScales[i];
            }

            group.vertices.push_back(QVector3D((float)x/vertexDensity, y, (float)z/vertexDensity));

            group.texCoords.push_back(QVector3D((float)x/(xRange*vertexDensity),(float)z/(zRange*vertexDensity), 0));

            heightMap.at<float>(x,z) = (y + maxScale) / (2*maxScale);
        }
    }

    //cv::imshow("heightMap", heightMap);
    cv::threshold(heightMap, heightMapThresh, 0.5, 1, 1);
    //cv::imshow("heightMapThresh", heightMapThresh);

    qDebug() << "step: " << step;

    // Tie vertices together. openGL indexing starts at 0 tydligen..
    for (int x = 1; x < xRange*vertexDensity; x++){
        for (int z = 1; z < zRange*vertexDensity; z++){

            // First triangle
            group.indices.push_back( (x-1)*step + z-1);  // 0
            group.indices.push_back( x*step     + z  );  // 3
            group.indices.push_back( x*step     + z-1);  // 2

            // Second triangle
            group.indices.push_back( (x-1)*step + z-1);  // 0
            group.indices.push_back( (x-1)*step + z  );  // 1
            group.indices.push_back( x*step     + z  );  // 3
        }
    }

    float y00, y01, y10;
    QVector3D tangent1, tangent2;
    QVector3D normal;

    // Calculate normals
    for (int z = 0; z < zRange*vertexDensity; z++){
        group.normals.push_back(QVector3D(0,1,0));
    }

    for (int x = 1; x < xRange*vertexDensity; x++){
        group.normals.push_back(QVector3D(0,1,0));
        for (int z = 1; z < zRange*vertexDensity; z++){

            y00 = heightMap.at<float>(x-1,z-1);
            y01 = heightMap.at<float>(x-1,z);
            y10 = heightMap.at<float>(x,z-1);

            tangent1 = QVector3D(1, y10-y00, 0);
            tangent2 = QVector3D(0, y01-y00, 1);

            normal = normal.crossProduct(tangent2, tangent1);
            normal.normalize();

            group.normals.push_back(normal);
        }
    }

    model->groups.push_back(group);
    model->uploadToGPU();

    return model;
}
Esempio n. 12
0
Terrain::Terrain( const QString & heightMapPath, const QVector3D & size, const QVector3D & offset, const int & smoothingPasses )
{
	QImage heightMap( heightMapPath );
	if( heightMap.isNull() )
	{
		qFatal( "\"%s\" not found!", heightMapPath.toLocal8Bit().constData() );
	}
	mMapSize = heightMap.size();
	mSize = size;
	mOffset = offset;
	mToMapFactor = QSizeF( (float)mMapSize.width()/(float)mSize.x(), (float)mMapSize.height()/(float)mSize.z() );

	mVertices.resize( mMapSize.width() * mMapSize.height() );

	// prepare positions
	QVector<QVector3D> rawPositions;
	for( int h=0; h<mMapSize.height(); h++ )
	{
		for( int w=0; w<mMapSize.width(); w++ )
		{
			rawPositions.push_back( offset + QVector3D(
				w*(mSize.x()/mMapSize.width()),
				(float)qRed( heightMap.pixel( w, h ) )*(mSize.y()/256.0),
				h*(mSize.z()/mMapSize.height())
			) );
		}
	}

	// smoothed positions
	for( int i=0; i<smoothingPasses; i++ )
		rawPositions = smoothedPositions( rawPositions, mMapSize );

	// copy smoothed positions to vertex array
	for( int i=0; i<mVertices.size(); i++ )
	{
		mVertices[i].position = rawPositions[i];
	}

	// normals
	for( int h=0; h<mMapSize.height()-1; h++ )
	{
		for( int w=0; w<mMapSize.width()-1; w++ )
		{
			vertex( w, h ).normal = QVector3D::normal(
				getVertexPosition( w,   h ),
				getVertexPosition( w,   h+1 ),
				getVertexPosition( w+1, h )
			);
		}
		vertex( mMapSize.width()-1, h ).normal = QVector3D(0,1,0);	// last vertex in row
	}
	for( int w=0; w<mMapSize.width(); w++ )
	{
		vertex( w, mMapSize.height()-1 ).normal = QVector3D(0,1,0);	// last row
	}

	// texture coordinates
	for( int h=0; h<mMapSize.height(); h++ )
	{
		for( int w=0; w<mMapSize.width(); w++ )
		{
			vertex( w, h ).texCoord = QVector2D( w, h );
		}
	}
	mVertexBuffer = QGLBuffer( QGLBuffer::VertexBuffer );
	mVertexBuffer.create();
	mVertexBuffer.bind();
	mVertexBuffer.setUsagePattern( QGLBuffer::StaticDraw );
	mVertexBuffer.allocate( mVertices.data(), mVertices.size()*VertexP3fN3fT2f::size() );
	mVertexBuffer.release();

	// indices
	QVector<unsigned int> indices;
	for( int h=0; h<mMapSize.height()-1; ++h )
	{
		for( int w=0; w<mMapSize.width(); ++w )
		{
			indices.push_back( w + h*(unsigned int)mMapSize.width() );
			indices.push_back( w + (h+1)*(unsigned int)mMapSize.width() );
		}
	}
	mIndexBuffer = QGLBuffer( QGLBuffer::IndexBuffer );
	mIndexBuffer.create();
	mIndexBuffer.bind();
	mIndexBuffer.setUsagePattern( QGLBuffer::StaticDraw );
	mIndexBuffer.allocate( indices.data(), indices.size()*sizeof(unsigned int) );
	mIndexBuffer.release();
}