Added 'float' flag to actors - fixes #153.

Fixed creation and selection of entities (and now actors) which float on
water.
Added ctrl+n/o/s keys to actor editor.

This was SVN commit r4417.
This commit is contained in:
Ykkrosh
2006-09-28 02:05:56 +00:00
parent b8a17f7ecd
commit cc8bf09cc5
11 changed files with 91 additions and 52 deletions
+1
View File
@@ -549,6 +549,7 @@ void CXMLReader::ReadCamera(XMBElement parent)
m_MapReader.pCamera->m_Orientation.Translate(translation);
m_MapReader.pCamera->UpdateFrustum();
}
void CXMLReader::ReadCinema(XMBElement parent)
{
#define EL(x) int el_##x = xmb_file.getElementID(#x)
+11 -1
View File
@@ -15,6 +15,7 @@ CObjectBase::CObjectBase()
{
m_Properties.m_CastShadows = true;
m_Properties.m_AutoFlatten = false;
m_Properties.m_FloatOnWater = false;
}
bool CObjectBase::Load(const char* filename)
@@ -37,7 +38,8 @@ bool CObjectBase::Load(const char* filename)
#define EL(x) int el_##x = XeroFile.getElementID(#x)
#define AT(x) int at_##x = XeroFile.getAttributeID(#x)
EL(actor);
//EL(castshadow);
EL(castshadow);
EL(float);
EL(material);
EL(group);
EL(variant);
@@ -201,6 +203,14 @@ bool CObjectBase::Load(const char* filename)
++currentGroup;
}
else if (child_name == el_castshadow)
{
m_Properties.m_CastShadows = true; // TODO: this is the default, so it's a bit useless
}
else if (child_name == el_float)
{
m_Properties.m_FloatOnWater = true;
}
else if (child_name == el_material)
{
m_Material = "art/materials/" + CStr(child.getText());
+2
View File
@@ -90,6 +90,8 @@ public:
bool m_AutoFlatten;
// cast shadows from this object
bool m_CastShadows;
// float on top of water
bool m_FloatOnWater;
} m_Properties;
// the material file
+3 -3
View File
@@ -29,11 +29,11 @@ public:
~CUnit();
// get unit's template object; never NULL
CObjectEntry* GetObject() { return m_Object; }
CObjectEntry* GetObject() const { return m_Object; }
// get unit's model data; never NULL
CModel* GetModel() { return m_Model; }
CModel* GetModel() const { return m_Model; }
// get actor's entity; can be NULL
CEntity* GetEntity() { return m_Entity; }
CEntity* GetEntity() const { return m_Entity; }
// Put here as it conveniently references both the model and the ObjectEntry
void ShowAmmunition();
@@ -56,6 +56,9 @@ ActorEditor::ActorEditor(wxWindow* parent)
m_CastShadows = new wxCheckBox(propertiesPanel, wxID_ANY, _("Cast shadow"));
propertiesSizer->Add(m_CastShadows, wxSizerFlags().Border(wxALL, 5));
m_Float = new wxCheckBox(propertiesPanel, wxID_ANY, _("Float on water"));
propertiesSizer->Add(m_Float, wxSizerFlags().Border(wxALL, 5));
// TODO: Orientation property.
//////////////////////////////////////////////////////////////////////////
@@ -79,10 +82,6 @@ ActorEditor::ActorEditor(wxWindow* parent)
m_Material = new wxComboBox(materialsPanel, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, materials);
materialsSizer->Add(m_Material, wxSizerFlags().Border(wxALL, 2));
//////////////////////////////////////////////////////////////////////////
// void convert_actors();
// convert_actors();
}
void ActorEditor::ThawData(AtObj& in)
@@ -90,11 +89,8 @@ void ActorEditor::ThawData(AtObj& in)
AtObj actor (in["actor"]);
m_ActorEditorListCtrl->ThawData(actor);
if (actor["castshadow"].defined())
m_CastShadows->SetValue(true);
else
m_CastShadows->SetValue(false);
m_CastShadows->SetValue(actor["castshadow"].defined());
m_Float->SetValue(actor["float"].defined());
m_Material->SetValue(actor["material"]);
}
@@ -105,6 +101,9 @@ AtObj ActorEditor::FreezeData()
if (m_CastShadows->IsChecked())
actor.set("castshadow", L"");
if (m_Float->IsChecked())
actor.set("float", L"");
if (m_Material->GetValue().length())
actor.set("material", m_Material->GetValue().c_str());
@@ -301,11 +300,8 @@ void ActorEditor::ImportData(AtObj& in)
AtObj actor (data["actor"]);
m_ActorEditorListCtrl->ImportData(actor);
if (actor["castshadow"].defined())
m_CastShadows->SetValue(true);
else
m_CastShadows->SetValue(false);
m_CastShadows->SetValue(actor["castshadow"].defined());
m_Float->SetValue(actor["float"].defined());
m_Material->SetValue(actor["material"]);
}
@@ -319,6 +315,9 @@ AtObj ActorEditor::ExportData()
if (m_CastShadows->IsChecked())
actor.set("castshadow", L"");
if (m_Float->IsChecked())
actor.set("float", L"");
if (m_Material->GetValue().length())
actor.set("material", m_Material->GetValue().c_str());
@@ -22,12 +22,16 @@ protected:
AtObj ExportData();
void ImportData(AtObj& in);
// TODO: er, what's the difference between freeze/thaw and export/import?
// Why is the code duplicated between them?
virtual wxString GetDefaultOpenDirectory();
private:
ActorEditorListCtrl* m_ActorEditorListCtrl;
wxCheckBox* m_CastShadows;
wxCheckBox* m_Float;
wxComboBox* m_Material;
DECLARE_EVENT_TABLE();
@@ -55,14 +55,14 @@ END_EVENT_TABLE()
IMPLEMENT_CLASS(AtlasWindow, wxFrame);
BEGIN_EVENT_TABLE(AtlasWindow, wxFrame)
EVT_MENU(ID_New, AtlasWindow::OnNew)
EVT_MENU(wxID_NEW, AtlasWindow::OnNew)
// EVT_MENU(ID_Import, AtlasWindow::OnImport)
// EVT_MENU(ID_Export, AtlasWindow::OnExport)
EVT_MENU(ID_Open, AtlasWindow::OnOpen)
EVT_MENU(ID_Save, AtlasWindow::OnSave)
EVT_MENU(ID_SaveAs, AtlasWindow::OnSaveAs)
EVT_MENU(wxID_OPEN, AtlasWindow::OnOpen)
EVT_MENU(wxID_SAVE, AtlasWindow::OnSave)
EVT_MENU(wxID_SAVEAS, AtlasWindow::OnSaveAs)
EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, AtlasWindow::OnMRUFile)
EVT_MENU(ID_Quit, AtlasWindow::OnQuit)
EVT_MENU(wxID_EXIT, AtlasWindow::OnQuit)
EVT_MENU(wxID_UNDO, AtlasWindow::OnUndo)
EVT_MENU(wxID_REDO, AtlasWindow::OnRedo)
@@ -81,19 +81,19 @@ AtlasWindow::AtlasWindow(wxWindow* parent, const wxString& title, const wxSize&
wxMenu *menuFile = new wxMenu;
m_MenuBar->Append(menuFile, _("&File"));
{
menuFile->Append(ID_New, _("&New"));
menuFile->Append(wxID_NEW, _("&New\tCtrl+N"));
// menuFile->Append(ID_Import, _("&Import..."));
// menuFile->Append(ID_Export, _("&Export..."));
menuFile->Append(ID_Open, _("&Open..."));
menuFile->Append(ID_Save, _("&Save"));
menuFile->Append(ID_SaveAs, _("Save &As..."));
menuFile->Append(wxID_OPEN, _("&Open...\tCtrl+O"));
menuFile->Append(wxID_SAVE, _("&Save\tCtrl+S"));
menuFile->Append(wxID_SAVEAS, _("Save &As..."));
menuFile->AppendSeparator();//-----------
menuFile->Append(ID_Quit, _("E&xit"));
menuFile->Append(wxID_EXIT, _("E&xit"));
m_FileHistory.UseMenu(menuFile);//-------
m_FileHistory.AddFilesToMenu();
}
m_menuItem_Save = menuFile->FindItem(ID_Save); // remember this item, to let it be greyed out
m_menuItem_Save = menuFile->FindItem(wxID_SAVE); // remember this item, to let it be greyed out
wxASSERT(m_menuItem_Save);
wxMenu *menuEdit = new wxMenu;
@@ -20,16 +20,11 @@ public:
enum
{
ID_Quit = 1,
ID_New,
// ID_Import,
// ID_Export,
ID_Open,
ID_Save,
ID_SaveAs,
// First available ID for custom window-specific menu items
ID_Custom
ID_Custom = 1
};
AtlasWindow(wxWindow* parent, const wxString& title, const wxSize& size);
@@ -19,6 +19,8 @@
#include "ps/CLogger.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/EntityTemplate.h"
#include "simulation/Entity.h"
@@ -34,6 +36,18 @@ static bool SortObjectsList(const sObjectsListItem& a, const sObjectsListItem& b
return wcscmp(a.name.c_str(), b.name.c_str()) < 0;
}
static bool IsFloating(const CUnit* unit)
{
if (! unit)
return false;
if (unit->GetEntity())
return (unit->GetEntity()->m_base->m_anchorType != L"Ground");
else
return unit->GetObject()->m_Base->m_Properties.m_FloatOnWater;
}
QUERYHANDLER(GetObjectsList)
{
std::vector<sObjectsListItem> objects;
@@ -92,7 +106,11 @@ void AtlasRenderSelection()
bound.GetCentre(centre);
CVector3D a = (bound[0] - centre) * 1.1f + centre;
CVector3D b = (bound[1] - centre) * 1.1f + centre;
float h = g_Game->GetWorld()->GetTerrain()->getExactGroundLevel(centre.X, centre.Z);
if (IsFloating(unit))
h = std::max(h, g_Renderer.GetWaterManager()->m_WaterHeight);
glColor3f(0.8f, 0.8f, 0.8f);
glBegin(GL_LINE_LOOP);
glVertex3f(a.X, h, a.Z);
@@ -216,18 +234,21 @@ END_COMMAND(SetObjectSettings);
static CUnit* g_PreviewUnit = NULL;
static CStrW g_PreviewUnitID;
static bool g_PreviewUnitFloating;
// Returns roughly the largest number smaller than f (i.e. closer to zero)
// (TODO: does this actually work correctly?)
static float flt_minus_epsilon(float f)
{
return f - (FLT_EPSILON * f);
}
static CVector3D GetUnitPos(const Position& pos)
static CVector3D GetUnitPos(const Position& pos, bool floating)
{
static CVector3D vec;
vec = pos.GetWorldSpace(vec); // if msg->pos is 'Unchanged', use the previous pos
vec = pos.GetWorldSpace(vec, floating); // if msg->pos is 'Unchanged', use the previous pos
// Check whether the position should be clamped to the edges of the world
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)
@@ -276,7 +297,7 @@ MESSAGEHANDLER(ObjectPreview)
CStrW name;
if (ParseObjectName(*msg->id, isEntity, name))
{
std::set<CStr8> selections; // TODO: get selections from user
std::set<CStr> selections; // TODO: get selections from user
// Create new unit
if (isEntity)
@@ -285,12 +306,14 @@ MESSAGEHANDLER(ObjectPreview)
if (base) // (ignore errors)
{
g_PreviewUnit = g_UnitMan.CreateUnit(base->m_actorName, NULL, selections);
g_PreviewUnitFloating = (base->m_anchorType != L"Ground");
// TODO: variations
}
}
else
{
g_PreviewUnit = g_UnitMan.CreateUnit(CStr(name), NULL, selections);
g_PreviewUnitFloating = IsFloating(g_PreviewUnit);
}
}
@@ -301,7 +324,7 @@ MESSAGEHANDLER(ObjectPreview)
{
// Update the unit's position and orientation:
CVector3D pos = GetUnitPos(msg->pos);
CVector3D pos = GetUnitPos(msg->pos, g_PreviewUnitFloating);
float s, c;
@@ -343,7 +366,7 @@ BEGIN_COMMAND(CreateObject)
{
// Calculate the position/orientation to create this unit with
m_Pos = GetUnitPos(msg->pos);
m_Pos = GetUnitPos(msg->pos, false);
if (msg->usetarget)
{
@@ -372,7 +395,7 @@ BEGIN_COMMAND(CreateObject)
CStrW name;
if (ParseObjectName(*msg->id, isEntity, name))
{
std::set<CStr8> selections;
std::set<CStr> selections;
if (isEntity)
{
@@ -477,8 +500,13 @@ QUERYHANDLER(PickObject)
// object's model-centre, so that callers know the offset to use when
// working out the screen coordinates to move the object to.
// (TODO: http://trac.0ad.homeip.net/ticket/99)
CVector3D centre = target->GetModel()->GetTransform().GetTranslation();
centre.Y = g_Game->GetWorld()->GetTerrain()->getExactGroundLevel(centre.X, centre.Z);
if (IsFloating(target))
centre.Y = std::max(centre.Y, g_Renderer.GetWaterManager()->m_WaterHeight);
float cx, cy;
g_Game->GetView()->GetCamera()->GetScreenCoordinates(centre, cx, cy);
@@ -501,6 +529,8 @@ BEGIN_COMMAND(MoveObject)
CUnit* unit = g_UnitMan.FindByID(msg->id);
if (! unit) return;
m_PosNew = GetUnitPos(msg->pos, IsFloating(unit));
if (unit->GetEntity())
{
m_PosOld = unit->GetEntity()->m_position;
@@ -511,8 +541,6 @@ BEGIN_COMMAND(MoveObject)
m_PosOld = m.GetTranslation();
}
m_PosNew = GetUnitPos(msg->pos);
SetPos(m_PosNew);
}
+6 -6
View File
@@ -8,7 +8,7 @@
#include "ps/Game.h"
#include "graphics/GameView.h"
CVector3D AtlasMessage::Position::GetWorldSpace() const
CVector3D AtlasMessage::Position::GetWorldSpace(bool floating) const
{
switch (type)
{
@@ -17,7 +17,7 @@ CVector3D AtlasMessage::Position::GetWorldSpace() const
break;
case 1:
return g_Game->GetView()->GetCamera()->GetWorldCoordinates(type1.x, type1.y);
return g_Game->GetView()->GetCamera()->GetWorldCoordinates(type1.x, type1.y, floating);
break;
case 2:
@@ -31,7 +31,7 @@ CVector3D AtlasMessage::Position::GetWorldSpace() const
}
}
CVector3D AtlasMessage::Position::GetWorldSpace(float h) const
CVector3D AtlasMessage::Position::GetWorldSpace(float h, bool floating) const
{
switch (type)
{
@@ -39,11 +39,11 @@ CVector3D AtlasMessage::Position::GetWorldSpace(float h) const
return g_Game->GetView()->GetCamera()->GetWorldCoordinates(type1.x, type1.y, h);
default:
return GetWorldSpace();
return GetWorldSpace(floating);
}
}
CVector3D AtlasMessage::Position::GetWorldSpace(const CVector3D& prev) const
CVector3D AtlasMessage::Position::GetWorldSpace(const CVector3D& prev, bool floating) const
{
switch (type)
{
@@ -51,7 +51,7 @@ CVector3D AtlasMessage::Position::GetWorldSpace(const CVector3D& prev) const
return prev;
default:
return GetWorldSpace();
return GetWorldSpace(floating);
}
}
@@ -39,9 +39,9 @@ struct Position
// Only for use in the game, not the UI.
// Implementations in Misc.cpp.
CVector3D GetWorldSpace() const;
CVector3D GetWorldSpace(float h) const;
CVector3D GetWorldSpace(const CVector3D& prev) const;
CVector3D GetWorldSpace(bool floating = false) const;
CVector3D GetWorldSpace(float h, bool floating = false) const;
CVector3D GetWorldSpace(const CVector3D& prev, bool floating = false) const;
void GetScreenSpace(float& x, float& y) const;
};
SHAREABLE_STRUCT(Position);