示例#1
0
文件: Block.cpp 项目: gbougard/NBK
	GLvoid CBlock::init()
	{
		// 1. setup visible surfaces		
		if (isLow())
		{
			visible[BFS_TOP]		= false;			
			visible[BFS_WATER_LAVA]	= isWater() || isLava();
			visible[BFS_BOTTOM]		= !visible[BFS_WATER_LAVA];
			visible[BFS_CEILING]	= true;
		}
		else
		{
			visible[BFS_TOP]		= true;
			visible[BFS_BOTTOM]		= false;
			visible[BFS_WATER_LAVA]	= false;
			visible[BFS_CEILING]	= false;
		}

		//visible[BFS_TOP]		= false; // uncomment to see the optimization

		vector2i tests[4] =
		{
			vector2i(0,1),	// BFS_FRONT
			vector2i(0,-1), // BFS_BACK
			vector2i(-1,0), // BFS_LEFT
			vector2i(1,0),	// BFS_RIGHT
		};  

		CBlock *testBlock = NULL;
		for (GLint i=BFS_FRONT; i<=BFS_RIGHT; i++)
		{
			testBlock = CV_GAME_MANAGER->getLevelManager()->getBlock(logicalPosition+tests[i]);
			visible[i] = isLow()?false:(testBlock && testBlock->isLow() || !testBlock);

			if (water || lava)
			{
				// since water and lava are submerged by 1 level we nned to handle them differently
				visible[i] = testBlock && (!testBlock->low || 
											testBlock->type==CV_BLOCK_TYPE_CLAIMED_LAND_ID ||
											testBlock->type==CV_BLOCK_TYPE_UNCLAIMED_LAND_ID);	
			}
		}

		// tmp 
		/*for (GLint v=BFS_FRONT+1; v<=BFS_WATER_LAVA; v++)
		{
			//if (v!=BFS_BOTTOM)
			{
				visible[v]=false;
			}
		}*/

		/*
			For every block change you must call:
			- block init
			- calc block height if needed
			- finalize
		*/
	}
示例#2
0
文件: Block.cpp 项目: gbougard/NBK
	bool CBlock::isBuildable(GLint playerID)
	{
		if (isWater() || isLava())
		{
			return true;
		}

		return (type == CV_BLOCK_TYPE_CLAIMED_LAND_ID && playerID == owner && !isSellable(playerID));
	}
void CPlanetTextureGenerator::genThreadWorker(const CHeightMap* heightMap, unsigned char* pixels, const unsigned int textureWidth, int part)
{	
	const unsigned int width = heightMap->getWidth();
	const unsigned int bpp = 4;

	glm::fvec3 currColor;
	unsigned int startX = 0;
	unsigned int stopX  = width / 2;
	unsigned int startY = 0;
	unsigned int stopY  = width / 2;
	if (part == 2)
	{
		startX = width / 2;
		stopX  = width;
		startY = 0 ;
		stopY = width / 2;
	}
	if (part == 3)
	{
		startX = 0;
		stopX = width / 2;
		startY = width / 2;
		stopY = width;
	}
	if (part == 4)
	{
		startX = width / 2;
		stopX = width;
		startY = width / 2;
		stopY = width;
	}

	unsigned int y;
	unsigned int x;
	for ( y = startY; y < stopY; y++)
	{
		for ( x = startX; x < stopX; x++)
		{			
			currColor = getTerrainColor(x, y, heightMap);

			pixels[(y*textureWidth + x)*bpp + 0] = (int)(currColor.r * 255);
			pixels[(y*textureWidth + x)*bpp + 1] = (int)(currColor.g * 255);
			pixels[(y*textureWidth + x)*bpp + 2] = (int)(currColor.b * 255);
			pixels[(y*textureWidth + x)*bpp + 3] = 255;

			if (isWater(x, y, heightMap) && hasLiquidTexture)
			{
				unsigned int pos = (y * textureWidth + width + x) * bpp;
				if (hasCloudTexture) pos = (y * textureWidth + width * 2 + x) * bpp;
				
				pixels[pos + 0] = 255;
				pixels[pos + 3] = 255;
			}
		}
	}
	CLog::getInstance()->addInfo("genThread stoped " + std::to_string(x) + " " + std::to_string(y));
}
示例#4
0
int TerrainTile::encode() const
{
  int res = 0;
  if (isTree())
  {
    res += 0x1;
    res += 0x10;
  }
  if (isRock())     { res +=  0x2; }
  if (isWater())    { res +=  0x4; }
  if (isBuilding()) { res +=  0x8; }
  if (isRoad())     { res += 0x40; }

  return res;
}
示例#5
0
	Uint16 Level::findWaterType() const
	{
		for (Int32 y = 0; y < getHeight(); y++)
		{
			for (Int32 x = 0; x < getWidth(); x++)
			{
				if (isWater(x, y))
				{
					return getBlock(x, y);
				}
			}
		}

		Uint16 waterBlocks[] = { 4, 16, 33 };
		return waterBlocks[rand() % 3];
	}
