diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index d37502c6ed..44adf92ecb 100644 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -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) diff --git a/source/graphics/ObjectBase.cpp b/source/graphics/ObjectBase.cpp index e41a2b52c0..185be661b8 100644 --- a/source/graphics/ObjectBase.cpp +++ b/source/graphics/ObjectBase.cpp @@ -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()); diff --git a/source/graphics/ObjectBase.h b/source/graphics/ObjectBase.h index d6c480fb61..72c0375435 100644 --- a/source/graphics/ObjectBase.h +++ b/source/graphics/ObjectBase.h @@ -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 diff --git a/source/graphics/Unit.h b/source/graphics/Unit.h index 5bbf1cc35a..2519fe6422 100644 --- a/source/graphics/Unit.h +++ b/source/graphics/Unit.h @@ -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(); diff --git a/source/tools/atlas/AtlasUI/ActorEditor/ActorEditor.cpp b/source/tools/atlas/AtlasUI/ActorEditor/ActorEditor.cpp index f034b5c204..51aead7da9 100644 --- a/source/tools/atlas/AtlasUI/ActorEditor/ActorEditor.cpp +++ b/source/tools/atlas/AtlasUI/ActorEditor/ActorEditor.cpp @@ -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()); diff --git a/source/tools/atlas/AtlasUI/ActorEditor/ActorEditor.h b/source/tools/atlas/AtlasUI/ActorEditor/ActorEditor.h index bfaf3588e3..fb3f202f76 100644 --- a/source/tools/atlas/AtlasUI/ActorEditor/ActorEditor.h +++ b/source/tools/atlas/AtlasUI/ActorEditor/ActorEditor.h @@ -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(); diff --git a/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.cpp b/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.cpp index 8ad4a08355..ec1fe77450 100644 --- a/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.cpp +++ b/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.cpp @@ -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; diff --git a/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.h b/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.h index 7958bef4b2..cca4f36469 100644 --- a/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.h +++ b/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.h @@ -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); diff --git a/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp index 10e68a4f8d..7e97edf580 100644 --- a/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp @@ -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 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 selections; // TODO: get selections from user + std::set 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 selections; + std::set 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); } diff --git a/source/tools/atlas/GameInterface/Misc.cpp b/source/tools/atlas/GameInterface/Misc.cpp index 6ff5d0b2f5..cb14318c75 100644 --- a/source/tools/atlas/GameInterface/Misc.cpp +++ b/source/tools/atlas/GameInterface/Misc.cpp @@ -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); } } diff --git a/source/tools/atlas/GameInterface/SharedTypes.h b/source/tools/atlas/GameInterface/SharedTypes.h index b76a97f9ed..1d130e67bc 100644 --- a/source/tools/atlas/GameInterface/SharedTypes.h +++ b/source/tools/atlas/GameInterface/SharedTypes.h @@ -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);