1
0
forked from 0ad/0ad

Terrain, Interact, LOSManager, Atlas, etc: Fixed some off-by-one and off-by-FLT_EPSILON problems with objects near/off the edge of the map. Also changed some model.GetBounds().GetCentre() into model.GetTransform().GetTranslation() to fix off-by-centre-of-bounds-minus-position problems. Thus, you can no longer make units in Atlas disappear off the edge and never be seen or selected again. Also changed out-of-bounds LOS value to make them visible if they somehow escape anyway. Also fixed out-of-bounds access of terrain heightmap.

MapReader: Tidied usage of Xeromyces.
Projectile: Avoided warnings.

This was SVN commit r3212.
This commit is contained in:
Ykkrosh 2005-12-09 01:08:08 +00:00
parent 12b8dd2d9b
commit bd2c1d73a3
11 changed files with 145 additions and 110 deletions

View File

@ -244,15 +244,12 @@ private:
CMapReader& m_MapReader; CMapReader& m_MapReader;
int el_scenario, el_entities, el_entity; int el_entity;
int el_template, el_player; int el_template, el_player;
int el_position, el_orientation; int el_position, el_orientation;
int el_nonentities, el_nonentity; int el_nonentity;
int el_actor; int el_actor;
int el_environment, el_suncolour, el_sunelevation, el_sunrotation;
int el_terrainambientcolour, el_unitsambientcolour;
int at_x, at_y, at_z; int at_x, at_y, at_z;
int at_r, at_g, at_b;
int at_angle; int at_angle;
XMBElementList nodes; // children of root XMBElementList nodes; // children of root
@ -295,34 +292,26 @@ void CXMLReader::Init(const CStr& xml_filename)
throw CFileUnpacker::CFileReadError(); throw CFileUnpacker::CFileReadError();
#endif #endif
// define all the elements and attributes used in the XML file. // define the elements and attributes that are frequently used in the XML file,
// so we don't need to do lots of string construction and comparison when
// reading the data.
// (Needs to be synchronised with the list in CXMLReader - ugh) // (Needs to be synchronised with the list in CXMLReader - ugh)
#define EL(x) el_##x = xmb_file.getElementID(#x) #define EL(x) el_##x = xmb_file.getElementID(#x)
#define AT(x) at_##x = xmb_file.getAttributeID(#x) #define AT(x) at_##x = xmb_file.getAttributeID(#x)
EL(scenario);
EL(entities);
EL(entity); EL(entity);
EL(template); EL(template);
EL(player); EL(player);
EL(position); EL(position);
EL(orientation); EL(orientation);
EL(nonentities);
EL(nonentity); EL(nonentity);
EL(actor); EL(actor);
EL(environment);
EL(suncolour);
EL(sunelevation);
EL(sunrotation);
EL(terrainambientcolour);
EL(unitsambientcolour);
AT(x); AT(y); AT(z); AT(x); AT(y); AT(z);
AT(r); AT(g); AT(b);
AT(angle); AT(angle);
#undef AT #undef AT
#undef EL #undef EL
XMBElement root = xmb_file.getRoot(); XMBElement root = xmb_file.getRoot();
debug_assert(root.getNodeName() == el_scenario); debug_assert(xmb_file.getElementString(root.getNodeName()) == "scenario");
nodes = root.getChildNodes(); nodes = root.getChildNodes();
// find out total number of entities+nonentities // find out total number of entities+nonentities
@ -336,6 +325,17 @@ void CXMLReader::Init(const CStr& xml_filename)
void CXMLReader::ReadEnvironment(XMBElement parent) void CXMLReader::ReadEnvironment(XMBElement parent)
{ {
#define EL(x) int el_##x = xmb_file.getElementID(#x)
#define AT(x) int at_##x = xmb_file.getAttributeID(#x)
EL(suncolour);
EL(sunelevation);
EL(sunrotation);
EL(terrainambientcolour);
EL(unitsambientcolour);
AT(r); AT(g); AT(b);
#undef AT
#undef EL
XERO_ITER_EL(parent, element) XERO_ITER_EL(parent, element)
{ {
int element_name = element.getNodeName(); int element_name = element.getNodeName();
@ -524,17 +524,18 @@ int CXMLReader::ProgressiveRead()
while (node_idx < nodes.Count) while (node_idx < nodes.Count)
{ {
XMBElement node = nodes.item(node_idx); XMBElement node = nodes.item(node_idx);
if (node.getNodeName() == el_environment) CStr name = xmb_file.getElementString(node.getNodeName());
if (name == "environment")
{ {
ReadEnvironment(node); ReadEnvironment(node);
} }
else if (node.getNodeName() == el_entities) else if (name == "entities")
{ {
ret = ReadEntities(node, end_time); ret = ReadEntities(node, end_time);
if (ret != 0) // error or timed out if (ret != 0) // error or timed out
return ret; return ret;
} }
else if (node.getNodeName() == el_nonentities) else if (name == "nonentities")
{ {
ret = ReadNonEntities(node, end_time); ret = ReadNonEntities(node, end_time);
if (ret != 0) // error or timed out if (ret != 0) // error or timed out

View File

@ -192,18 +192,18 @@ float CTerrain::getExactGroundLevel(float x, float y) const
{ {
xi = 0; xf = 0.0f; xi = 0; xf = 0.0f;
} }
else if (xi >= (int)m_MapSize) else if (xi >= (int)m_MapSize-1)
{ {
xi = m_MapSize - 1; xf = 1.0f; xi = m_MapSize - 2; xf = 1.0f;
} }
if (yi < 0) if (yi < 0)
{ {
yi = 0; yf = 0.0f; yi = 0; yf = 0.0f;
} }
else if (yi >= (int)m_MapSize) else if (yi >= (int)m_MapSize-1)
{ {
yi = m_MapSize - 1; yf = 1.0f; yi = m_MapSize - 2; yf = 1.0f;
} }
/* /*

View File

@ -32,11 +32,11 @@ public:
inline bool isOnMap( float x, float y ) const inline bool isOnMap( float x, float y ) const
{ {
return( ( x >= 0.0f ) && ( x <= (float)( m_MapSize * CELL_SIZE ) ) && ( y >= 0.0f ) && ( y <= (float)( m_MapSize * CELL_SIZE ) ) ); return( ( x >= 0.0f ) && ( x < (float)( (m_MapSize-1) * CELL_SIZE ) ) && ( y >= 0.0f ) && ( y < (float)( (m_MapSize-1) * CELL_SIZE ) ) );
} }
inline bool isOnMap( const CVector2D& v ) const inline bool isOnMap( const CVector2D& v ) const
{ {
return( ( v.x >= 0.0f ) && ( v.x <= (float)( m_MapSize * CELL_SIZE ) ) && ( v.y >= 0.0f ) && ( v.y <= (float)( m_MapSize * CELL_SIZE ) ) ); 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 getVertexGroundLevel( int x, int y ) const ;
float getExactGroundLevel( float x, float y ) const ; float getExactGroundLevel( float x, float y ) const ;

View File

@ -1177,8 +1177,7 @@ void CBuildingPlacer::update( float timeStep )
} }
CTerrain *pTerrain=g_Game->GetWorld()->GetTerrain(); CTerrain *pTerrain=g_Game->GetWorld()->GetTerrain();
int mapSize = (pTerrain->GetVerticesPerSide() - 1) * CELL_SIZE; // use vertices-1 to get number of tiles m_valid = pTerrain->isOnMap(pos.X, pos.Z) && getCollisionObject(m_bounds)==0;
m_valid = pos.X>=0 && pos.Z>=0 && pos.X<mapSize && pos.Z<mapSize && getCollisionObject(m_bounds)==0;
CColor col; CColor col;
if(m_valid) if(m_valid)

View File

@ -110,7 +110,7 @@ class XMBFile
{ {
public: public:
XMBFile() : m_Pointer(NULL) {}; XMBFile() : m_Pointer(NULL) {}
// Initialise from the contents of an XMB file. // Initialise from the contents of an XMB file.
// FileData must remain allocated and unchanged while // FileData must remain allocated and unchanged while

View File

@ -177,7 +177,7 @@ return LOS_VISIBLE;
// Ensure that units off the map don't cause the visibility arrays to be // Ensure that units off the map don't cause the visibility arrays to be
// accessed out of bounds // accessed out of bounds
if ((unsigned)tx >= m_TilesPerSide || (unsigned)tz >= m_TilesPerSide) if ((unsigned)tx >= m_TilesPerSide || (unsigned)tz >= m_TilesPerSide)
return LOS_UNEXPLORED; return LOS_VISIBLE; // because we don't want them to be permanently hidden
// TODO: Make the mask depend on the player's diplomacy (just OR all his allies' masks) // TODO: Make the mask depend on the player's diplomacy (just OR all his allies' masks)
@ -212,8 +212,7 @@ ELOSStatus CLOSManager::GetStatus(float fx, float fz, CPlayer* player)
EUnitLOSStatus CLOSManager::GetUnitStatus(CUnit* unit, CPlayer* player) EUnitLOSStatus CLOSManager::GetUnitStatus(CUnit* unit, CPlayer* player)
{ {
CVector3D centre; CVector3D centre = unit->GetModel()->GetTransform().GetTranslation();
unit->GetModel()->GetBounds().GetCentre(centre);
ELOSStatus status = GetStatus(centre.X, centre.Z, player); ELOSStatus status = GetStatus(centre.X, centre.Z, player);
if(status & LOS_VISIBLE) if(status & LOS_VISIBLE)

View File

@ -147,7 +147,7 @@ JSBool CProjectile::Construct( JSContext* cx, JSObject* UNUSED(obj), uint argc,
goto fail; goto fail;
} }
} }
else if( !ToPrimitive<CStr>( cx, argv[0], ModelString ) || !( oe = g_ObjMan.FindObject( ModelString ) ) || !( Model = oe->m_Model ) ) else if( !ToPrimitive<CStr>( cx, argv[0], ModelString ) || NULL == ( oe = g_ObjMan.FindObject( ModelString ) ) || NULL == ( Model = oe->m_Model ) )
{ {
err = "Invalid actor"; err = "Invalid actor";
goto fail; goto fail;

View File

@ -12,6 +12,7 @@ class TransformObject : public StateDrivenTool<TransformObject>
DECLARE_DYNAMIC_CLASS(TransformObject); DECLARE_DYNAMIC_CLASS(TransformObject);
std::vector<AtlasMessage::ObjectID> m_Selection; std::vector<AtlasMessage::ObjectID> m_Selection;
int m_dx, m_dy;
public: public:
TransformObject() TransformObject()
@ -39,6 +40,8 @@ public:
qry.Post(); qry.Post();
obj->m_Selection.clear(); obj->m_Selection.clear();
obj->m_Selection.push_back(qry.id); obj->m_Selection.push_back(qry.id);
obj->m_dx = qry.offsetx;
obj->m_dy = qry.offsety;
POST_MESSAGE(SetSelectionPreview(obj->m_Selection)); POST_MESSAGE(SetSelectionPreview(obj->m_Selection));
ScenarioEditor::GetCommandProc().FinaliseLastCommand(); ScenarioEditor::GetCommandProc().FinaliseLastCommand();
SET_STATE(Dragging); SET_STATE(Dragging);
@ -82,7 +85,7 @@ public:
} }
else if (evt.Dragging()) else if (evt.Dragging())
{ {
Position pos (evt.GetPosition()); Position pos (evt.GetPosition() + wxPoint(obj->m_dx, obj->m_dy));
for (size_t i = 0; i < obj->m_Selection.size(); ++i) for (size_t i = 0; i < obj->m_Selection.size(); ++i)
POST_COMMAND(MoveObject, (obj->m_Selection[i], pos)); POST_COMMAND(MoveObject, (obj->m_Selection[i], pos));
return true; return true;

View File

@ -9,6 +9,7 @@
#include "graphics/UnitManager.h" #include "graphics/UnitManager.h"
#include "graphics/Model.h" #include "graphics/Model.h"
#include "maths/Matrix3D.h" #include "maths/Matrix3D.h"
#include "maths/MathUtil.h"
#include "ps/CLogger.h" #include "ps/CLogger.h"
#include "ps/Game.h" #include "ps/Game.h"
#include "lib/ogl.h" #include "lib/ogl.h"
@ -43,7 +44,7 @@ void AtlasRenderSelection()
CUnit* unit = static_cast<CUnit*>(g_Selection[i]); CUnit* unit = static_cast<CUnit*>(g_Selection[i]);
if (unit->GetEntity()) if (unit->GetEntity())
unit->GetEntity()->renderSelectionOutline(); unit->GetEntity()->renderSelectionOutline();
else if (unit->GetModel()) else
{ {
const CBound& bound = unit->GetModel()->GetBounds(); const CBound& bound = unit->GetModel()->GetBounds();
// Expand bounds by 10% around the centre // Expand bounds by 10% around the centre
@ -76,10 +77,26 @@ MESSAGEHANDLER(SetSelectionPreview)
static CUnit* g_PreviewUnit = NULL; static CUnit* g_PreviewUnit = NULL;
static CStrW g_PreviewUnitID; static CStrW g_PreviewUnitID;
// Returns roughly the largest number smaller than f (i.e. closer to zero)
static float flt_minus_epsilon(float f)
{
return f - (FLT_EPSILON * f);
}
static CVector3D GetUnitPos(const Position& pos) static CVector3D GetUnitPos(const Position& pos)
{ {
static CVector3D vec; static CVector3D vec;
pos.GetWorldSpace(vec, vec); // if msg->pos is 'Unchanged', use the previous pos pos.GetWorldSpace(vec, vec); // if msg->pos is 'Unchanged', use the previous pos
float xOnMap = clamp(vec.X, 0.f, flt_minus_epsilon((g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide()-1)*CELL_SIZE));
float zOnMap = clamp(vec.Z, 0.f, flt_minus_epsilon((g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide()-1)*CELL_SIZE));
if (xOnMap != vec.X || zOnMap != vec.Z)
{
vec.X = xOnMap;
vec.Z = zOnMap;
vec.Y = g_Game->GetWorld()->GetTerrain()->getExactGroundLevel(xOnMap, zOnMap);
}
return vec; return vec;
} }
@ -206,6 +223,20 @@ QUERYHANDLER(SelectObject)
CUnit* target = g_UnitMan.PickUnit(rayorigin, raydir); CUnit* target = g_UnitMan.PickUnit(rayorigin, raydir);
msg->id = static_cast<void*>(target); msg->id = static_cast<void*>(target);
if (target)
{
CVector3D centre = target->GetModel()->GetTransform().GetTranslation();
centre.Y = g_Game->GetWorld()->GetTerrain()->getExactGroundLevel(centre.X, centre.Z);
float cx, cy;
g_Game->GetView()->GetCamera()->GetScreenCoordinates(centre, cx, cy);
msg->offsetx = (int)(cx - x);
msg->offsety = (int)(cy - y);
}
else
{
msg->offsetx = msg->offsety = 0;
}
} }
@ -224,7 +255,7 @@ BEGIN_COMMAND(MoveObject)
{ {
m_PosOld = unit->GetEntity()->m_position; m_PosOld = unit->GetEntity()->m_position;
} }
else if (unit->GetModel()) else
{ {
CMatrix3D m = unit->GetModel()->GetTransform(); CMatrix3D m = unit->GetModel()->GetTransform();
m_PosOld = m.GetTranslation(); m_PosOld = m.GetTranslation();
@ -246,7 +277,7 @@ BEGIN_COMMAND(MoveObject)
{ {
unit->GetEntity()->m_position = pos; unit->GetEntity()->m_position = pos;
} }
else if (unit->GetModel()) else
{ {
CMatrix3D m = unit->GetModel()->GetTransform(); CMatrix3D m = unit->GetModel()->GetTransform();
m.Translate(pos - m.GetTranslation()); m.Translate(pos - m.GetTranslation());
@ -301,7 +332,7 @@ BEGIN_COMMAND(RotateObject)
m_AngleNew = d->angle; m_AngleNew = d->angle;
} }
} }
else if (unit->GetModel()) else
{ {
m_TransformOld = unit->GetModel()->GetTransform(); m_TransformOld = unit->GetModel()->GetTransform();
@ -343,7 +374,7 @@ BEGIN_COMMAND(RotateObject)
{ {
unit->GetEntity()->m_orientation = angle; unit->GetEntity()->m_orientation = angle;
} }
else if (unit->GetModel()) else
{ {
unit->GetModel()->SetTransform(transform); unit->GetModel()->SetTransform(transform);
} }

View File

@ -173,6 +173,8 @@ QUERY(SelectObject,
((Position, pos)) ((Position, pos))
, ,
((ObjectID, id)) ((ObjectID, id))
((int, offsetx)) // offset of object centre from input position
((int, offsety)) //
); );
COMMAND(MoveObject, MERGE, COMMAND(MoveObject, MERGE,