// TAC - AI Explore from Ship endless loop fix - koma13 - START
bool CvArea::isEuropePlayer() const
{
	if (isWater())
	{
		return false;
	}

	for (int iI = 0; iI < MAX_PLAYERS; iI++)
	{
		CvPlayerAI& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
		if (kLoopPlayer.isAlive() && !kLoopPlayer.isNative())
		{
			if (this->getCitiesPerPlayer((PlayerTypes)iI) > 0)
			{
				return true;
			}
		}
	}

	return false;
}
示例#7
0
	Water::Type Level::getWaterType(Int32 x, Int32 y) const
	{
		if (isWater(x, y))
		{
			Uint16 block = getBlock(x, y);
			if (block == 4)
			{
				return Water::Type::Blue;
			}
			else if (block == 16)
			{
				return Water::Type::Red;
			}
			else if (block == 33)
			{
				return Water::Type::Green;
			}
		}

		return Water::Type::None;
	}
int CvArea::countCoastalLand() const
{
	if (isWater())
	{
		return 0;
	}

	int iCount = 0;

	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (pLoopPlot->getArea() == getID())
		{
			if (pLoopPlot->isCoastalLand())
			{
				iCount++;
			}
		}
	}

	return iCount;
}
示例#9
0
/**
 * Check what the videocard + drivers support and divide the loaded map into sectors that can be drawn.
 * It also determines the lightmap size.
 */
