colobot/src/graphics/engine/terrain.h

426 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
*
* 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://gnu.org/licenses
*/
/**
* \file graphics/engine/terrain.h
* \brief Terrain rendering - CTerrain class
*/
#pragma once
#include "graphics/engine/engine.h"
// 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.
*
* Underground 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();
~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, resources and all other associated data
void FlushRelief();
//! Load relief from image
bool LoadRelief(const std::string& fileName, float scaleRelief, bool adjustBorder);
//! Load ramdomized relief
bool RandomizeRelief();
//! 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:
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