Serious-Engine/Sources/Engine/Terrain/TerrainEditing.cpp
Daniel Gibson 72edf1c720 Commented out unused functions and variables
many unused functions and variables are now commented out

You'll still get tons of warnings, which should mostly fall in one of
the following categories:
1. Unnecessary variables or values generated from .es scripts
2. Pointers assigned to from functions with side-effects: DO NOT REMOVE!
   Like CEntity *penNew = CreateEntity_t(...); - even if penNew isn't
   used, CreateEntity() must be called there!
2016-05-09 18:51:03 +02:00

542 lines
18 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "Engine/StdH.h"
#include <Engine/Terrain/Terrain.h>
#include <Engine/Terrain/TerrainRender.h>
#include <Engine/Terrain/TerrainEditing.h>
#include <Engine/Terrain/TerrainMisc.h>
#include <Engine/Entities/Entity.h>
extern FLOAT3D _vViewerAbs; // Viewer pos
extern CStaticStackArray<GFXColor> _aiExtColors;
// Selection preview
static CTerrain *_ptrSelectionTerrain; // Terrain that needs to show vertex selection
static CTextureData *_ptdSelectionBrush; // Brush that will be used for vertex selection preview
static GFXColor _colSelection; // Selection color
static Rect _rcSelectionExtract; // Rect of selection vertices that will be shown
static FLOAT _fSelectionStrenght; // Selection preview strenght
static SelectionFill _sfSelectionFill; // Type of fill for selection preview
static FLOATaabbox3D CalculateAABBoxFromRect(CTerrain *ptrTerrain, Rect rcExtract)
{
ASSERT(ptrTerrain!=NULL);
ASSERT(ptrTerrain->tr_penEntity!=NULL);
// Get entity that holds this terrain
//CEntity *penEntity = ptrTerrain->tr_penEntity;
FLOATaabbox3D bboxExtract;
FLOATaabbox3D bboxAllTerrain;
ptrTerrain->GetAllTerrainBBox(bboxAllTerrain);
FLOAT fMinY = bboxAllTerrain.minvect(2);
FLOAT fMaxY = bboxAllTerrain.maxvect(2);
bboxExtract.minvect = FLOAT3D(rcExtract.rc_iLeft * ptrTerrain->tr_vStretch(1),fMinY,rcExtract.rc_iTop * ptrTerrain->tr_vStretch(3));
bboxExtract.maxvect = FLOAT3D(rcExtract.rc_iRight * ptrTerrain->tr_vStretch(1),fMaxY,rcExtract.rc_iBottom * ptrTerrain->tr_vStretch(3));
return bboxExtract;
}
// Find if there are any tiles in given rect that are not in lowest nor in highest lod without using TT_NO_LODING flag
static INDEX GetFirstTileInMidLod(CTerrain *ptrTerrain, Rect &rcExtract)
{
FLOATaabbox3D bboxExtract = CalculateAABBoxFromRect(ptrTerrain,rcExtract);
// for each terrain tile
for(INDEX itt=0;itt<ptrTerrain->tr_ctTiles;itt++) {
QuadTreeNode &qtn = ptrTerrain->tr_aqtnQuadTreeNodes[itt];
//CTerrainTile &tt = ptrTerrain->tr_attTiles[itt];
// if it is coliding with given box
if(qtn.qtn_aabbox.HasContactWith(bboxExtract)) {
// calculate its real distance factor
FLOAT fDistance = (qtn.qtn_aabbox.Center() - _vViewerAbs).Length();
INDEX iRealLod = Clamp((INDEX)(fDistance/ptrTerrain->tr_fDistFactor),(INDEX)0,ptrTerrain->tr_iMaxTileLod);
if(iRealLod>0 && iRealLod<ptrTerrain->tr_iMaxTileLod) {
// found one
return itt;
}
}
}
return -1;
}
// Add given flags to all tiles in rect
static void AddFlagsToTilesInRect(CTerrain *ptrTerrain, Rect &rcExtract, ULONG ulFlags, BOOL bRegenerateTiles=FALSE)
{
ASSERT(ptrTerrain!=NULL);
FLOATaabbox3D bboxExtract = CalculateAABBoxFromRect(ptrTerrain, rcExtract);
// for each terrain tile
for(INDEX itt=0;itt<ptrTerrain->tr_ctTiles;itt++) {
QuadTreeNode &qtn = ptrTerrain->tr_aqtnQuadTreeNodes[itt];
CTerrainTile &tt = ptrTerrain->tr_attTiles[itt];
// if it is coliding with given box
if(qtn.qtn_aabbox.HasContactWith(bboxExtract)) {
// if tile must regenerate
if(bRegenerateTiles) {
// add tile to regen queue
ptrTerrain->AddTileToRegenQueue(itt);
}
// add given flags to tile
tt.AddFlag(ulFlags);
}
}
}
// Update given rect of topmap
static void UpdateShadowMapRect(CTerrain *ptrTerrain, Rect &rcExtract)
{
FLOATaabbox3D bboxExtract = CalculateAABBoxFromRect(ptrTerrain,rcExtract);
ptrTerrain->UpdateShadowMap(&bboxExtract);
}
// Update terrain top map
static void UpdateTerrainGlobalTopMap(CTerrain *ptrTerrain, Rect &rcExtract)
{
// if there aren't any tiles in
if(GetFirstTileInMidLod(ptrTerrain,rcExtract)==(-1)) {
// update gloabal terrain top map now
ptrTerrain->UpdateTopMap(-1);
// else
} else {
// gloabal terrain top map will be updated when first tile chage its lod
ptrTerrain->AddFlag(TR_REGENERATE_TOP_MAP);
}
}
//
void ShowSelectionInternal(CTerrain *ptrTerrain, Rect &rcExtract, CTextureData *ptdBrush, GFXColor colSelection, FLOAT fStrenght, SelectionFill sfFill)
{
ASSERT(ptrTerrain!=NULL);
ASSERT(ptdBrush!=NULL);
Rect rcSelection;
FLOATaabbox3D bboxSelection;
// Clamp rect used for extraction
rcSelection.rc_iLeft = Clamp(rcExtract.rc_iLeft , 0, ptrTerrain->tr_pixHeightMapWidth);
rcSelection.rc_iTop = Clamp(rcExtract.rc_iTop , 0, ptrTerrain->tr_pixHeightMapHeight);
rcSelection.rc_iRight = Clamp(rcExtract.rc_iRight , 0, ptrTerrain->tr_pixHeightMapWidth);
rcSelection.rc_iBottom = Clamp(rcExtract.rc_iBottom , 0, ptrTerrain->tr_pixHeightMapHeight);
// Prepare box for vertex selection
bboxSelection = FLOAT3D(rcSelection.rc_iLeft, 0, rcSelection.rc_iTop);
bboxSelection |= FLOAT3D(rcSelection.rc_iRight, 0, rcSelection.rc_iBottom);
// Stretch selection box
bboxSelection.minvect(1) *= ptrTerrain->tr_vStretch(1);
bboxSelection.minvect(3) *= ptrTerrain->tr_vStretch(3);
bboxSelection.maxvect(1) *= ptrTerrain->tr_vStretch(1);
bboxSelection.maxvect(3) *= ptrTerrain->tr_vStretch(3);
// Set selection box height
FLOATaabbox3D bboxAllTerrain;
ptrTerrain->GetAllTerrainBBox(bboxAllTerrain);
bboxSelection.minvect(2) = bboxAllTerrain.minvect(2);
bboxSelection.maxvect(2) = bboxAllTerrain.maxvect(2);
GFXVertex *pavVertices;
INDEX *paiIndices;
INDEX ctVertices;
INDEX ctIndices;
// Extract vertices in selection rect
ExtractVerticesInRect(ptrTerrain, rcSelection, &pavVertices, &paiIndices, ctVertices, ctIndices);
if(ctVertices!=rcSelection.Width()*rcSelection.Height()) {
ASSERT(FALSE);
return;
}
// if no vertices
if(ctVertices==0) {
return;
}
// Prepare vertex colors for selection preview
PIX pixWidth = rcSelection.Width();
PIX pixHeight = rcSelection.Height();
INDEX iStepX = ptdBrush->GetWidth() - pixWidth;
INDEX iFirst = 0;
if(rcExtract.rc_iTop<0) {
iFirst += -rcExtract.rc_iTop*ptdBrush->GetWidth();
}
if(rcExtract.rc_iLeft<0) {
iFirst += -rcExtract.rc_iLeft;
}
_aiExtColors.Push(ctVertices);
GFXColor *pacolColor = (GFXColor*)&_aiExtColors[0];
GFXColor *pacolBrush = (GFXColor*)&ptdBrush->td_pulFrames[iFirst];
// Fill vertex colors for selection preview
SLONG slStrength = (SLONG) (Clamp(Abs(fStrenght),0.0f,1.0f) * 256.0f);
// for each row
for(INDEX iy=0;iy<pixHeight;iy++) {
// for each col
for(INDEX ix=0;ix<pixWidth;ix++) {
pacolColor->ul.abgr = colSelection.ul.abgr;
pacolColor->ub.a = (pacolBrush->ub.r*slStrength)>>8;
pacolColor++;
pacolBrush++;
}
pacolBrush+=iStepX;
}
// Render selected polygons for selection preview
if(sfFill == SF_WIREFRAME) {
gfxPolygonMode(GFX_LINE);
gfxEnableDepthBias();
}
if(sfFill != SF_POINTS) {
// Draw selection
gfxDisableTexture();
gfxDisableAlphaTest();
gfxEnableBlend();
gfxBlendFunc(GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA);
gfxSetVertexArray(pavVertices,ctVertices);
gfxSetColorArray(&_aiExtColors[0]);
gfxLockArrays();
gfxDrawElements(ctIndices,paiIndices);
gfxUnlockArrays();
gfxDisableBlend();
}
if(sfFill == SF_WIREFRAME) {
gfxDisableDepthBias();
gfxPolygonMode(GFX_FILL);
}
if(sfFill == SF_POINTS) {
DrawSelectedVertices(pavVertices,&_aiExtColors[0],ctVertices);
}
}
void ShowSelectionInternal(CTerrain *ptrTerrain)
{
// just in case
if(ptrTerrain!=_ptrSelectionTerrain) {
return;
}
// Show selection
ShowSelectionInternal(ptrTerrain,_rcSelectionExtract,_ptdSelectionBrush,_colSelection,_fSelectionStrenght,_sfSelectionFill);
}
void ShowSelection(CTerrain *ptrTerrain, Rect &rcExtract, CTextureData *ptdBrush, COLOR colSelection, FLOAT fStrenght, SelectionFill sfFill/*=SF_POLYGON*/)
{
_ptrSelectionTerrain = ptrTerrain;
_ptdSelectionBrush = ptdBrush;
_colSelection = colSelection;
_rcSelectionExtract = rcExtract;
_fSelectionStrenght = fStrenght;
_sfSelectionFill = sfFill,
// all tiles in rect must be in zero lod
AddFlagsToTilesInRect(ptrTerrain,rcExtract,TT_NO_LODING);
// Make sure selection is visible on next render
ptrTerrain->AddFlag(TR_SHOW_SELECTION);
}
static void UpdateEditedTerrainTiles(CTerrain *ptrTerrain, Rect &rcExtract, BufferType btBufferType)
{
// Update terrain tiles
if(btBufferType == BT_HEIGHT_MAP) {
AddFlagsToTilesInRect(ptrTerrain, rcExtract, TT_NO_LODING|TT_QUADTREENODE_REGEN, TRUE);
UpdateShadowMapRect(ptrTerrain, rcExtract);
} else if(btBufferType == BT_LAYER_MASK) {
AddFlagsToTilesInRect(ptrTerrain, rcExtract, TT_NO_LODING|TT_FORCE_TOPMAP_REGEN, TRUE);
UpdateTerrainGlobalTopMap(ptrTerrain,rcExtract);
} else if(btBufferType == BT_EDGE_MAP) {
AddFlagsToTilesInRect(ptrTerrain, rcExtract, TT_NO_LODING|TT_FORCE_TOPMAP_REGEN, TRUE);
UpdateTerrainGlobalTopMap(ptrTerrain,rcExtract);
} else {
ASSERTALWAYS("Ilegal buffer type");
return;
}
}
UWORD *GetBufferForEditing(CTerrain *ptrTerrain, Rect &rcExtract, BufferType btBufferType, INDEX iBufferData/*=-1*/)
{
ASSERT(ptrTerrain!=NULL);
ASSERT(rcExtract.Width()>0);
ASSERT(rcExtract.Height()>0);
PIX pixLeft = rcExtract.rc_iLeft;
PIX pixRight = rcExtract.rc_iRight;
PIX pixTop = rcExtract.rc_iTop;
PIX pixBottom = rcExtract.rc_iBottom;
PIX pixWidht = pixRight-pixLeft;
PIX pixHeight = pixBottom-pixTop;
PIX pixMaxWidth = ptrTerrain->tr_pixHeightMapWidth;
PIX pixMaxHeight = ptrTerrain->tr_pixHeightMapHeight;
// allocate memory for editing buffer
UWORD *pauwEditingBuffer = (UWORD*)AllocMemory(pixWidht*pixHeight*sizeof(UWORD));
// Get pointer to first member in editing pointer
UWORD *puwBufferData = &pauwEditingBuffer[0];
// if buffer type is height map
if(btBufferType==BT_HEIGHT_MAP) {
// Extract data from terrain height map
UWORD *puwFirstInHeightMap = &ptrTerrain->tr_auwHeightMap[0];
// for each row
for(PIX pixY=pixTop;pixY<pixBottom;pixY++) {
PIX pixRealY = Clamp(pixY,0,pixMaxHeight-1);
// for each col
for(PIX pixX=pixLeft;pixX<pixRight;pixX++) {
PIX pixRealX = Clamp(pixX,0,pixMaxWidth-1);
// Copy current pixel from height map to dest buffer
UWORD *puwHeight = &puwFirstInHeightMap[pixRealX + pixRealY*pixMaxWidth];
*puwBufferData = *puwHeight;
puwBufferData++;
}
}
// if buffer type is layer mask
} else if(btBufferType==BT_LAYER_MASK) {
// Extract data from layer mask
CTerrainLayer &tl = ptrTerrain->GetLayer(iBufferData);
UBYTE *pubFirstInLayer = &tl.tl_aubColors[0];
// for each row
for(PIX pixY=pixTop;pixY<pixBottom;pixY++) {
PIX pixRealY = Clamp(pixY,0,pixMaxHeight-1);
// for each col
for(PIX pixX=pixLeft;pixX<pixRight;pixX++) {
PIX pixRealX = Clamp(pixX,0,pixMaxWidth-1);
// Copy current pixel from layer mask to dest buffer
UBYTE *pubMaskValue = &pubFirstInLayer[pixRealX + pixRealY*pixMaxWidth];
*puwBufferData = (*pubMaskValue)<<8|(*pubMaskValue);
puwBufferData++;
}
}
// if buffer type is edge map
} else if(btBufferType==BT_EDGE_MAP) {
// Extract data from edge map
UBYTE *pubFirstInEdgeMap = &ptrTerrain->tr_aubEdgeMap[0];
// for each row
for(PIX pixY=pixTop;pixY<pixBottom;pixY++) {
PIX pixRealY = Clamp(pixY,0,pixMaxHeight-1);
// for each col
for(PIX pixX=pixLeft;pixX<pixRight;pixX++) {
PIX pixRealX = Clamp(pixX,0,pixMaxWidth-1);
// Copy current pixel from layer mask to dest buffer
UBYTE *pubEdgeValue = &pubFirstInEdgeMap[pixRealX + pixRealY*pixMaxWidth];
if((*pubEdgeValue)==255) {
*puwBufferData = 1;
} else {
*puwBufferData = 0;
}
puwBufferData++;
}
}
} else {
ASSERTALWAYS("Ilegal buffer type");
}
return &pauwEditingBuffer[0];
}
void SetBufferForEditing(CTerrain *ptrTerrain, UWORD *puwEditedBuffer, Rect &rcExtract, BufferType btBufferType, INDEX iBufferData/*=-1*/)
{
ASSERT(ptrTerrain!=NULL);
ASSERT(rcExtract.Width()>0);
ASSERT(rcExtract.Height()>0);
PIX pixLeft = rcExtract.rc_iLeft;
PIX pixRight = rcExtract.rc_iRight;
PIX pixTop = rcExtract.rc_iTop;
PIX pixBottom = rcExtract.rc_iBottom;
//PIX pixWidht = pixRight-pixLeft;
//PIX pixHeight = pixBottom-pixTop;
PIX pixMaxWidth = ptrTerrain->tr_pixHeightMapWidth;
PIX pixMaxHeight = ptrTerrain->tr_pixHeightMapHeight;
// Get pointer to first member in editing buffer
UWORD *puwBufferData = &puwEditedBuffer[0];
// if buffer type is height map
if(btBufferType==BT_HEIGHT_MAP) {
// put data from buffer to terrain height map
UWORD *puwFirstInHeightMap = &ptrTerrain->tr_auwHeightMap[0];
// for each row
for(PIX pixY=pixTop;pixY<pixBottom;pixY++) {
// if pixY is inside terrain rect
if(pixY>=0 && pixY<pixMaxHeight) {
// for each col
for(PIX pixX=pixLeft;pixX<pixRight;pixX++) {
// if pixX is inside terrain rect
if(pixX>=0 && pixX<pixMaxWidth) {
// Copy current pixel from editing buffer to height map
UWORD *puwHeight = &puwFirstInHeightMap[pixX + pixY*pixMaxWidth];
*puwHeight = *puwBufferData;
}
puwBufferData++;
}
// else pixY is not inside terrain rect
} else {
// increment buffer data pointer
puwBufferData+=pixRight-pixLeft;
}
}
} else if(btBufferType==BT_LAYER_MASK) {
// Extract data from layer mask
CTerrainLayer &tl = ptrTerrain->GetLayer(iBufferData);
UBYTE *pubFirstInLayer = &tl.tl_aubColors[0];
// for each row
for(PIX pixY=pixTop;pixY<pixBottom;pixY++) {
// if pixY is inside terrain rect
if(pixY>=0 && pixY<pixMaxHeight) {
// for each col
for(PIX pixX=pixLeft;pixX<pixRight;pixX++) {
// if pixX is inside terrain rect
if(pixX>=0 && pixX<pixMaxWidth) {
// Copy current pixel from editing buffer to height map
UBYTE *pubMask = &pubFirstInLayer[pixX + pixY*pixMaxWidth];
*pubMask = (*puwBufferData)>>8;
}
puwBufferData++;
}
// else pixY is not inside terrain rect
} else {
// increment buffer data pointer
puwBufferData+=pixRight-pixLeft;
}
}
} else if(btBufferType==BT_EDGE_MAP) {
// Extract data from edge map
UBYTE *pubFirstInEdgeMap = &ptrTerrain->tr_aubEdgeMap[0];
// for each row
for(PIX pixY=pixTop;pixY<pixBottom;pixY++) {
// if pixY is inside terrain rect
if(pixY>=0 && pixY<pixMaxHeight) {
// for each col
for(PIX pixX=pixLeft;pixX<pixRight;pixX++) {
// if pixX is inside terrain rect
if(pixX>=0 && pixX<pixMaxWidth) {
// Copy current pixel from editing buffer to edge map
UBYTE *pubMask = &pubFirstInEdgeMap[pixX + pixY*pixMaxWidth];
if(*puwBufferData>=1) {
*pubMask = 255;
} else {
*pubMask = 0;
}
}
puwBufferData++;
}
// else pixY is not inside terrain rect
} else {
// increment buffer data pointer
puwBufferData+=pixRight-pixLeft;
}
}
} else {
ASSERTALWAYS("Ilegal buffer type");
return;
}
UpdateEditedTerrainTiles(ptrTerrain,rcExtract,btBufferType);
}
// check whether a polygon is below given point, but not too far away
BOOL IsTerrainBelowPoint(CTerrain *ptrTerrain, const FLOAT3D &vPoint, FLOAT fMaxDist, const FLOAT3D &vGravityDir)
{
return TRUE;
/*
// get distance from point to the plane
FLOAT fD = plPolygon.PointDistance(vPoint);
// if the point is behind the plane
if (fD<-0.01f) {
// it cannot be below
_pfPhysicsProfile.StopTimer(CPhysicsProfile::PTI_ISSTANDINGONPOLYGON);
return FALSE;
}
// find distance of point from the polygon along gravity vector
FLOAT fDistance = -fD/fCos;
// if too far away
if (fDistance > fMaxDist) {
// it cannot be below
_pfPhysicsProfile.StopTimer(CPhysicsProfile::PTI_ISSTANDINGONPOLYGON);
return FALSE;
}
// project point to the polygon along gravity vector
FLOAT3D vProjected = vPoint + en_vGravityDir*fDistance;
// find major axes of the polygon plane
INDEX iMajorAxis1, iMajorAxis2;
GetMajorAxesForPlane(plPolygon, iMajorAxis1, iMajorAxis2);
// create an intersector
CIntersector isIntersector(vProjected(iMajorAxis1), vProjected(iMajorAxis2));
// for all edges in the polygon
FOREACHINSTATICARRAY(pbpo->bpo_abpePolygonEdges, CBrushPolygonEdge, itbpePolygonEdge) {
// get edge vertices (edge direction is irrelevant here!)
const FLOAT3D &vVertex0 = itbpePolygonEdge->bpe_pbedEdge->bed_pbvxVertex0->bvx_vAbsolute;
const FLOAT3D &vVertex1 = itbpePolygonEdge->bpe_pbedEdge->bed_pbvxVertex1->bvx_vAbsolute;
// pass the edge to the intersector
isIntersector.AddEdge(
vVertex0(iMajorAxis1), vVertex0(iMajorAxis2),
vVertex1(iMajorAxis1), vVertex1(iMajorAxis2));
}
// if the point is inside polygon
if (isIntersector.IsIntersecting()) {
// it is below
_pfPhysicsProfile.StopTimer(CPhysicsProfile::PTI_ISSTANDINGONPOLYGON);
return TRUE;
// if the point is outside polygon
} else {
// it is not below
_pfPhysicsProfile.StopTimer(CPhysicsProfile::PTI_ISSTANDINGONPOLYGON);
return FALSE;
}
*/
}