1
0
forked from 0ad/0ad

# More consistent terrain-space coordinate names

# Removed more ancient unused code
# Partial VC2005 compatibility for Atlas editor / AoE3Ed
# Terrain overlay rendering system; used to implemented Atlas brush
display
# Renamed 'right' to 'left'

This was SVN commit r3771.
This commit is contained in:
Ykkrosh 2006-04-17 20:02:51 +00:00
parent ca12496c2f
commit 8a11f53011
19 changed files with 517 additions and 769 deletions

View File

@ -83,9 +83,9 @@ void CTerrain::CalcPosition(i32 i, i32 j, CVector3D& pos) const
height = m_Heightmap[j*m_MapSize + i];
else
height = 0;
pos.X = float(i)*CELL_SIZE;
pos.Y = float(height)*HEIGHT_SCALE;
pos.Z = float(j)*CELL_SIZE;
pos.X = float(i*CELL_SIZE);
pos.Y = float(height*HEIGHT_SCALE);
pos.Z = float(j*CELL_SIZE);
}
@ -137,58 +137,50 @@ void CTerrain::CalcNormal(u32 i, u32 j, CVector3D& normal) const
///////////////////////////////////////////////////////////////////////////////
// GetPatch: return the patch at (x,z) in patch space, or null if the patch is
// GetPatch: return the patch at (i,j) in patch space, or null if the patch is
// out of bounds
CPatch* CTerrain::GetPatch(i32 x, i32 z) const
CPatch* CTerrain::GetPatch(i32 i, i32 j) const
{
if (x<0 || x>=i32(m_MapSizePatches)) return 0;
if (z<0 || z>=i32(m_MapSizePatches)) return 0;
return &m_Patches[(z*m_MapSizePatches)+x];
if (i<0 || i>=i32(m_MapSizePatches)) return 0;
if (j<0 || j>=i32(m_MapSizePatches)) return 0;
return &m_Patches[(j*m_MapSizePatches)+i];
}
///////////////////////////////////////////////////////////////////////////////
// GetPatch: return the tile at (x,z) in tile space, or null if the tile is out
// GetPatch: return the tile at (i,j) in tile space, or null if the tile is out
// of bounds
CMiniPatch* CTerrain::GetTile(i32 x, i32 z) const
CMiniPatch* CTerrain::GetTile(i32 i, i32 j) const
{
if (x<0 || x>=i32(m_MapSize)-1) return 0;
if (z<0 || z>=i32(m_MapSize)-1) return 0;
if (i<0 || i>=i32(m_MapSize)-1) return 0;
if (j<0 || j>=i32(m_MapSize)-1) return 0;
CPatch* patch=GetPatch(x/PATCH_SIZE,z/PATCH_SIZE);
return &patch->m_MiniPatches[z%PATCH_SIZE][x%PATCH_SIZE];
CPatch* patch=GetPatch(i/PATCH_SIZE, j/PATCH_SIZE);
return &patch->m_MiniPatches[j%PATCH_SIZE][i%PATCH_SIZE];
}
float CTerrain::getVertexGroundLevel(int x, int z) const
float CTerrain::getVertexGroundLevel(int i, int j) const
{
if (x < 0)
{
x = 0;
}
else if (x >= (int) m_MapSize)
{
x = m_MapSize - 1;
}
if (i < 0)
i = 0;
else if (i >= (int) m_MapSize)
i = m_MapSize - 1;
if (z < 0)
{
z = 0;
}
else if (z >= (int) m_MapSize)
{
z = m_MapSize - 1;
}
if (j < 0)
j = 0;
else if (j >= (int) m_MapSize)
j = m_MapSize - 1;
return HEIGHT_SCALE * m_Heightmap[z*m_MapSize + x];
return HEIGHT_SCALE * m_Heightmap[j*m_MapSize + i];
}
float CTerrain::getSlope(float x, float y) const
float CTerrain::getSlope(float x, float z) const
{
x /= (float)CELL_SIZE;
y /= (float)CELL_SIZE;
z /= (float)CELL_SIZE;
int xi = (int)floor(x);
int yi = (int)floor(y);
int zi = (int)floor(z);
if (xi < 0)
{
@ -199,33 +191,33 @@ float CTerrain::getSlope(float x, float y) const
xi = m_MapSize - 2;
}
if (yi < 0)
if (zi < 0)
{
yi = 0;
zi = 0;
}
else if (yi >= (int)m_MapSize-1)
else if (zi >= (int)m_MapSize-1)
{
yi = m_MapSize - 2;
zi = m_MapSize - 2;
}
float h00 = m_Heightmap[yi*m_MapSize + xi];
float h01 = m_Heightmap[yi*m_MapSize + xi + m_MapSize];
float h10 = m_Heightmap[yi*m_MapSize + xi + 1];
float h11 = m_Heightmap[yi*m_MapSize + xi + m_MapSize + 1];
float h00 = m_Heightmap[zi*m_MapSize + xi];
float h01 = m_Heightmap[zi*m_MapSize + xi + m_MapSize];
float h10 = m_Heightmap[zi*m_MapSize + xi + 1];
float h11 = m_Heightmap[zi*m_MapSize + xi + m_MapSize + 1];
return MAX(MAX(h00, h01), MAX(h10, h11)) -
MIN(MIN(h00, h01), MIN(h10, h11));
}
float CTerrain::getExactGroundLevel(float x, float y) const
float CTerrain::getExactGroundLevel(float x, float z) const
{
x /= (float)CELL_SIZE;
y /= (float)CELL_SIZE;
z /= (float)CELL_SIZE;
int xi = (int)floor(x);
int yi = (int)floor(y);
int zi = (int)floor(z);
float xf = x - (float)xi;
float yf = y - (float)yi;
float zf = z - (float)zi;
if (xi < 0)
{
@ -236,13 +228,13 @@ float CTerrain::getExactGroundLevel(float x, float y) const
xi = m_MapSize - 2; xf = 1.0f;
}
if (yi < 0)
if (zi < 0)
{
yi = 0; yf = 0.0f;
zi = 0; zf = 0.0f;
}
else if (yi >= (int)m_MapSize-1)
else if (zi >= (int)m_MapSize-1)
{
yi = m_MapSize - 2; yf = 1.0f;
zi = m_MapSize - 2; zf = 1.0f;
}
/*
@ -252,13 +244,13 @@ float CTerrain::getExactGroundLevel(float x, float y) const
return 0.0f;
*/
float h00 = m_Heightmap[yi*m_MapSize + xi];
float h01 = m_Heightmap[yi*m_MapSize + xi + m_MapSize];
float h10 = m_Heightmap[yi*m_MapSize + xi + 1];
float h11 = m_Heightmap[yi*m_MapSize + xi + m_MapSize + 1];
float h00 = m_Heightmap[zi*m_MapSize + xi];
float h01 = m_Heightmap[zi*m_MapSize + xi + m_MapSize];
float h10 = m_Heightmap[zi*m_MapSize + xi + 1];
float h11 = m_Heightmap[zi*m_MapSize + xi + m_MapSize + 1];
return (HEIGHT_SCALE * (
(1 - yf) * ((1 - xf) * h00 + xf * h10)
+ yf * ((1 - xf) * h01 + xf * h11)));
(1 - zf) * ((1 - xf) * h00 + xf * h10)
+ zf * ((1 - xf) * h01 + xf * h11)));
}
///////////////////////////////////////////////////////////////////////////////
@ -407,12 +399,12 @@ void CTerrain::SetHeightMap(u16* heightmap)
///////////////////////////////////////////////////////////////////////////////
// FlattenArea: flatten out an area of terrain (specified in world space
// coords); return the average height of the flattened area
float CTerrain::FlattenArea(float x0,float x1,float z0,float z1)
float CTerrain::FlattenArea(float x0, float x1, float z0, float z1)
{
u32 tx0=u32(clamp(int(float(x0/CELL_SIZE)),0,int(m_MapSize)));
u32 tx1=u32(clamp(int(float(x1/CELL_SIZE)+1.0f),0,int(m_MapSize)));
u32 tz0=u32(clamp(int(float(z0/CELL_SIZE)),0,int(m_MapSize)));
u32 tz1=u32(clamp(int(float(z1/CELL_SIZE)+1.0f),0,int(m_MapSize)));
u32 tx0=u32(clamp(int(float(x0/CELL_SIZE)), 0, int(m_MapSize)));
u32 tx1=u32(clamp(int(float(x1/CELL_SIZE)+1.0f), 0, int(m_MapSize)));
u32 tz0=u32(clamp(int(float(z0/CELL_SIZE)), 0, int(m_MapSize)));
u32 tz1=u32(clamp(int(float(z1/CELL_SIZE)+1.0f), 0, int(m_MapSize)));
u32 count=0;
u32 y=0;
@ -437,15 +429,15 @@ float CTerrain::FlattenArea(float x0,float x1,float z0,float z1)
///////////////////////////////////////////////////////////////////////////////
void CTerrain::MakeDirty(int x0, int z0, int x1, int z1, int dirtyFlags)
void CTerrain::MakeDirty(int i0, int j0, int i1, int j1, int dirtyFlags)
{
// flag vertex data as dirty for affected patches, and rebuild bounds of these patches
int px0 = clamp((x0/PATCH_SIZE)-1, 0, (int)m_MapSizePatches);
int px1 = clamp((x1/PATCH_SIZE)+1, 0, (int)m_MapSizePatches);
int pz0 = clamp((z0/PATCH_SIZE)-1, 0, (int)m_MapSizePatches);
int pz1 = clamp((z1/PATCH_SIZE)+1, 0, (int)m_MapSizePatches);
for (int j = pz0; j < pz1; j++) {
for (int i = px0; i < px1; i++) {
int pi0 = clamp((i0/PATCH_SIZE)-1, 0, (int)m_MapSizePatches);
int pi1 = clamp((i1/PATCH_SIZE)+1, 0, (int)m_MapSizePatches);
int pj0 = clamp((j0/PATCH_SIZE)-1, 0, (int)m_MapSizePatches);
int pj1 = clamp((j1/PATCH_SIZE)+1, 0, (int)m_MapSizePatches);
for (int j = pj0; j < pj1; j++) {
for (int i = pi0; i < pi1; i++) {
CPatch* patch = GetPatch(i,j);
if (dirtyFlags & RENDERDATA_UPDATE_VERTICES)
patch->CalcBounds();

View File

@ -23,26 +23,28 @@ public:
CTerrain();
~CTerrain();
bool Initialize(u32 size,const u16* ptr);
// Coordinate naming convention: world-space coordinates are float x,z;
// tile-space coordinates are int i,j.
bool Initialize(u32 size, const u16* ptr);
// return number of vertices along edge of the terrain
u32 GetVerticesPerSide() const { return m_MapSize; }
// return number of tiles along edge of the terrain
u32 GetTilesPerSide() const { return GetVerticesPerSide()-1; }
// return number of patches along edge of the terrain
u32 GetPatchesPerSide() const { return m_MapSizePatches; }
inline bool isOnMap( float x, float y ) const
inline bool isOnMap(float x, float z) const
{
return( ( x >= 0.0f ) && ( x < (float)( (m_MapSize-1) * CELL_SIZE ) ) && ( y >= 0.0f ) && ( y < (float)( (m_MapSize-1) * CELL_SIZE ) ) );
return ((x >= 0.0f) && (x < (float)((m_MapSize-1) * CELL_SIZE)) && (z >= 0.0f) && (z < (float)((m_MapSize-1) * CELL_SIZE)));
}
inline bool isOnMap( const CVector2D& v ) const
{
return( ( v.x >= 0.0f ) && ( v.x < (float)( (m_MapSize-1) * CELL_SIZE ) ) && ( v.y >= 0.0f ) && ( v.y < (float)( (m_MapSize-1) * CELL_SIZE ) ) );
}
float getVertexGroundLevel( int x, int y ) const ;
float getExactGroundLevel( float x, float y ) const ;
inline float getExactGroundLevel( const CVector2D& v ) const { return( getExactGroundLevel( v.x, v.y ) ); }
inline bool isOnMap(const CVector2D& v) const { return isOnMap(v.x, v.y); }
float getVertexGroundLevel(int i, int j) const;
float getExactGroundLevel(float x, float z) const;
inline float getExactGroundLevel(const CVector2D& v) const { return getExactGroundLevel(v.x, v.y); }
float getSlope(float x, float y) const ;
float getSlope(float x, float z) const ;
// resize this terrain such that each side has given number of patches
void Resize(u32 size);
@ -54,10 +56,10 @@ public:
// get patch at given coordinates, expressed in patch-space; return 0 if
// coordinates represent patch off the edge of the map
CPatch* GetPatch(i32 x, i32 z) const;
CPatch* GetPatch(i32 i, i32 j) const;
// get tile at given coordinates, expressed in tile-space; return 0 if
// coordinates represent tile off the edge of the map
CMiniPatch* GetTile(i32 x, i32 z) const;
CMiniPatch* GetTile(i32 i, i32 j) const;
// calculate the position of a given vertex
void CalcPosition(i32 i, i32 j, CVector3D& pos) const;
@ -68,20 +70,20 @@ public:
j = i32_from_float(pos.Z/CELL_SIZE);
}
// calculate the vertex under a given position (rounding down coordinates)
static void CalcFromPosition(float x, float y, i32& i, i32& j)
static void CalcFromPosition(float x, float z, i32& i, i32& j)
{
i = i32_from_float(x/CELL_SIZE);
j = i32_from_float(y/CELL_SIZE);
j = i32_from_float(z/CELL_SIZE);
}
// calculate the normal at a given vertex
void CalcNormal(u32 i, u32 j, CVector3D& normal) const;
// flatten out an area of terrain (specified in world space coords); return
// the average height of the flattened area
float FlattenArea(float x0,float x1,float z0,float z1);
float FlattenArea(float x0, float x1, float z0, float z1);
// mark a specific square of tiles as dirty - use this after modifying the heightmap
void MakeDirty(int x0, int z0, int x1, int z1, int dirtyFlags);
void MakeDirty(int i0, int j0, int i1, int j1, int dirtyFlags);
// mark the entire map as dirty
void MakeDirty(int dirtyFlags);

View File

@ -1,250 +0,0 @@
#include "precompiled.h"
#if 0
// last modified Thursday, May 08, 2003
#include <time.h>
#include <cstdlib>
#include "MathUtil.h"
// MathUtil Errors
DEFINE_ERROR(ERRONEOUS_BOUND_ERROR, "Lower Bound is >= Upper Bound");
//////////////////////////////////////////////////////////////////////
// NAME: CompareFloat
// PURPOSE: Returns true if two floating point numbers are within
// FL_FP_TOLERANCE of each other.
//
bool MathUtil::CompareFloat(const double &num1, const double &num2)
{
if( Abs(num1 - num2) < FL_FP_TOLERANCE )
return true;
else
return false;
}
//////////////////////////////////////////////////////////////////////
// NAME: RadiansToDegrees
// PURPOSE: Converts from Radians to Degrees
//
inline double MathUtil::RadiansToDegrees(const double &num)
{
return num*(PI/180);
}
//////////////////////////////////////////////////////////////////////
// NAME: RadiansToDegrees
// PURPOSE: Converts from Degrees to Radians
//
inline double MathUtil::DegreesToRadians(const double &num)
{
return (num*180)/PI;
}
/*
//////////////////////////////////////////////////////////////////////
// NAME: Random
// PURPOSE: returns a random floating point number between lowerBound
// and upperBound
// NOTES: returns -1 if lowerBound >= upperBound
//
float MathUtil::Random(const float &lowerBound, const float &upperBound)
{
if( lowerBound >= upperBound)
return -1;
else
{
// seed generator with current time
srand( static_cast<unsigned>( time(NULL) ) );
// finds a floating point number between 0 and 1.0
float randVar = ( static_cast<float>( rand() )/RAND_MAX );
// maps the number onto the set from 0 to upperBound
randVar *= Abs(lowerBound - upperBound ) + 1;
//translate to the proper range
randVar += lowerBound;
return randVar;
}
}
//////////////////////////////////////////////////////////////////////
// NAME: Random
// PURPOSE: returns a random number between lowerBound and upperBound
// NOTES: returns -1 if lowerBound >= upperBound
//
int MathUtil::Random(const int &lowerBound,const int &upperBound)
{
if( lowerBound >= upperBound)
return -1;
else
{
// seed generator with current time
srand( static_cast<unsigned>( time(NULL) ) );
// find a random variable between 0 and range size
int randVar = rand()%( Abs(upperBound - lowerBound) + 1);
// translate to proper range
randVar += lowerBound;
return randVar;
}
}
*/
//////////////////////////////////////////////////////////
// NAME: Round
// PURPOSE: Rounds a number.
// NOTES: Round rounds to the nearest representable number
// float version.
//
int MathUtil::Round(const float &num)
{
if( num > 0 )
return static_cast<int>(num + .5);
else if (num < 0 )
return static_cast<int>(num - .5);
else
return 0;
}
//////////////////////////////////////////////////////////
// NAME: Round
// PURPOSE: Rounds a number.
// NOTES: Round rounds to the nearest representable number
// double version.
//
int MathUtil::Round(const double &num)
{
if( num > 0 )
return static_cast<int>(num + .5);
else if (num < 0 )
return static_cast<int>(num - .5);
else
return 0;
}
//////////////////////////////////////////////////////////////////////
// NAME: SignedModulus
// PURPOSE: returns a mathematically correct modulus for int
//
int MathUtil::SignedModulus(const int &num, const int &n)
{
if( num >= 0 )
return num%n;
else
{
// the % operator reflects the range if num < 0, so
// we have to multiply by -1 to reflect it back. This method
// is faster than calling Abs() and then doing the modulus.
int Tnum = -1*(num%n);
// if num%n equals 0, then n - Tnum will be n, which, logically
// speaking, is 0 in a different form, but we have to make sure it's
// in the form 0, and not n. Therefore, if Tnum = 0, simply leave
// it like that.
if( Tnum != 0)
Tnum = n - Tnum;
return Tnum;
}
}
//////////////////////////////////////////////////////////////////////
// NAME: SignedModulus
// PURPOSE: returns a mathematically correct modulus for long
//
long MathUtil::SignedModulus(const long &num, const long &n)
{
if( num >= 0 )
return num%n;
else
{
// the % operator reflects the range if num < 0, so
// we have to multiply by -1 to reflect it back. This method
// is faster than calling Abs() and then doing the modulus.
long Tnum = -1*(num%n);
// if num%n equals 0, then n - Tnum will be n, which, logically
// speaking, is 0 in a different form, but we have to make sure it's
// in the form 0, and not n. Therefore, if Tnum = 0, simply leave
// it like that.
if( Tnum != 0)
Tnum = n - Tnum;
return Tnum;
}
}
//////////////////////////////////////////////////////////////////////
// NAME: SignedModulus
// PURPOSE: returns a mathematically correct modulus for float
// NOTES: uses fmod() in math.h, which returns the modulus of floats
//
float MathUtil::SignedModulus(const float &num, const float &n)
{
if( num >=0 )
return static_cast<float>( fmod(num,n) );
else
{
// the % operator reflects the range if num < 0, so
// we have to multiply by -1 to reflect it back. This method
// is faster than calling Abs() and then doing the modulus.
float Tnum = -1*( static_cast<float>( fmod(num,n) ) );
// if num%n equals 0, then n - Tnum will be n, which, logically
// speaking, is 0 in a different form, but we have to make sure it's
// in the form 0, and not n. Therefore, if Tnum = 0, simply leave
// it like that.
if( Tnum != 0)
Tnum = n - Tnum;
return Tnum;
}
}
//////////////////////////////////////////////////////////////////////
// NAME: SignedModulus
// PURPOSE: returns a mathematically correct modulus for double
// NOTES: uses fmod() in math.h, which returns the modulus of floats
//
double MathUtil::SignedModulus(const double &num, const double &n)
{
if( num >=0 )
return fmod(num,n);
else
{
// the % operator reflects the range if num < 0, so
// we have to multiply by -1 to reflect it back. This method
// is faster than calling Abs() and then doing the modulus.
double Tnum = -1*( fmod(num,n) );
// if num%n equals 0, then n - Tnum will be n, which, logically
// speaking, is 0 in a different form, but we have to make sure it's
// in the form 0, and not n. Therefore, if Tnum = 0, simply leave
// it like that.
if( Tnum != 0)
Tnum = n - Tnum;
return Tnum;
}
}
#endif

View File

@ -43,209 +43,4 @@ static inline int RoundUpToPowerOf2(int x)
return d<<1;
}
#if 0
/*
Math utility functions
by Michael Reiland
recondite_phreak@yahool.com
--Overview--
Contains common math functions like Abs, Sign, Max, Min, etc.
--More info--
TODO: actually write corresponding documentation
http://wildfiregames.com/0ad/codepit/TDD/math_utils.html
*/
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include "Pyrogenesis.h" // Standard Engine Include
#include <math.h> // Needed for fmod()
//--------------------------------------------------------
// Error declarations
//--------------------------------------------------------
// MathUtil Errors
DECLARE_ERROR(ERRONEOUS_BOUND_ERROR);
//--------------------------------------------------------
// Declarations
//--------------------------------------------------------
namespace MathUtil
{
const double PI = 3.14159265358932384;
const double FL_FP_TOLERANCE = .000000001;
//--------------------------------------------------------
// Template functions
//--------------------------------------------------------
//--------------------------------------------------------
// Declarations
//--------------------------------------------------------
//////////////////////////////////////////////////////////
// NAME: Abs
// PURPOSE: Calculates the Absolute value
//
template <typename T>
T Abs(const T &num)
{
if( num < 0)
return -1*num;
return num;
}
//////////////////////////////////////////////////////////
// NAME: Clamp
// PURPOSE: Forces num to be between lowerBound and upperBound
//
template <typename T>
T Clamp(T &num, const int &lowerBound,const int &upperBound)
{
if(num <= lowerBound)
num = static_cast<T>(lowerBound);
else if( num >= upperBound)
num = static_cast<T>(upperBound);
}
//////////////////////////////////////////////////////////
// NAME: Max
// PURPOSE: Returns the largest number.
//
template <typename T>
T Max(const T &num1, const T &num2)
{
if( num1 > num2)
return num1;
else
return num2;
}
//////////////////////////////////////////////////////////
// NAME: Min
// PURPOSE: Returns the smallest number.
//
template <typename T>
T Min(const T &num1, const T &num2)
{
if( num1 < num2)
return num1;
else
return num2;
}
//////////////////////////////////////////////////////////
// NAME: Sign
// PURPOSE: Returns 1 if the number is > 0, -1 if it's < 0,
// otherwise returns 0.
//
template <typename T>
int Sign(const T &num)
{
if( num > 0 )
return 1;
else if( num < 0 )
return -1;
else
return 0;
}
//////////////////////////////////////////////////////////
// NAME: Square
// PURPOSE: Returns the square of a number
// NOTES: Num should be less than the square root of the
// maximum representable number for the data type.
//
template <typename T>
inline double Square(const T &num)
{
return num*num;
}
//////////////////////////////////////////////////////////
// NAME: Swap
// PURPOSE: Swaps two numbers
//
template <typename T>
void Swap(T *num1, T *num2)
{
T temp = num1;
num1 = num2;
num2 = temp;
}
//////////////////////////////////////////////////////////
// NAME: Wrap
// PURPOSE: Wraps num between lowerBound and upperBound.
//
template <typename T>
int Wrap(T *num,const T &lowerBound, const T &upperBound)
{
if(lowerBound >= upperBound)
return -1;
else
{
// translate to range 0 to n-1, find the modulus, then
// translate back to range lowerBound to upperBound.
num -= lowerBound;
num = SignedModulus( num, Abs(upperBound - lowerBound) );
num += lowerBound;
}
return 0;
}
//--------------------------------------------------------
// Non-template functions
//--------------------------------------------------------
int Ceiling(const float &num);
int Ceiling(const double &num);
bool CompareFloat(const double &, const double &);
int Floor(const float &num);
int Floor(const double &num);
inline double RadiansToDegrees(const double &num);
inline double DegreesToRadians(const double &num);
float Random(const float &, const float &);
int Random(const int &,const int &);
int Round(const float &num);
int Round(const double &num);
int SignedModulus(const int &num, const int &n);
long SignedModulus(const long &num, const long &n);
float SignedModulus(const float &num, const float &n);
double SignedModulus(const double &num, const double &n);
}
#endif
#endif

View File

@ -60,6 +60,9 @@ class CVector3D
//Returns length of the vector
float GetLength () const;
void Normalize ();
// Returns 3 element array of floats, e.g. for glVertex3fv
const float* GetFloatArray() const { return &X; }
};
#endif

View File

@ -1,167 +0,0 @@
/*
Sound.h
by Raj
Classes to play sounds or music using FMOD
Usage: Create a CWindow object, call Create, call Run.
If you want to handle events like mouse clicks, you need to derive your
own class from CBaseWindow, and override the OnXXX() functions. For example,
OnActivate() or OnPaint().
*/
#if 0
-----support pan, volume, and crossfading
struct SSoundEffect
{
Position
Radius
Volume
Actual sound effect
Layer
};
struct SoundScheme
{
include several different sounds
specify the looping time for this scheme
and,
}
Class methods
-SetCrossFadeSpeed: how quickly it takes to crossfade between current music and new music
#ifndef SOUND_H
#define SOUND_H
#pragma warning (disable: 4786)
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include <Flamer.h>
#include <Sound.h>
#include <map>
#include <fmod.h>
#include <string>
#include <FileIO.h>
using namespace std;
DECLARE_ERROR(PS_SOUND_INIT);
typedef bool STREAM_OPTION;
const int STREAMING = true;
const int NO_STREAMING = false;
class CSample
{
public:
operator FSOUND_STREAM * ();
operator FSOUND_SAMPLE * ();
operator = (FSOUND_STREAM *);
operator = (FSOUND_SAMPLE *);
private:
union
{
FSOUND_STREAM *stream;
FSOUND_SAMPLE *sample;
};
};
// CSound: Class which plays sounds or music
class CSound
{
public:
CSound();
~CSound();
PS_RESULT Init();
PS_RESULT Release();
PS_RESULT Load(string filename, string nickname, STREAM_OPTION useStreaming=false);
PS_RESULT Play(string nickname);
PS_RESULT SetMasterVolume(float vol);
PS_RESULT SetSampleVolume(string sample, float vol);
PS_RESULT Pause();
PS_RESULT Resume();
private:
map <string, CSample> soundList;
};
PS_RESULT CSound::Load(string filename, string nickname, STREAM_OPTION useStreaming)
{
CSample newFile;
if(useStreaming == STREAMING)
{
}
else if(useStreaming == NO_STREAMING)
{
FSOUND_Sample_Load(FSOUND_FREE, //let FSOUND select an arbitrary sample slot
filename.c_str(), //name of the file to load
FSOUND_LOADMEMORY,
);
}
return PS_OK;
}
PS_RESULT CSound::Play(string nickname)
{
return PS_OK;
}
PS_RESULT CSound::Release()
{
return PS_OK;
}
PS_RESULT CSound::SetMasterVolume(float vol)
{
return PS_OK;
}
PS_RESULT CSound::SetSampleVolume(string sample, float vol)
{
return PS_OK;
}
PS_RESULT CSound::Pause()
{
return PS_OK;
}
PS_RESULT CSound::Resume()
{
return PS_OK;
}
#endif
#endif

View File

@ -54,6 +54,7 @@
#include "renderer/RenderModifiers.h"
#include "renderer/RenderPathVertexShader.h"
#include "renderer/ShadowMap.h"
#include "renderer/TerrainOverlay.h"
#include "renderer/TerrainRenderer.h"
#include "renderer/TransparencyRenderer.h"
#include "renderer/WaterManager.h"
@ -962,6 +963,9 @@ void CRenderer::FlushFrame()
RenderPatches();
oglCheck();
// render debug-related terrain overlays
TerrainOverlay::RenderOverlays();
MICROLOG(L"render models");
RenderModels();
oglCheck();

View File

@ -0,0 +1,184 @@
#include "precompiled.h"
#include "TerrainOverlay.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "graphics/Terrain.h"
#include "maths/MathUtil.h"
#include "lib/ogl.h"
// Handy things for STL:
/**
* Functor for sorting pairs, using the &lt;-ordering of their second values.
*/
struct compare2nd
{
template<typename S, typename T> bool operator()(const std::pair<S, T>& a, const std::pair<S, T>& b) const
{
return a.second < b.second;
}
};
/**
* Functor for comparing the firsts of pairs to a specified value.
*/
template<typename S> struct equal1st
{
const S& val;
equal1st(const S& val) : val(val) {}
template <typename T> bool operator()(const std::pair<S, T>& a) const
{
return a.first == val;
}
private:
const equal1st& operator=(const equal1st& rhs);
};
/**
* Functor for calling ->Render on pairs' firsts.
*/
struct render1st
{
template<typename S, typename T> void operator()(const std::pair<S, T>& a) const
{
a.first->Render();
}
};
//////////////////////////////////////////////////////////////////////////
// Global overlay list management:
static std::vector<std::pair<TerrainOverlay*, int> > g_TerrainOverlayList;
TerrainOverlay::TerrainOverlay(int priority)
{
// Add to global list of overlays
g_TerrainOverlayList.push_back(std::make_pair(this, priority));
// Sort by overlays by priority. Do stable sort so that adding/removing
// overlays doesn't randomly disturb all the existing ones (which would
// be noticeable if they have the same priority and overlap).
std::stable_sort(g_TerrainOverlayList.begin(), g_TerrainOverlayList.end(),
compare2nd());
}
TerrainOverlay::~TerrainOverlay()
{
std::vector<std::pair<TerrainOverlay*, int> >::iterator newEnd =
std::remove_if(g_TerrainOverlayList.begin(), g_TerrainOverlayList.end(),
equal1st<TerrainOverlay*>(this));
g_TerrainOverlayList.erase(newEnd, g_TerrainOverlayList.end());
}
void TerrainOverlay::RenderOverlays()
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_FALSE);
// To ensure that outlines are drawn on top of the terrain correctly (and
// don't Z-fight and flicker nastily), draw them as QUADS with the LINE
// PolygonMode, and use PolygonOffset to pull them towards the camera.
// (See e.g. http://www.opengl.org/resources/faq/technical/polygonoffset.htm)
glPolygonOffset(-1.f, -1.f);
glEnable(GL_POLYGON_OFFSET_LINE);
std::for_each(g_TerrainOverlayList.begin(), g_TerrainOverlayList.end(),
render1st());
// Clean up state to at least be consistent
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_POLYGON_OFFSET_LINE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_BLEND);
}
//////////////////////////////////////////////////////////////////////////
void TerrainOverlay::GetTileExtents(
int& min_i_inclusive, int& min_j_inclusive,
int& max_i_inclusive, int& max_j_inclusive)
{
// Default to whole map
min_i_inclusive = min_j_inclusive = 0;
max_i_inclusive = max_j_inclusive = m_Terrain->GetTilesPerSide()-1;
}
void TerrainOverlay::Render()
{
m_Terrain = g_Game->GetWorld()->GetTerrain();
int min_i, min_j, max_i, max_j;
GetTileExtents(min_i, min_j, max_i, max_j);
// Clamp the min to 0, but the max to -1 - so tile -1 can never be rendered,
// but if unclamped_max<0 then no tiles at all will be rendered. And the same
// for the upper limit.
min_i = clamp(min_i, 0, (int)m_Terrain->GetTilesPerSide());
min_j = clamp(min_j, 0, (int)m_Terrain->GetTilesPerSide());
max_i = clamp(max_i, -1, (int)m_Terrain->GetTilesPerSide()-1);
max_j = clamp(max_j, -1, (int)m_Terrain->GetTilesPerSide()-1);
for (m_j = min_j; m_j <= max_j; ++m_j)
for (m_i = min_i; m_i <= max_i; ++m_i)
ProcessTile(m_i, m_j);
}
void TerrainOverlay::RenderTile(const CColor& colour, bool draw_hidden)
{
// TODO: if this is unpleasantly slow, make it much more efficient
// (e.g. buffering data and making a single draw call? or at least
// far fewer calls than it makes now)
if (draw_hidden)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
}
else
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
CVector3D pos;
glBegin(GL_QUADS);
glColor4fv(colour.FloatArray());
m_Terrain->CalcPosition(m_i, m_j, pos); glVertex3fv(pos.GetFloatArray());
m_Terrain->CalcPosition(m_i+1, m_j, pos); glVertex3fv(pos.GetFloatArray());
m_Terrain->CalcPosition(m_i+1, m_j+1, pos); glVertex3fv(pos.GetFloatArray());
m_Terrain->CalcPosition(m_i, m_j+1, pos); glVertex3fv(pos.GetFloatArray());
glEnd();
}
void TerrainOverlay::RenderTileOutline(const CColor& colour, int line_width, bool draw_hidden)
{
if (draw_hidden)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
}
else
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glLineWidth((float)line_width);
CVector3D pos;
glBegin(GL_QUADS);
glColor4fv(colour.FloatArray());
m_Terrain->CalcPosition(m_i, m_j, pos); glVertex3fv(pos.GetFloatArray());
m_Terrain->CalcPosition(m_i+1, m_j, pos); glVertex3fv(pos.GetFloatArray());
m_Terrain->CalcPosition(m_i+1, m_j+1, pos); glVertex3fv(pos.GetFloatArray());
m_Terrain->CalcPosition(m_i, m_j+1, pos); glVertex3fv(pos.GetFloatArray());
glEnd();
}

