colobot/src/graphics/engine/terrain.h

425 lines
14 KiB
C++

// * This file is part of the COLOBOT source code
// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
// *
// * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
// * (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
/**
* \file graphics/engine/terrain.h
* \brief Terrain rendering - CTerrain class
*/
#pragma once
#include "graphics/engine/engine.h"
class CInstanceManager;
// Graphics module namespace
namespace Gfx {
class CEngine;
class CWater;
//! Limit of slope considered a flat piece of land
const float TERRAIN_FLATLIMIT = (5.0f*Math::PI/180.0f);
/**
* \enum TerrainRes
* \brief Underground resource type
*/
enum TerrainRes
{
//! No resource
TR_NULL = 0,
//! Titanium
TR_STONE = 1,
//! Uranium
TR_URANIUM = 2,
//! Energy
TR_POWER = 3,
//! Vault keys
//@{
TR_KEY_A = 4,
TR_KEY_B = 5,
TR_KEY_C = 6,
TR_KEY_D = 7
//@}
};
/**
* \struct BuildingLevel
* \brief Flat level for building
*/
struct BuildingLevel
{
Math::Vector center;
float factor;
float min;
float max;
float level;
float height;
float bboxMinX;
float bboxMaxX;
float bboxMinZ;
float bboxMaxZ;
BuildingLevel()
{
factor = min = max = level = height = 0.0f;
bboxMinX = bboxMaxX = bboxMinZ = bboxMaxZ = 0.0f;
}
};
/**
* \struct TerrainMaterial
* \brief Material for ground surface
*/
struct TerrainMaterial
{
//! Unique ID
short id;
//! Texture
std::string texName;
//! UV texture coordinates
Math::Point uv;
//! Terrain hardness (defines e.g. sound of walking)
float hardness;
//! IDs of neighbor materials: up, right, down, left
char mat[4];
TerrainMaterial()
{
id = 0;
hardness = 0.0f;
mat[0] = mat[1] = mat[2] = mat[3] = 0;
}
};
/**
* \struct TerrainMaterialPoint
* \brief Material used for terrain point
*/
struct TerrainMaterialPoint
{
//! ID of material
short id;
//! IDs of neighbor materials: up, right, down, left
char mat[4];
TerrainMaterialPoint()
{
id = 0;
mat[0] = mat[1] = mat[2] = mat[3] = 0;
}
};
/**
* \struct FlyingLimit
* \brief Spherical limit of flight
*/
struct FlyingLimit
{
Math::Vector center;
float extRadius;
float intRadius;
float maxHeight;
FlyingLimit()
{
extRadius = intRadius = maxHeight = 0.0f;
}
};
/**
* \class CTerrain
* \brief Terrain loader/generator and manager
*
* \section Mapping Terrain mapping
*
* Terrain is created from relief textures specifying a XY plane with height
* values which are then scaled and translated into XZ surface forming the
* terrain of game level.
*
* The basic unit of terrain is called "brick", which is two triangles
* forming a quad. Bricks have constant size (brick size)
* in X and Z direction.
* Points forming the bricks correspond one-to-one to relief data points
* (pixels in relief image).
*
* Bricks are grouped into "mosaics". Mosaic is a square containing
* brickCount x brickCount bricks where brickCount is an even power of 2.
* Each mosaic corresponds to one created engine object.
*
* The whole terrain is also a square formed by mosaicCount * mosaicCount
* of mosaics.
*
* Image coordinates are converted in the following way to world coordinates
* of brick points (Wx, Wy, Wz - world coordinates, Ix, Iy - image coordinates,
* Pxy - pixel value at Ix,Iy):
*
* Wx = (Ix - brickCount*mosaicCount / 2.0f) * brickSize \n
* Wz = (Iy - brickCount*mosaicCount / 2.0f) * brickSize \n
* Wy = (Pxy / 255.0f) * reliefScale
*
* To create and initialize a terrain, you must call Generate() as the first function,
* setting the number of bricks, mosaics etc.
*
* \section Materials Materials and textures
*
* The terrain can be textured in two ways:
* - by applying texture index table
* - by specifying one or more "materials" that cover "material points"
*
* Textures are applied to subdivisions of mosaics (groups of bricks of size
* brickCount / textureSubdivCount).
*
* \subsection TextureIndexes Texture indexes
*
* Texture indexes specify the texture for each textured point by concatenating
* base name of texture, the index number and texture extension.
*
* Texture indexes are specified directly in InitTextures().
*
* \subsection TerrainMaterials Terrain materials
*
* Terrain materials are more sophisticated system. Each material is a texture,
* applied to one area, but specifying also the textures to use on surrounding areas:
* left, right, bottom and top.
*
* You specify one or more terrain materials in AddMaterial() function.
* The function will add a material for given circle on the ground, with some
* randomized matching of supplied materials and sophisticated logic for ensuring
* that borders between neighboring materials follow the specified rules.
*
* \subsection BuildingLevels Other features
*
* Terrain can have specified building levels - flat space expanses,
* where relief data is specifically adjusted to level space to allow
* construction of buildings.
*
* Undergound resources can be supplied by loading them from image like relief data.
*
* Terrain also specifies flying limits for player: one global level and possible
* additional spherical restrictions.
*/
class CTerrain
{
public:
CTerrain(CInstanceManager* iMan);
~CTerrain();
//! Generates a new flat terrain
bool Generate(int mosaicCount, int brickCountPow2, float brickSize, float vision, int depth, float hardness);
//! Initializes the names of textures to use for the land
bool InitTextures(const std::string& baseName, int* table, int dx, int dy);
//! Clears all terrain materials
void FlushMaterials();
//! Adds a terrain material the names of textures to use for the land
void AddMaterial(int id, const std::string& baseName, const Math::Point& uv,
int up, int right, int down, int left, float hardness);
//! Initializes all the ground with one material
bool InitMaterials(int id);
//! Generates a level in the terrain
bool GenerateMaterials(int *id, float min, float max, float slope, float freq, Math::Vector center, float radius);
//! Clears the relief data to zero
void FlushRelief();
//! Load relief from image
bool LoadRelief(const std::string& fileName, float scaleRelief, bool adjustBorder);
//! Load resources from image
bool LoadResources(const std::string& fileName);
//! Creates all objects of the terrain within the 3D engine
bool CreateObjects();
//! Modifies the terrain's relief
bool Terraform(const Math::Vector& p1, const Math::Vector& p2, float height);
//@{
//! Management of the wind
void SetWind(Math::Vector speed);
Math::Vector GetWind();
//@}
//! Gives the exact slope of the terrain at 2D (XZ) position
float GetFineSlope(const Math::Vector& pos);
//! Gives the approximate slope of the terrain at 2D (XZ) position
float GetCoarseSlope(const Math::Vector& pos);
//! Gives the normal vector at 2D (XZ) position
bool GetNormal(Math::Vector& n, const Math::Vector &p);
//! Returns the height of the ground level at 2D (XZ) position
float GetFloorLevel(const Math::Vector& pos, bool brut=false, bool water=false);
//! Returns the distance to the ground level from 3D position
float GetHeightToFloor(const Math::Vector& pos, bool brut=false, bool water=false);
//! Modifies the Y coordinate of 3D position to rest on the ground floor
bool AdjustToFloor(Math::Vector& pos, bool brut=false, bool water=false);
//! Adjusts 3D position so that it is within standard terrain boundaries
bool AdjustToStandardBounds(Math::Vector &pos);
//! Adjusts 3D position so that it is within terrain boundaries and the given margin
bool AdjustToBounds(Math::Vector& pos, float margin);
//! Returns the resource type available underground at 2D (XZ) position
TerrainRes GetResource(const Math::Vector& pos);
//! Empty the table of elevations
void FlushBuildingLevel();
//! Adds a new elevation for a building
bool AddBuildingLevel(Math::Vector center, float min, float max, float height, float factor);
//! Updates the elevation for a building when it was moved up (after a terraforming)
bool UpdateBuildingLevel(Math::Vector center);
//! Removes the elevation for a building when it was destroyed
bool DeleteBuildingLevel(Math::Vector center);
//! Returns the influence factor whether a position is on a possible rise
float GetBuildingFactor(const Math::Vector& pos);
//! Returns the hardness of the ground in a given place
float GetHardness(const Math::Vector& pos);
//! Returns number of mosaics
int GetMosaicCount();
//! Returns number of bricks in mosaic
int GetBrickCount();
//! Returns brick size
float GetBrickSize();
//! Returns the vertical scale of relief
float GetReliefScale();
//! Shows the flat areas on the ground
void ShowFlatGround(Math::Vector pos);
//! Calculates the radius of the largest flat area available
float GetFlatZoneRadius(Math::Vector center, float max);
//@{
//! Management of the global max flying height
void SetFlyingMaxHeight(float height);
float GetFlyingMaxHeight();
//@}
//! Empty the table of flying limits
void FlushFlyingLimit();
//! Adds a new flying limit
void AddFlyingLimit(Math::Vector center, float extRadius, float intRadius, float maxHeight);
//! Returns the maximum height of flight
float GetFlyingLimit(Math::Vector pos, bool noLimit);
protected:
//! Adds a point of elevation in the buffer of relief
bool AddReliefPoint(Math::Vector pos, float scaleRelief);
//! Adjust the edges of each mosaic to be compatible with all lower resolutions
void AdjustRelief();
//! Calculates a vector of the terrain
Math::Vector GetVector(int x, int y);
//! Calculates a vertex of the terrain
VertexTex2 GetVertex(int x, int y, int step);
//! Creates all objects of a mosaic
bool CreateMosaic(int ox, int oy, int step, int objRank, const Material& mat);
//! Creates all objects in a mesh square ground
bool CreateSquare(int x, int y);
//! Seeks a material based on its ID
TerrainMaterial* FindMaterial(int id);
//! Seeks a material based on neighbor values
int FindMaterialByNeighbors(char *mat);
//! Returns the texture name and UV coords to use for a given square
void GetTexture(int x, int y, std::string& name, Math::Point& uv);
//! Returns the height of the terrain
float GetHeight(int x, int y);
//! Decide whether a point is using the materials
bool CheckMaterialPoint(int x, int y, float min, float max, float slope);
//! Modifies the state of a point and its four neighbors, without testing if possible
void SetMaterialPoint(int x, int y, int id, char *mat);
//! Modifies the state of a point
bool ChangeMaterialPoint(int x, int y, int id);
//! Tests if a material can give a place, according to its four neighbors. If yes, puts the point.
bool CondChangeMaterialPoint(int x, int y, int id, char *mat);
//! Initializes material points array
void InitMaterialPoints();
//! Clears the material points
void FlushMaterialPoints();
//! Adjusts a position according to a possible rise
void AdjustBuildingLevel(Math::Vector &p);
protected:
CInstanceManager* m_iMan;
CEngine* m_engine;
CWater* m_water;
//! Relief data points
std::vector<float> m_relief;
//! Resources data
std::vector<unsigned char> m_resources;
//! Texture indices
std::vector<int> m_textures;
//! Object ranks for mosaic objects
std::vector<int> m_objRanks;
//! Number of mosaics (along one dimension)
int m_mosaicCount;
//! Number of bricks per mosaic (along one dimension)
int m_brickCount;
//! Number of terrain material dots (along one dimension)
int m_materialPointCount;
//! Size of single brick (along X and Z axis)
float m_brickSize;
//! Vertical (relief) scale
float m_scaleRelief;
//! Subdivision of material points in mosaic
int m_textureSubdivCount;
//! Number of different resolutions (1,2,3,4)
int m_depth;
//! Scale of texture mapping
float m_textureScale;
//! Vision before a change of resolution
float m_vision;
//! Base name for single texture
std::string m_texBaseName;
//! Extension for single texture
std::string m_texBaseExt;
//! Default hardness for level material
float m_defaultHardness;
//! True if using terrain material mapping
bool m_useMaterials;
//! Terrain materials
std::vector<TerrainMaterial> m_materials;
//! Material for terrain points
std::vector<TerrainMaterialPoint> m_materialPoints;
//! Maximum level ID (no ID is >= to this)
int m_maxMaterialID;
//! Internal counter for auto generation of material IDs
int m_materialAutoID;
std::vector<BuildingLevel> m_buildingLevels;
//! Wind speed
Math::Vector m_wind;
//! Global flying height limit
float m_flyingMaxHeight;
//! List of local flight limits
std::vector<FlyingLimit> m_flyingLimits;
};
} // namespace Gfx