411 lines
14 KiB
C++
411 lines
14 KiB
C++
/*
|
|
* This file is part of the Colobot: Gold Edition source code
|
|
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
|
|
* http://epsitec.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/core/vertex.h"
|
|
|
|
#include "math/const.h"
|
|
|
|
#include <glm/glm.hpp>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
|
|
// 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
|
|
//@}
|
|
};
|
|
//! Converts TerrainRes to color
|
|
Gfx::IntColor ResourceToColor(TerrainRes res);
|
|
|
|
/**
|
|
* \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& texName, const glm::vec2& 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, glm::vec3 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 glm::vec3& p1, const glm::vec3& p2, float height);
|
|
|
|
//@{
|
|
//! Management of the wind
|
|
void SetWind(glm::vec3 speed);
|
|
glm::vec3 GetWind();
|
|
//@}
|
|
|
|
//! Gives the exact slope of the terrain at 2D (XZ) position
|
|
float GetFineSlope(const glm::vec3& pos);
|
|
//! Gives the approximate slope of the terrain at 2D (XZ) position
|
|
float GetCoarseSlope(const glm::vec3& pos);
|
|
//! Gives the normal vector at 2D (XZ) position
|
|
bool GetNormal(glm::vec3& n, const glm::vec3 &p);
|
|
//! Returns the height of the ground level at 2D (XZ) position
|
|
float GetFloorLevel(const glm::vec3& pos, bool brut=false, bool water=false);
|
|
//! Returns the distance to the ground level from 3D position
|
|
float GetHeightToFloor(const glm::vec3& pos, bool brut=false, bool water=false);
|
|
//! Modifies the Y coordinate of 3D position to rest on the ground floor
|
|
bool AdjustToFloor(glm::vec3& pos, bool brut=false, bool water=false);
|
|
//! Adjusts 3D position so that it is within standard terrain boundaries
|
|
bool AdjustToStandardBounds(glm::vec3 &pos);
|
|
//! Adjusts 3D position so that it is within terrain boundaries and the given margin
|
|
bool AdjustToBounds(glm::vec3& pos, float margin);
|
|
//! Returns the resource type available underground at 2D (XZ) position
|
|
TerrainRes GetResource(const glm::vec3& pos);
|
|
|
|
//! Empty the table of elevations
|
|
void FlushBuildingLevel();
|
|
//! Adds a new elevation for a building
|
|
bool AddBuildingLevel(glm::vec3 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(glm::vec3 center);
|
|
//! Removes the elevation for a building when it was destroyed
|
|
bool DeleteBuildingLevel(glm::vec3 center);
|
|
//! Returns the influence factor whether a position is on a possible rise
|
|
float GetBuildingFactor(const glm::vec3& pos);
|
|
//! Returns the hardness of the ground in a given place
|
|
float GetHardness(const glm::vec3& 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(glm::vec3 pos);
|
|
//! Calculates the radius of the largest flat area available
|
|
float GetFlatZoneRadius(glm::vec3 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(glm::vec3 center, float extRadius, float intRadius, float maxHeight);
|
|
//! Returns the maximum height of flight
|
|
float GetFlyingLimit(glm::vec3 pos, bool noLimit);
|
|
|
|
protected:
|
|
//! Adds a point of elevation in the buffer of relief
|
|
bool AddReliefPoint(glm::vec3 pos, float scaleRelief);
|
|
//! Adjust the edges of each mosaic to be compatible with all lower resolutions
|
|
void AdjustRelief();
|
|
//! Calculates a vector of the terrain
|
|
glm::vec3 GetVector(int x, int y);
|
|
//! Calculates a vertex of the terrain
|
|
Vertex3D GetVertex(int x, int y, int step);
|
|
//! Creates all objects of a mosaic
|
|
bool CreateMosaic(int ox, int oy, int step, int objRank);
|
|
//! Creates all objects in a mesh square ground
|
|
bool CreateSquare(int x, int y);
|
|
|
|
struct TerrainMaterial;
|
|
//! 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, glm::vec2& 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(glm::vec3 &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;
|
|
/**
|
|
* \struct TerrainMaterial
|
|
* \brief Material for ground surface
|
|
*/
|
|
struct TerrainMaterial
|
|
{
|
|
//! Unique ID
|
|
short id = 0;
|
|
//! Texture
|
|
std::string texName;
|
|
//! UV texture coordinates
|
|
glm::vec2 uv;
|
|
//! Terrain hardness (defines e.g. sound of walking)
|
|
float hardness = 0.0f;
|
|
//! IDs of neighbor materials: up, right, down, left
|
|
char mat[4] = {};
|
|
};
|
|
//! Terrain materials
|
|
std::vector<TerrainMaterial> m_materials;
|
|
|
|
/**
|
|
* \struct TerrainMaterialPoint
|
|
* \brief Material used for terrain point
|
|
*/
|
|
struct TerrainMaterialPoint
|
|
{
|
|
//! ID of material
|
|
short id = 0;
|
|
//! IDs of neighbor materials: up, right, down, left
|
|
char mat[4] = {};
|
|
};
|
|
|
|
|
|
//! Material for terrain points
|
|
std::vector<TerrainMaterialPoint> m_materialPoints;
|
|
|
|
//! True if using terrain material mapping
|
|
bool m_useMaterials;
|
|
//! Maximum level ID (no ID is >= to this)
|
|
int m_maxMaterialID;
|
|
//! Internal counter for auto generation of material IDs
|
|
int m_materialAutoID;
|
|
|
|
/**
|
|
* \struct BuildingLevel
|
|
* \brief Flat level for building
|
|
*/
|
|
struct BuildingLevel
|
|
{
|
|
glm::vec3 center{ 0, 0, 0 };
|
|
float factor = 0.0f;
|
|
float min = 0.0f;
|
|
float max = 0.0f;
|
|
float level = 0.0f;
|
|
float height = 0.0f;
|
|
float bboxMinX = 0.0f;
|
|
float bboxMaxX = 0.0f;
|
|
float bboxMinZ = 0.0f;
|
|
float bboxMaxZ = 0.0f;
|
|
};
|
|
std::vector<BuildingLevel> m_buildingLevels;
|
|
|
|
//! Wind speed
|
|
glm::vec3 m_wind{ 0, 0, 0 };
|
|
|
|
//! Global flying height limit
|
|
float m_flyingMaxHeight;
|
|
|
|
/**
|
|
* \struct FlyingLimit
|
|
* \brief Spherical limit of flight
|
|
*/
|
|
struct FlyingLimit
|
|
{
|
|
glm::vec3 center{ 0, 0, 0 };
|
|
float extRadius = 0.0f;
|
|
float intRadius = 0.0f;
|
|
float maxHeight = 0.0f;
|
|
};
|
|
//! List of local flight limits
|
|
std::vector<FlyingLimit> m_flyingLimits;
|
|
};
|
|
|
|
|
|
} // namespace Gfx
|
|
|