Serious-Engine/Sources/Engine/Terrain/TerrainLayer.cpp
Ryan C. Gordon 24cb244d43 First attempt to hand-merge Ryan's Linux and Mac OS X port.
This was a _ton_ of changes, made 15 years ago, so there are probably some
problems to work out still.

Among others: Engine/Base/Stream.* was mostly abandoned and will need to be
re-ported.

Still, this is a pretty good start, and probably holds a world record for
lines of changes or something.  :)
2016-03-28 23:46:13 -04:00

524 lines
14 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
#include "Engine/StdH.h"
#include <Engine/Base/Stream.h>
#include <Engine/Base/ErrorReporting.h>
#include <Engine/Base/Translation.h>
#include <Engine/Terrain/TerrainLayer.h>
#include <Engine/Terrain/TerrainMisc.h>
#include <Engine/Templates/Stock_CTextureData.h>
#include <Engine/Graphics/ImageInfo.h>
CTerrainLayer::CTerrainLayer()
{
tl_ptdTexture = NULL;
tl_aubColors = NULL;
tl_iMaskWidth = 0;
tl_iMaskHeight = 0;
ResetLayerParams();
}
CTerrainLayer::~CTerrainLayer()
{
Clear();
}
CTextureData *CTerrainLayer::GetThumbnail(INDEX iWidth, INDEX iHeight)
{
tl_tdThumbNail.Clear();
tl_tdThumbNail.DefaultAnimation();
INDEX iMaskWidth = tl_iMaskWidth-1;
INDEX iMaskHeight = tl_iMaskHeight-1;
if(iWidth>iMaskWidth) {
// ASSERT(FALSE);
iWidth = iMaskWidth;
}
if(iHeight>iMaskHeight) {
// ASSERT(FALSE);
iHeight = iMaskHeight;
}
CreateTexture(tl_tdThumbNail,iWidth,iHeight,TEX_STATIC);
INDEX iStepX = iMaskWidth/iWidth;
INDEX iStepY = iMaskHeight/iHeight - 1;
UBYTE *paubMask = tl_aubColors;
GFXColor *pcolTexture = (GFXColor*)tl_tdThumbNail.td_pulFrames;
for(INDEX iy=0;iy<iHeight;iy++) {
for(INDEX ix=0;ix<iWidth;ix++) {
pcolTexture->ub.r = *paubMask;
pcolTexture->ub.g = *paubMask;
pcolTexture->ub.b = *paubMask;
pcolTexture->ub.a = 0xFF;
pcolTexture++;
paubMask+=iStepX;
}
paubMask+=(tl_iMaskWidth*iStepY)+1;
}
// make mipmaps
INDEX ctMips = GetNoOfMipmaps(iWidth,iHeight);
MakeMipmaps(ctMips, tl_tdThumbNail.td_pulFrames, iWidth, iHeight);
tl_tdThumbNail.SetAsCurrent(0,TRUE);
return &tl_tdThumbNail;
}
// Set layer size
void CTerrainLayer::SetLayerSize(INDEX iTerrainWidth, INDEX iTerrainHeight)
{
// if array of vertex colors was initialized
if(tl_aubColors!=NULL) {
// free array
FreeMemory(tl_aubColors);
tl_aubColors = NULL;
}
// if size of mask is greater than 0
INDEX iSize = iTerrainWidth*iTerrainHeight;
if(iSize>0) {
// Allocate new memory for vertex colors
tl_aubColors = (UBYTE*)AllocMemory(iSize);
// Reset color values
memset(&tl_aubColors[0],0,sizeof(UBYTE)*iSize);
}
tl_iMaskWidth = iTerrainWidth;
tl_iMaskHeight = iTerrainHeight;
}
// Set base texture this layer will be using
void CTerrainLayer::SetLayerTexture_t(CTFileName fnTexture)
{
// if layer has valid texture
if(tl_ptdTexture!=NULL) {
// release texture from stock
_pTextureStock->Release(tl_ptdTexture);
tl_ptdTexture = NULL;
}
// get reguested texture
tl_ptdTexture = _pTextureStock->Obtain_t(fnTexture);
tl_ptdTexture->Force(TEX_STATIC);
// if this is tile layer
if(tl_ltType == LT_TILE) {
// Update tile widht and height
SetTilesPerRow(GetTilesPerRow());
}
}
// Set num of tiles in one row
void CTerrainLayer::SetTilesPerRow(INDEX ctTilesInRow)
{
ASSERT(tl_ltType == LT_TILE);
tl_ctTilesInRow = ctTilesInRow;
// Calc one tile widht
tl_pixTileWidth = tl_ptdTexture->GetPixWidth() / ctTilesInRow;
// Calc num of tiles in texture col
tl_ctTilesInCol = tl_ptdTexture->GetPixHeight() / tl_pixTileWidth;
tl_fTileU = 1.0f / tl_ctTilesInRow;
tl_fTileV = 1.0f / tl_ctTilesInCol;
}
INDEX CTerrainLayer::GetTilesPerRow()
{
ASSERT(tl_ltType == LT_TILE);
return tl_ctTilesInRow;
}
// Import layer mask from targa file
void CTerrainLayer::ImportLayerMask_t(CTFileName fnLayerMask)
{
// Load targa file
CImageInfo iiLayerMask;
iiLayerMask.LoadAnyGfxFormat_t(fnLayerMask);
if(iiLayerMask.ii_Width != tl_iMaskWidth) {
ThrowF_t(TRANS("Layer mask width is %d, but it must be same size as terrain width %d"),iiLayerMask.ii_Width,tl_iMaskWidth);
}
if(iiLayerMask.ii_Height != tl_iMaskHeight) {
ThrowF_t(TRANS("Layer mask height is %d, but it must be same size as terrain height %d"),iiLayerMask.ii_Height,tl_iMaskHeight);
}
UBYTE *pubSrc = &iiLayerMask.ii_Picture[0];
UBYTE *pubDst = &tl_aubColors[0];
INDEX iBpp = iiLayerMask.ii_BitsPerPixel/8;
// for each byte in loaded image
INDEX iMaskSize = tl_iMaskWidth * tl_iMaskHeight;
for(INDEX ib=0;ib<iMaskSize;ib++) {
// copy red value from image
*pubDst = *(UBYTE*)pubSrc;
pubDst++;
pubSrc+=iBpp;
}
}
// Export layer mask to targa file
void CTerrainLayer::ExportLayerMask_t(CTFileName fnLayerMask)
{
ASSERT(tl_aubColors!=NULL);
INDEX iSize = tl_iMaskWidth*tl_iMaskHeight;
CImageInfo iiHeightMap;
iiHeightMap.ii_Width = tl_iMaskWidth;
iiHeightMap.ii_Height = tl_iMaskHeight;
iiHeightMap.ii_BitsPerPixel = 32;
iiHeightMap.ii_Picture = (UBYTE*)AllocMemory(iSize*iiHeightMap.ii_BitsPerPixel/8);
GFXColor *pacolImage = (GFXColor*)&iiHeightMap.ii_Picture[0];
UBYTE *pubMask = &tl_aubColors[0];
for(INDEX ipix=0;ipix<iSize;ipix++) {
pacolImage->ul.abgr = 0x00000000;
pacolImage->ub.r = *pubMask;
pacolImage++;
pubMask++;
}
iiHeightMap.SaveTGA_t(fnLayerMask);
iiHeightMap.Clear();
}
// Reset layer mask
void CTerrainLayer::ResetLayerMask(UBYTE ubMaskFill)
{
memset(&tl_aubColors[0],ubMaskFill,sizeof(UBYTE) * tl_iMaskWidth * tl_iMaskHeight);
}
// Reset layer params
void CTerrainLayer::ResetLayerParams()
{
tl_iMaskWidth = 0;
tl_iMaskHeight = 0;
tl_strName = "NoName";
tl_bVisible = TRUE;
tl_colMultiply = C_GRAY|CT_OPAQUE;
tl_fSmoothness = 1.0f;
tl_ltType = LT_NORMAL;
tl_fRotateX=0.0f;
tl_fRotateY=0.0f;
tl_fStretchX=1.0f;
tl_fStretchY=1.0f;
tl_fOffsetX=0;
tl_fOffsetY=0;
tl_bAutoRegenerated=FALSE;
tl_fCoverage=1.0f;
tl_fCoverageNoise=0.5f;
tl_fCoverageRandom=0.0f;
tl_bApplyMinAltitude=TRUE;
tl_fMinAltitude=0.0f;
tl_fMinAltitudeFade=0.25f;
tl_fMinAltitudeNoise=0.25f;
tl_fMinAltitudeRandom=0;
tl_bApplyMaxAltitude=TRUE;
tl_fMaxAltitude=1.0f;
tl_fMaxAltitudeFade=0.25f;
tl_fMaxAltitudeNoise=0.25f;
tl_fMaxAltitudeRandom=0;
tl_bApplyMinSlope=TRUE;
tl_fMinSlope=0.0f;
tl_fMinSlopeFade=0.25f;
tl_fMinSlopeNoise=0.25f;
tl_fMinSlopeRandom=0;
tl_bApplyMaxSlope=TRUE;
tl_fMaxSlope=1.0f;
tl_fMaxSlopeFade=0.25f;
tl_fMaxSlopeNoise=0.25f;
tl_fMaxSlopeRandom=0;
// Tile layer properties
tl_ctTilesInRow = 1;
tl_ctTilesInCol = 1;
tl_iSelectedTile = 0;
tl_pixTileWidth = 128;
tl_pixTileHeight = 128;
tl_fTileU = 1.0f;
tl_fTileV = 1.0f;
}
void CTerrainLayer::operator=(const CTerrainLayer &tlOther)
{
Copy(tlOther);
}
// Copy terrain data from other terrain
void CTerrainLayer::Copy(const CTerrainLayer &tlOther)
{
// clear current layer data
Clear();
// if texture exists
if(tlOther.tl_ptdTexture!=NULL) {
// Copy texture
SetLayerTexture_t(tlOther.tl_ptdTexture->GetName());
}
// Allocate memory for vertex colors
SetLayerSize(tlOther.tl_iMaskWidth,tlOther.tl_iMaskHeight);
// Copy vertex colors
memcpy(tl_aubColors,tlOther.tl_aubColors,sizeof(UBYTE) * tl_iMaskWidth * tl_iMaskHeight);
// Copy reast of params
tl_strName = tlOther.tl_strName;
tl_bVisible = tlOther.tl_bVisible;
tl_colMultiply = tlOther.tl_colMultiply;
tl_fSmoothness = tlOther.tl_fSmoothness;
tl_ltType = tlOther.tl_ltType;
tl_fRotateX = tlOther.tl_fRotateX;
tl_fRotateY = tlOther.tl_fRotateY;
tl_fStretchX = tlOther.tl_fStretchX;
tl_fStretchY = tlOther.tl_fStretchY;
tl_fOffsetX = tlOther.tl_fOffsetX;
tl_fOffsetY = tlOther.tl_fOffsetY;
tl_bAutoRegenerated = tlOther.tl_bAutoRegenerated;
tl_fCoverage = tlOther.tl_fCoverage;
tl_fCoverageNoise = tlOther.tl_fCoverageNoise;
tl_fCoverageRandom = tlOther.tl_fCoverageRandom;
tl_bApplyMinAltitude = tlOther.tl_bApplyMinAltitude;
tl_fMinAltitude = tlOther.tl_fMinAltitude;
tl_fMinAltitudeFade = tlOther.tl_fMinAltitudeFade;
tl_fMinAltitudeNoise = tlOther.tl_fMinAltitudeNoise;
tl_fMinAltitudeRandom = tlOther.tl_fMinAltitudeRandom;
tl_bApplyMaxAltitude = tlOther.tl_bApplyMaxAltitude;
tl_fMaxAltitude = tlOther.tl_fMaxAltitude;
tl_fMaxAltitudeFade = tlOther.tl_fMaxAltitudeFade;
tl_fMaxAltitudeNoise = tlOther.tl_fMaxAltitudeNoise;
tl_fMaxAltitudeRandom = tlOther.tl_fMaxAltitudeRandom;
tl_bApplyMinSlope = tlOther.tl_bApplyMinSlope;
tl_fMinSlope = tlOther.tl_fMinSlope;
tl_fMinSlopeFade = tlOther.tl_fMinSlopeFade;
tl_fMinSlopeNoise = tlOther.tl_fMinSlopeNoise;
tl_fMinSlopeRandom = tlOther.tl_fMinSlopeRandom;
tl_bApplyMaxSlope = tlOther.tl_bApplyMaxSlope;
tl_fMaxSlope = tlOther.tl_fMaxSlope;
tl_fMaxSlopeFade = tlOther.tl_fMaxSlopeFade;
tl_fMaxSlopeNoise = tlOther.tl_fMaxSlopeNoise;
tl_fMaxSlopeRandom = tlOther.tl_fMaxSlopeRandom;
// Tile layer properties
tl_ctTilesInRow = tlOther.tl_ctTilesInRow;
tl_ctTilesInCol = tlOther.tl_ctTilesInCol;
tl_iSelectedTile = tlOther.tl_iSelectedTile;
tl_pixTileWidth = tlOther.tl_pixTileWidth;
tl_pixTileHeight = tlOther.tl_pixTileHeight;
tl_fTileU = tlOther.tl_fTileU;
tl_fTileV = tlOther.tl_fTileV;
}
// Read from stream.
void CTerrainLayer::Read_t(CTStream *istrFile,INDEX iSavedVersion)
{
CTFileName fn;
INDEX iMaskWidth;
INDEX iMaskHeight;
// Read terrain layer texture
(*istrFile).ExpectID_t("TLTX"); // 'Terrain layer texture'
(*istrFile)>>fn;
// Add texture to layer
SetLayerTexture_t(fn);
// Read terrain layer mask
(*istrFile).ExpectID_t("TLMA"); // 'Terrain layer mask'
(*istrFile)>>iMaskWidth;
(*istrFile)>>iMaskHeight;
// Set layer size
SetLayerSize(iMaskWidth,iMaskHeight);
(*istrFile).Read_t(&tl_aubColors[0],sizeof(UBYTE) * tl_iMaskWidth * tl_iMaskHeight);
if(istrFile->PeekID_t()==CChunkID("TLPA")) { // 'Terrain edge map'
// Read terrain layer params
(*istrFile).ExpectID_t("TLPA"); // 'Terrain layer params'
(*istrFile)>>tl_strName;
(*istrFile)>>tl_bVisible;
FLOAT fDummy;
(*istrFile)>>tl_fRotateX;
(*istrFile)>>tl_fRotateY;
(*istrFile)>>tl_fStretchX;
(*istrFile)>>tl_fStretchY;
(*istrFile)>>tl_fOffsetX;
(*istrFile)>>tl_fOffsetY;
(*istrFile)>>tl_bAutoRegenerated;
(*istrFile)>>tl_fCoverage;
(*istrFile)>>tl_fCoverageNoise;
(*istrFile)>>fDummy;
(*istrFile)>>fDummy;
(*istrFile)>>fDummy;
(*istrFile)>>fDummy;
(*istrFile)>>tl_fMinSlope;
(*istrFile)>>tl_fMaxSlope;
(*istrFile)>>fDummy;
(*istrFile)>>fDummy;
} else {
// Read terrain layer params
(*istrFile).ExpectID_t("TLPR"); // 'Terrain layer params'
(*istrFile)>>tl_strName;
(*istrFile)>>tl_bVisible;
(*istrFile)>>tl_fRotateX;
(*istrFile)>>tl_fRotateY;
(*istrFile)>>tl_fStretchX;
(*istrFile)>>tl_fStretchY;
(*istrFile)>>tl_fOffsetX;
(*istrFile)>>tl_fOffsetY;
(*istrFile)>>tl_bAutoRegenerated;
(*istrFile)>>tl_fCoverage;
(*istrFile)>>tl_fCoverageNoise;
(*istrFile)>>tl_fCoverageRandom;
(*istrFile)>>tl_bApplyMinAltitude;
(*istrFile)>>tl_fMinAltitude;
(*istrFile)>>tl_fMinAltitudeFade;
(*istrFile)>>tl_fMinAltitudeNoise;
(*istrFile)>>tl_fMinAltitudeRandom;
(*istrFile)>>tl_bApplyMaxAltitude;
(*istrFile)>>tl_fMaxAltitude;
(*istrFile)>>tl_fMaxAltitudeFade;
(*istrFile)>>tl_fMaxAltitudeNoise;
(*istrFile)>>tl_fMaxAltitudeRandom;
(*istrFile)>>tl_bApplyMinSlope;
(*istrFile)>>tl_fMinSlope;
(*istrFile)>>tl_fMinSlopeFade;
(*istrFile)>>tl_fMinSlopeNoise;
(*istrFile)>>tl_fMinSlopeRandom;
(*istrFile)>>tl_bApplyMaxSlope;
(*istrFile)>>tl_fMaxSlope;
(*istrFile)>>tl_fMaxSlopeFade;
(*istrFile)>>tl_fMaxSlopeNoise;
(*istrFile)>>tl_fMaxSlopeRandom;
if(iSavedVersion>=9) {
INDEX iType;
(*istrFile)>>tl_colMultiply;
(*istrFile)>>tl_fSmoothness;
(*istrFile)>>iType;
tl_ltType = (LayerType)iType;
// Tile layer properties
(*istrFile)>>tl_ctTilesInRow;
(*istrFile)>>tl_ctTilesInCol;
(*istrFile)>>tl_iSelectedTile;
(*istrFile)>>tl_pixTileWidth;
(*istrFile)>>tl_pixTileHeight;
(*istrFile)>>tl_fTileU;
(*istrFile)>>tl_fTileV;
}
}
}
// Write to stream.
void CTerrainLayer::Write_t( CTStream *ostrFile)
{
(*ostrFile).WriteID_t("TLTX"); // 'Terrain layer texture'
const CTFileName &fn = tl_ptdTexture->GetName();
(*ostrFile)<<fn;
// write terrain layer mask
(*ostrFile).WriteID_t("TLMA"); // 'Terrain layer mask'
(*ostrFile)<<tl_iMaskWidth;
(*ostrFile)<<tl_iMaskHeight;
(*ostrFile).Write_t(&tl_aubColors[0],sizeof(UBYTE) * tl_iMaskWidth * tl_iMaskHeight);
// Write terrain layer params
(*ostrFile).WriteID_t("TLPR"); // 'Terrain layer params'
(*ostrFile)<<tl_strName;
(*ostrFile)<<tl_bVisible;
(*ostrFile)<<tl_fRotateX;
(*ostrFile)<<tl_fRotateY;
(*ostrFile)<<tl_fStretchX;
(*ostrFile)<<tl_fStretchY;
(*ostrFile)<<tl_fOffsetX;
(*ostrFile)<<tl_fOffsetY;
(*ostrFile)<<tl_bAutoRegenerated;
(*ostrFile)<<tl_fCoverage;
(*ostrFile)<<tl_fCoverageNoise;
(*ostrFile)<<tl_fCoverageRandom;
(*ostrFile)<<tl_bApplyMinAltitude;
(*ostrFile)<<tl_fMinAltitude;
(*ostrFile)<<tl_fMinAltitudeFade;
(*ostrFile)<<tl_fMinAltitudeNoise;
(*ostrFile)<<tl_fMinAltitudeRandom;
(*ostrFile)<<tl_bApplyMaxAltitude;
(*ostrFile)<<tl_fMaxAltitude;
(*ostrFile)<<tl_fMaxAltitudeFade;
(*ostrFile)<<tl_fMaxAltitudeNoise;
(*ostrFile)<<tl_fMaxAltitudeRandom;
(*ostrFile)<<tl_bApplyMinSlope;
(*ostrFile)<<tl_fMinSlope;
(*ostrFile)<<tl_fMinSlopeFade;
(*ostrFile)<<tl_fMinSlopeNoise;
(*ostrFile)<<tl_fMinSlopeRandom;
(*ostrFile)<<tl_bApplyMaxSlope;
(*ostrFile)<<tl_fMaxSlope;
(*ostrFile)<<tl_fMaxSlopeFade;
(*ostrFile)<<tl_fMaxSlopeNoise;
(*ostrFile)<<tl_fMaxSlopeRandom;
(*ostrFile)<<tl_colMultiply;
(*ostrFile)<<tl_fSmoothness;
(*ostrFile)<<(INDEX)tl_ltType;
// Tile layer properties
(*ostrFile)<<tl_ctTilesInRow;
(*ostrFile)<<tl_ctTilesInCol;
(*ostrFile)<<tl_iSelectedTile;
(*ostrFile)<<tl_pixTileWidth;
(*ostrFile)<<tl_pixTileHeight;
(*ostrFile)<<tl_fTileU;
(*ostrFile)<<tl_fTileV;
}
// Clear terrain layer
void CTerrainLayer::Clear()
{
// if array of vertex colors was initialized
if(tl_aubColors!=NULL) {
// free array
FreeMemory(tl_aubColors);
tl_aubColors = NULL;
}
// if layer has valid texture
if(tl_ptdTexture!=NULL) {
// release texture from stock
_pTextureStock->Release(tl_ptdTexture);
tl_ptdTexture = NULL;
}
// Clear tumbnail texture
tl_tdThumbNail.Clear();
}
// Count used memory
SLONG CTerrainLayer::GetUsedMemory(void)
{
SLONG slUsedMemory=0;
slUsedMemory += sizeof(CTerrainLayer);
slUsedMemory += sizeof(UBYTE)*tl_iMaskWidth*tl_iMaskHeight;
return slUsedMemory;
}