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:
parent
12b8dd2d9b
commit
bd2c1d73a3
@ -244,15 +244,12 @@ private:
|
||||
|
||||
CMapReader& m_MapReader;
|
||||
|
||||
int el_scenario, el_entities, el_entity;
|
||||
int el_entity;
|
||||
int el_template, el_player;
|
||||
int el_position, el_orientation;
|
||||
int el_nonentities, el_nonentity;
|
||||
int el_nonentity;
|
||||
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_r, at_g, at_b;
|
||||
int at_angle;
|
||||
|
||||
XMBElementList nodes; // children of root
|
||||
@ -295,34 +292,26 @@ void CXMLReader::Init(const CStr& xml_filename)
|
||||
throw CFileUnpacker::CFileReadError();
|
||||
#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)
|
||||
#define EL(x) el_##x = xmb_file.getElementID(#x)
|
||||
#define AT(x) at_##x = xmb_file.getAttributeID(#x)
|
||||
EL(scenario);
|
||||
EL(entities);
|
||||
EL(entity);
|
||||
EL(template);
|
||||
EL(player);
|
||||
EL(position);
|
||||
EL(orientation);
|
||||
EL(nonentities);
|
||||
EL(nonentity);
|
||||
EL(actor);
|
||||
EL(environment);
|
||||
EL(suncolour);
|
||||
EL(sunelevation);
|
||||
EL(sunrotation);
|
||||
EL(terrainambientcolour);
|
||||
EL(unitsambientcolour);
|
||||
AT(x); AT(y); AT(z);
|
||||
AT(r); AT(g); AT(b);
|
||||
AT(angle);
|
||||
#undef AT
|
||||
#undef EL
|
||||
|
||||
XMBElement root = xmb_file.getRoot();
|
||||
debug_assert(root.getNodeName() == el_scenario);
|
||||
debug_assert(xmb_file.getElementString(root.getNodeName()) == "scenario");
|
||||
nodes = root.getChildNodes();
|
||||
|
||||
// find out total number of entities+nonentities
|
||||
@ -336,6 +325,17 @@ void CXMLReader::Init(const CStr& xml_filename)
|
||||
|
||||
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)
|
||||
{
|
||||
int element_name = element.getNodeName();
|
||||
@ -524,17 +524,18 @@ int CXMLReader::ProgressiveRead()
|
||||
while (node_idx < nodes.Count)
|
||||
{
|
||||
XMBElement node = nodes.item(node_idx);
|
||||
if (node.getNodeName() == el_environment)
|
||||
CStr name = xmb_file.getElementString(node.getNodeName());
|
||||
if (name == "environment")
|
||||
{
|
||||
ReadEnvironment(node);
|
||||
}
|
||||
else if (node.getNodeName() == el_entities)
|
||||
else if (name == "entities")
|
||||
{
|
||||
ret = ReadEntities(node, end_time);
|
||||
if (ret != 0) // error or timed out
|
||||
return ret;
|
||||
}
|
||||
else if (node.getNodeName() == el_nonentities)
|
||||
else if (name == "nonentities")
|
||||
{
|
||||
ret = ReadNonEntities(node, end_time);
|
||||
if (ret != 0) // error or timed out
|
||||
|
@ -192,18 +192,18 @@ float CTerrain::getExactGroundLevel(float x, float y) const
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -32,11 +32,11 @@ public:
|
||||
|
||||
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
|
||||
{
|
||||
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 getExactGroundLevel( float x, float y ) const ;
|
||||
|
@ -1,71 +1,71 @@
|
||||
/*
|
||||
|
||||
CTerrainProperties
|
||||
|
||||
Basically represents a set of terrain attributes loaded from XML. These
|
||||
objects are organized in an inheritance tree, determined at load time.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef graphics_TerrainProperties_H
|
||||
#define graphics_TerrainProperties_H
|
||||
|
||||
#include "CStr.h"
|
||||
/*
|
||||
|
||||
CTerrainProperties
|
||||
|
||||
Basically represents a set of terrain attributes loaded from XML. These
|
||||
objects are organized in an inheritance tree, determined at load time.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef graphics_TerrainProperties_H
|
||||
#define graphics_TerrainProperties_H
|
||||
|
||||
#include "CStr.h"
|
||||
#include "boost/shared_ptr.hpp"
|
||||
|
||||
class CTerrainGroup;
|
||||
class XMBElement;
|
||||
class CXeromyces;
|
||||
class CTerrainProperties;
|
||||
|
||||
typedef boost::shared_ptr<CTerrainProperties> CTerrainPropertiesPtr;
|
||||
|
||||
class CTerrainProperties
|
||||
{
|
||||
public:
|
||||
typedef std::vector<CTerrainGroup *> GroupVector;
|
||||
|
||||
private:
|
||||
CTerrainPropertiesPtr m_pParent;
|
||||
|
||||
// BGRA color of topmost mipmap level, for coloring minimap, or a color
|
||||
// manually specified in the Terrain XML (or by any parent)
|
||||
// ..Valid is true if the base color is specified in this terrain XML
|
||||
// No caching here, since ideally, a saved XML file of an object should
|
||||
// produce be equivalent to the source file
|
||||
u32 m_BaseColor;
|
||||
bool m_HasBaseColor;
|
||||
|
||||
// All terrain type groups we're a member of
|
||||
GroupVector m_Groups;
|
||||
|
||||
void LoadXML(XMBElement node, CXeromyces *pFile);
|
||||
|
||||
public:
|
||||
CTerrainProperties(CTerrainPropertiesPtr parent);
|
||||
|
||||
// Create a new object and load the XML file specified. Returns NULL upon
|
||||
// failure
|
||||
// The parent pointer may be NULL, for the "root" terrainproperties object.
|
||||
static CTerrainPropertiesPtr FromXML(CTerrainPropertiesPtr parent, const char* path);
|
||||
|
||||
// Save the object to an XML file. Implement when needed! ;-)
|
||||
// bool WriteXML(CStr path);
|
||||
|
||||
inline CTerrainPropertiesPtr GetParent() const
|
||||
{ return m_pParent; }
|
||||
|
||||
// Return true if this property object or any of its parents has a basecolor
|
||||
// override (mmap attribute in the XML file)
|
||||
bool HasBaseColor();
|
||||
// Return the minimap color specified in this property object or in any of
|
||||
// its parents. If no minimap color is specified, return garbage.
|
||||
// Use HasBaseColor() to see if the value is valid.
|
||||
// The color value is in BGRA format
|
||||
u32 GetBaseColor();
|
||||
|
||||
const GroupVector &GetGroups() const
|
||||
{ return m_Groups; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class CTerrainGroup;
|
||||
class XMBElement;
|
||||
class CXeromyces;
|
||||
class CTerrainProperties;
|
||||
|
||||
typedef boost::shared_ptr<CTerrainProperties> CTerrainPropertiesPtr;
|
||||
|
||||
class CTerrainProperties
|
||||
{
|
||||
public:
|
||||
typedef std::vector<CTerrainGroup *> GroupVector;
|
||||
|
||||
private:
|
||||
CTerrainPropertiesPtr m_pParent;
|
||||
|
||||
// BGRA color of topmost mipmap level, for coloring minimap, or a color
|
||||
// manually specified in the Terrain XML (or by any parent)
|
||||
// ..Valid is true if the base color is specified in this terrain XML
|
||||
// No caching here, since ideally, a saved XML file of an object should
|
||||
// produce be equivalent to the source file
|
||||
u32 m_BaseColor;
|
||||
bool m_HasBaseColor;
|
||||
|
||||
// All terrain type groups we're a member of
|
||||
GroupVector m_Groups;
|
||||
|
||||
void LoadXML(XMBElement node, CXeromyces *pFile);
|
||||
|
||||
public:
|
||||
CTerrainProperties(CTerrainPropertiesPtr parent);
|
||||
|
||||
// Create a new object and load the XML file specified. Returns NULL upon
|
||||
// failure
|
||||
// The parent pointer may be NULL, for the "root" terrainproperties object.
|
||||
static CTerrainPropertiesPtr FromXML(CTerrainPropertiesPtr parent, const char* path);
|
||||
|
||||
// Save the object to an XML file. Implement when needed! ;-)
|
||||
// bool WriteXML(CStr path);
|
||||
|
||||
inline CTerrainPropertiesPtr GetParent() const
|
||||
{ return m_pParent; }
|
||||
|
||||
// Return true if this property object or any of its parents has a basecolor
|
||||
// override (mmap attribute in the XML file)
|
||||
bool HasBaseColor();
|
||||
// Return the minimap color specified in this property object or in any of
|
||||
// its parents. If no minimap color is specified, return garbage.
|
||||
// Use HasBaseColor() to see if the value is valid.
|
||||
// The color value is in BGRA format
|
||||
u32 GetBaseColor();
|
||||
|
||||
const GroupVector &GetGroups() const
|
||||
{ return m_Groups; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1177,8 +1177,7 @@ void CBuildingPlacer::update( float timeStep )
|
||||
}
|
||||
|
||||
CTerrain *pTerrain=g_Game->GetWorld()->GetTerrain();
|
||||
int mapSize = (pTerrain->GetVerticesPerSide() - 1) * CELL_SIZE; // use vertices-1 to get number of tiles
|
||||
m_valid = pos.X>=0 && pos.Z>=0 && pos.X<mapSize && pos.Z<mapSize && getCollisionObject(m_bounds)==0;
|
||||
m_valid = pTerrain->isOnMap(pos.X, pos.Z) && getCollisionObject(m_bounds)==0;
|
||||
|
||||
CColor col;
|
||||
if(m_valid)
|
||||
|
@ -110,7 +110,7 @@ class XMBFile
|
||||
{
|
||||
public:
|
||||
|
||||
XMBFile() : m_Pointer(NULL) {};
|
||||
XMBFile() : m_Pointer(NULL) {}
|
||||
|
||||
// Initialise from the contents of an XMB file.
|
||||
// FileData must remain allocated and unchanged while
|
||||
@ -207,7 +207,7 @@ class XMBAttributeList
|
||||
{
|
||||
public:
|
||||
XMBAttributeList(char* offset, int count)
|
||||
: Count(count), m_Pointer(offset), m_LastItemID( -2 ) {};
|
||||
: Count(count), m_Pointer(offset), m_LastItemID(-2) {};
|
||||
|
||||
// Get the attribute value directly (unlike Xerces)
|
||||
utf16string getNamedItem(const int AttributeName) const;
|
||||
|
@ -177,7 +177,7 @@ return LOS_VISIBLE;
|
||||
// Ensure that units off the map don't cause the visibility arrays to be
|
||||
// accessed out of bounds
|
||||
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)
|
||||
|
||||
@ -212,8 +212,7 @@ ELOSStatus CLOSManager::GetStatus(float fx, float fz, CPlayer* player)
|
||||
|
||||
EUnitLOSStatus CLOSManager::GetUnitStatus(CUnit* unit, CPlayer* player)
|
||||
{
|
||||
CVector3D centre;
|
||||
unit->GetModel()->GetBounds().GetCentre(centre);
|
||||
CVector3D centre = unit->GetModel()->GetTransform().GetTranslation();
|
||||
ELOSStatus status = GetStatus(centre.X, centre.Z, player);
|
||||
|
||||
if(status & LOS_VISIBLE)
|
||||
|
@ -147,7 +147,7 @@ JSBool CProjectile::Construct( JSContext* cx, JSObject* UNUSED(obj), uint argc,
|
||||
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";
|
||||
goto fail;
|
||||
|
@ -12,6 +12,7 @@ class TransformObject : public StateDrivenTool<TransformObject>
|
||||
DECLARE_DYNAMIC_CLASS(TransformObject);
|
||||
|
||||
std::vector<AtlasMessage::ObjectID> m_Selection;
|
||||
int m_dx, m_dy;
|
||||
|
||||
public:
|
||||
TransformObject()
|
||||
@ -39,6 +40,8 @@ public:
|
||||
qry.Post();
|
||||
obj->m_Selection.clear();
|
||||
obj->m_Selection.push_back(qry.id);
|
||||
obj->m_dx = qry.offsetx;
|
||||
obj->m_dy = qry.offsety;
|
||||
POST_MESSAGE(SetSelectionPreview(obj->m_Selection));
|
||||
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
||||
SET_STATE(Dragging);
|
||||
@ -82,7 +85,7 @@ public:
|
||||
}
|
||||
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)
|
||||
POST_COMMAND(MoveObject, (obj->m_Selection[i], pos));
|
||||
return true;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "graphics/UnitManager.h"
|
||||
#include "graphics/Model.h"
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Game.h"
|
||||
#include "lib/ogl.h"
|
||||
@ -43,7 +44,7 @@ void AtlasRenderSelection()
|
||||
CUnit* unit = static_cast<CUnit*>(g_Selection[i]);
|
||||
if (unit->GetEntity())
|
||||
unit->GetEntity()->renderSelectionOutline();
|
||||
else if (unit->GetModel())
|
||||
else
|
||||
{
|
||||
const CBound& bound = unit->GetModel()->GetBounds();
|
||||
// Expand bounds by 10% around the centre
|
||||
@ -76,10 +77,26 @@ MESSAGEHANDLER(SetSelectionPreview)
|
||||
static CUnit* g_PreviewUnit = NULL;
|
||||
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 vec;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -206,6 +223,20 @@ QUERYHANDLER(SelectObject)
|
||||
CUnit* target = g_UnitMan.PickUnit(rayorigin, raydir);
|
||||
|
||||
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;
|
||||
}
|
||||
else if (unit->GetModel())
|
||||
else
|
||||
{
|
||||
CMatrix3D m = unit->GetModel()->GetTransform();
|
||||
m_PosOld = m.GetTranslation();
|
||||
@ -246,7 +277,7 @@ BEGIN_COMMAND(MoveObject)
|
||||
{
|
||||
unit->GetEntity()->m_position = pos;
|
||||
}
|
||||
else if (unit->GetModel())
|
||||
else
|
||||
{
|
||||
CMatrix3D m = unit->GetModel()->GetTransform();
|
||||
m.Translate(pos - m.GetTranslation());
|
||||
@ -301,7 +332,7 @@ BEGIN_COMMAND(RotateObject)
|
||||
m_AngleNew = d->angle;
|
||||
}
|
||||
}
|
||||
else if (unit->GetModel())
|
||||
else
|
||||
{
|
||||
m_TransformOld = unit->GetModel()->GetTransform();
|
||||
|
||||
@ -343,7 +374,7 @@ BEGIN_COMMAND(RotateObject)
|
||||
{
|
||||
unit->GetEntity()->m_orientation = angle;
|
||||
}
|
||||
else if (unit->GetModel())
|
||||
else
|
||||
{
|
||||
unit->GetModel()->SetTransform(transform);
|
||||
}
|
||||
|
@ -173,6 +173,8 @@ QUERY(SelectObject,
|
||||
((Position, pos))
|
||||
,
|
||||
((ObjectID, id))
|
||||
((int, offsetx)) // offset of object centre from input position
|
||||
((int, offsety)) //
|
||||
);
|
||||
|
||||
COMMAND(MoveObject, MERGE,
|
||||
|
Loading…
Reference in New Issue
Block a user