mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-09-21 20:06:40 +00:00
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:
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user