View File

@ -0,0 +1,150 @@
/**
* =========================================================================
* File : TerrainOverlay.h
* Project : Pyrogenesis
* Description : System for representing tile-based information on top of
* : the terrain.
* =========================================================================
*/
#ifndef __TERRAINOVERLAY_H__
#define __TERRAINOVERLAY_H__
#include "ps/Overlay.h" // for CColor
class CTerrain;
/**
* Base class for (relatively) simple drawing of
* data onto terrain tiles, intended for debugging purposes and for the Atlas
* editor (hence not trying to be very efficient).
* <p>
* To start drawing a terrain overlay, first create a subclass of TerrainOverlay.
* Override the method GetTileExtents if you want to change the range over which
* it is drawn.
* Override ProcessTile to do your processing for each tile, which should call
* RenderTile and RenderTileOutline as appropriate.
* See the end of TerrainOverlay.h for an example.
* <p>
* A TerrainOverlay object will be rendered for as long as it exists.
*
*/
class TerrainOverlay
{
public:
virtual ~TerrainOverlay();
protected:
/**
* Construct the object and register it with the global
* list of terrain overlays.
* <p>
* The priority parameter controls the order in which overlays are drawn,
* if several exist - they are processed in order of increasing priority,
* so later ones draw on top of earlier ones.
* Most should use the default of 100. Numbers from 200 are used
* by Atlas.
*
* @param priority controls the order of drawing
*/
TerrainOverlay(int priority = 100);
/**
* Override to limit the range over which ProcessTile will
* be called. Defaults to the size of the map.
*
* @param min_i_inclusive [output] smallest <i>i</i> coordinate, in tile-space units
* (1 unit per tile, <i>+i</i> is world-space <i>+x</i> and game-space East)
* @param min_j_inclusive [output] smallest <i>j</i> coordinate
* (<i>+j</i> is world-space <i>+z</i> and game-space North)
* @param max_i_inclusive [output] largest <i>i</i> coordinate
* @param max_j_inclusive [output] largest <i>j</i> coordinate
*/
virtual void GetTileExtents(int& min_i_inclusive, int& min_j_inclusive,
int& max_i_inclusive, int& max_j_inclusive);
/**
* Override to perform processing of each tile. Typically calls
* RenderTile and/or RenderTileOutline.
*
* @param i <i>i</i> coordinate of tile being processed
* @param j <i>j</i> coordinate of tile being processed
*/
virtual void ProcessTile(int i, int j) = 0;
/**
* Draw a filled quad on top of the current tile.
*
* @param colour colour to draw. May be transparent (alpha &lt; 1)
* @param draw_hidden true if hidden tiles (i.e. those behind other tiles)
* should be drawn
*/
void RenderTile(const CColor& colour, bool draw_hidden);
/**
* Draw an outlined quad on top of the current tile.
*
* @param colour colour to draw. May be transparent (alpha &lt; 1)
* @param line_width width of lines in pixels. 1 is a sensible value
* @param draw_hidden true if hidden tiles (i.e. those behind other tiles)
* should be drawn
*/
void RenderTileOutline(const CColor& colour, int line_width, bool draw_hidden);
public:
/// Draw all TerrainOverlay objects that exist.
static void RenderOverlays();
private:
/// Copying not allowed.
TerrainOverlay(const TerrainOverlay&);
friend struct render1st;
// Process all tiles
void Render();
// Temporary storage of tile coordinates, so ProcessTile doesn't need to
// pass it to RenderTile/etc (and doesn't have a chance to get it wrong)
int m_i, m_j;
CTerrain* m_Terrain;
};
/* Example usage:
class ExampleTerrainOverlay : public TerrainOverlay
{
public:
char random[1021];
ExampleTerrainOverlay()
{
for (int i = 0; i < ARRAY_SIZE(random); ++i)
random[i] = rand(0, 5);
}
virtual void GetTileExtents(
int& min_i_inclusive, int& min_j_inclusive,
int& max_i_inclusive, int& max_j_inclusive)
{
min_i_inclusive = 5;
min_j_inclusive = 10;
max_i_inclusive = 70;
max_j_inclusive = 50;
}
virtual void ProcessTile(int i, int j)
{
if (!random[(i*97+j*101) % ARRAY_SIZE(random)])
return;
RenderTile(CColor(random[(i*79+j*13) % ARRAY_SIZE(random)]/4.f, 1, 0, 0.3f), false);
RenderTileOutline(CColor(1, 1, 1, 1), 1, true);
}
};
ExampleTerrainOverlay test; // or allocate it dynamically somewhere
*/
#endif // __TERRAINOVERLAY_H__