bool initTerrain(void)
{
	int i, j, x, y, a, b, absX, absY;
	PIELIGHT colour[2][2], centerColour;
	int layer = 0;
	
	RenderVertex *geometry;
	RenderVertex *water;
	DecalVertex *decaldata;
	int geometrySize, geometryIndexSize;
	int waterSize, waterIndexSize;
	int textureSize, textureIndexSize;
	GLuint *geometryIndex;
	GLuint *waterIndex;
	GLuint *textureIndex;
	PIELIGHT *texture;
	int decalSize;
	int maxSectorSizeIndices, maxSectorSizeVertices;
	bool decreasedSize = false;

	// call VBO support hack before using it
	screen_EnableVBO();
	
	// this information is useful to prevent crashes with buggy opengl implementations
	glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &GLmaxElementsVertices);
	glGetIntegerv(GL_MAX_ELEMENTS_INDICES,  &GLmaxElementsIndices);

	// testing for crappy cards
	debug(LOG_TERRAIN, "GL_MAX_ELEMENTS_VERTICES: %i", (int)GLmaxElementsVertices);
	debug(LOG_TERRAIN, "GL_MAX_ELEMENTS_INDICES:  %i", (int)GLmaxElementsIndices);
	
	// now we know these values, determine the maximum sector size achievable
	maxSectorSizeVertices = iSqrt(GLmaxElementsVertices/2)-1;
	maxSectorSizeIndices = iSqrt(GLmaxElementsIndices/12);

	debug(LOG_TERRAIN, "preferred sector size: %i", sectorSize);
	debug(LOG_TERRAIN, "maximum sector size due to vertices: %i", maxSectorSizeVertices);
	debug(LOG_TERRAIN, "maximum sector size due to indices: %i", maxSectorSizeIndices);
	
	if (sectorSize > maxSectorSizeVertices)
	{
		sectorSize = maxSectorSizeVertices;
		decreasedSize = true;
	}
	if (sectorSize > maxSectorSizeIndices)
	{
		sectorSize = maxSectorSizeIndices;
		decreasedSize = true;
	}
	if (decreasedSize)
	{
		if (sectorSize < 1)
		{
			debug(LOG_WARNING, "GL_MAX_ELEMENTS_VERTICES: %i", (int)GLmaxElementsVertices);
			debug(LOG_WARNING, "GL_MAX_ELEMENTS_INDICES:  %i", (int)GLmaxElementsIndices);
			debug(LOG_WARNING, "maximum sector size due to vertices: %i", maxSectorSizeVertices);
			debug(LOG_WARNING, "maximum sector size due to indices: %i", maxSectorSizeIndices);
			debug(LOG_ERROR, "Your graphics card and/or drivers do not seem to support glDrawRangeElements, needed for the terrain renderer.");
			debug(LOG_ERROR, "- Do other 3D games work?");
			debug(LOG_ERROR, "- Did you install the latest drivers correctly?");
			debug(LOG_ERROR, "- Do you have a 3D window manager (Aero/Compiz) running?");
			return false;
		}
		debug(LOG_WARNING, "decreasing sector size to %i to fit graphics card constraints", sectorSize);
	}

	// +4 = +1 for iHypot rounding, +1 for sector size rounding, +2 for edge of visibility
	terrainDistance = iHypot(visibleTiles.x/2, visibleTiles.y/2)+4+sectorSize/2;
	debug(LOG_TERRAIN, "visible tiles x:%i y: %i", visibleTiles.x, visibleTiles.y);
	debug(LOG_TERRAIN, "terrain view distance: %i", terrainDistance);
	
	/////////////////////
	// Create the sectors
	xSectors = (mapWidth +sectorSize-1)/sectorSize;
	ySectors = (mapHeight+sectorSize-1)/sectorSize;
	sectors = (Sector *)malloc(sizeof(Sector)*xSectors*ySectors);
	
	////////////////////
	// fill the geometry part of the sectors
	geometry = (RenderVertex *)malloc(sizeof(RenderVertex)*xSectors*ySectors*(sectorSize+1)*(sectorSize+1)*2);
	geometryIndex = (GLuint *)malloc(sizeof(GLuint)*xSectors*ySectors*sectorSize*sectorSize*12);
	geometrySize = 0;
	geometryIndexSize = 0;
	
	water = (RenderVertex *)malloc(sizeof(RenderVertex)*xSectors*ySectors*(sectorSize+1)*(sectorSize+1)*2);
	waterIndex = (GLuint *)malloc(sizeof(GLuint)*xSectors*ySectors*sectorSize*sectorSize*12);
	waterSize = 0;
	waterIndexSize = 0;
	for (x = 0; x < xSectors; x++)
	{
		for (y = 0; y < ySectors; y++)
		{
			sectors[x*ySectors + y].dirty = false;
			sectors[x*ySectors + y].geometryOffset = geometrySize;
			sectors[x*ySectors + y].geometrySize = 0;
			sectors[x*ySectors + y].waterOffset = waterSize;
			sectors[x*ySectors + y].waterSize = 0;
			
			setSectorGeometry(x, y, geometry, water, &geometrySize, &waterSize);
			
			sectors[x*ySectors + y].geometrySize = geometrySize - sectors[x*ySectors + y].geometryOffset;
			sectors[x*ySectors + y].waterSize = waterSize - sectors[x*ySectors + y].waterOffset;
			// and do the index buffers
			sectors[x*ySectors + y].geometryIndexOffset = geometryIndexSize;
			sectors[x*ySectors + y].geometryIndexSize = 0;
			sectors[x*ySectors + y].waterIndexOffset = waterIndexSize;
			sectors[x*ySectors + y].waterIndexSize = 0;
			
			for (i = 0; i < sectorSize; i++)
			{
				for (j = 0; j < sectorSize; j++)
				{
					if (x*sectorSize+i >= mapWidth || y*sectorSize+j >= mapHeight)
					{
						continue; // off map, so skip
					}

					/* One tile is composed of 4 triangles,
					 * we need _2_ vertices per tile (1)
					 * 		e.g. center and bottom left
					 * 	the other 3 vertices are from the adjacent tiles
					 * 	on their top and right.
					 * (1) The top row and right column of tiles need 4 vertices per tile
					 * 	because they do not have adjacent tiles on their top and right,
					 * 	that is why we add _1_ row and _1_ column to provide the geometry
					 * 	for these tiles.
					 * This is the source of the '*2' and '+1' in the index math below.
					 */
#define q(i,j,center) ((x*ySectors+y)*(sectorSize+1)*(sectorSize+1)*2 + ((i)*(sectorSize+1)+(j))*2+(center))
					// First triangle
					geometryIndex[geometryIndexSize+0]  = q(i  ,j  ,1);	// Center vertex
					geometryIndex[geometryIndexSize+1]  = q(i  ,j  ,0);	// Bottom left
					geometryIndex[geometryIndexSize+2]  = q(i+1,j  ,0);	// Bottom right
					// Second triangle
					geometryIndex[geometryIndexSize+3]  = q(i  ,j  ,1);	// Center vertex
					geometryIndex[geometryIndexSize+4]  = q(i  ,j+1,0);	// Top left
					geometryIndex[geometryIndexSize+5]  = q(i  ,j  ,0);	// Bottom left
					// Third triangle
					geometryIndex[geometryIndexSize+6]  = q(i  ,j  ,1);	// Center vertex
					geometryIndex[geometryIndexSize+7]  = q(i+1,j+1,0);	// Top right
					geometryIndex[geometryIndexSize+8]  = q(i  ,j+1,0);	// Top left
					// Fourth triangle
					geometryIndex[geometryIndexSize+9]  = q(i  ,j  ,1);	// Center vertex
					geometryIndex[geometryIndexSize+10] = q(i+1,j  ,0);	// Bottom right
					geometryIndex[geometryIndexSize+11] = q(i+1,j+1,0);	// Top right
					geometryIndexSize += 12;
					if (isWater(i+x*sectorSize,j+y*sectorSize))
					{
						waterIndex[waterIndexSize+0]  = q(i  ,j  ,1);
						waterIndex[waterIndexSize+1]  = q(i  ,j  ,0);
						waterIndex[waterIndexSize+2]  = q(i+1,j  ,0);
						
						waterIndex[waterIndexSize+3]  = q(i  ,j  ,1);
						waterIndex[waterIndexSize+4]  = q(i  ,j+1,0);
						waterIndex[waterIndexSize+5]  = q(i  ,j  ,0);
						
						waterIndex[waterIndexSize+6]  = q(i  ,j  ,1);
						waterIndex[waterIndexSize+7]  = q(i+1,j+1,0);
						waterIndex[waterIndexSize+8]  = q(i  ,j+1,0);
						
						waterIndex[waterIndexSize+9]  = q(i  ,j  ,1);
						waterIndex[waterIndexSize+10] = q(i+1,j  ,0);
						waterIndex[waterIndexSize+11] = q(i+1,j+1,0);
						waterIndexSize += 12;
					}
				}
			}
			sectors[x*ySectors + y].geometryIndexSize = geometryIndexSize - sectors[x*ySectors + y].geometryIndexOffset;
			sectors[x*ySectors + y].waterIndexSize = waterIndexSize - sectors[x*ySectors + y].waterIndexOffset;
		}
	}
	glGenBuffers(1, &geometryVBO); glError();
	glBindBuffer(GL_ARRAY_BUFFER, geometryVBO); glError();
	glBufferData(GL_ARRAY_BUFFER, sizeof(RenderVertex)*geometrySize, geometry, GL_DYNAMIC_DRAW); glError();
	free(geometry);
	
	glGenBuffers(1, &geometryIndexVBO); glError();
	glBindBuffer(GL_ARRAY_BUFFER, geometryIndexVBO); glError();
	glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint)*geometryIndexSize, geometryIndex, GL_STATIC_DRAW); glError();
	free(geometryIndex);
	
	glGenBuffers(1, &waterVBO); glError();
	glBindBuffer(GL_ARRAY_BUFFER, waterVBO); glError();
	glBufferData(GL_ARRAY_BUFFER, sizeof(RenderVertex)*waterSize, water, GL_DYNAMIC_DRAW); glError();
	free(water);
	
	glGenBuffers(1, &waterIndexVBO); glError();
	glBindBuffer(GL_ARRAY_BUFFER, waterIndexVBO); glError();
	glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint)*waterIndexSize, waterIndex, GL_STATIC_DRAW); glError();
	free(waterIndex);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	
	////////////////////
	// fill the texture part of the sectors
	texture = (PIELIGHT *)malloc(sizeof(PIELIGHT)*xSectors*ySectors*(sectorSize+1)*(sectorSize+1)*2*numGroundTypes);
	textureIndex = (GLuint *)malloc(sizeof(GLuint)*xSectors*ySectors*sectorSize*sectorSize*12*numGroundTypes);
	textureSize = 0;
	textureIndexSize = 0;
	for (layer = 0; layer < numGroundTypes; layer++)
	{
		for (x = 0; x < xSectors; x++)
		{
			for (y = 0; y < ySectors; y++)
			{
				if (layer == 0)
				{
					sectors[x*ySectors + y].textureOffset = (int *)malloc(sizeof(int)*numGroundTypes);
					sectors[x*ySectors + y].textureSize = (int *)malloc(sizeof(int)*numGroundTypes);
					sectors[x*ySectors + y].textureIndexOffset = (int *)malloc(sizeof(int)*numGroundTypes);
					sectors[x*ySectors + y].textureIndexSize = (int *)malloc(sizeof(int)*numGroundTypes);
				}

				sectors[x*ySectors + y].textureOffset[layer] = textureSize;
				sectors[x*ySectors + y].textureSize[layer] = 0;
				sectors[x*ySectors + y].textureIndexOffset[layer] = textureIndexSize;
				sectors[x*ySectors + y].textureIndexSize[layer] = 0;
				//debug(LOG_WARNING, "offset when filling %i: %i", layer, xSectors*ySectors*(sectorSize+1)*(sectorSize+1)*2*layer);
				for (i = 0; i < sectorSize+1; i++)
				{
					for (j = 0; j < sectorSize+1; j++)
					{
						bool draw = false;
						bool off_map;

						// set transparency
						for (a=0;a<2;a++)
						{
							for(b=0;b<2;b++)
							{
								absX = x*sectorSize+i+a;
								absY = y*sectorSize+j+b;
								colour[a][b].rgba = 0x00FFFFFF; // transparent
								
								// extend the terrain type for the bottom and left edges of the map
								off_map = false;
								if (absX == mapWidth)
								{
									off_map = true;
									absX--;
								}
								if (absY == mapHeight)
								{
									off_map = true;
									absY--;
								}
								
								if (absX < 0 || absY < 0 || absX >= mapWidth || absY >= mapHeight)
								{
									// not on the map, so don't draw
									continue;
								}
								if (mapTile(absX,absY)->ground == layer)
								{
									colour[a][b].rgba = 0xFFFFFFFF;
									if (!off_map)
									{
										// if this point lies on the edge is may not force this tile to be drawn
										// otherwise this will give a bright line when fog is enabled
										draw = true;
									}
								}
							}
						}
						texture[xSectors*ySectors*(sectorSize+1)*(sectorSize+1)*2*layer+((x*ySectors+y)*(sectorSize+1)*(sectorSize+1)*2 + (i*(sectorSize+1)+j)*2)].rgba = colour[0][0].rgba;
						averageColour(&centerColour, colour[0][0], colour[0][1], colour[1][0], colour[1][1]);
						texture[xSectors*ySectors*(sectorSize+1)*(sectorSize+1)*2*layer+((x*ySectors+y)*(sectorSize+1)*(sectorSize+1)*2 + (i*(sectorSize+1)+j)*2+1)].rgba = centerColour.rgba;
						textureSize += 2;
						if ((draw) && i < sectorSize && j < sectorSize)
						{
							textureIndex[textureIndexSize+0]  = q(i  ,j  ,1);
							textureIndex[textureIndexSize+1]  = q(i  ,j  ,0);
							textureIndex[textureIndexSize+2]  = q(i+1,j  ,0);
							
							textureIndex[textureIndexSize+3]  = q(i  ,j  ,1);
							textureIndex[textureIndexSize+4]  = q(i  ,j+1,0);
							textureIndex[textureIndexSize+5]  = q(i  ,j  ,0);
							
							textureIndex[textureIndexSize+6]  = q(i  ,j  ,1);
							textureIndex[textureIndexSize+7]  = q(i+1,j+1,0);
							textureIndex[textureIndexSize+8]  = q(i  ,j+1,0);
							
							textureIndex[textureIndexSize+9]  = q(i  ,j  ,1);
							textureIndex[textureIndexSize+10] = q(i+1,j  ,0);
							textureIndex[textureIndexSize+11] = q(i+1,j+1,0);
							textureIndexSize += 12;
						}

					}
				}
				sectors[x*ySectors + y].textureSize[layer] = textureSize - sectors[x*ySectors + y].textureOffset[layer];
				sectors[x*ySectors + y].textureIndexSize[layer] = textureIndexSize - sectors[x*ySectors + y].textureIndexOffset[layer];
			}
		}
	}
	glGenBuffers(1, &textureVBO); glError();
	glBindBuffer(GL_ARRAY_BUFFER, textureVBO); glError();
	glBufferData(GL_ARRAY_BUFFER, sizeof(PIELIGHT)*xSectors*ySectors*(sectorSize+1)*(sectorSize+1)*2*numGroundTypes, texture, GL_STATIC_DRAW); glError();
	free(texture);
	
	glGenBuffers(1, &textureIndexVBO); glError();
	glBindBuffer(GL_ARRAY_BUFFER, textureIndexVBO); glError();
	glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint)*textureIndexSize, textureIndex, GL_STATIC_DRAW); glError();
	free(textureIndex);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	// and finally the decals
	decaldata = (DecalVertex *)malloc(sizeof(DecalVertex)*mapWidth*mapHeight*12);
	decalSize = 0;
	for (x = 0; x < xSectors; x++)
	{
		for (y = 0; y < ySectors; y++)
		{
			sectors[x*ySectors + y].decalOffset = decalSize;
			sectors[x*ySectors + y].decalSize = 0;
			setSectorDecals(x, y, decaldata, &decalSize);
			sectors[x*ySectors + y].decalSize = decalSize - sectors[x*ySectors + y].decalOffset;
		}
	}
	debug(LOG_TERRAIN, "%i decals found", decalSize/12);
	glGenBuffers(1, &decalVBO); glError();
	glBindBuffer(GL_ARRAY_BUFFER, decalVBO); glError();
	glBufferData(GL_ARRAY_BUFFER, sizeof(DecalVertex)*decalSize, decaldata, GL_STATIC_DRAW); glError();
	free(decaldata);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	
	lightmap_tex_num = 0;
	lightmapLastUpdate = 0;
	lightmapWidth = 1;
	lightmapHeight = 1;
	// determine the smallest power-of-two size we can use for the lightmap
	while (mapWidth > (lightmapWidth <<= 1)) {}
	while (mapHeight > (lightmapHeight <<= 1)) {}
	debug(LOG_TERRAIN, "the size of the map is %ix%i", mapWidth, mapHeight);
	debug(LOG_TERRAIN, "lightmap texture size is %ix%i", lightmapWidth, lightmapHeight);

	// Prepare the lightmap pixmap and texture
	lightmapPixmap = (GLubyte *)calloc(lightmapWidth * lightmapHeight, 3 * sizeof(GLubyte));
	if (lightmapPixmap == NULL)
	{
		debug(LOG_FATAL, "Out of memory!");
		abort();
		return false;
	}

	glGenTextures(1, &lightmap_tex_num);
	glBindTexture(GL_TEXTURE_2D, lightmap_tex_num);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, lightmapWidth, lightmapHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmapPixmap);

	terrainInitalised = true;

	glBindBuffer(GL_ARRAY_BUFFER, 0);  // HACK Must unbind GL_ARRAY_BUFFER (in this function, at least), otherwise text rendering may mysteriously crash.

	return true;
}
bool CvArea::isLake() const
{
	return (isWater() && (getNumTiles() <= GC.getLAKE_MAX_AREA_SIZE()));
}