1
0
forked from 0ad/0ad

Fix #472 (fixed-point CTerrain::GetExactGroundLevel), based on patch from JubJub

This was SVN commit r7443.
This commit is contained in:
Ykkrosh 2010-04-06 17:31:38 +00:00
parent c02771fef2
commit 2f34e5fbc6
4 changed files with 93 additions and 7 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -340,6 +340,26 @@ float CTerrain::GetExactGroundLevel(float x, float z) const
+ zf * ((1 - xf) * h01 + xf * h11)));
}
CFixed_23_8 CTerrain::GetExactGroundLevelFixed(CFixed_23_8 x, CFixed_23_8 z) const
{
// Clamp to size-2 so we can use the tiles (xi,zi)-(xi+1,zi+1)
const ssize_t xi = clamp((ssize_t)(x/CELL_SIZE).ToInt_RoundToZero(), (ssize_t)0, m_MapSize-2);
const ssize_t zi = clamp((ssize_t)(z/CELL_SIZE).ToInt_RoundToZero(), (ssize_t)0, m_MapSize-2);
const CFixed_23_8 one = CFixed_23_8::FromInt(1);
const CFixed_23_8 xf = clamp((x/CELL_SIZE)-CFixed_23_8::FromInt(xi), CFixed_23_8::FromInt(0), one);
const CFixed_23_8 zf = clamp((z/CELL_SIZE)-CFixed_23_8::FromInt(zi), CFixed_23_8::FromInt(0), one);
u16 h00 = m_Heightmap[zi*m_MapSize + xi];
u16 h01 = m_Heightmap[(zi+1)*m_MapSize + xi];
u16 h10 = m_Heightmap[zi*m_MapSize + (xi+1)];
u16 h11 = m_Heightmap[(zi+1)*m_MapSize + (xi+1)];
// Linearly interpolate
return ((one - zf).Multiply((one - xf) * h00 + xf * h10)
+ zf.Multiply((one - xf) * h01 + xf * h11)) / HEIGHT_UNITS_PER_METRE;
}
///////////////////////////////////////////////////////////////////////////////
// Resize: resize this terrain to the given size (in patches per side)
void CTerrain::Resize(ssize_t size)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -23,6 +23,7 @@
#define INCLUDED_TERRAIN
#include "maths/Vector3D.h"
#include "maths/Fixed.h"
#include "graphics/SColor.h"
#include "lib/sysdep/cpu.h"
@ -80,6 +81,7 @@ public:
float GetVertexGroundLevel(ssize_t i, ssize_t j) const;
float GetExactGroundLevel(float x, float z) const;
CFixed_23_8 GetExactGroundLevelFixed(CFixed_23_8 x, CFixed_23_8 z) const;
float GetExactGroundLevel(const CVector2D& v) const;
float GetSlope(float x, float z) const ;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -22,6 +22,7 @@
#include "graphics/Patch.h"
#include "graphics/RenderableObject.h"
#include "maths/FixedVector3D.h"
#include "maths/Fixed.h"
class TestTerrain : public CxxTest::TestSuite
{
@ -53,7 +54,73 @@ class TestTerrain : public CxxTest::TestSuite
}
void SetHighPlateau(CTerrain& terrain, int height)
{
SetVertex(terrain, 4, 0, 100 + height*CELL_SIZE*HEIGHT_UNITS_PER_METRE);
SetVertex(terrain, 4, 1, 100 + height*CELL_SIZE*HEIGHT_UNITS_PER_METRE);
SetVertex(terrain, 4, 2, 100 + height*CELL_SIZE*HEIGHT_UNITS_PER_METRE);
SetVertex(terrain, 5, 0, 100 + height*CELL_SIZE*HEIGHT_UNITS_PER_METRE);
SetVertex(terrain, 5, 1, 100 + height*CELL_SIZE*HEIGHT_UNITS_PER_METRE);
SetVertex(terrain, 5, 2, 100 + height*CELL_SIZE*HEIGHT_UNITS_PER_METRE);
}
public:
void test_GetExactGroundLevel()
{
CTerrain terrain;
terrain.Initialize(4, NULL);
Set45Slope(terrain);
SetHighPlateau(terrain, 20);
float ground;
ground = terrain.GetExactGroundLevel(0.f, 1.5f*CELL_SIZE);
TS_ASSERT_DELTA(ground, 100.f/HEIGHT_UNITS_PER_METRE, 0.01f);
ground = terrain.GetExactGroundLevel(0.5f*CELL_SIZE, 1.5f*CELL_SIZE);
TS_ASSERT_DELTA(ground, 100.f/HEIGHT_UNITS_PER_METRE+0.5f*CELL_SIZE, 0.01f);
ground = terrain.GetExactGroundLevel(1.5f*CELL_SIZE, 1.5f*CELL_SIZE);
TS_ASSERT_DELTA(ground, 100.f/HEIGHT_UNITS_PER_METRE+1.5f*CELL_SIZE, 0.01f);
ground = terrain.GetExactGroundLevel(2.5f*CELL_SIZE, 1.5f*CELL_SIZE);
TS_ASSERT_DELTA(ground, 100.f/HEIGHT_UNITS_PER_METRE+2.f*CELL_SIZE, 0.01f);
ground = terrain.GetExactGroundLevel(3.5f*CELL_SIZE, 1.5f*CELL_SIZE);
TS_ASSERT_DELTA(ground, 100.f/HEIGHT_UNITS_PER_METRE+11.f*CELL_SIZE, 0.01f);
ground = terrain.GetExactGroundLevel(4.5f*CELL_SIZE, 1.5f*CELL_SIZE);
TS_ASSERT_DELTA(ground, 100.f/HEIGHT_UNITS_PER_METRE+20.f*CELL_SIZE, 0.01f);
}
void test_GetExactGroundLevelFixed()
{
CTerrain terrain;
terrain.Initialize(4, NULL);
Set45Slope(terrain);
SetHighPlateau(terrain, 20);
CFixed_23_8 ground;
ground = terrain.GetExactGroundLevelFixed(CFixed_23_8::FromFloat(0.f), CFixed_23_8::FromFloat(1.5f*CELL_SIZE));
TS_ASSERT_DELTA(ground.ToFloat(), 100.f/HEIGHT_UNITS_PER_METRE, 0.01f);
ground = terrain.GetExactGroundLevelFixed(CFixed_23_8::FromFloat(0.5f*CELL_SIZE), CFixed_23_8::FromFloat(1.5f*CELL_SIZE));
TS_ASSERT_DELTA(ground.ToFloat(), 100.f/HEIGHT_UNITS_PER_METRE+0.5f*CELL_SIZE, 0.01f);
ground = terrain.GetExactGroundLevelFixed(CFixed_23_8::FromFloat(1.5f*CELL_SIZE), CFixed_23_8::FromFloat(1.5f*CELL_SIZE));
TS_ASSERT_DELTA(ground.ToFloat(), 100.f/HEIGHT_UNITS_PER_METRE+1.5f*CELL_SIZE, 0.01f);
ground = terrain.GetExactGroundLevelFixed(CFixed_23_8::FromFloat(2.5f*CELL_SIZE), CFixed_23_8::FromFloat(1.5f*CELL_SIZE));
TS_ASSERT_DELTA(ground.ToFloat(), 100.f/HEIGHT_UNITS_PER_METRE+2.f*CELL_SIZE, 0.01f);
ground = terrain.GetExactGroundLevelFixed(CFixed_23_8::FromFloat(3.5f*CELL_SIZE), CFixed_23_8::FromFloat(1.5f*CELL_SIZE));
TS_ASSERT_DELTA(ground.ToFloat(), 100.f/HEIGHT_UNITS_PER_METRE+11.f*CELL_SIZE, 0.01f);
ground = terrain.GetExactGroundLevelFixed(CFixed_23_8::FromFloat(4.5f*CELL_SIZE), CFixed_23_8::FromFloat(1.5f*CELL_SIZE));
TS_ASSERT_DELTA(ground.ToFloat(), 100.f/HEIGHT_UNITS_PER_METRE+20.f*CELL_SIZE, 0.01f);
}
void test_CalcNormal()
{
CTerrain terrain;

View File

@ -60,10 +60,7 @@ public:
virtual entity_pos_t GetGroundLevel(entity_pos_t x, entity_pos_t z)
{
float height = m_Terrain->GetExactGroundLevel(x.ToFloat(), z.ToFloat());
// TODO: get rid of floats
return entity_pos_t::FromFloat(height);
return m_Terrain->GetExactGroundLevelFixed(x, z);
}
virtual float GetGroundLevel(float x, float z)