View File

@ -69,7 +69,7 @@ CVertexBuffer::VBChunk* CVertexBufferManager::Allocate(size_t vertexSize,size_t
}
///////////////////////////////////////////////////////////////////////////////
// Release: return given chunk to it's owner
// Release: return given chunk to its owner
void CVertexBufferManager::Release(CVertexBuffer::VBChunk* chunk)
{
debug_assert(chunk);

View File

@ -3,18 +3,18 @@
#include <assert.h>
#ifdef _MSC_VER
# ifndef NDEBUG
# pragma comment(lib, "xerces-c_2D.lib")
# else
#ifdef _MSC_VER
# ifndef NDEBUG
# pragma comment(lib, "xerces-c_2D.lib")
# else
# pragma comment(lib, "xerces-c_2.lib")
# endif
// Disable some warnings:
# endif
// Disable some warnings:
// "warning C4673: throwing 'blahblahException' the following types will not be considered at the catch site ..."
// "warning C4671: 'XMemory' : the copy constructor is inaccessible"
# pragma warning(disable: 4673 4671)
// "warning C4671: 'XMemory' : the copy constructor is inaccessible"
# pragma warning(disable: 4673 4671)
#endif // _MSC_VER
#include <xercesc/parsers/XercesDOMParser.hpp>
@ -136,7 +136,8 @@ static AtSmartPtr<AtNode> ConvertNode(DOMElement* element)
// Text inside the element. Append it to the current node's string.
// TODO: Make this work on GCC, where wchar_t != XMLCh
std::wstring value_wstr (node->getNodeValue());
assert(sizeof(wchar_t) == sizeof(XMLCh));
std::wstring value_wstr (reinterpret_cast<const wchar_t*>(node->getNodeValue()));
obj->value += value_wstr;
}
}
@ -152,7 +153,7 @@ static AtSmartPtr<AtNode> ConvertNode(DOMElement* element)
// Get name and value. (TODO: GCC)
char* name = XMLString::transcode(attr->getName());
const wchar_t* value = attr->getValue();
const wchar_t* value = reinterpret_cast<const wchar_t*>(attr->getValue());
// Prefix the name with an @, to differentiate it from an element
std::string newName ("@"); newName += name;
@ -201,7 +202,8 @@ static DOMAttr* BuildDOMAttr(DOMDocument* doc, const XMLCh* name, AtNode::Ptr p)
DOMAttr* attr = doc->createAttribute(name);
attr->setValue(p->value.c_str());
// TODO: make work on GCC
attr->setValue(reinterpret_cast<const XMLCh*>(p->value.c_str()));
return attr;
}
@ -215,7 +217,7 @@ static DOMNode* BuildDOMNode(DOMDocument* doc, const XMLCh* name, AtNode::Ptr p)
{
// TODO: make this work on GCC
if (p->value.length())
node->setTextContent(p->value.c_str());
node->setTextContent(reinterpret_cast<const XMLCh*>(p->value.c_str()));
XMLCh tempStr[256]; // urgh, nasty fixed-size buffer
for (AtNode::child_maptype::const_iterator it = p->children.begin(); it != p->children.end(); ++it)

View File

@ -4,6 +4,12 @@
# define HAVE_PCH
#endif
#ifdef _MSC_VER
// Please shut up about all the deprecations
# define _CRT_SECURE_NO_DEPRECATE
# pragma warning(disable: 4996)
#endif
#ifdef HAVE_PCH
// Exclude rarely-used stuff from Windows headers
@ -37,8 +43,8 @@
// Nicer memory-leak detection:
#ifdef _DEBUG
#include <crtdbg.h>
#define new new(_NORMAL_BLOCK ,__FILE__, __LINE__)
# include <crtdbg.h>
# define new new(_NORMAL_BLOCK ,__FILE__, __LINE__)
#endif
#endif // HAVE_PCH

View File

@ -482,7 +482,8 @@ private:
std::wstring errorText;
void complain(const SAXParseException& err, const wchar_t* severity) {
sawErrors = true;
errorText += (std::wstring)L"XML "+severity+L": "+ err.getSystemId() + L" / " + err.getMessage();
C_ASSERT(sizeof(wchar_t) == sizeof(XMLCh));
errorText += (std::wstring)L"XML "+severity+L": "+ (wchar_t*)err.getSystemId() + L" / " + (wchar_t*)err.getMessage();
}
};
@ -569,7 +570,7 @@ void XeroHandler::endDocument()
void XeroHandler::startElement(const XMLCh* const /*uri*/, const XMLCh* const localname, const XMLCh* const /*qname*/, const Attributes& attrs)
{
utf16string elementName = localname;
utf16string elementName = (utf16_t*)localname;
// Create a new element
XMLElement* e = new XMLElement;
@ -579,10 +580,10 @@ void XeroHandler::startElement(const XMLCh* const /*uri*/, const XMLCh* const lo
// Store all the attributes in the new element
for (unsigned int i = 0; i < attrs.getLength(); ++i)
{
utf16string attrName = attrs.getLocalName(i);
utf16string attrName = (utf16_t*)attrs.getLocalName(i);
XMLAttribute attr;
attr.name = attrName;
attr.value = attrs.getValue(i);
attr.value = (utf16_t*)attrs.getValue(i);
e->attrs.push_back(attr);
}
@ -628,5 +629,5 @@ void XeroHandler::endElement(const XMLCh* const /*uri*/, const XMLCh* const /*lo
void XeroHandler::characters(const XMLCh* const chars, const unsigned int length)
{
ElementStack.top()->text += utf16string(chars, length);
ElementStack.top()->text += utf16string((utf16_t*)chars, length);
}

View File

@ -4,6 +4,10 @@
# define HAVE_PCH
#endif
#ifdef _MSC_VER
# define _SCL_SECURE_NO_DEPRECATE // shut up, std::copy isn't deprecated
#endif
#ifdef HAVE_PCH
// Exclude rarely-used stuff from Windows headers

View File

@ -7,16 +7,55 @@
#include "graphics/Terrain.h"
#include "lib/ogl.h"
#include "maths/MathUtil.h"
#include "renderer/TerrainOverlay.h"
using namespace AtlasMessage;
class BrushTerrainOverlay : public TerrainOverlay
{
public:
BrushTerrainOverlay(const Brush* brush)
: TerrainOverlay(300), m_Brush(brush)
{
}
void GetTileExtents(
int& min_i_inclusive, int& min_j_inclusive,
int& max_i_inclusive, int& max_j_inclusive)
{
m_Brush->GetBottomLeft(min_i_inclusive, min_j_inclusive);
m_Brush->GetTopRight(max_i_inclusive, max_j_inclusive);
// But since brushes deal with vertices instead of tiles,
// we don't want to include the top/right row
--max_i_inclusive;
--max_j_inclusive;
}
void ProcessTile(int i, int j)
{
int i0, j0;
m_Brush->GetBottomLeft(i0, j0);
// Colour this tile based on the average of the surrounding vertices
float avg = (
m_Brush->Get(i-i0, j-j0) + m_Brush->Get(i-i0+1, j-j0) +
m_Brush->Get(i-i0, j-j0+1) + m_Brush->Get(i-i0+1, j-j0+1)
) / 4.f;
RenderTile(CColor(0, 1, 0, avg*0.8f), false);
RenderTileOutline(CColor(1, 1, 1, 0.4f), 1, true);
}
const AtlasMessage::Brush* m_Brush;
};
Brush::Brush()
: m_W(0), m_H(0), m_Data(NULL), m_Enabled(false)
: m_W(0), m_H(0), m_TerrainOverlay(NULL), m_Data(NULL)
{
}
Brush::~Brush()
{
delete m_TerrainOverlay;
delete[] m_Data;
}
@ -41,49 +80,31 @@ void Brush::GetCentre(int& x, int& y) const
y = cy;
}
void Brush::GetBottomRight(int& x, int& y) const
void Brush::GetBottomLeft(int& x, int& y) const
{
GetCentre(x, y);
x -= (m_W-1)/2;
y -= (m_H-1)/2;
}
void Brush::SetRenderEnabled(bool enabled)
void Brush::GetTopRight(int& x, int& y) const
{
m_Enabled = enabled;
GetBottomLeft(x, y);
x += m_W-1;
y += m_H-1;
}
void Brush::Render()
void Brush::SetRenderEnabled(bool enabled)
{
if (! m_Enabled)
return;
glPointSize(4.f); // TODO: does this clobber state that other people expect to stay unchanged?
glDisable(GL_DEPTH_TEST);
glBegin(GL_POINTS);
int x0, y0;
GetBottomRight(x0, y0);
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
for (int dy = 0; dy < m_H; ++dy)
if (enabled && !m_TerrainOverlay)
{
for (int dx = 0; dx < m_W; ++dx)
{
glColor3f(0.f, clamp(m_Data[dx + dy*m_W], 0.f, 1.f), 0.f);
CVector3D pos;
terrain->CalcPosition(x0+dx, y0+dy, pos);
glVertex3f(pos.X, pos.Y, pos.Z);
//debug_printf("%f %f %f\n", pos.X, pos.Y, pos.Z);
}
m_TerrainOverlay = new BrushTerrainOverlay(this);
}
else if (!enabled && m_TerrainOverlay)
{
delete m_TerrainOverlay;
m_TerrainOverlay = NULL;
}
glEnd();
glEnable(GL_DEPTH_TEST);
}
Brush AtlasMessage::g_CurrentBrush;

View File

@ -1,5 +1,7 @@
#include "maths/Vector3D.h"
class TerrainOverlay;
namespace AtlasMessage {
struct Brush
@ -10,10 +12,10 @@ struct Brush
void SetData(int w, int h, const float* data);
void SetRenderEnabled(bool enabled); // initial state is disabled
void Render(); // only does anything if enabled
void GetCentre(int& x, int& y) const;
void GetBottomRight(int& x, int& y) const;
void GetBottomLeft(int& x, int& y) const;
void GetTopRight(int& x, int& y) const;
float Get(int x, int y) const
{
@ -24,8 +26,8 @@ struct Brush
int m_W, m_H;
CVector3D m_Centre;
private:
TerrainOverlay* m_TerrainOverlay; // NULL if rendering is not enabled
const float* m_Data;
bool m_Enabled;
};
extern Brush g_CurrentBrush;

View File

@ -31,7 +31,6 @@ namespace AtlasMessage
void AtlasRender()
{
Render();
g_CurrentBrush.Render();
AtlasRenderSelection();
}

View File

@ -108,7 +108,7 @@ BEGIN_COMMAND(AlterElevation)
previousPosition = g_CurrentBrush.m_Centre;
int x0, y0;
g_CurrentBrush.GetBottomRight(x0, y0);
g_CurrentBrush.GetBottomLeft(x0, y0);
for (int dy = 0; dy < g_CurrentBrush.m_H; ++dy)
for (int dx = 0; dx < g_CurrentBrush.m_W; ++dx)
@ -171,7 +171,7 @@ BEGIN_COMMAND(FlattenElevation)
u16 height = m_TerrainDelta.GetVertex(xc, yc);
int x0, y0;
g_CurrentBrush.GetBottomRight(x0, y0);
g_CurrentBrush.GetBottomLeft(x0, y0);
for (int dy = 0; dy < g_CurrentBrush.m_H; ++dy)
for (int dx = 0; dx < g_CurrentBrush.m_W; ++dx)

View File

@ -163,7 +163,7 @@ BEGIN_COMMAND(PaintTerrain)
d->pos.GetWorldSpace(g_CurrentBrush.m_Centre);
int x0, y0;
g_CurrentBrush.GetBottomRight(x0, y0);
g_CurrentBrush.GetBottomLeft(x0, y0);
CTextureEntry* texentry = g_TexMan.FindTexture(CStrW(d->texture));
if (! texentry)