mirror of
https://github.com/id-Software/GtkRadiant.git
synced 2026-03-19 16:39:26 +01:00
The GtkRadiant sources as originally released under the GPL license.
This commit is contained in:
23
plugins/entity/angle.cpp
Normal file
23
plugins/entity/angle.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "angle.h"
|
||||
|
||||
101
plugins/entity/angle.h
Normal file
101
plugins/entity/angle.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_ANGLE_H)
|
||||
#define INCLUDED_ANGLE_H
|
||||
|
||||
#include "ientity.h"
|
||||
|
||||
#include "math/quaternion.h"
|
||||
#include "generic/callback.h"
|
||||
#include "stringio.h"
|
||||
|
||||
const float ANGLEKEY_IDENTITY = 0;
|
||||
|
||||
inline void default_angle(float& angle)
|
||||
{
|
||||
angle = ANGLEKEY_IDENTITY;
|
||||
}
|
||||
inline void normalise_angle(float& angle)
|
||||
{
|
||||
angle = static_cast<float>(float_mod(angle, 360.0));
|
||||
}
|
||||
inline void read_angle(float& angle, const char* value)
|
||||
{
|
||||
if(!string_parse_float(value, angle))
|
||||
{
|
||||
angle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
normalise_angle(angle);
|
||||
}
|
||||
}
|
||||
inline void write_angle(float angle, Entity* entity)
|
||||
{
|
||||
if(angle == 0)
|
||||
{
|
||||
entity->setKeyValue("angle", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
char value[64];
|
||||
sprintf(value, "%g", angle);
|
||||
entity->setKeyValue("angle", value);
|
||||
}
|
||||
}
|
||||
|
||||
class AngleKey
|
||||
{
|
||||
Callback m_angleChanged;
|
||||
public:
|
||||
float m_angle;
|
||||
|
||||
|
||||
AngleKey(const Callback& angleChanged)
|
||||
: m_angleChanged(angleChanged), m_angle(ANGLEKEY_IDENTITY)
|
||||
{
|
||||
}
|
||||
|
||||
void angleChanged(const char* value)
|
||||
{
|
||||
read_angle(m_angle, value);
|
||||
m_angleChanged();
|
||||
}
|
||||
typedef MemberCaller1<AngleKey, const char*, &AngleKey::angleChanged> AngleChangedCaller;
|
||||
|
||||
void write(Entity* entity) const
|
||||
{
|
||||
write_angle(m_angle, entity);
|
||||
}
|
||||
};
|
||||
|
||||
inline float angle_rotated(float angle, const Quaternion& rotation)
|
||||
{
|
||||
return matrix4_get_rotation_euler_xyz_degrees(
|
||||
matrix4_multiplied_by_matrix4(
|
||||
matrix4_rotation_for_z_degrees(angle),
|
||||
matrix4_rotation_for_quaternion_quantised(rotation)
|
||||
)
|
||||
).z();
|
||||
}
|
||||
|
||||
#endif
|
||||
23
plugins/entity/angles.cpp
Normal file
23
plugins/entity/angles.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "angles.h"
|
||||
|
||||
140
plugins/entity/angles.h
Normal file
140
plugins/entity/angles.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_ANGLES_H)
|
||||
#define INCLUDED_ANGLES_H
|
||||
|
||||
#include "ientity.h"
|
||||
|
||||
#include "math/quaternion.h"
|
||||
#include "generic/callback.h"
|
||||
#include "stringio.h"
|
||||
|
||||
#include "angle.h"
|
||||
|
||||
const Vector3 ANGLESKEY_IDENTITY = Vector3(0, 0, 0);
|
||||
|
||||
inline void default_angles(Vector3& angles)
|
||||
{
|
||||
angles = ANGLESKEY_IDENTITY;
|
||||
}
|
||||
inline void normalise_angles(Vector3& angles)
|
||||
{
|
||||
angles[0] = static_cast<float>(float_mod(angles[0], 360));
|
||||
angles[1] = static_cast<float>(float_mod(angles[1], 360));
|
||||
angles[2] = static_cast<float>(float_mod(angles[2], 360));
|
||||
}
|
||||
inline void read_angle(Vector3& angles, const char* value)
|
||||
{
|
||||
if(!string_parse_float(value, angles[2]))
|
||||
{
|
||||
default_angles(angles);
|
||||
}
|
||||
else
|
||||
{
|
||||
angles[0] = 0;
|
||||
angles[1] = 0;
|
||||
normalise_angles(angles);
|
||||
}
|
||||
}
|
||||
inline void read_angles(Vector3& angles, const char* value)
|
||||
{
|
||||
if(!string_parse_vector3(value, angles))
|
||||
{
|
||||
default_angles(angles);
|
||||
}
|
||||
else
|
||||
{
|
||||
angles = Vector3(angles[2], angles[0], angles[1]);
|
||||
normalise_angles(angles);
|
||||
}
|
||||
}
|
||||
inline void write_angles(const Vector3& angles, Entity* entity)
|
||||
{
|
||||
if(angles[0] == 0
|
||||
&& angles[1] == 0
|
||||
&& angles[2] == 0)
|
||||
{
|
||||
entity->setKeyValue("angle", "");
|
||||
entity->setKeyValue("angles", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
char value[64];
|
||||
|
||||
if(angles[0] == 0 && angles[1] == 0)
|
||||
{
|
||||
entity->setKeyValue("angles", "");
|
||||
write_angle(angles[2], entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(value, "%g %g %g", angles[1], angles[2], angles[0]);
|
||||
entity->setKeyValue("angle", "");
|
||||
entity->setKeyValue("angles", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline Vector3 angles_rotated(const Vector3& angles, const Quaternion& rotation)
|
||||
{
|
||||
return matrix4_get_rotation_euler_xyz_degrees(
|
||||
matrix4_multiplied_by_matrix4(
|
||||
matrix4_rotation_for_euler_xyz_degrees(angles),
|
||||
matrix4_rotation_for_quaternion_quantised(rotation)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
class AnglesKey
|
||||
{
|
||||
Callback m_anglesChanged;
|
||||
public:
|
||||
Vector3 m_angles;
|
||||
|
||||
|
||||
AnglesKey(const Callback& anglesChanged)
|
||||
: m_anglesChanged(anglesChanged), m_angles(ANGLESKEY_IDENTITY)
|
||||
{
|
||||
}
|
||||
|
||||
void angleChanged(const char* value)
|
||||
{
|
||||
read_angle(m_angles, value);
|
||||
m_anglesChanged();
|
||||
}
|
||||
typedef MemberCaller1<AnglesKey, const char*, &AnglesKey::angleChanged> AngleChangedCaller;
|
||||
|
||||
void anglesChanged(const char* value)
|
||||
{
|
||||
read_angles(m_angles, value);
|
||||
m_anglesChanged();
|
||||
}
|
||||
typedef MemberCaller1<AnglesKey, const char*, &AnglesKey::anglesChanged> AnglesChangedCaller;
|
||||
|
||||
void write(Entity* entity) const
|
||||
{
|
||||
write_angles(m_angles, entity);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
23
plugins/entity/colour.cpp
Normal file
23
plugins/entity/colour.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "colour.h"
|
||||
|
||||
102
plugins/entity/colour.h
Normal file
102
plugins/entity/colour.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_COLOUR_H)
|
||||
#define INCLUDED_COLOUR_H
|
||||
|
||||
#include "ientity.h"
|
||||
#include "irender.h"
|
||||
|
||||
#include "math/vector.h"
|
||||
#include "eclasslib.h"
|
||||
#include "generic/callback.h"
|
||||
#include "stringio.h"
|
||||
|
||||
inline void default_colour(Vector3& colour)
|
||||
{
|
||||
colour = Vector3(1, 1, 1);
|
||||
}
|
||||
inline void read_colour(Vector3& colour, const char* value)
|
||||
{
|
||||
if(!string_parse_vector3(value, colour))
|
||||
{
|
||||
default_colour(colour);
|
||||
}
|
||||
}
|
||||
inline void write_colour(const Vector3& colour, Entity* entity)
|
||||
{
|
||||
char value[64];
|
||||
|
||||
sprintf(value, "%f %f %f", colour[0], colour[1], colour[2]);
|
||||
entity->setKeyValue("_color", value);
|
||||
}
|
||||
|
||||
class Colour
|
||||
{
|
||||
Callback m_colourChanged;
|
||||
Shader* m_state;
|
||||
|
||||
void capture_state()
|
||||
{
|
||||
m_state = colour_capture_state_fill(m_colour);
|
||||
}
|
||||
void release_state()
|
||||
{
|
||||
colour_release_state_fill(m_colour);
|
||||
}
|
||||
|
||||
public:
|
||||
Vector3 m_colour;
|
||||
|
||||
Colour(const Callback& colourChanged)
|
||||
: m_colourChanged(colourChanged)
|
||||
{
|
||||
default_colour(m_colour);
|
||||
capture_state();
|
||||
}
|
||||
~Colour()
|
||||
{
|
||||
release_state();
|
||||
}
|
||||
|
||||
void colourChanged(const char* value)
|
||||
{
|
||||
release_state();
|
||||
read_colour(m_colour, value);
|
||||
capture_state();
|
||||
|
||||
m_colourChanged();
|
||||
}
|
||||
typedef MemberCaller1<Colour, const char*, &Colour::colourChanged> ColourChangedCaller;
|
||||
|
||||
|
||||
void write(Entity* entity) const
|
||||
{
|
||||
write_colour(m_colour, entity);
|
||||
}
|
||||
|
||||
Shader* state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
23
plugins/entity/curve.cpp
Normal file
23
plugins/entity/curve.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "curve.h"
|
||||
|
||||
521
plugins/entity/curve.h
Normal file
521
plugins/entity/curve.h
Normal file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_CURVE_H)
|
||||
#define INCLUDED_CURVE_H
|
||||
|
||||
#include "ientity.h"
|
||||
#include "selectable.h"
|
||||
#include "renderable.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "math/curve.h"
|
||||
#include "stream/stringstream.h"
|
||||
#include "selectionlib.h"
|
||||
#include "render.h"
|
||||
#include "stringio.h"
|
||||
|
||||
class RenderableCurve : public OpenGLRenderable
|
||||
{
|
||||
public:
|
||||
std::vector<PointVertex> m_vertices;
|
||||
void render(RenderStateFlags state) const
|
||||
{
|
||||
pointvertex_gl_array(&m_vertices.front());
|
||||
glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_vertices.size()));
|
||||
}
|
||||
};
|
||||
|
||||
inline void plotBasisFunction(std::size_t numSegments, int point, int degree)
|
||||
{
|
||||
Knots knots;
|
||||
KnotVector_openUniform(knots, 4, degree);
|
||||
|
||||
globalOutputStream() << "plotBasisFunction point " << point << " of 4, knot vector:";
|
||||
for(Knots::iterator i = knots.begin(); i != knots.end(); ++i)
|
||||
{
|
||||
globalOutputStream() << " " << *i;
|
||||
}
|
||||
globalOutputStream() << "\n";
|
||||
globalOutputStream() << "t=0 basis=" << BSpline_basis(knots, point, degree, 0.0) << "\n";
|
||||
for(std::size_t i = 1; i < numSegments; ++i)
|
||||
{
|
||||
double t = (1.0 / double(numSegments)) * double(i);
|
||||
globalOutputStream() << "t=" << t << " basis=" << BSpline_basis(knots, point, degree, t) << "\n";
|
||||
}
|
||||
globalOutputStream() << "t=1 basis=" << BSpline_basis(knots, point, degree, 1.0) << "\n";
|
||||
}
|
||||
|
||||
inline bool ControlPoints_parse(ControlPoints& controlPoints, const char* value)
|
||||
{
|
||||
StringTokeniser tokeniser(value, " ");
|
||||
|
||||
std::size_t size;
|
||||
if(!string_parse_size(tokeniser.getToken(), size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(size < 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
controlPoints.resize(size);
|
||||
|
||||
if(!string_equal(tokeniser.getToken(), "("))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for(ControlPoints::iterator i = controlPoints.begin(); i != controlPoints.end(); ++i)
|
||||
{
|
||||
if(!string_parse_float(tokeniser.getToken(), (*i).x())
|
||||
|| !string_parse_float(tokeniser.getToken(), (*i).y())
|
||||
|| !string_parse_float(tokeniser.getToken(), (*i).z()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!string_equal(tokeniser.getToken(), ")"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void ControlPoints_write(const ControlPoints& controlPoints, StringOutputStream& value)
|
||||
{
|
||||
value << Unsigned(controlPoints.size()) << " (";
|
||||
for(ControlPoints::const_iterator i = controlPoints.begin(); i != controlPoints.end(); ++i)
|
||||
{
|
||||
value << " " << (*i).x() << " " << (*i).y() << " " << (*i).z() << " ";
|
||||
}
|
||||
value << ")";
|
||||
}
|
||||
|
||||
inline void ControlPoint_testSelect(const Vector3& point, ObservedSelectable& selectable, Selector& selector, SelectionTest& test)
|
||||
{
|
||||
SelectionIntersection best;
|
||||
test.TestPoint(point, best);
|
||||
if(best.valid())
|
||||
{
|
||||
Selector_add(selector, selectable, best);
|
||||
}
|
||||
}
|
||||
|
||||
class ControlPointTransform
|
||||
{
|
||||
const Matrix4& m_matrix;
|
||||
public:
|
||||
ControlPointTransform(const Matrix4& matrix) : m_matrix(matrix)
|
||||
{
|
||||
}
|
||||
void operator()(Vector3& point) const
|
||||
{
|
||||
matrix4_transform_point(m_matrix, point);
|
||||
}
|
||||
};
|
||||
|
||||
class ControlPointSnap
|
||||
{
|
||||
float m_snap;
|
||||
public:
|
||||
ControlPointSnap(float snap) : m_snap(snap)
|
||||
{
|
||||
}
|
||||
void operator()(Vector3& point) const
|
||||
{
|
||||
vector3_snap(point, m_snap);
|
||||
}
|
||||
};
|
||||
|
||||
const Colour4b colour_vertex(0, 255, 0, 255);
|
||||
const Colour4b colour_selected(0, 0, 255, 255);
|
||||
|
||||
class ControlPointAdd
|
||||
{
|
||||
RenderablePointVector& m_points;
|
||||
public:
|
||||
ControlPointAdd(RenderablePointVector& points) : m_points(points)
|
||||
{
|
||||
}
|
||||
void operator()(const Vector3& point) const
|
||||
{
|
||||
m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_vertex));
|
||||
}
|
||||
};
|
||||
|
||||
class ControlPointAddSelected
|
||||
{
|
||||
RenderablePointVector& m_points;
|
||||
public:
|
||||
ControlPointAddSelected(RenderablePointVector& points) : m_points(points)
|
||||
{
|
||||
}
|
||||
void operator()(const Vector3& point) const
|
||||
{
|
||||
m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_selected));
|
||||
}
|
||||
};
|
||||
|
||||
class CurveEditType
|
||||
{
|
||||
public:
|
||||
Shader* m_controlsShader;
|
||||
Shader* m_selectedShader;
|
||||
};
|
||||
|
||||
inline void ControlPoints_write(ControlPoints& controlPoints, const char* key, Entity& entity)
|
||||
{
|
||||
StringOutputStream value(256);
|
||||
if(!controlPoints.empty())
|
||||
{
|
||||
ControlPoints_write(controlPoints, value);
|
||||
}
|
||||
entity.setKeyValue(key, value.c_str());
|
||||
}
|
||||
|
||||
class CurveEdit
|
||||
{
|
||||
SelectionChangeCallback m_selectionChanged;
|
||||
ControlPoints& m_controlPoints;
|
||||
typedef Array<ObservedSelectable> Selectables;
|
||||
Selectables m_selectables;
|
||||
|
||||
RenderablePointVector m_controlsRender;
|
||||
mutable RenderablePointVector m_selectedRender;
|
||||
|
||||
public:
|
||||
typedef Static<CurveEditType> Type;
|
||||
|
||||
CurveEdit(ControlPoints& controlPoints, const SelectionChangeCallback& selectionChanged) :
|
||||
m_selectionChanged(selectionChanged),
|
||||
m_controlPoints(controlPoints),
|
||||
m_controlsRender(GL_POINTS),
|
||||
m_selectedRender(GL_POINTS)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
const Functor& forEachSelected(const Functor& functor)
|
||||
{
|
||||
ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
|
||||
ControlPoints::iterator p = m_controlPoints.begin();
|
||||
for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
|
||||
{
|
||||
if((*i).isSelected())
|
||||
{
|
||||
functor(*p);
|
||||
}
|
||||
}
|
||||
return functor;
|
||||
}
|
||||
template<typename Functor>
|
||||
const Functor& forEachSelected(const Functor& functor) const
|
||||
{
|
||||
ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
|
||||
ControlPoints::const_iterator p = m_controlPoints.begin();
|
||||
for(Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
|
||||
{
|
||||
if((*i).isSelected())
|
||||
{
|
||||
functor(*p);
|
||||
}
|
||||
}
|
||||
return functor;
|
||||
}
|
||||
template<typename Functor>
|
||||
const Functor& forEach(const Functor& functor) const
|
||||
{
|
||||
for(ControlPoints::const_iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i)
|
||||
{
|
||||
functor(*i);
|
||||
}
|
||||
return functor;
|
||||
}
|
||||
|
||||
void testSelect(Selector& selector, SelectionTest& test)
|
||||
{
|
||||
ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
|
||||
ControlPoints::const_iterator p = m_controlPoints.begin();
|
||||
for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p)
|
||||
{
|
||||
ControlPoint_testSelect(*p, *i, selector, test);
|
||||
}
|
||||
}
|
||||
|
||||
bool isSelected() const
|
||||
{
|
||||
for(Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
|
||||
{
|
||||
if((*i).isSelected())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void setSelected(bool selected)
|
||||
{
|
||||
for(Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i)
|
||||
{
|
||||
(*i).setSelected(selected);
|
||||
}
|
||||
}
|
||||
|
||||
void write(const char* key, Entity& entity)
|
||||
{
|
||||
ControlPoints_write(m_controlPoints, key, entity);
|
||||
}
|
||||
|
||||
void transform(const Matrix4& matrix)
|
||||
{
|
||||
forEachSelected(ControlPointTransform(matrix));
|
||||
}
|
||||
void snapto(float snap)
|
||||
{
|
||||
forEachSelected(ControlPointSnap(snap));
|
||||
}
|
||||
|
||||
void updateSelected() const
|
||||
{
|
||||
m_selectedRender.clear();
|
||||
forEachSelected(ControlPointAddSelected(m_selectedRender));
|
||||
}
|
||||
|
||||
void renderComponents(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
|
||||
{
|
||||
renderer.SetState(Type::instance().m_controlsShader, Renderer::eWireframeOnly);
|
||||
renderer.SetState(Type::instance().m_controlsShader, Renderer::eFullMaterials);
|
||||
renderer.addRenderable(m_controlsRender, localToWorld);
|
||||
}
|
||||
|
||||
void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
|
||||
{
|
||||
updateSelected();
|
||||
if(!m_selectedRender.empty())
|
||||
{
|
||||
renderer.Highlight(Renderer::ePrimitive, false);
|
||||
renderer.SetState(Type::instance().m_selectedShader, Renderer::eWireframeOnly);
|
||||
renderer.SetState(Type::instance().m_selectedShader, Renderer::eFullMaterials);
|
||||
renderer.addRenderable(m_selectedRender, localToWorld);
|
||||
}
|
||||
}
|
||||
|
||||
void curveChanged()
|
||||
{
|
||||
m_selectables.resize(m_controlPoints.size(), m_selectionChanged);
|
||||
|
||||
m_controlsRender.clear();
|
||||
m_controlsRender.reserve(m_controlPoints.size());
|
||||
forEach(ControlPointAdd(m_controlsRender));
|
||||
|
||||
m_selectedRender.reserve(m_controlPoints.size());
|
||||
}
|
||||
typedef MemberCaller<CurveEdit, &CurveEdit::curveChanged> CurveChangedCaller;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const int NURBS_degree = 3;
|
||||
|
||||
class NURBSCurve
|
||||
{
|
||||
typedef std::set<Callback> Callbacks;
|
||||
Callbacks m_curveChanged;
|
||||
Callback m_boundsChanged;
|
||||
public:
|
||||
ControlPoints m_controlPoints;
|
||||
ControlPoints m_controlPointsTransformed;
|
||||
NURBSWeights m_weights;
|
||||
Knots m_knots;
|
||||
RenderableCurve m_renderCurve;
|
||||
AABB m_bounds;
|
||||
|
||||
NURBSCurve(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
|
||||
{
|
||||
}
|
||||
|
||||
void attach(const Callback& curveChanged)
|
||||
{
|
||||
m_curveChanged.insert(curveChanged);
|
||||
curveChanged();
|
||||
}
|
||||
void detach(const Callback& curveChanged)
|
||||
{
|
||||
m_curveChanged.erase(curveChanged);
|
||||
}
|
||||
void notify()
|
||||
{
|
||||
std::for_each(m_curveChanged.begin(), m_curveChanged.end(), CallbackInvoke());
|
||||
}
|
||||
|
||||
void tesselate()
|
||||
{
|
||||
if(!m_controlPointsTransformed.empty())
|
||||
{
|
||||
const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
|
||||
m_renderCurve.m_vertices.resize(numSegments + 1);
|
||||
m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
|
||||
for(std::size_t i = 1; i < numSegments; ++i)
|
||||
{
|
||||
m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(NURBS_evaluate(m_controlPointsTransformed, m_weights, m_knots, NURBS_degree, (1.0 / double(numSegments)) * double(i)));
|
||||
}
|
||||
m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_renderCurve.m_vertices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void curveChanged()
|
||||
{
|
||||
tesselate();
|
||||
|
||||
m_bounds = AABB();
|
||||
for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
|
||||
{
|
||||
aabb_extend_by_point_safe(m_bounds, (*i));
|
||||
}
|
||||
|
||||
m_boundsChanged();
|
||||
notify();
|
||||
}
|
||||
|
||||
bool parseCurve(const char* value)
|
||||
{
|
||||
if(!ControlPoints_parse(m_controlPoints, value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_weights.resize(m_controlPoints.size());
|
||||
for(NURBSWeights::iterator i = m_weights.begin(); i != m_weights.end(); ++i)
|
||||
{
|
||||
(*i) = 1;
|
||||
}
|
||||
|
||||
KnotVector_openUniform(m_knots, m_controlPoints.size(), NURBS_degree);
|
||||
|
||||
//plotBasisFunction(8, 0, NURBS_degree);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void curveChanged(const char* value)
|
||||
{
|
||||
if(string_empty(value) || !parseCurve(value))
|
||||
{
|
||||
m_controlPoints.resize(0);
|
||||
m_knots.resize(0);
|
||||
m_weights.resize(0);
|
||||
}
|
||||
m_controlPointsTransformed = m_controlPoints;
|
||||
curveChanged();
|
||||
}
|
||||
typedef MemberCaller1<NURBSCurve, const char*, &NURBSCurve::curveChanged> CurveChangedCaller;
|
||||
};
|
||||
|
||||
class CatmullRomSpline
|
||||
{
|
||||
typedef std::set<Callback> Callbacks;
|
||||
Callbacks m_curveChanged;
|
||||
Callback m_boundsChanged;
|
||||
public:
|
||||
ControlPoints m_controlPoints;
|
||||
ControlPoints m_controlPointsTransformed;
|
||||
RenderableCurve m_renderCurve;
|
||||
AABB m_bounds;
|
||||
|
||||
CatmullRomSpline(const Callback& boundsChanged) : m_boundsChanged(boundsChanged)
|
||||
{
|
||||
}
|
||||
|
||||
void attach(const Callback& curveChanged)
|
||||
{
|
||||
m_curveChanged.insert(curveChanged);
|
||||
curveChanged();
|
||||
}
|
||||
void detach(const Callback& curveChanged)
|
||||
{
|
||||
m_curveChanged.erase(curveChanged);
|
||||
}
|
||||
void notify()
|
||||
{
|
||||
std::for_each(m_curveChanged.begin(), m_curveChanged.end(), CallbackInvoke());
|
||||
}
|
||||
|
||||
void tesselate()
|
||||
{
|
||||
if(!m_controlPointsTransformed.empty())
|
||||
{
|
||||
const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
|
||||
m_renderCurve.m_vertices.resize(numSegments + 1);
|
||||
m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
|
||||
for(std::size_t i = 1; i < numSegments; ++i)
|
||||
{
|
||||
m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(CatmullRom_evaluate(m_controlPointsTransformed, (1.0 / double(numSegments)) * double(i)));
|
||||
}
|
||||
m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_renderCurve.m_vertices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool parseCurve(const char* value)
|
||||
{
|
||||
return ControlPoints_parse(m_controlPoints, value);
|
||||
}
|
||||
|
||||
void curveChanged()
|
||||
{
|
||||
tesselate();
|
||||
|
||||
m_bounds = AABB();
|
||||
for(ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i)
|
||||
{
|
||||
aabb_extend_by_point_safe(m_bounds, (*i));
|
||||
}
|
||||
|
||||
m_boundsChanged();
|
||||
notify();
|
||||
}
|
||||
|
||||
void curveChanged(const char* value)
|
||||
{
|
||||
if(string_empty(value) || !parseCurve(value))
|
||||
{
|
||||
m_controlPoints.resize(0);
|
||||
}
|
||||
m_controlPointsTransformed = m_controlPoints;
|
||||
curveChanged();
|
||||
}
|
||||
typedef MemberCaller1<CatmullRomSpline, const char*, &CatmullRomSpline::curveChanged> CurveChangedCaller;
|
||||
};
|
||||
|
||||
const char* const curve_Nurbs = "curve_Nurbs";
|
||||
const char* const curve_CatmullRomSpline = "curve_CatmullRomSpline";
|
||||
|
||||
|
||||
#endif
|
||||
809
plugins/entity/doom3group.cpp
Normal file
809
plugins/entity/doom3group.cpp
Normal file
@@ -0,0 +1,809 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
///\file
|
||||
///\brief Represents any Doom3 entity which does not have a fixed size specified in its entity-definition (e.g. func_static).
|
||||
///
|
||||
/// This entity behaves as a group only when the "model" key is empty or is the same as the "name" key. Otherwise it behaves as a model.
|
||||
/// When behaving as a group, the "origin" key is the translation to be applied to all brushes (not patches) grouped under this entity.
|
||||
/// When behaving as a model, the "origin", "angle" and "rotation" keys directly control the entity's local-to-parent transform.
|
||||
/// When either the "curve_Nurbs" or "curve_CatmullRomSpline" keys define a curve, the curve is rendered and can be edited.
|
||||
|
||||
#include "doom3group.h"
|
||||
|
||||
#include "cullable.h"
|
||||
#include "renderable.h"
|
||||
#include "editable.h"
|
||||
#include "modelskin.h"
|
||||
|
||||
#include "selectionlib.h"
|
||||
#include "instancelib.h"
|
||||
#include "transformlib.h"
|
||||
#include "traverselib.h"
|
||||
#include "entitylib.h"
|
||||
#include "render.h"
|
||||
#include "eclasslib.h"
|
||||
#include "stream/stringstream.h"
|
||||
#include "pivot.h"
|
||||
|
||||
#include "targetable.h"
|
||||
#include "origin.h"
|
||||
#include "angle.h"
|
||||
#include "rotation.h"
|
||||
#include "model.h"
|
||||
#include "filters.h"
|
||||
#include "namedentity.h"
|
||||
#include "keyobservers.h"
|
||||
#include "namekeys.h"
|
||||
#include "curve.h"
|
||||
#include "modelskinkey.h"
|
||||
|
||||
#include "entity.h"
|
||||
|
||||
inline void PointVertexArray_testSelect(PointVertex* first, std::size_t count, SelectionTest& test, SelectionIntersection& best)
|
||||
{
|
||||
test.TestLineStrip(
|
||||
VertexPointer(
|
||||
reinterpret_cast<VertexPointer::pointer>(&first->vertex),
|
||||
sizeof(PointVertex)
|
||||
),
|
||||
IndexPointer::index_type(count),
|
||||
best
|
||||
);
|
||||
}
|
||||
|
||||
class Doom3Group :
|
||||
public Bounded,
|
||||
public Snappable
|
||||
{
|
||||
EntityKeyValues m_entity;
|
||||
KeyObserverMap m_keyObservers;
|
||||
TraversableNodeSet m_traverse;
|
||||
MatrixTransform m_transform;
|
||||
|
||||
SingletonModel m_model;
|
||||
OriginKey m_originKey;
|
||||
Vector3 m_origin;
|
||||
RotationKey m_rotationKey;
|
||||
Float9 m_rotation;
|
||||
|
||||
ClassnameFilter m_filter;
|
||||
NamedEntity m_named;
|
||||
NameKeys m_nameKeys;
|
||||
TraversableObserverPairRelay m_traverseObservers;
|
||||
Doom3GroupOrigin m_funcStaticOrigin;
|
||||
RenderablePivot m_renderOrigin;
|
||||
RenderableNamedEntity m_renderName;
|
||||
ModelSkinKey m_skin;
|
||||
|
||||
public:
|
||||
NURBSCurve m_curveNURBS;
|
||||
CatmullRomSpline m_curveCatmullRom;
|
||||
private:
|
||||
mutable AABB m_curveBounds;
|
||||
|
||||
Callback m_transformChanged;
|
||||
Callback m_evaluateTransform;
|
||||
|
||||
CopiedString m_name;
|
||||
CopiedString m_modelKey;
|
||||
bool m_isModel;
|
||||
|
||||
scene::Traversable* m_traversable;
|
||||
|
||||
void construct()
|
||||
{
|
||||
default_rotation(m_rotation);
|
||||
|
||||
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
|
||||
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
|
||||
m_keyObservers.insert("model", Doom3Group::ModelChangedCaller(*this));
|
||||
m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
|
||||
m_keyObservers.insert("angle", RotationKey::AngleChangedCaller(m_rotationKey));
|
||||
m_keyObservers.insert("rotation", RotationKey::RotationChangedCaller(m_rotationKey));
|
||||
m_keyObservers.insert("name", NameChangedCaller(*this));
|
||||
m_keyObservers.insert(curve_Nurbs, NURBSCurve::CurveChangedCaller(m_curveNURBS));
|
||||
m_keyObservers.insert(curve_CatmullRomSpline, CatmullRomSpline::CurveChangedCaller(m_curveCatmullRom));
|
||||
m_keyObservers.insert("skin", ModelSkinKey::SkinChangedCaller(m_skin));
|
||||
|
||||
m_traverseObservers.attach(m_funcStaticOrigin);
|
||||
m_isModel = false;
|
||||
m_nameKeys.setKeyIsName(keyIsNameDoom3Doom3Group);
|
||||
attachTraverse();
|
||||
|
||||
m_entity.attach(m_keyObservers);
|
||||
}
|
||||
void destroy()
|
||||
{
|
||||
m_entity.detach(m_keyObservers);
|
||||
|
||||
if(isModel())
|
||||
{
|
||||
detachModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
detachTraverse();
|
||||
}
|
||||
|
||||
m_traverseObservers.detach(m_funcStaticOrigin);
|
||||
}
|
||||
|
||||
void attachModel()
|
||||
{
|
||||
m_traversable = &m_model.getTraversable();
|
||||
m_model.attach(&m_traverseObservers);
|
||||
}
|
||||
void detachModel()
|
||||
{
|
||||
m_traversable = 0;
|
||||
m_model.detach(&m_traverseObservers);
|
||||
}
|
||||
void attachTraverse()
|
||||
{
|
||||
m_traversable = &m_traverse;
|
||||
m_traverse.attach(&m_traverseObservers);
|
||||
}
|
||||
void detachTraverse()
|
||||
{
|
||||
m_traversable = 0;
|
||||
m_traverse.detach(&m_traverseObservers);
|
||||
}
|
||||
|
||||
bool isModel() const
|
||||
{
|
||||
return m_isModel;
|
||||
}
|
||||
|
||||
void setIsModel(bool newValue)
|
||||
{
|
||||
if(newValue && !m_isModel)
|
||||
{
|
||||
detachTraverse();
|
||||
attachModel();
|
||||
|
||||
m_nameKeys.setKeyIsName(Static<KeyIsName>::instance().m_keyIsName);
|
||||
m_model.modelChanged(m_modelKey.c_str());
|
||||
}
|
||||
else if(!newValue && m_isModel)
|
||||
{
|
||||
detachModel();
|
||||
attachTraverse();
|
||||
|
||||
m_nameKeys.setKeyIsName(keyIsNameDoom3Doom3Group);
|
||||
}
|
||||
m_isModel = newValue;
|
||||
updateTransform();
|
||||
}
|
||||
|
||||
void updateIsModel()
|
||||
{
|
||||
setIsModel(!string_empty(m_modelKey.c_str()) && !string_equal(m_modelKey.c_str(), m_name.c_str()));
|
||||
}
|
||||
|
||||
void nameChanged(const char* value)
|
||||
{
|
||||
m_name = value;
|
||||
updateIsModel();
|
||||
}
|
||||
typedef MemberCaller1<Doom3Group, const char*, &Doom3Group::nameChanged> NameChangedCaller;
|
||||
|
||||
void modelChanged(const char* value)
|
||||
{
|
||||
m_modelKey = value;
|
||||
updateIsModel();
|
||||
if(isModel())
|
||||
{
|
||||
m_model.modelChanged(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_model.modelChanged("");
|
||||
}
|
||||
}
|
||||
typedef MemberCaller1<Doom3Group, const char*, &Doom3Group::modelChanged> ModelChangedCaller;
|
||||
|
||||
void updateTransform()
|
||||
{
|
||||
m_transform.localToParent() = g_matrix4_identity;
|
||||
if(isModel())
|
||||
{
|
||||
matrix4_translate_by_vec3(m_transform.localToParent(), m_originKey.m_origin);
|
||||
matrix4_multiply_by_matrix4(m_transform.localToParent(), rotation_toMatrix(m_rotationKey.m_rotation));
|
||||
}
|
||||
m_transformChanged();
|
||||
if(!isModel())
|
||||
{
|
||||
m_funcStaticOrigin.originChanged();
|
||||
}
|
||||
}
|
||||
typedef MemberCaller<Doom3Group, &Doom3Group::updateTransform> UpdateTransformCaller;
|
||||
|
||||
void originChanged()
|
||||
{
|
||||
m_origin = m_originKey.m_origin;
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<Doom3Group, &Doom3Group::originChanged> OriginChangedCaller;
|
||||
|
||||
void rotationChanged()
|
||||
{
|
||||
rotation_assign(m_rotation, m_rotationKey.m_rotation);
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<Doom3Group, &Doom3Group::rotationChanged> RotationChangedCaller;
|
||||
|
||||
void skinChanged()
|
||||
{
|
||||
if(isModel())
|
||||
{
|
||||
scene::Node* node = m_model.getNode();
|
||||
if(node != 0)
|
||||
{
|
||||
Node_modelSkinChanged(*node);
|
||||
}
|
||||
}
|
||||
}
|
||||
typedef MemberCaller<Doom3Group, &Doom3Group::skinChanged> SkinChangedCaller;
|
||||
|
||||
public:
|
||||
Doom3Group(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform) :
|
||||
m_entity(eclass),
|
||||
m_originKey(OriginChangedCaller(*this)),
|
||||
m_origin(ORIGINKEY_IDENTITY),
|
||||
m_rotationKey(RotationChangedCaller(*this)),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_funcStaticOrigin(m_traverse, m_origin),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_skin(SkinChangedCaller(*this)),
|
||||
m_curveNURBS(boundsChanged),
|
||||
m_curveCatmullRom(boundsChanged),
|
||||
m_transformChanged(transformChanged),
|
||||
m_evaluateTransform(evaluateTransform),
|
||||
m_traversable(0)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
Doom3Group(const Doom3Group& other, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform) :
|
||||
m_entity(other.m_entity),
|
||||
m_originKey(OriginChangedCaller(*this)),
|
||||
m_origin(ORIGINKEY_IDENTITY),
|
||||
m_rotationKey(RotationChangedCaller(*this)),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_funcStaticOrigin(m_traverse, m_origin),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_skin(SkinChangedCaller(*this)),
|
||||
m_curveNURBS(boundsChanged),
|
||||
m_curveCatmullRom(boundsChanged),
|
||||
m_transformChanged(transformChanged),
|
||||
m_evaluateTransform(evaluateTransform),
|
||||
m_traversable(0)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
~Doom3Group()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
InstanceCounter m_instanceCounter;
|
||||
void instanceAttach(const scene::Path& path)
|
||||
{
|
||||
if(++m_instanceCounter.m_count == 1)
|
||||
{
|
||||
m_filter.instanceAttach();
|
||||
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_traverse.instanceAttach(path_find_mapfile(path.begin(), path.end()));
|
||||
|
||||
m_funcStaticOrigin.enable();
|
||||
}
|
||||
}
|
||||
void instanceDetach(const scene::Path& path)
|
||||
{
|
||||
if(--m_instanceCounter.m_count == 0)
|
||||
{
|
||||
m_funcStaticOrigin.disable();
|
||||
|
||||
m_traverse.instanceDetach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_filter.instanceDetach();
|
||||
}
|
||||
}
|
||||
|
||||
EntityKeyValues& getEntity()
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
const EntityKeyValues& getEntity() const
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
|
||||
scene::Traversable& getTraversable()
|
||||
{
|
||||
return *m_traversable;
|
||||
}
|
||||
Namespaced& getNamespaced()
|
||||
{
|
||||
return m_nameKeys;
|
||||
}
|
||||
Nameable& getNameable()
|
||||
{
|
||||
return m_named;
|
||||
}
|
||||
TransformNode& getTransformNode()
|
||||
{
|
||||
return m_transform;
|
||||
}
|
||||
ModelSkin& getModelSkin()
|
||||
{
|
||||
return m_skin.get();
|
||||
}
|
||||
|
||||
void attach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_traverseObservers.attach(*observer);
|
||||
}
|
||||
void detach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_traverseObservers.detach(*observer);
|
||||
}
|
||||
|
||||
const AABB& localAABB() const
|
||||
{
|
||||
m_curveBounds = m_curveNURBS.m_bounds;
|
||||
aabb_extend_by_aabb_safe(m_curveBounds, m_curveCatmullRom.m_bounds);
|
||||
return m_curveBounds;
|
||||
}
|
||||
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
|
||||
{
|
||||
if(isModel() && selected)
|
||||
{
|
||||
m_renderOrigin.render(renderer, volume, localToWorld);
|
||||
}
|
||||
|
||||
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
|
||||
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials);
|
||||
|
||||
if(!m_curveNURBS.m_renderCurve.m_vertices.empty())
|
||||
{
|
||||
renderer.addRenderable(m_curveNURBS.m_renderCurve, localToWorld);
|
||||
}
|
||||
if(!m_curveCatmullRom.m_renderCurve.m_vertices.empty())
|
||||
{
|
||||
renderer.addRenderable(m_curveCatmullRom.m_renderCurve, localToWorld);
|
||||
}
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
|
||||
{
|
||||
renderSolid(renderer, volume, localToWorld, selected);
|
||||
if(g_showNames && isModel())
|
||||
{
|
||||
renderer.addRenderable(m_renderName, localToWorld);
|
||||
}
|
||||
}
|
||||
|
||||
void testSelect(Selector& selector, SelectionTest& test, SelectionIntersection& best)
|
||||
{
|
||||
PointVertexArray_testSelect(&m_curveNURBS.m_renderCurve.m_vertices[0], m_curveNURBS.m_renderCurve.m_vertices.size(), test, best);
|
||||
PointVertexArray_testSelect(&m_curveCatmullRom.m_renderCurve.m_vertices[0], m_curveCatmullRom.m_renderCurve.m_vertices.size(), test, best);
|
||||
}
|
||||
|
||||
void translate(const Vector3& translation)
|
||||
{
|
||||
m_origin = origin_translated(m_origin, translation);
|
||||
}
|
||||
void rotate(const Quaternion& rotation)
|
||||
{
|
||||
rotation_rotate(m_rotation, rotation);
|
||||
}
|
||||
void snapto(float snap)
|
||||
{
|
||||
m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
|
||||
m_originKey.write(&m_entity);
|
||||
}
|
||||
void revertTransform()
|
||||
{
|
||||
m_origin = m_originKey.m_origin;
|
||||
rotation_assign(m_rotation, m_rotationKey.m_rotation);
|
||||
m_curveNURBS.m_controlPointsTransformed = m_curveNURBS.m_controlPoints;
|
||||
m_curveCatmullRom.m_controlPointsTransformed = m_curveCatmullRom.m_controlPoints;
|
||||
}
|
||||
void freezeTransform()
|
||||
{
|
||||
m_originKey.m_origin = m_origin;
|
||||
m_originKey.write(&m_entity);
|
||||
rotation_assign(m_rotationKey.m_rotation, m_rotation);
|
||||
m_rotationKey.write(&m_entity);
|
||||
m_curveNURBS.m_controlPoints = m_curveNURBS.m_controlPointsTransformed;
|
||||
ControlPoints_write(m_curveNURBS.m_controlPoints, curve_Nurbs, m_entity);
|
||||
m_curveCatmullRom.m_controlPoints = m_curveCatmullRom.m_controlPointsTransformed;
|
||||
ControlPoints_write(m_curveCatmullRom.m_controlPoints, curve_CatmullRomSpline, m_entity);
|
||||
}
|
||||
void transformChanged()
|
||||
{
|
||||
revertTransform();
|
||||
m_evaluateTransform();
|
||||
updateTransform();
|
||||
m_curveNURBS.curveChanged();
|
||||
m_curveCatmullRom.curveChanged();
|
||||
}
|
||||
typedef MemberCaller<Doom3Group, &Doom3Group::transformChanged> TransformChangedCaller;
|
||||
};
|
||||
|
||||
class ControlPointAddBounds
|
||||
{
|
||||
AABB& m_bounds;
|
||||
public:
|
||||
ControlPointAddBounds(AABB& bounds) : m_bounds(bounds)
|
||||
{
|
||||
}
|
||||
void operator()(const Vector3& point) const
|
||||
{
|
||||
aabb_extend_by_point_safe(m_bounds, point);
|
||||
}
|
||||
};
|
||||
|
||||
class Doom3GroupInstance :
|
||||
public TargetableInstance,
|
||||
public TransformModifier,
|
||||
public Renderable,
|
||||
public SelectionTestable,
|
||||
public ComponentSelectionTestable,
|
||||
public ComponentEditable,
|
||||
public ComponentSnappable
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
InstanceTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
|
||||
InstanceContainedCast<Doom3GroupInstance, Bounded>::install(m_casts);
|
||||
InstanceStaticCast<Doom3GroupInstance, Renderable>::install(m_casts);
|
||||
InstanceStaticCast<Doom3GroupInstance, SelectionTestable>::install(m_casts);
|
||||
InstanceStaticCast<Doom3GroupInstance, ComponentSelectionTestable>::install(m_casts);
|
||||
InstanceStaticCast<Doom3GroupInstance, ComponentEditable>::install(m_casts);
|
||||
InstanceStaticCast<Doom3GroupInstance, ComponentSnappable>::install(m_casts);
|
||||
InstanceStaticCast<Doom3GroupInstance, Transformable>::install(m_casts);
|
||||
InstanceIdentityCast<Doom3GroupInstance>::install(m_casts);
|
||||
}
|
||||
InstanceTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
Doom3Group& m_contained;
|
||||
CurveEdit m_curveNURBS;
|
||||
CurveEdit m_curveCatmullRom;
|
||||
mutable AABB m_aabb_component;
|
||||
public:
|
||||
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
|
||||
Bounded& get(NullType<Bounded>)
|
||||
{
|
||||
return m_contained;
|
||||
}
|
||||
|
||||
STRING_CONSTANT(Name, "Doom3GroupInstance");
|
||||
|
||||
Doom3GroupInstance(const scene::Path& path, scene::Instance* parent, Doom3Group& contained) :
|
||||
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
|
||||
TransformModifier(Doom3Group::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
|
||||
m_contained(contained),
|
||||
m_curveNURBS(m_contained.m_curveNURBS.m_controlPointsTransformed, SelectionChangedComponentCaller(*this)),
|
||||
m_curveCatmullRom(m_contained.m_curveCatmullRom.m_controlPointsTransformed, SelectionChangedComponentCaller(*this))
|
||||
{
|
||||
m_contained.instanceAttach(Instance::path());
|
||||
m_contained.m_curveNURBS.attach(CurveEdit::CurveChangedCaller(m_curveNURBS));
|
||||
m_contained.m_curveCatmullRom.attach(CurveEdit::CurveChangedCaller(m_curveCatmullRom));
|
||||
|
||||
StaticRenderableConnectionLines::instance().attach(*this);
|
||||
}
|
||||
~Doom3GroupInstance()
|
||||
{
|
||||
StaticRenderableConnectionLines::instance().detach(*this);
|
||||
|
||||
m_contained.m_curveCatmullRom.detach(CurveEdit::CurveChangedCaller(m_curveCatmullRom));
|
||||
m_contained.m_curveNURBS.detach(CurveEdit::CurveChangedCaller(m_curveNURBS));
|
||||
m_contained.instanceDetach(Instance::path());
|
||||
}
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
|
||||
|
||||
m_curveNURBS.renderComponentsSelected(renderer, volume, localToWorld());
|
||||
m_curveCatmullRom.renderComponentsSelected(renderer, volume, localToWorld());
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
|
||||
|
||||
m_curveNURBS.renderComponentsSelected(renderer, volume, localToWorld());
|
||||
m_curveCatmullRom.renderComponentsSelected(renderer, volume, localToWorld());
|
||||
}
|
||||
void renderComponents(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
|
||||
{
|
||||
m_curveNURBS.renderComponents(renderer, volume, localToWorld());
|
||||
m_curveCatmullRom.renderComponents(renderer, volume, localToWorld());
|
||||
}
|
||||
}
|
||||
|
||||
void testSelect(Selector& selector, SelectionTest& test)
|
||||
{
|
||||
test.BeginMesh(localToWorld());
|
||||
SelectionIntersection best;
|
||||
|
||||
m_contained.testSelect(selector, test, best);
|
||||
|
||||
if(best.valid())
|
||||
{
|
||||
Selector_add(selector, getSelectable(), best);
|
||||
}
|
||||
}
|
||||
|
||||
bool isSelectedComponents() const
|
||||
{
|
||||
return m_curveNURBS.isSelected() || m_curveCatmullRom.isSelected();
|
||||
}
|
||||
void setSelectedComponents(bool selected, SelectionSystem::EComponentMode mode)
|
||||
{
|
||||
if(mode == SelectionSystem::eVertex)
|
||||
{
|
||||
m_curveNURBS.setSelected(selected);
|
||||
m_curveCatmullRom.setSelected(selected);
|
||||
}
|
||||
}
|
||||
void testSelectComponents(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
|
||||
{
|
||||
if(mode == SelectionSystem::eVertex)
|
||||
{
|
||||
test.BeginMesh(localToWorld());
|
||||
m_curveNURBS.testSelect(selector, test);
|
||||
m_curveCatmullRom.testSelect(selector, test);
|
||||
}
|
||||
}
|
||||
|
||||
void transformComponents(const Matrix4& matrix)
|
||||
{
|
||||
if(m_curveNURBS.isSelected())
|
||||
{
|
||||
m_curveNURBS.transform(matrix);
|
||||
}
|
||||
if(m_curveCatmullRom.isSelected())
|
||||
{
|
||||
m_curveCatmullRom.transform(matrix);
|
||||
}
|
||||
}
|
||||
|
||||
const AABB& getSelectedComponentsBounds() const
|
||||
{
|
||||
m_aabb_component = AABB();
|
||||
m_curveNURBS.forEachSelected(ControlPointAddBounds(m_aabb_component));
|
||||
m_curveCatmullRom.forEachSelected(ControlPointAddBounds(m_aabb_component));
|
||||
return m_aabb_component;
|
||||
}
|
||||
|
||||
void snapComponents(float snap)
|
||||
{
|
||||
if(m_curveNURBS.isSelected())
|
||||
{
|
||||
m_curveNURBS.snapto(snap);
|
||||
m_curveNURBS.write(curve_Nurbs, m_contained.getEntity());
|
||||
}
|
||||
if(m_curveCatmullRom.isSelected())
|
||||
{
|
||||
m_curveCatmullRom.snapto(snap);
|
||||
m_curveCatmullRom.write(curve_CatmullRomSpline, m_contained.getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
void evaluateTransform()
|
||||
{
|
||||
if(getType() == TRANSFORM_PRIMITIVE)
|
||||
{
|
||||
m_contained.translate(getTranslation());
|
||||
m_contained.rotate(getRotation());
|
||||
}
|
||||
else
|
||||
{
|
||||
transformComponents(calculateTransform());
|
||||
}
|
||||
}
|
||||
void applyTransform()
|
||||
{
|
||||
m_contained.revertTransform();
|
||||
evaluateTransform();
|
||||
m_contained.freezeTransform();
|
||||
}
|
||||
typedef MemberCaller<Doom3GroupInstance, &Doom3GroupInstance::applyTransform> ApplyTransformCaller;
|
||||
|
||||
void selectionChangedComponent(const Selectable& selectable)
|
||||
{
|
||||
GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable);
|
||||
GlobalSelectionSystem().onComponentSelection(*this, selectable);
|
||||
}
|
||||
typedef MemberCaller1<Doom3GroupInstance, const Selectable&, &Doom3GroupInstance::selectionChangedComponent> SelectionChangedComponentCaller;
|
||||
};
|
||||
|
||||
class Doom3GroupNode :
|
||||
public scene::Node::Symbiot,
|
||||
public scene::Instantiable,
|
||||
public scene::Cloneable,
|
||||
public scene::Traversable::Observer
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
NodeTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
NodeStaticCast<Doom3GroupNode, scene::Instantiable>::install(m_casts);
|
||||
NodeStaticCast<Doom3GroupNode, scene::Cloneable>::install(m_casts);
|
||||
NodeContainedCast<Doom3GroupNode, scene::Traversable>::install(m_casts);
|
||||
NodeContainedCast<Doom3GroupNode, Snappable>::install(m_casts);
|
||||
NodeContainedCast<Doom3GroupNode, TransformNode>::install(m_casts);
|
||||
NodeContainedCast<Doom3GroupNode, Entity>::install(m_casts);
|
||||
NodeContainedCast<Doom3GroupNode, Nameable>::install(m_casts);
|
||||
NodeContainedCast<Doom3GroupNode, Namespaced>::install(m_casts);
|
||||
NodeContainedCast<Doom3GroupNode, ModelSkin>::install(m_casts);
|
||||
}
|
||||
NodeTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
scene::Node m_node;
|
||||
InstanceSet m_instances;
|
||||
Doom3Group m_contained;
|
||||
|
||||
void construct()
|
||||
{
|
||||
m_contained.attach(this);
|
||||
}
|
||||
void destroy()
|
||||
{
|
||||
m_contained.detach(this);
|
||||
}
|
||||
public:
|
||||
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
scene::Traversable& get(NullType<scene::Traversable>)
|
||||
{
|
||||
return m_contained.getTraversable();
|
||||
}
|
||||
Snappable& get(NullType<Snappable>)
|
||||
{
|
||||
return m_contained;
|
||||
}
|
||||
TransformNode& get(NullType<TransformNode>)
|
||||
{
|
||||
return m_contained.getTransformNode();
|
||||
}
|
||||
Entity& get(NullType<Entity>)
|
||||
{
|
||||
return m_contained.getEntity();
|
||||
}
|
||||
Nameable& get(NullType<Nameable>)
|
||||
{
|
||||
return m_contained.getNameable();
|
||||
}
|
||||
Namespaced& get(NullType<Namespaced>)
|
||||
{
|
||||
return m_contained.getNamespaced();
|
||||
}
|
||||
ModelSkin& get(NullType<ModelSkin>)
|
||||
{
|
||||
return m_contained.getModelSkin();
|
||||
}
|
||||
|
||||
Doom3GroupNode(EntityClass* eclass) :
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSet::BoundsChangedCaller(m_instances), InstanceSetEvaluateTransform<Doom3GroupInstance>::Caller(m_instances))
|
||||
{
|
||||
construct();
|
||||
}
|
||||
Doom3GroupNode(const Doom3GroupNode& other) :
|
||||
scene::Node::Symbiot(other),
|
||||
scene::Instantiable(other),
|
||||
scene::Cloneable(other),
|
||||
scene::Traversable::Observer(other),
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSet::BoundsChangedCaller(m_instances), InstanceSetEvaluateTransform<Doom3GroupInstance>::Caller(m_instances))
|
||||
{
|
||||
construct();
|
||||
}
|
||||
~Doom3GroupNode()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
scene::Node& node()
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
scene::Node& clone() const
|
||||
{
|
||||
return (new Doom3GroupNode(*this))->node();
|
||||
}
|
||||
|
||||
void insert(scene::Node& child)
|
||||
{
|
||||
m_instances.insert(child);
|
||||
}
|
||||
void erase(scene::Node& child)
|
||||
{
|
||||
m_instances.erase(child);
|
||||
}
|
||||
|
||||
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
|
||||
{
|
||||
return new Doom3GroupInstance(path, parent, m_contained);
|
||||
}
|
||||
void forEachInstance(const scene::Instantiable::Visitor& visitor)
|
||||
{
|
||||
m_instances.forEachInstance(visitor);
|
||||
}
|
||||
void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
|
||||
{
|
||||
m_instances.insert(observer, path, instance);
|
||||
}
|
||||
scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
|
||||
{
|
||||
return m_instances.erase(observer, path);
|
||||
}
|
||||
};
|
||||
|
||||
void Doom3Group_construct()
|
||||
{
|
||||
CurveEdit::Type::instance().m_controlsShader = GlobalShaderCache().capture("$POINT");
|
||||
CurveEdit::Type::instance().m_selectedShader = GlobalShaderCache().capture("$SELPOINT");
|
||||
}
|
||||
|
||||
void Doom3Group_destroy()
|
||||
{
|
||||
GlobalShaderCache().release("$SELPOINT");
|
||||
GlobalShaderCache().release("$POINT");
|
||||
}
|
||||
|
||||
scene::Node& New_Doom3Group(EntityClass* eclass)
|
||||
{
|
||||
return (new Doom3GroupNode(eclass))->node();
|
||||
}
|
||||
35
plugins/entity/doom3group.h
Normal file
35
plugins/entity/doom3group.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_STATIC_H)
|
||||
#define INCLUDED_STATIC_H
|
||||
|
||||
namespace scene
|
||||
{
|
||||
class Node;
|
||||
}
|
||||
class EntityClass;
|
||||
|
||||
void Doom3Group_construct();
|
||||
void Doom3Group_destroy();
|
||||
scene::Node& New_Doom3Group(EntityClass* eclass);
|
||||
|
||||
#endif
|
||||
526
plugins/entity/eclassmodel.cpp
Normal file
526
plugins/entity/eclassmodel.cpp
Normal file
@@ -0,0 +1,526 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
///\file
|
||||
///\brief Represents any entity which has a fixed size specified in its entity-definition and displays a model (e.g. ammo_bfg).
|
||||
///
|
||||
/// This entity displays the model specified in its entity-definition.
|
||||
/// The "origin" and "angle" keys directly control the entity's local-to-parent transform.
|
||||
/// The "rotation" key directly controls the entity's local-to-parent transform for Doom3 only.
|
||||
|
||||
#include "eclassmodel.h"
|
||||
|
||||
#include "cullable.h"
|
||||
#include "renderable.h"
|
||||
#include "editable.h"
|
||||
|
||||
#include "selectionlib.h"
|
||||
#include "instancelib.h"
|
||||
#include "transformlib.h"
|
||||
#include "traverselib.h"
|
||||
#include "entitylib.h"
|
||||
#include "render.h"
|
||||
#include "eclasslib.h"
|
||||
#include "pivot.h"
|
||||
|
||||
#include "targetable.h"
|
||||
#include "origin.h"
|
||||
#include "angle.h"
|
||||
#include "rotation.h"
|
||||
#include "model.h"
|
||||
#include "filters.h"
|
||||
#include "namedentity.h"
|
||||
#include "keyobservers.h"
|
||||
#include "namekeys.h"
|
||||
#include "modelskinkey.h"
|
||||
|
||||
#include "entity.h"
|
||||
|
||||
class EclassModel :
|
||||
public Snappable
|
||||
{
|
||||
MatrixTransform m_transform;
|
||||
EntityKeyValues m_entity;
|
||||
KeyObserverMap m_keyObservers;
|
||||
|
||||
OriginKey m_originKey;
|
||||
Vector3 m_origin;
|
||||
AngleKey m_angleKey;
|
||||
float m_angle;
|
||||
RotationKey m_rotationKey;
|
||||
Float9 m_rotation;
|
||||
SingletonModel m_model;
|
||||
|
||||
ClassnameFilter m_filter;
|
||||
NamedEntity m_named;
|
||||
NameKeys m_nameKeys;
|
||||
RenderablePivot m_renderOrigin;
|
||||
RenderableNamedEntity m_renderName;
|
||||
ModelSkinKey m_skin;
|
||||
|
||||
Callback m_transformChanged;
|
||||
Callback m_evaluateTransform;
|
||||
|
||||
void construct()
|
||||
{
|
||||
default_rotation(m_rotation);
|
||||
|
||||
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
|
||||
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
|
||||
if(g_gameType == eGameTypeDoom3)
|
||||
{
|
||||
m_keyObservers.insert("angle", RotationKey::AngleChangedCaller(m_rotationKey));
|
||||
m_keyObservers.insert("rotation", RotationKey::RotationChangedCaller(m_rotationKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_keyObservers.insert("angle", AngleKey::AngleChangedCaller(m_angleKey));
|
||||
}
|
||||
m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
|
||||
}
|
||||
|
||||
void updateTransform()
|
||||
{
|
||||
m_transform.localToParent() = g_matrix4_identity;
|
||||
matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
|
||||
|
||||
if(g_gameType == eGameTypeDoom3)
|
||||
{
|
||||
matrix4_multiply_by_matrix4(m_transform.localToParent(), rotation_toMatrix(m_rotation));
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix4_multiply_by_matrix4(m_transform.localToParent(), matrix4_rotation_for_z_degrees(m_angle));
|
||||
}
|
||||
|
||||
m_transformChanged();
|
||||
}
|
||||
typedef MemberCaller<EclassModel, &EclassModel::updateTransform> UpdateTransformCaller;
|
||||
|
||||
void originChanged()
|
||||
{
|
||||
m_origin = m_originKey.m_origin;
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<EclassModel, &EclassModel::originChanged> OriginChangedCaller;
|
||||
void angleChanged()
|
||||
{
|
||||
m_angle = m_angleKey.m_angle;
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<EclassModel, &EclassModel::angleChanged> AngleChangedCaller;
|
||||
void rotationChanged()
|
||||
{
|
||||
rotation_assign(m_rotation, m_rotationKey.m_rotation);
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<EclassModel, &EclassModel::rotationChanged> RotationChangedCaller;
|
||||
|
||||
void skinChanged()
|
||||
{
|
||||
scene::Node* node = m_model.getNode();
|
||||
if(node != 0)
|
||||
{
|
||||
Node_modelSkinChanged(*node);
|
||||
}
|
||||
}
|
||||
typedef MemberCaller<EclassModel, &EclassModel::skinChanged> SkinChangedCaller;
|
||||
|
||||
public:
|
||||
|
||||
EclassModel(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
|
||||
m_entity(eclass),
|
||||
m_originKey(OriginChangedCaller(*this)),
|
||||
m_origin(ORIGINKEY_IDENTITY),
|
||||
m_angleKey(AngleChangedCaller(*this)),
|
||||
m_angle(ANGLEKEY_IDENTITY),
|
||||
m_rotationKey(RotationChangedCaller(*this)),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_skin(SkinChangedCaller(*this)),
|
||||
m_transformChanged(transformChanged),
|
||||
m_evaluateTransform(evaluateTransform)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
EclassModel(const EclassModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
|
||||
m_entity(other.m_entity),
|
||||
m_originKey(OriginChangedCaller(*this)),
|
||||
m_origin(ORIGINKEY_IDENTITY),
|
||||
m_angleKey(AngleChangedCaller(*this)),
|
||||
m_angle(ANGLEKEY_IDENTITY),
|
||||
m_rotationKey(RotationChangedCaller(*this)),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_skin(SkinChangedCaller(*this)),
|
||||
m_transformChanged(transformChanged),
|
||||
m_evaluateTransform(evaluateTransform)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
InstanceCounter m_instanceCounter;
|
||||
void instanceAttach(const scene::Path& path)
|
||||
{
|
||||
if(++m_instanceCounter.m_count == 1)
|
||||
{
|
||||
m_filter.instanceAttach();
|
||||
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_entity.attach(m_keyObservers);
|
||||
m_model.modelChanged(m_entity.getEntityClass().modelpath());
|
||||
m_skin.skinChanged(m_entity.getEntityClass().skin());
|
||||
}
|
||||
}
|
||||
void instanceDetach(const scene::Path& path)
|
||||
{
|
||||
if(--m_instanceCounter.m_count == 0)
|
||||
{
|
||||
m_skin.skinChanged("");
|
||||
m_model.modelChanged("");
|
||||
m_entity.detach(m_keyObservers);
|
||||
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_filter.instanceDetach();
|
||||
}
|
||||
}
|
||||
|
||||
EntityKeyValues& getEntity()
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
const EntityKeyValues& getEntity() const
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
|
||||
scene::Traversable& getTraversable()
|
||||
{
|
||||
return m_model.getTraversable();
|
||||
}
|
||||
Namespaced& getNamespaced()
|
||||
{
|
||||
return m_nameKeys;
|
||||
}
|
||||
Nameable& getNameable()
|
||||
{
|
||||
return m_named;
|
||||
}
|
||||
TransformNode& getTransformNode()
|
||||
{
|
||||
return m_transform;
|
||||
}
|
||||
ModelSkin& getModelSkin()
|
||||
{
|
||||
return m_skin.get();
|
||||
}
|
||||
|
||||
void attach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_model.attach(observer);
|
||||
}
|
||||
void detach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_model.detach(observer);
|
||||
}
|
||||
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
|
||||
{
|
||||
if(selected)
|
||||
{
|
||||
m_renderOrigin.render(renderer, volume, localToWorld);
|
||||
}
|
||||
|
||||
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
|
||||
{
|
||||
renderSolid(renderer, volume, localToWorld, selected);
|
||||
if(g_showNames)
|
||||
{
|
||||
renderer.addRenderable(m_renderName, localToWorld);
|
||||
}
|
||||
}
|
||||
|
||||
void translate(const Vector3& translation)
|
||||
{
|
||||
m_origin = origin_translated(m_origin, translation);
|
||||
}
|
||||
void rotate(const Quaternion& rotation)
|
||||
{
|
||||
if(g_gameType == eGameTypeDoom3)
|
||||
{
|
||||
rotation_rotate(m_rotation, rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_angle = angle_rotated(m_angle, rotation);
|
||||
}
|
||||
}
|
||||
void snapto(float snap)
|
||||
{
|
||||
m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
|
||||
m_originKey.write(&m_entity);
|
||||
}
|
||||
void revertTransform()
|
||||
{
|
||||
m_origin = m_originKey.m_origin;
|
||||
if(g_gameType == eGameTypeDoom3)
|
||||
{
|
||||
rotation_assign(m_rotation, m_rotationKey.m_rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_angle = m_angleKey.m_angle;
|
||||
}
|
||||
}
|
||||
void freezeTransform()
|
||||
{
|
||||
m_originKey.m_origin = m_origin;
|
||||
m_originKey.write(&m_entity);
|
||||
if(g_gameType == eGameTypeDoom3)
|
||||
{
|
||||
rotation_assign(m_rotationKey.m_rotation, m_rotation);
|
||||
m_rotationKey.write(&m_entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_angleKey.m_angle = m_angle;
|
||||
m_angleKey.write(&m_entity);
|
||||
}
|
||||
}
|
||||
void transformChanged()
|
||||
{
|
||||
revertTransform();
|
||||
m_evaluateTransform();
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<EclassModel, &EclassModel::transformChanged> TransformChangedCaller;
|
||||
};
|
||||
|
||||
class EclassModelInstance : public TargetableInstance, public TransformModifier, public Renderable
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
InstanceTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
|
||||
InstanceStaticCast<EclassModelInstance, Renderable>::install(m_casts);
|
||||
InstanceStaticCast<EclassModelInstance, Transformable>::install(m_casts);
|
||||
InstanceIdentityCast<EclassModelInstance>::install(m_casts);
|
||||
}
|
||||
InstanceTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
EclassModel& m_contained;
|
||||
public:
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
STRING_CONSTANT(Name, "EclassModelInstance");
|
||||
|
||||
EclassModelInstance(const scene::Path& path, scene::Instance* parent, EclassModel& contained) :
|
||||
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
|
||||
TransformModifier(EclassModel::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
|
||||
m_contained(contained)
|
||||
{
|
||||
m_contained.instanceAttach(Instance::path());
|
||||
|
||||
StaticRenderableConnectionLines::instance().attach(*this);
|
||||
}
|
||||
~EclassModelInstance()
|
||||
{
|
||||
StaticRenderableConnectionLines::instance().detach(*this);
|
||||
|
||||
m_contained.instanceDetach(Instance::path());
|
||||
}
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
|
||||
}
|
||||
|
||||
void evaluateTransform()
|
||||
{
|
||||
if(getType() == TRANSFORM_PRIMITIVE)
|
||||
{
|
||||
m_contained.translate(getTranslation());
|
||||
m_contained.rotate(getRotation());
|
||||
}
|
||||
}
|
||||
void applyTransform()
|
||||
{
|
||||
m_contained.revertTransform();
|
||||
evaluateTransform();
|
||||
m_contained.freezeTransform();
|
||||
}
|
||||
typedef MemberCaller<EclassModelInstance, &EclassModelInstance::applyTransform> ApplyTransformCaller;
|
||||
};
|
||||
|
||||
class EclassModelNode :
|
||||
public scene::Node::Symbiot,
|
||||
public scene::Instantiable,
|
||||
public scene::Cloneable,
|
||||
public scene::Traversable::Observer
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
NodeTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
NodeStaticCast<EclassModelNode, scene::Instantiable>::install(m_casts);
|
||||
NodeStaticCast<EclassModelNode, scene::Cloneable>::install(m_casts);
|
||||
NodeContainedCast<EclassModelNode, scene::Traversable>::install(m_casts);
|
||||
NodeContainedCast<EclassModelNode, Snappable>::install(m_casts);
|
||||
NodeContainedCast<EclassModelNode, TransformNode>::install(m_casts);
|
||||
NodeContainedCast<EclassModelNode, Entity>::install(m_casts);
|
||||
NodeContainedCast<EclassModelNode, Nameable>::install(m_casts);
|
||||
NodeContainedCast<EclassModelNode, Namespaced>::install(m_casts);
|
||||
NodeContainedCast<EclassModelNode, ModelSkin>::install(m_casts);
|
||||
}
|
||||
NodeTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
scene::Node m_node;
|
||||
InstanceSet m_instances;
|
||||
EclassModel m_contained;
|
||||
|
||||
void construct()
|
||||
{
|
||||
m_contained.attach(this);
|
||||
}
|
||||
void destroy()
|
||||
{
|
||||
m_contained.detach(this);
|
||||
}
|
||||
|
||||
public:
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
scene::Traversable& get(NullType<scene::Traversable>)
|
||||
{
|
||||
return m_contained.getTraversable();
|
||||
}
|
||||
Snappable& get(NullType<Snappable>)
|
||||
{
|
||||
return m_contained;
|
||||
}
|
||||
TransformNode& get(NullType<TransformNode>)
|
||||
{
|
||||
return m_contained.getTransformNode();
|
||||
}
|
||||
Entity& get(NullType<Entity>)
|
||||
{
|
||||
return m_contained.getEntity();
|
||||
}
|
||||
Nameable& get(NullType<Nameable>)
|
||||
{
|
||||
return m_contained.getNameable();
|
||||
}
|
||||
Namespaced& get(NullType<Namespaced>)
|
||||
{
|
||||
return m_contained.getNamespaced();
|
||||
}
|
||||
ModelSkin& get(NullType<ModelSkin>)
|
||||
{
|
||||
return m_contained.getModelSkin();
|
||||
}
|
||||
|
||||
EclassModelNode(EntityClass* eclass) :
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
|
||||
{
|
||||
construct();
|
||||
}
|
||||
EclassModelNode(const EclassModelNode& other) :
|
||||
scene::Node::Symbiot(other),
|
||||
scene::Instantiable(other),
|
||||
scene::Cloneable(other),
|
||||
scene::Traversable::Observer(other),
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<EclassModelInstance>::Caller(m_instances))
|
||||
{
|
||||
construct();
|
||||
}
|
||||
~EclassModelNode()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
void release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
scene::Node& node()
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
void insert(scene::Node& child)
|
||||
{
|
||||
m_instances.insert(child);
|
||||
}
|
||||
void erase(scene::Node& child)
|
||||
{
|
||||
m_instances.erase(child);
|
||||
}
|
||||
|
||||
scene::Node& clone() const
|
||||
{
|
||||
return (new EclassModelNode(*this))->node();
|
||||
}
|
||||
|
||||
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
|
||||
{
|
||||
return new EclassModelInstance(path, parent, m_contained);
|
||||
}
|
||||
void forEachInstance(const scene::Instantiable::Visitor& visitor)
|
||||
{
|
||||
m_instances.forEachInstance(visitor);
|
||||
}
|
||||
void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
|
||||
{
|
||||
m_instances.insert(observer, path, instance);
|
||||
}
|
||||
scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
|
||||
{
|
||||
return m_instances.erase(observer, path);
|
||||
}
|
||||
};
|
||||
|
||||
scene::Node& New_EclassModel(EntityClass* eclass)
|
||||
{
|
||||
return (new EclassModelNode(eclass))->node();
|
||||
}
|
||||
|
||||
35
plugins/entity/eclassmodel.h
Normal file
35
plugins/entity/eclassmodel.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_ECLASSMODEL_H)
|
||||
#define INCLUDED_ECLASSMODEL_H
|
||||
|
||||
namespace scene
|
||||
{
|
||||
class Node;
|
||||
};
|
||||
class EntityClass;
|
||||
|
||||
scene::Node& New_EclassModel(EntityClass* eclass);
|
||||
|
||||
#include "entity.h"
|
||||
|
||||
#endif
|
||||
383
plugins/entity/entity.cpp
Normal file
383
plugins/entity/entity.cpp
Normal file
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "entity.h"
|
||||
|
||||
#include "ifilter.h"
|
||||
#include "selectable.h"
|
||||
#include "namespace.h"
|
||||
|
||||
#include "scenelib.h"
|
||||
#include "entitylib.h"
|
||||
#include "eclasslib.h"
|
||||
#include "pivot.h"
|
||||
|
||||
#include "targetable.h"
|
||||
#include "uniquenames.h"
|
||||
#include "namekeys.h"
|
||||
#include "stream/stringstream.h"
|
||||
#include "filters.h"
|
||||
|
||||
|
||||
#include "miscmodel.h"
|
||||
#include "light.h"
|
||||
#include "group.h"
|
||||
#include "eclassmodel.h"
|
||||
#include "generic.h"
|
||||
#include "doom3group.h"
|
||||
|
||||
|
||||
|
||||
EGameType g_gameType;
|
||||
|
||||
inline scene::Node& entity_for_eclass(EntityClass* eclass)
|
||||
{
|
||||
if(classname_equal(eclass->name(), "misc_model")
|
||||
|| classname_equal(eclass->name(), "misc_gamemodel")
|
||||
|| classname_equal(eclass->name(), "model_static"))
|
||||
{
|
||||
return New_MiscModel(eclass);
|
||||
}
|
||||
else if(classname_equal(eclass->name(), "light")
|
||||
|| classname_equal(eclass->name(), "lightJunior"))
|
||||
{
|
||||
return New_Light(eclass);
|
||||
}
|
||||
if(!eclass->fixedsize)
|
||||
{
|
||||
if(g_gameType == eGameTypeDoom3)
|
||||
{
|
||||
return New_Doom3Group(eclass);
|
||||
}
|
||||
else
|
||||
{
|
||||
return New_Group(eclass);
|
||||
}
|
||||
}
|
||||
else if(!string_empty(eclass->modelpath()))
|
||||
{
|
||||
return New_EclassModel(eclass);
|
||||
}
|
||||
else
|
||||
{
|
||||
return New_GenericEntity(eclass);
|
||||
}
|
||||
}
|
||||
|
||||
void Entity_setName(Entity& entity, const char* name)
|
||||
{
|
||||
entity.setKeyValue("name", name);
|
||||
}
|
||||
typedef ReferenceCaller1<Entity, const char*, Entity_setName> EntitySetNameCaller;
|
||||
|
||||
inline Namespaced* Node_getNamespaced(scene::Node& node)
|
||||
{
|
||||
return NodeTypeCast<Namespaced>::cast(node);
|
||||
}
|
||||
|
||||
inline scene::Node& node_for_eclass(EntityClass* eclass)
|
||||
{
|
||||
scene::Node& node = entity_for_eclass(eclass);
|
||||
Node_getEntity(node)->setKeyValue("classname", eclass->name());
|
||||
|
||||
if(g_gameType == eGameTypeDoom3
|
||||
&& string_not_empty(eclass->name())
|
||||
&& !string_equal(eclass->name(), "worldspawn")
|
||||
&& !string_equal(eclass->name(), "UNKNOWN_CLASS"))
|
||||
{
|
||||
char buffer[1024];
|
||||
strcpy(buffer, eclass->name());
|
||||
strcat(buffer, "_1");
|
||||
GlobalNamespace().makeUnique(buffer, EntitySetNameCaller(*Node_getEntity(node)));
|
||||
}
|
||||
|
||||
Namespaced* namespaced = Node_getNamespaced(node);
|
||||
if(namespaced != 0)
|
||||
{
|
||||
namespaced->setNamespace(GlobalNamespace());
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
EntityCreator::KeyValueChangedFunc EntityKeyValues::m_entityKeyValueChanged = 0;
|
||||
EntityCreator::KeyValueChangedFunc KeyValue::m_entityKeyValueChanged = 0;
|
||||
Counter* EntityKeyValues::m_counter = 0;
|
||||
|
||||
bool g_showNames = true;
|
||||
bool g_showAngles = true;
|
||||
bool g_newLightDraw = true;
|
||||
bool g_lightRadii = false;
|
||||
|
||||
class ConnectEntities
|
||||
{
|
||||
public:
|
||||
Entity* m_e1;
|
||||
Entity* m_e2;
|
||||
ConnectEntities(Entity* e1, Entity* e2) : m_e1(e1), m_e2(e2)
|
||||
{
|
||||
}
|
||||
void connect(const char* name)
|
||||
{
|
||||
m_e1->setKeyValue("target", name);
|
||||
m_e2->setKeyValue("targetname", name);
|
||||
}
|
||||
typedef MemberCaller1<ConnectEntities, const char*, &ConnectEntities::connect> ConnectCaller;
|
||||
};
|
||||
|
||||
inline Entity* ScenePath_getEntity(const scene::Path& path)
|
||||
{
|
||||
Entity* entity = Node_getEntity(path.top());
|
||||
if(entity == 0)
|
||||
{
|
||||
entity = Node_getEntity(path.parent());
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
class Quake3EntityCreator : public EntityCreator
|
||||
{
|
||||
public:
|
||||
scene::Node& createEntity(EntityClass* eclass)
|
||||
{
|
||||
return node_for_eclass(eclass);
|
||||
}
|
||||
void setKeyValueChangedFunc(KeyValueChangedFunc func)
|
||||
{
|
||||
EntityKeyValues::setKeyValueChangedFunc(func);
|
||||
}
|
||||
void setCounter(Counter* counter)
|
||||
{
|
||||
EntityKeyValues::setCounter(counter);
|
||||
}
|
||||
void connectEntities(const scene::Path& path, const scene::Path& targetPath)
|
||||
{
|
||||
Entity* e1 = ScenePath_getEntity(path);
|
||||
Entity* e2 = ScenePath_getEntity(targetPath);
|
||||
|
||||
if(e1 == 0 || e2 == 0)
|
||||
{
|
||||
globalErrorStream() << "entityConnectSelected: both of the selected instances must be an entity\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if(e1 == e2)
|
||||
{
|
||||
globalErrorStream() << "entityConnectSelected: the selected instances must not both be from the same entity\n";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
UndoableCommand undo("entityConnectSelected");
|
||||
|
||||
if(g_gameType == eGameTypeDoom3)
|
||||
{
|
||||
StringOutputStream key(16);
|
||||
for(unsigned int i = 0; ; ++i)
|
||||
{
|
||||
key << "target";
|
||||
if(i != 0)
|
||||
{
|
||||
key << i;
|
||||
}
|
||||
const char* value = e1->getKeyValue(key.c_str());
|
||||
if(string_empty(value))
|
||||
{
|
||||
e1->setKeyValue(key.c_str(), e2->getKeyValue("name"));
|
||||
break;
|
||||
}
|
||||
key.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectEntities connector(e1, e2);
|
||||
const char* value = e2->getKeyValue("targetname");
|
||||
if(string_empty(value))
|
||||
{
|
||||
value = e1->getKeyValue("target");
|
||||
}
|
||||
if(!string_empty(value))
|
||||
{
|
||||
connector.connect(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* type = e2->getKeyValue("classname");
|
||||
if(string_empty(type))
|
||||
{
|
||||
type = "t";
|
||||
}
|
||||
StringOutputStream key(64);
|
||||
key << type << "1";
|
||||
GlobalNamespace().makeUnique(key.c_str(), ConnectEntities::ConnectCaller(connector));
|
||||
}
|
||||
}
|
||||
|
||||
SceneChangeNotify();
|
||||
}
|
||||
void setLightRadii(bool lightRadii)
|
||||
{
|
||||
g_lightRadii = lightRadii;
|
||||
}
|
||||
bool getLightRadii()
|
||||
{
|
||||
return g_lightRadii;
|
||||
}
|
||||
void setShowNames(bool showNames)
|
||||
{
|
||||
g_showNames = showNames;
|
||||
}
|
||||
bool getShowNames()
|
||||
{
|
||||
return g_showNames;
|
||||
}
|
||||
void setShowAngles(bool showAngles)
|
||||
{
|
||||
g_showAngles = showAngles;
|
||||
}
|
||||
bool getShowAngles()
|
||||
{
|
||||
return g_showAngles;
|
||||
}
|
||||
};
|
||||
|
||||
Quake3EntityCreator g_Quake3EntityCreator;
|
||||
|
||||
EntityCreator& GetEntityCreator()
|
||||
{
|
||||
return g_Quake3EntityCreator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class filter_entity_classname : public EntityFilter
|
||||
{
|
||||
const char* m_classname;
|
||||
public:
|
||||
filter_entity_classname(const char* classname) : m_classname(classname)
|
||||
{
|
||||
}
|
||||
bool filter(const Entity& entity) const
|
||||
{
|
||||
return string_equal(entity.getKeyValue("classname"), m_classname);
|
||||
}
|
||||
};
|
||||
|
||||
class filter_entity_classgroup : public EntityFilter
|
||||
{
|
||||
const char* m_classgroup;
|
||||
std::size_t m_length;
|
||||
public:
|
||||
filter_entity_classgroup(const char* classgroup) : m_classgroup(classgroup), m_length(string_length(m_classgroup))
|
||||
{
|
||||
}
|
||||
bool filter(const Entity& entity) const
|
||||
{
|
||||
return string_equal_n(entity.getKeyValue("classname"), m_classgroup, m_length);
|
||||
}
|
||||
};
|
||||
|
||||
filter_entity_classname g_filter_entity_world("worldspawn");
|
||||
filter_entity_classname g_filter_entity_func_group("func_group");
|
||||
filter_entity_classname g_filter_entity_light("light");
|
||||
filter_entity_classname g_filter_entity_misc_model("misc_model");
|
||||
filter_entity_classgroup g_filter_entity_trigger("trigger_");
|
||||
filter_entity_classgroup g_filter_entity_path("path_");
|
||||
|
||||
class filter_entity_doom3model : public EntityFilter
|
||||
{
|
||||
public:
|
||||
bool filter(const Entity& entity) const
|
||||
{
|
||||
return string_equal(entity.getKeyValue("classname"), "func_static")
|
||||
&& !string_equal(entity.getKeyValue("model"), entity.getKeyValue("name"));
|
||||
}
|
||||
};
|
||||
|
||||
filter_entity_doom3model g_filter_entity_doom3model;
|
||||
|
||||
|
||||
void Entity_InitFilters()
|
||||
{
|
||||
add_entity_filter(g_filter_entity_world, EXCLUDE_WORLD);
|
||||
add_entity_filter(g_filter_entity_func_group, EXCLUDE_WORLD);
|
||||
add_entity_filter(g_filter_entity_world, EXCLUDE_ENT, true);
|
||||
add_entity_filter(g_filter_entity_trigger, EXCLUDE_TRIGGERS);
|
||||
add_entity_filter(g_filter_entity_misc_model, EXCLUDE_MODELS);
|
||||
add_entity_filter(g_filter_entity_doom3model, EXCLUDE_MODELS);
|
||||
add_entity_filter(g_filter_entity_light, EXCLUDE_LIGHTS);
|
||||
add_entity_filter(g_filter_entity_path, EXCLUDE_PATHS);
|
||||
}
|
||||
|
||||
|
||||
#include "preferencesystem.h"
|
||||
|
||||
void Entity_Construct(EGameType gameType)
|
||||
{
|
||||
g_gameType = gameType;
|
||||
if(g_gameType == eGameTypeDoom3)
|
||||
{
|
||||
g_targetable_nameKey = "name";
|
||||
|
||||
Static<KeyIsName>::instance().m_keyIsName = keyIsNameDoom3;
|
||||
Static<KeyIsName>::instance().m_nameKey = "name";
|
||||
}
|
||||
else
|
||||
{
|
||||
Static<KeyIsName>::instance().m_keyIsName = keyIsNameQuake3;
|
||||
Static<KeyIsName>::instance().m_nameKey = "targetname";
|
||||
}
|
||||
|
||||
GlobalPreferenceSystem().registerPreference("SI_ShowNames", BoolImportStringCaller(g_showNames), BoolExportStringCaller(g_showNames));
|
||||
GlobalPreferenceSystem().registerPreference("SI_ShowAngles", BoolImportStringCaller(g_showAngles), BoolExportStringCaller(g_showAngles));
|
||||
GlobalPreferenceSystem().registerPreference("NewLightStyle", BoolImportStringCaller(g_newLightDraw), BoolExportStringCaller(g_newLightDraw));
|
||||
GlobalPreferenceSystem().registerPreference("LightRadiuses", BoolImportStringCaller(g_lightRadii), BoolExportStringCaller(g_lightRadii));
|
||||
|
||||
Entity_InitFilters();
|
||||
LightType lightType = LIGHTTYPE_DEFAULT;
|
||||
if(g_gameType == eGameTypeRTCW)
|
||||
{
|
||||
lightType = LIGHTTYPE_RTCW;
|
||||
}
|
||||
else if(g_gameType == eGameTypeDoom3)
|
||||
{
|
||||
lightType = LIGHTTYPE_DOOM3;
|
||||
}
|
||||
Light_Construct(lightType);
|
||||
MiscModel_construct();
|
||||
Doom3Group_construct();
|
||||
|
||||
RenderablePivot::StaticShader::instance() = GlobalShaderCache().capture("$PIVOT");
|
||||
|
||||
GlobalShaderCache().attachRenderable(StaticRenderableConnectionLines::instance());
|
||||
}
|
||||
|
||||
void Entity_Destroy()
|
||||
{
|
||||
GlobalShaderCache().detachRenderable(StaticRenderableConnectionLines::instance());
|
||||
|
||||
GlobalShaderCache().release("$PIVOT");
|
||||
|
||||
Doom3Group_destroy();
|
||||
MiscModel_destroy();
|
||||
Light_Destroy();
|
||||
}
|
||||
230
plugins/entity/entity.dsp
Normal file
230
plugins/entity/entity.dsp
Normal file
@@ -0,0 +1,230 @@
|
||||
# Microsoft Developer Studio Project File - Name="entity" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=entity - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "entity.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "entity.mak" CFG="entity - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "entity - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "entity - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName "entity"
|
||||
# PROP Scc_LocalPath "..\.."
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "entity - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
F90=df.exe
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /O2 /I "..\..\..\libxml2\include\\" /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\libs\nvtristrip" /I "..\..\..\STLPort\stlport" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40c /d "NDEBUG"
|
||||
# ADD RSC /l 0x40c /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 mathlib.lib glib-2.0.lib /nologo /dll /machine:I386 /def:".\entity.def" /libpath:"..\..\libs\mathlib\release" /libpath:"..\..\..\gtk2-win32\lib\\"
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
# Begin Special Build Tool
|
||||
SOURCE="$(InputPath)"
|
||||
PostBuild_Desc=Copy to dir...
|
||||
PostBuild_Cmds=copy Release\entity.dll "../../install/modules"
|
||||
# End Special Build Tool
|
||||
|
||||
!ELSEIF "$(CFG)" == "entity - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
F90=df.exe
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\..\shared" /I "..\..\..\libxml2\include" /I "..\..\include" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /I "..\common" /I "..\..\libs" /I "..\..\libs\nvtristrip" /I "..\..\..\STLPort\stlport" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /FR /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x40c /d "_DEBUG"
|
||||
# ADD RSC /l 0x40c /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 mathlib.lib glib-2.0.lib /nologo /dll /debug /machine:I386 /def:".\entity.def" /pdbtype:sept /libpath:"..\..\libs\mathlib\debug" /libpath:"..\..\..\gtk2-win32\lib\\"
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
# Begin Special Build Tool
|
||||
SOURCE="$(InputPath)"
|
||||
PostBuild_Desc=Copy to dir...
|
||||
PostBuild_Cmds=copy Debug\entity.dll "../../install/modules"
|
||||
# End Special Build Tool
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "entity - Win32 Release"
|
||||
# Name "entity - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\eclassmodel.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\entity.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\entity.def
|
||||
# PROP Exclude_From_Build 1
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\generic.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\group.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\light.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\miscmodel.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\plugin.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\targetable.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Group "API"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\ifilesystem.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\igl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\imodel.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\ishaders.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\isurface.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\qerplugin.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\qertypes.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\angle.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\angles.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colour.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\entity.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\light.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\model.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\origin.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\plugin.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\scale.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\targetable.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Conscript
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
46
plugins/entity/entity.h
Normal file
46
plugins/entity/entity.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_ENTITY_H)
|
||||
#define INCLUDED_ENTITY_H
|
||||
|
||||
class EntityCreator;
|
||||
EntityCreator& GetEntityCreator();
|
||||
|
||||
enum EGameType
|
||||
{
|
||||
eGameTypeQuake3,
|
||||
eGameTypeRTCW,
|
||||
eGameTypeDoom3,
|
||||
};
|
||||
|
||||
extern EGameType g_gameType;
|
||||
|
||||
class FilterSystem;
|
||||
void Entity_Construct(EGameType gameType = eGameTypeQuake3);
|
||||
void Entity_Destroy();
|
||||
|
||||
extern bool g_showNames;
|
||||
extern bool g_showAngles;
|
||||
extern bool g_newLightDraw;
|
||||
extern bool g_lightRadii;
|
||||
|
||||
#endif
|
||||
7
plugins/entity/entityq3.def
Normal file
7
plugins/entity/entityq3.def
Normal file
@@ -0,0 +1,7 @@
|
||||
; entityq3.def : Declares the module parameters for the DLL.
|
||||
|
||||
LIBRARY "ENTITYQ3"
|
||||
|
||||
EXPORTS
|
||||
; Explicit exports can go here
|
||||
Radiant_RegisterModules @1
|
||||
343
plugins/entity/entityq3.vcproj
Normal file
343
plugins/entity/entityq3.vcproj
Normal file
@@ -0,0 +1,343 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="entityq3"
|
||||
ProjectGUID="{49C5823A-5E50-4029-ACEE-1627EBB79E47}"
|
||||
RootNamespace="entityq3"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../../include;../../libs;"../../../STLPort-4.6/stlport""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;ENTITYQ3_EXPORTS"
|
||||
StringPooling="TRUE"
|
||||
MinimalRebuild="TRUE"
|
||||
ExceptionHandling="FALSE"
|
||||
BasicRuntimeChecks="0"
|
||||
RuntimeLibrary="3"
|
||||
BufferSecurityCheck="FALSE"
|
||||
ForceConformanceInForLoopScope="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"
|
||||
DisableSpecificWarnings="4610;4510;4512;4505;4100;4127"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/entityq3.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="msvcprtd.lib"
|
||||
ModuleDefinitionFile="$(ProjectName).def"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/entityq3.pdb"
|
||||
SubSystem="2"
|
||||
ImportLibrary="$(OutDir)/entityq3.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
CommandLine="copy "$(TargetPath)" "$(SolutionDir)install\modules"
|
||||
copy "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)install\modules"
|
||||
"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="TRUE">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
GlobalOptimizations="TRUE"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="TRUE"
|
||||
FavorSizeOrSpeed="1"
|
||||
OptimizeForWindowsApplication="FALSE"
|
||||
AdditionalIncludeDirectories="../../include;../../libs;"../../../STLPort-4.6/stlport""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;ENTITYQ3_EXPORTS"
|
||||
StringPooling="TRUE"
|
||||
ExceptionHandling="FALSE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="FALSE"
|
||||
ForceConformanceInForLoopScope="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"
|
||||
DisableSpecificWarnings="4610;4510;4512;4505;4100;4127"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/entityq3.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="msvcprt.lib"
|
||||
ModuleDefinitionFile="$(ProjectName).def"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
ImportLibrary="$(OutDir)/entityq3.lib"
|
||||
TargetMachine="1"
|
||||
FixedBaseAddress="0"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
CommandLine="copy "$(TargetPath)" "$(SolutionDir)install\modules"
|
||||
copy "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)install\modules"
|
||||
"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="src"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\plugin.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\plugin.h">
|
||||
</File>
|
||||
<Filter
|
||||
Name="entities"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\doom3group.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\doom3group.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\eclassmodel.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\eclassmodel.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\generic.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\generic.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\group.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\group.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\light.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\light.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\miscmodel.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\miscmodel.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="modules"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\entity.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\entity.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\skincache.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\skincache.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="components"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\angle.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\angle.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\angles.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\angles.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\colour.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\colour.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\curve.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\curve.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\filters.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\filters.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\keyobservers.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\keyobservers.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\model.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\model.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\modelskinkey.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\modelskinkey.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\namedentity.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\namedentity.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\namekeys.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\namekeys.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\origin.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\origin.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\rotation.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\rotation.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\scale.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\scale.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\targetable.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\targetable.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath="..\..\debug.py">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="python "$(SolutionDir)debug.py"
|
||||
"
|
||||
AdditionalDependencies=""$(SolutionDir)install\modules\$(TargetName).pdb""
|
||||
Outputs=""$(TargetDir)$(TargetName).pdb""/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="python "$(SolutionDir)debug.py"
|
||||
"
|
||||
AdditionalDependencies=""$(SolutionDir)install\modules\$(TargetName).pdb""
|
||||
Outputs=""$(TargetDir)$(TargetName).pdb""/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\entityq3.def">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="python "$(SolutionDir)touch.py" "$(TargetPath)"
|
||||
"
|
||||
AdditionalDependencies=""$(SolutionDir)install\modules\$(TargetFileName)""
|
||||
Outputs=""$(TargetPath)""/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="python "$(SolutionDir)touch.py" "$(TargetPath)"
|
||||
"
|
||||
AdditionalDependencies=""$(SolutionDir)install\modules\$(TargetFileName)""
|
||||
Outputs=""$(TargetPath)""/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
72
plugins/entity/filters.cpp
Normal file
72
plugins/entity/filters.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
#include "ifilter.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
class EntityFilterWrapper : public Filter
|
||||
{
|
||||
bool m_active;
|
||||
bool m_invert;
|
||||
EntityFilter& m_filter;
|
||||
public:
|
||||
EntityFilterWrapper(EntityFilter& filter, bool invert) : m_invert(invert), m_filter(filter)
|
||||
{
|
||||
}
|
||||
void setActive(bool active)
|
||||
{
|
||||
m_active = active;
|
||||
}
|
||||
bool active()
|
||||
{
|
||||
return m_active;
|
||||
}
|
||||
bool filter(const Entity& entity)
|
||||
{
|
||||
return m_invert ^ m_filter.filter(entity);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef std::list<EntityFilterWrapper> EntityFilters;
|
||||
EntityFilters g_entityFilters;
|
||||
|
||||
void add_entity_filter(EntityFilter& filter, int mask, bool invert)
|
||||
{
|
||||
g_entityFilters.push_back(EntityFilterWrapper(filter, invert));
|
||||
GlobalFilterSystem().addFilter(g_entityFilters.back(), mask);
|
||||
}
|
||||
|
||||
bool entity_filtered(Entity& entity)
|
||||
{
|
||||
for(EntityFilters::iterator i = g_entityFilters.begin(); i != g_entityFilters.end(); ++i)
|
||||
{
|
||||
if((*i).active() && (*i).filter(entity))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
82
plugins/entity/filters.h
Normal file
82
plugins/entity/filters.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_FILTERS_H)
|
||||
#define INCLUDED_FILTERS_H
|
||||
|
||||
#include "ifilter.h"
|
||||
|
||||
#include "generic/callback.h"
|
||||
#include "scenelib.h"
|
||||
|
||||
class Entity;
|
||||
|
||||
class EntityFilter
|
||||
{
|
||||
public:
|
||||
virtual bool filter(const Entity& entity) const = 0;
|
||||
};
|
||||
|
||||
bool entity_filtered(Entity& entity);
|
||||
void add_entity_filter(EntityFilter& filter, int mask, bool invert = false);
|
||||
|
||||
class ClassnameFilter : public Filterable
|
||||
{
|
||||
scene::Node& m_node;
|
||||
public:
|
||||
Entity& m_entity;
|
||||
|
||||
ClassnameFilter(Entity& entity, scene::Node& node) : m_node(node), m_entity(entity)
|
||||
{
|
||||
}
|
||||
~ClassnameFilter()
|
||||
{
|
||||
}
|
||||
|
||||
void instanceAttach()
|
||||
{
|
||||
GlobalFilterSystem().registerFilterable(*this);
|
||||
}
|
||||
void instanceDetach()
|
||||
{
|
||||
GlobalFilterSystem().unregisterFilterable(*this);
|
||||
}
|
||||
|
||||
void updateFiltered()
|
||||
{
|
||||
if(entity_filtered(m_entity))
|
||||
{
|
||||
m_node.enable(scene::Node::eFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_node.disable(scene::Node::eFiltered);
|
||||
}
|
||||
}
|
||||
|
||||
void classnameChanged(const char* value)
|
||||
{
|
||||
updateFiltered();
|
||||
}
|
||||
typedef MemberCaller1<ClassnameFilter, const char*, &ClassnameFilter::classnameChanged> ClassnameChangedCaller;
|
||||
};
|
||||
|
||||
#endif
|
||||
494
plugins/entity/generic.cpp
Normal file
494
plugins/entity/generic.cpp
Normal file
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
///\file
|
||||
///\brief Represents any entity which has a fixed size specified in its entity-definition and does not display a model (e.g. info_player_start).
|
||||
///
|
||||
/// This entity displays an axis-aligned bounding box of the size and colour specified in its entity-definition.
|
||||
/// The "origin" key directly controls the entity's local-to-parent transform.
|
||||
/// An arrow is drawn to visualise the "angle" key.
|
||||
|
||||
#include "cullable.h"
|
||||
#include "renderable.h"
|
||||
#include "editable.h"
|
||||
|
||||
#include "math/frustum.h"
|
||||
#include "selectionlib.h"
|
||||
#include "instancelib.h"
|
||||
#include "transformlib.h"
|
||||
#include "entitylib.h"
|
||||
#include "render.h"
|
||||
#include "eclasslib.h"
|
||||
#include "math/line.h"
|
||||
|
||||
#include "targetable.h"
|
||||
#include "origin.h"
|
||||
#include "angle.h"
|
||||
#include "filters.h"
|
||||
#include "namedentity.h"
|
||||
#include "keyobservers.h"
|
||||
#include "namekeys.h"
|
||||
#include "rotation.h"
|
||||
|
||||
#include "entity.h"
|
||||
|
||||
|
||||
class RenderableArrow : public OpenGLRenderable
|
||||
{
|
||||
const Ray& m_ray;
|
||||
|
||||
public:
|
||||
RenderableArrow(const Ray& ray)
|
||||
: m_ray(ray)
|
||||
{
|
||||
}
|
||||
|
||||
void render(RenderStateFlags state) const
|
||||
{
|
||||
arrow_draw(m_ray.origin, m_ray.direction);
|
||||
}
|
||||
};
|
||||
|
||||
inline void read_aabb(AABB& aabb, const EntityClass& eclass)
|
||||
{
|
||||
aabb = aabb_for_minmax(eclass.mins, eclass.maxs);
|
||||
}
|
||||
|
||||
|
||||
class GenericEntity :
|
||||
public Cullable,
|
||||
public Bounded,
|
||||
public Snappable
|
||||
{
|
||||
EntityKeyValues m_entity;
|
||||
KeyObserverMap m_keyObservers;
|
||||
MatrixTransform m_transform;
|
||||
|
||||
OriginKey m_originKey;
|
||||
Vector3 m_origin;
|
||||
AngleKey m_angleKey;
|
||||
float m_angle;
|
||||
|
||||
ClassnameFilter m_filter;
|
||||
NamedEntity m_named;
|
||||
NameKeys m_nameKeys;
|
||||
|
||||
AABB m_aabb_local;
|
||||
Ray m_ray;
|
||||
|
||||
RenderableArrow m_arrow;
|
||||
RenderableSolidAABB m_aabb_solid;
|
||||
RenderableWireframeAABB m_aabb_wire;
|
||||
RenderableNamedEntity m_renderName;
|
||||
|
||||
Callback m_transformChanged;
|
||||
Callback m_evaluateTransform;
|
||||
|
||||
void construct()
|
||||
{
|
||||
read_aabb(m_aabb_local, m_entity.getEntityClass());
|
||||
m_ray.origin = m_aabb_local.origin;
|
||||
m_ray.direction[0] = 1;
|
||||
m_ray.direction[1] = 0;
|
||||
m_ray.direction[2] = 0;
|
||||
|
||||
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
|
||||
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
|
||||
m_keyObservers.insert("angle", AngleKey::AngleChangedCaller(m_angleKey));
|
||||
m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
|
||||
}
|
||||
|
||||
void updateTransform()
|
||||
{
|
||||
m_transform.localToParent() = g_matrix4_identity;
|
||||
matrix4_translate_by_vec3(m_transform.localToParent(), m_origin);
|
||||
m_ray.direction = matrix4_transformed_direction(matrix4_rotation_for_z(degrees_to_radians(m_angle)), Vector3(1, 0, 0));
|
||||
m_transformChanged();
|
||||
}
|
||||
typedef MemberCaller<GenericEntity, &GenericEntity::updateTransform> UpdateTransformCaller;
|
||||
void originChanged()
|
||||
{
|
||||
m_origin = m_originKey.m_origin;
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<GenericEntity, &GenericEntity::originChanged> OriginChangedCaller;
|
||||
void angleChanged()
|
||||
{
|
||||
m_angle = m_angleKey.m_angle;
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<GenericEntity, &GenericEntity::angleChanged> AngleChangedCaller;
|
||||
public:
|
||||
|
||||
GenericEntity(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
|
||||
m_entity(eclass),
|
||||
m_originKey(OriginChangedCaller(*this)),
|
||||
m_origin(ORIGINKEY_IDENTITY),
|
||||
m_angleKey(AngleChangedCaller(*this)),
|
||||
m_angle(ANGLEKEY_IDENTITY),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_arrow(m_ray),
|
||||
m_aabb_solid(m_aabb_local),
|
||||
m_aabb_wire(m_aabb_local),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_transformChanged(transformChanged),
|
||||
m_evaluateTransform(evaluateTransform)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
GenericEntity(const GenericEntity& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
|
||||
m_entity(other.m_entity),
|
||||
m_originKey(OriginChangedCaller(*this)),
|
||||
m_origin(ORIGINKEY_IDENTITY),
|
||||
m_angleKey(AngleChangedCaller(*this)),
|
||||
m_angle(ANGLEKEY_IDENTITY),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_arrow(m_ray),
|
||||
m_aabb_solid(m_aabb_local),
|
||||
m_aabb_wire(m_aabb_local),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_transformChanged(transformChanged),
|
||||
m_evaluateTransform(evaluateTransform)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
InstanceCounter m_instanceCounter;
|
||||
void instanceAttach(const scene::Path& path)
|
||||
{
|
||||
if(++m_instanceCounter.m_count == 1)
|
||||
{
|
||||
m_filter.instanceAttach();
|
||||
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_entity.attach(m_keyObservers);
|
||||
}
|
||||
}
|
||||
void instanceDetach(const scene::Path& path)
|
||||
{
|
||||
if(--m_instanceCounter.m_count == 0)
|
||||
{
|
||||
m_entity.detach(m_keyObservers);
|
||||
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_filter.instanceDetach();
|
||||
}
|
||||
}
|
||||
|
||||
EntityKeyValues& getEntity()
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
const EntityKeyValues& getEntity() const
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
|
||||
Namespaced& getNamespaced()
|
||||
{
|
||||
return m_nameKeys;
|
||||
}
|
||||
Nameable& getNameable()
|
||||
{
|
||||
return m_named;
|
||||
}
|
||||
TransformNode& getTransformNode()
|
||||
{
|
||||
return m_transform;
|
||||
}
|
||||
|
||||
const AABB& localAABB() const
|
||||
{
|
||||
return m_aabb_local;
|
||||
}
|
||||
|
||||
VolumeIntersectionValue intersectVolume(const VolumeTest& volume, const Matrix4& localToWorld) const
|
||||
{
|
||||
return volume.TestAABB(localAABB(), localToWorld);
|
||||
}
|
||||
|
||||
void renderArrow(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
|
||||
{
|
||||
if(g_showAngles)
|
||||
{
|
||||
renderer.addRenderable(m_arrow, localToWorld);
|
||||
}
|
||||
}
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
|
||||
{
|
||||
renderer.SetState(m_entity.getEntityClass().m_state_fill, Renderer::eFullMaterials);
|
||||
renderer.addRenderable(m_aabb_solid, localToWorld);
|
||||
renderArrow(renderer, volume, localToWorld);
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
|
||||
{
|
||||
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
|
||||
renderer.addRenderable(m_aabb_wire, localToWorld);
|
||||
renderArrow(renderer, volume, localToWorld);
|
||||
if(g_showNames)
|
||||
{
|
||||
renderer.addRenderable(m_renderName, localToWorld);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
|
||||
{
|
||||
test.BeginMesh(localToWorld);
|
||||
|
||||
SelectionIntersection best;
|
||||
aabb_testselect(m_aabb_local, test, best);
|
||||
if(best.valid())
|
||||
{
|
||||
selector.addIntersection(best);
|
||||
}
|
||||
}
|
||||
|
||||
void translate(const Vector3& translation)
|
||||
{
|
||||
m_origin = origin_translated(m_origin, translation);
|
||||
}
|
||||
void rotate(const Quaternion& rotation)
|
||||
{
|
||||
m_angle = angle_rotated(m_angle, rotation);
|
||||
}
|
||||
void snapto(float snap)
|
||||
{
|
||||
m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
|
||||
m_originKey.write(&m_entity);
|
||||
}
|
||||
void revertTransform()
|
||||
{
|
||||
m_origin = m_originKey.m_origin;
|
||||
m_angle = m_angleKey.m_angle;
|
||||
}
|
||||
void freezeTransform()
|
||||
{
|
||||
m_originKey.m_origin = m_origin;
|
||||
m_originKey.write(&m_entity);
|
||||
m_angleKey.m_angle = m_angle;
|
||||
m_angleKey.write(&m_entity);
|
||||
}
|
||||
void transformChanged()
|
||||
{
|
||||
revertTransform();
|
||||
m_evaluateTransform();
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<GenericEntity, &GenericEntity::transformChanged> TransformChangedCaller;
|
||||
};
|
||||
|
||||
class GenericEntityInstance :
|
||||
public TargetableInstance,
|
||||
public TransformModifier,
|
||||
public Renderable,
|
||||
public SelectionTestable
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
InstanceTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
|
||||
InstanceContainedCast<GenericEntityInstance, Bounded>::install(m_casts);
|
||||
InstanceContainedCast<GenericEntityInstance, Cullable>::install(m_casts);
|
||||
InstanceStaticCast<GenericEntityInstance, Renderable>::install(m_casts);
|
||||
InstanceStaticCast<GenericEntityInstance, SelectionTestable>::install(m_casts);
|
||||
InstanceStaticCast<GenericEntityInstance, Transformable>::install(m_casts);
|
||||
InstanceIdentityCast<GenericEntityInstance>::install(m_casts);
|
||||
}
|
||||
InstanceTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
GenericEntity& m_contained;
|
||||
mutable AABB m_bounds;
|
||||
public:
|
||||
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
Bounded& get(NullType<Bounded>)
|
||||
{
|
||||
return m_contained;
|
||||
}
|
||||
Cullable& get(NullType<Cullable>)
|
||||
{
|
||||
return m_contained;
|
||||
}
|
||||
|
||||
STRING_CONSTANT(Name, "GenericEntityInstance");
|
||||
|
||||
GenericEntityInstance(const scene::Path& path, scene::Instance* parent, GenericEntity& contained) :
|
||||
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
|
||||
TransformModifier(GenericEntity::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
|
||||
m_contained(contained)
|
||||
{
|
||||
m_contained.instanceAttach(Instance::path());
|
||||
|
||||
StaticRenderableConnectionLines::instance().attach(*this);
|
||||
}
|
||||
~GenericEntityInstance()
|
||||
{
|
||||
StaticRenderableConnectionLines::instance().detach(*this);
|
||||
|
||||
m_contained.instanceDetach(Instance::path());
|
||||
}
|
||||
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderSolid(renderer, volume, Instance::localToWorld());
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderWireframe(renderer, volume, Instance::localToWorld());
|
||||
}
|
||||
|
||||
void testSelect(Selector& selector, SelectionTest& test)
|
||||
{
|
||||
m_contained.testSelect(selector, test, Instance::localToWorld());
|
||||
}
|
||||
|
||||
void evaluateTransform()
|
||||
{
|
||||
if(getType() == TRANSFORM_PRIMITIVE)
|
||||
{
|
||||
m_contained.translate(getTranslation());
|
||||
m_contained.rotate(getRotation());
|
||||
}
|
||||
}
|
||||
void applyTransform()
|
||||
{
|
||||
m_contained.revertTransform();
|
||||
evaluateTransform();
|
||||
m_contained.freezeTransform();
|
||||
}
|
||||
typedef MemberCaller<GenericEntityInstance, &GenericEntityInstance::applyTransform> ApplyTransformCaller;
|
||||
};
|
||||
|
||||
class GenericEntityNode :
|
||||
public scene::Node::Symbiot,
|
||||
public scene::Instantiable,
|
||||
public scene::Cloneable
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
NodeTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
NodeStaticCast<GenericEntityNode, scene::Instantiable>::install(m_casts);
|
||||
NodeStaticCast<GenericEntityNode, scene::Cloneable>::install(m_casts);
|
||||
NodeContainedCast<GenericEntityNode, Snappable>::install(m_casts);
|
||||
NodeContainedCast<GenericEntityNode, TransformNode>::install(m_casts);
|
||||
NodeContainedCast<GenericEntityNode, Entity>::install(m_casts);
|
||||
NodeContainedCast<GenericEntityNode, Nameable>::install(m_casts);
|
||||
NodeContainedCast<GenericEntityNode, Namespaced>::install(m_casts);
|
||||
}
|
||||
NodeTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
InstanceSet m_instances;
|
||||
|
||||
scene::Node m_node;
|
||||
GenericEntity m_contained;
|
||||
|
||||
public:
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
Snappable& get(NullType<Snappable>)
|
||||
{
|
||||
return m_contained;
|
||||
}
|
||||
TransformNode& get(NullType<TransformNode>)
|
||||
{
|
||||
return m_contained.getTransformNode();
|
||||
}
|
||||
Entity& get(NullType<Entity>)
|
||||
{
|
||||
return m_contained.getEntity();
|
||||
}
|
||||
Nameable& get(NullType<Nameable>)
|
||||
{
|
||||
return m_contained.getNameable();
|
||||
}
|
||||
Namespaced& get(NullType<Namespaced>)
|
||||
{
|
||||
return m_contained.getNamespaced();
|
||||
}
|
||||
|
||||
GenericEntityNode(EntityClass* eclass) :
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller(m_instances))
|
||||
{
|
||||
}
|
||||
GenericEntityNode(const GenericEntityNode& other) :
|
||||
scene::Node::Symbiot(other),
|
||||
scene::Instantiable(other),
|
||||
scene::Cloneable(other),
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller(m_instances))
|
||||
{
|
||||
}
|
||||
void release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
scene::Node& node()
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
scene::Node& clone() const
|
||||
{
|
||||
return (new GenericEntityNode(*this))->node();
|
||||
}
|
||||
|
||||
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
|
||||
{
|
||||
return new GenericEntityInstance(path, parent, m_contained);
|
||||
}
|
||||
void forEachInstance(const scene::Instantiable::Visitor& visitor)
|
||||
{
|
||||
m_instances.forEachInstance(visitor);
|
||||
}
|
||||
void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
|
||||
{
|
||||
m_instances.insert(observer, path, instance);
|
||||
}
|
||||
scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
|
||||
{
|
||||
return m_instances.erase(observer, path);
|
||||
}
|
||||
};
|
||||
|
||||
scene::Node& New_GenericEntity(EntityClass* eclass)
|
||||
{
|
||||
return (new GenericEntityNode(eclass))->node();
|
||||
}
|
||||
27
plugins/entity/generic.h
Normal file
27
plugins/entity/generic.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_GENERIC_H)
|
||||
#define INCLUDED_GENERIC_H
|
||||
|
||||
scene::Node& New_GenericEntity(EntityClass* eclass);
|
||||
|
||||
#endif
|
||||
444
plugins/entity/group.cpp
Normal file
444
plugins/entity/group.cpp
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
///\file
|
||||
///\brief Represents any entity which does not have a fixed size specified in its entity-definition (except misc_model).
|
||||
///
|
||||
/// This entity behaves as a group, i.e. it contains brushes.
|
||||
|
||||
#include "cullable.h"
|
||||
#include "renderable.h"
|
||||
#include "editable.h"
|
||||
|
||||
#include "selectionlib.h"
|
||||
#include "instancelib.h"
|
||||
#include "transformlib.h"
|
||||
#include "traverselib.h"
|
||||
#include "entitylib.h"
|
||||
#include "render.h"
|
||||
#include "eclasslib.h"
|
||||
|
||||
#include "targetable.h"
|
||||
#include "origin.h"
|
||||
#include "angles.h"
|
||||
#include "scale.h"
|
||||
#include "filters.h"
|
||||
#include "namedentity.h"
|
||||
#include "keyobservers.h"
|
||||
#include "namekeys.h"
|
||||
|
||||
#include "entity.h"
|
||||
|
||||
class Group
|
||||
{
|
||||
EntityKeyValues m_entity;
|
||||
KeyObserverMap m_keyObservers;
|
||||
MatrixTransform m_transform;
|
||||
TraversableNodeSet m_traverse;
|
||||
|
||||
ClassnameFilter m_filter;
|
||||
NamedEntity m_named;
|
||||
NameKeys m_nameKeys;
|
||||
|
||||
RenderableNamedEntity m_renderName;
|
||||
|
||||
Callback m_transformChanged;
|
||||
|
||||
void construct()
|
||||
{
|
||||
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
|
||||
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
|
||||
}
|
||||
|
||||
public:
|
||||
Group(EntityClass* eclass, scene::Node& node, const Callback& transformChanged) :
|
||||
m_entity(eclass),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_transformChanged(transformChanged)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
Group(const Group& other, scene::Node& node, const Callback& transformChanged) :
|
||||
m_entity(other.m_entity),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_transformChanged(transformChanged)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
InstanceCounter m_instanceCounter;
|
||||
void instanceAttach(const scene::Path& path)
|
||||
{
|
||||
if(++m_instanceCounter.m_count == 1)
|
||||
{
|
||||
m_filter.instanceAttach();
|
||||
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_traverse.instanceAttach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_entity.attach(m_keyObservers);
|
||||
}
|
||||
}
|
||||
void instanceDetach(const scene::Path& path)
|
||||
{
|
||||
if(--m_instanceCounter.m_count == 0)
|
||||
{
|
||||
m_entity.detach(m_keyObservers);
|
||||
m_traverse.instanceDetach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_filter.instanceDetach();
|
||||
}
|
||||
}
|
||||
|
||||
EntityKeyValues& getEntity()
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
const EntityKeyValues& getEntity() const
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
|
||||
scene::Traversable& getTraversable()
|
||||
{
|
||||
return m_traverse;
|
||||
}
|
||||
Namespaced& getNamespaced()
|
||||
{
|
||||
return m_nameKeys;
|
||||
}
|
||||
Nameable& getNameable()
|
||||
{
|
||||
return m_named;
|
||||
}
|
||||
TransformNode& getTransformNode()
|
||||
{
|
||||
return m_transform;
|
||||
}
|
||||
|
||||
void attach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_traverse.attach(observer);
|
||||
}
|
||||
void detach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_traverse.detach(observer);
|
||||
}
|
||||
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
|
||||
{
|
||||
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
|
||||
{
|
||||
renderSolid(renderer, volume, localToWorld);
|
||||
#if 0
|
||||
if(g_showNames)
|
||||
{
|
||||
renderer.addRenderable(m_renderName, g_matrix4_identity);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
class TransformableSetTranslation
|
||||
{
|
||||
Translation m_value;
|
||||
public:
|
||||
TransformableSetTranslation(const Translation& value) : m_value(value)
|
||||
{
|
||||
}
|
||||
void operator()(Transformable& transformable) const
|
||||
{
|
||||
transformable.setTranslation(m_value);
|
||||
}
|
||||
};
|
||||
|
||||
class TransformableSetRotation
|
||||
{
|
||||
Rotation m_value;
|
||||
public:
|
||||
TransformableSetRotation(const Rotation& value) : m_value(value)
|
||||
{
|
||||
}
|
||||
void operator()(Transformable& transformable) const
|
||||
{
|
||||
transformable.setRotation(m_value);
|
||||
}
|
||||
};
|
||||
|
||||
class TransformableSetScale
|
||||
{
|
||||
Scale m_value;
|
||||
public:
|
||||
TransformableSetScale(const Scale& value) : m_value(value)
|
||||
{
|
||||
}
|
||||
void operator()(Transformable& transformable) const
|
||||
{
|
||||
transformable.setScale(m_value);
|
||||
}
|
||||
};
|
||||
|
||||
class TransformableSetType
|
||||
{
|
||||
TransformModifierType m_value;
|
||||
public:
|
||||
TransformableSetType(const TransformModifierType& value) : m_value(value)
|
||||
{
|
||||
}
|
||||
void operator()(Transformable& transformable) const
|
||||
{
|
||||
transformable.setType(m_value);
|
||||
}
|
||||
};
|
||||
|
||||
class TransformableFreezeTransform
|
||||
{
|
||||
TransformModifierType m_value;
|
||||
public:
|
||||
void operator()(Transformable& transformable) const
|
||||
{
|
||||
transformable.freezeTransform();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Functor>
|
||||
inline void Scene_forEachChildTransformable(const Functor& functor, const scene::Path& path)
|
||||
{
|
||||
GlobalSceneGraph().traverse_subgraph(ChildInstanceWalker< InstanceApply<Transformable, Functor> >(functor), path);
|
||||
}
|
||||
#endif
|
||||
|
||||
class GroupInstance :
|
||||
public TargetableInstance,
|
||||
#if 0
|
||||
public Transformable,
|
||||
#endif
|
||||
public Renderable
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
InstanceTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
|
||||
InstanceStaticCast<GroupInstance, Renderable>::install(m_casts);
|
||||
#if 0
|
||||
InstanceStaticCast<GroupInstance, Transformable>::install(m_casts);
|
||||
#endif
|
||||
}
|
||||
InstanceTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
Group& m_contained;
|
||||
public:
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
GroupInstance(const scene::Path& path, scene::Instance* parent, Group& group) :
|
||||
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), group.getEntity(), *this),
|
||||
m_contained(group)
|
||||
{
|
||||
m_contained.instanceAttach(Instance::path());
|
||||
StaticRenderableConnectionLines::instance().attach(*this);
|
||||
}
|
||||
~GroupInstance()
|
||||
{
|
||||
StaticRenderableConnectionLines::instance().detach(*this);
|
||||
m_contained.instanceDetach(Instance::path());
|
||||
}
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderSolid(renderer, volume, Instance::localToWorld());
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderWireframe(renderer, volume, Instance::localToWorld());
|
||||
}
|
||||
|
||||
#if 0
|
||||
void setType(TransformModifierType type)
|
||||
{
|
||||
Scene_forEachChildTransformable(TransformableSetType(type), Instance::path());
|
||||
}
|
||||
void setTranslation(const Translation& value)
|
||||
{
|
||||
Scene_forEachChildTransformable(TransformableSetTranslation(value), Instance::path());
|
||||
}
|
||||
void setRotation(const Rotation& value)
|
||||
{
|
||||
Scene_forEachChildTransformable(TransformableSetRotation(value), Instance::path());
|
||||
}
|
||||
void setScale(const Scale& value)
|
||||
{
|
||||
Scene_forEachChildTransformable(TransformableSetScale(value), Instance::path());
|
||||
}
|
||||
void freezeTransform()
|
||||
{
|
||||
Scene_forEachChildTransformable(TransformableFreezeTransform(), Instance::path());
|
||||
}
|
||||
|
||||
void evaluateTransform()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class GroupNode :
|
||||
public scene::Node::Symbiot,
|
||||
public scene::Instantiable,
|
||||
public scene::Cloneable,
|
||||
public scene::Traversable::Observer
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
NodeTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
NodeStaticCast<GroupNode, scene::Instantiable>::install(m_casts);
|
||||
NodeStaticCast<GroupNode, scene::Cloneable>::install(m_casts);
|
||||
NodeContainedCast<GroupNode, scene::Traversable>::install(m_casts);
|
||||
NodeContainedCast<GroupNode, TransformNode>::install(m_casts);
|
||||
NodeContainedCast<GroupNode, Entity>::install(m_casts);
|
||||
NodeContainedCast<GroupNode, Nameable>::install(m_casts);
|
||||
NodeContainedCast<GroupNode, Namespaced>::install(m_casts);
|
||||
}
|
||||
NodeTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
scene::Node m_node;
|
||||
InstanceSet m_instances;
|
||||
Group m_contained;
|
||||
|
||||
void construct()
|
||||
{
|
||||
m_contained.attach(this);
|
||||
}
|
||||
void destroy()
|
||||
{
|
||||
m_contained.detach(this);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
scene::Traversable& get(NullType<scene::Traversable>)
|
||||
{
|
||||
return m_contained.getTraversable();
|
||||
}
|
||||
TransformNode& get(NullType<TransformNode>)
|
||||
{
|
||||
return m_contained.getTransformNode();
|
||||
}
|
||||
Entity& get(NullType<Entity>)
|
||||
{
|
||||
return m_contained.getEntity();
|
||||
}
|
||||
Nameable& get(NullType<Nameable>)
|
||||
{
|
||||
return m_contained.getNameable();
|
||||
}
|
||||
Namespaced& get(NullType<Namespaced>)
|
||||
{
|
||||
return m_contained.getNamespaced();
|
||||
}
|
||||
|
||||
GroupNode(EntityClass* eclass) :
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances))
|
||||
{
|
||||
construct();
|
||||
}
|
||||
GroupNode(const GroupNode& other) :
|
||||
scene::Node::Symbiot(other),
|
||||
scene::Instantiable(other),
|
||||
scene::Cloneable(other),
|
||||
scene::Traversable::Observer(other),
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances))
|
||||
{
|
||||
construct();
|
||||
}
|
||||
~GroupNode()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
scene::Node& node()
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
scene::Node& clone() const
|
||||
{
|
||||
return (new GroupNode(*this))->node();
|
||||
}
|
||||
|
||||
void insert(scene::Node& child)
|
||||
{
|
||||
m_instances.insert(child);
|
||||
}
|
||||
void erase(scene::Node& child)
|
||||
{
|
||||
m_instances.erase(child);
|
||||
}
|
||||
|
||||
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
|
||||
{
|
||||
return new GroupInstance(path, parent, m_contained);
|
||||
}
|
||||
void forEachInstance(const scene::Instantiable::Visitor& visitor)
|
||||
{
|
||||
m_instances.forEachInstance(visitor);
|
||||
}
|
||||
void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
|
||||
{
|
||||
m_instances.insert(observer, path, instance);
|
||||
}
|
||||
scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
|
||||
{
|
||||
return m_instances.erase(observer, path);
|
||||
}
|
||||
};
|
||||
|
||||
scene::Node& New_Group(EntityClass* eclass)
|
||||
{
|
||||
return (new GroupNode(eclass))->node();
|
||||
}
|
||||
27
plugins/entity/group.h
Normal file
27
plugins/entity/group.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_GROUP_H)
|
||||
#define INCLUDED_GROUP_H
|
||||
|
||||
scene::Node& New_Group(EntityClass* eclass);
|
||||
|
||||
#endif
|
||||
23
plugins/entity/keyobservers.cpp
Normal file
23
plugins/entity/keyobservers.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "keyobservers.h"
|
||||
|
||||
53
plugins/entity/keyobservers.h
Normal file
53
plugins/entity/keyobservers.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_KEYOBSERVERS_H)
|
||||
#define INCLUDED_KEYOBSERVERS_H
|
||||
|
||||
#include "entitylib.h"
|
||||
#include <map>
|
||||
|
||||
class KeyObserverMap : public EntityKeyValues::Observer
|
||||
{
|
||||
typedef std::multimap<const char*, KeyObserver, RawStringLess> KeyObservers;
|
||||
KeyObservers m_keyObservers;
|
||||
public:
|
||||
void insert(const char* key, const KeyObserver& observer)
|
||||
{
|
||||
m_keyObservers.insert(KeyObservers::value_type(key, observer));
|
||||
}
|
||||
void insert(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
for(KeyObservers::const_iterator i = m_keyObservers.find(key); i != m_keyObservers.end() && string_equal((*i).first, key); ++i)
|
||||
{
|
||||
value.attach((*i).second);
|
||||
}
|
||||
}
|
||||
void erase(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
for(KeyObservers::const_iterator i = m_keyObservers.find(key); i != m_keyObservers.end() && string_equal((*i).first, key); ++i)
|
||||
{
|
||||
value.detach((*i).second);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
1839
plugins/entity/light.cpp
Normal file
1839
plugins/entity/light.cpp
Normal file
File diff suppressed because it is too large
Load Diff
41
plugins/entity/light.h
Normal file
41
plugins/entity/light.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_LIGHT_H)
|
||||
#define INCLUDED_LIGHT_H
|
||||
|
||||
namespace scene
|
||||
{
|
||||
class Node;
|
||||
};
|
||||
class EntityClass;
|
||||
|
||||
scene::Node& New_Light(EntityClass* eclass);
|
||||
enum LightType
|
||||
{
|
||||
LIGHTTYPE_DEFAULT,
|
||||
LIGHTTYPE_RTCW,
|
||||
LIGHTTYPE_DOOM3
|
||||
};
|
||||
void Light_Construct(LightType lightType);
|
||||
void Light_Destroy();
|
||||
|
||||
#endif
|
||||
470
plugins/entity/miscmodel.cpp
Normal file
470
plugins/entity/miscmodel.cpp
Normal file
@@ -0,0 +1,470 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
///\file
|
||||
///\brief Represents the Quake3 misc_model entity.
|
||||
///
|
||||
/// This entity displays the model specified in its "model" key.
|
||||
/// The "origin", "angles" and "modelscale*" keys directly control the entity's local-to-parent transform.
|
||||
|
||||
#include "cullable.h"
|
||||
#include "renderable.h"
|
||||
#include "editable.h"
|
||||
|
||||
#include "selectionlib.h"
|
||||
#include "instancelib.h"
|
||||
#include "transformlib.h"
|
||||
#include "traverselib.h"
|
||||
#include "entitylib.h"
|
||||
#include "eclasslib.h"
|
||||
#include "render.h"
|
||||
#include "pivot.h"
|
||||
|
||||
#include "targetable.h"
|
||||
#include "origin.h"
|
||||
#include "angles.h"
|
||||
#include "scale.h"
|
||||
#include "model.h"
|
||||
#include "filters.h"
|
||||
#include "namedentity.h"
|
||||
#include "keyobservers.h"
|
||||
#include "namekeys.h"
|
||||
|
||||
#include "entity.h"
|
||||
|
||||
class MiscModel :
|
||||
public Snappable
|
||||
{
|
||||
EntityKeyValues m_entity;
|
||||
KeyObserverMap m_keyObservers;
|
||||
MatrixTransform m_transform;
|
||||
|
||||
OriginKey m_originKey;
|
||||
Vector3 m_origin;
|
||||
AnglesKey m_anglesKey;
|
||||
Vector3 m_angles;
|
||||
ScaleKey m_scaleKey;
|
||||
Vector3 m_scale;
|
||||
|
||||
SingletonModel m_model;
|
||||
|
||||
ClassnameFilter m_filter;
|
||||
NamedEntity m_named;
|
||||
NameKeys m_nameKeys;
|
||||
RenderablePivot m_renderOrigin;
|
||||
RenderableNamedEntity m_renderName;
|
||||
|
||||
Callback m_transformChanged;
|
||||
Callback m_evaluateTransform;
|
||||
|
||||
void construct()
|
||||
{
|
||||
m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
|
||||
m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
|
||||
m_keyObservers.insert("model", SingletonModel::ModelChangedCaller(m_model));
|
||||
m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
|
||||
m_keyObservers.insert("angle", AnglesKey::AngleChangedCaller(m_anglesKey));
|
||||
m_keyObservers.insert("angles", AnglesKey::AnglesChangedCaller(m_anglesKey));
|
||||
m_keyObservers.insert("modelscale", ScaleKey::UniformScaleChangedCaller(m_scaleKey));
|
||||
m_keyObservers.insert("modelscale_vec", ScaleKey::ScaleChangedCaller(m_scaleKey));
|
||||
}
|
||||
|
||||
void updateTransform()
|
||||
{
|
||||
m_transform.localToParent() = g_matrix4_identity;
|
||||
matrix4_transform_by_euler_xyz_degrees(m_transform.localToParent(), m_origin, m_angles, m_scale);
|
||||
m_transformChanged();
|
||||
}
|
||||
void originChanged()
|
||||
{
|
||||
m_origin = m_originKey.m_origin;
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<MiscModel, &MiscModel::originChanged> OriginChangedCaller;
|
||||
void anglesChanged()
|
||||
{
|
||||
m_angles = m_anglesKey.m_angles;
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<MiscModel, &MiscModel::anglesChanged> AnglesChangedCaller;
|
||||
void scaleChanged()
|
||||
{
|
||||
m_scale = m_scaleKey.m_scale;
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<MiscModel, &MiscModel::scaleChanged> ScaleChangedCaller;
|
||||
public:
|
||||
|
||||
MiscModel(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
|
||||
m_entity(eclass),
|
||||
m_originKey(OriginChangedCaller(*this)),
|
||||
m_origin(ORIGINKEY_IDENTITY),
|
||||
m_anglesKey(AnglesChangedCaller(*this)),
|
||||
m_angles(ANGLESKEY_IDENTITY),
|
||||
m_scaleKey(ScaleChangedCaller(*this)),
|
||||
m_scale(SCALEKEY_IDENTITY),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_transformChanged(transformChanged),
|
||||
m_evaluateTransform(evaluateTransform)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
MiscModel(const MiscModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform) :
|
||||
m_entity(other.m_entity),
|
||||
m_originKey(OriginChangedCaller(*this)),
|
||||
m_origin(ORIGINKEY_IDENTITY),
|
||||
m_anglesKey(AnglesChangedCaller(*this)),
|
||||
m_angles(ANGLESKEY_IDENTITY),
|
||||
m_scaleKey(ScaleChangedCaller(*this)),
|
||||
m_scale(SCALEKEY_IDENTITY),
|
||||
m_filter(m_entity, node),
|
||||
m_named(m_entity),
|
||||
m_nameKeys(m_entity),
|
||||
m_renderName(m_named, g_vector3_identity),
|
||||
m_transformChanged(transformChanged),
|
||||
m_evaluateTransform(evaluateTransform)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
InstanceCounter m_instanceCounter;
|
||||
void instanceAttach(const scene::Path& path)
|
||||
{
|
||||
if(++m_instanceCounter.m_count == 1)
|
||||
{
|
||||
m_filter.instanceAttach();
|
||||
m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_entity.attach(m_keyObservers);
|
||||
}
|
||||
}
|
||||
void instanceDetach(const scene::Path& path)
|
||||
{
|
||||
if(--m_instanceCounter.m_count == 0)
|
||||
{
|
||||
m_entity.detach(m_keyObservers);
|
||||
m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
|
||||
m_filter.instanceDetach();
|
||||
}
|
||||
}
|
||||
|
||||
EntityKeyValues& getEntity()
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
const EntityKeyValues& getEntity() const
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
|
||||
scene::Traversable& getTraversable()
|
||||
{
|
||||
return m_model.getTraversable();
|
||||
}
|
||||
Namespaced& getNamespaced()
|
||||
{
|
||||
return m_nameKeys;
|
||||
}
|
||||
Nameable& getNameable()
|
||||
{
|
||||
return m_named;
|
||||
}
|
||||
TransformNode& getTransformNode()
|
||||
{
|
||||
return m_transform;
|
||||
}
|
||||
|
||||
void attach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_model.attach(observer);
|
||||
}
|
||||
void detach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_model.detach(observer);
|
||||
}
|
||||
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
|
||||
{
|
||||
if(selected)
|
||||
{
|
||||
m_renderOrigin.render(renderer, volume, localToWorld);
|
||||
}
|
||||
|
||||
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
|
||||
{
|
||||
renderSolid(renderer, volume, localToWorld, selected);
|
||||
if(g_showNames)
|
||||
{
|
||||
renderer.addRenderable(m_renderName, localToWorld);
|
||||
}
|
||||
}
|
||||
|
||||
void translate(const Vector3& translation)
|
||||
{
|
||||
m_origin = origin_translated(m_origin, translation);
|
||||
}
|
||||
void rotate(const Quaternion& rotation)
|
||||
{
|
||||
m_angles = angles_rotated(m_angles, rotation);
|
||||
}
|
||||
void scale(const Vector3& scaling)
|
||||
{
|
||||
m_scale = scale_scaled(m_scale, scaling);
|
||||
}
|
||||
void snapto(float snap)
|
||||
{
|
||||
m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
|
||||
m_originKey.write(&m_entity);
|
||||
}
|
||||
void revertTransform()
|
||||
{
|
||||
m_origin = m_originKey.m_origin;
|
||||
m_angles = m_anglesKey.m_angles;
|
||||
m_scale = m_scaleKey.m_scale;
|
||||
}
|
||||
void freezeTransform()
|
||||
{
|
||||
m_originKey.m_origin = m_origin;
|
||||
m_originKey.write(&m_entity);
|
||||
m_anglesKey.m_angles = m_angles;
|
||||
m_anglesKey.write(&m_entity);
|
||||
m_scaleKey.m_scale = m_scale;
|
||||
m_scaleKey.write(&m_entity);
|
||||
}
|
||||
void transformChanged()
|
||||
{
|
||||
revertTransform();
|
||||
m_evaluateTransform();
|
||||
updateTransform();
|
||||
}
|
||||
typedef MemberCaller<MiscModel, &MiscModel::transformChanged> TransformChangedCaller;
|
||||
};
|
||||
|
||||
class MiscModelInstance : public TargetableInstance, public TransformModifier, public Renderable
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
InstanceTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
m_casts = TargetableInstance::StaticTypeCasts::instance().get();
|
||||
InstanceStaticCast<MiscModelInstance, Renderable>::install(m_casts);
|
||||
InstanceStaticCast<MiscModelInstance, Transformable>::install(m_casts);
|
||||
InstanceIdentityCast<MiscModelInstance>::install(m_casts);
|
||||
}
|
||||
InstanceTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
MiscModel& m_contained;
|
||||
public:
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
STRING_CONSTANT(Name, "MiscModelInstance");
|
||||
|
||||
MiscModelInstance(const scene::Path& path, scene::Instance* parent, MiscModel& miscmodel) :
|
||||
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), miscmodel.getEntity(), *this),
|
||||
TransformModifier(MiscModel::TransformChangedCaller(miscmodel), ApplyTransformCaller(*this)),
|
||||
m_contained(miscmodel)
|
||||
{
|
||||
m_contained.instanceAttach(Instance::path());
|
||||
StaticRenderableConnectionLines::instance().attach(*this);
|
||||
}
|
||||
~MiscModelInstance()
|
||||
{
|
||||
StaticRenderableConnectionLines::instance().detach(*this);
|
||||
m_contained.instanceDetach(Instance::path());
|
||||
}
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
|
||||
}
|
||||
void evaluateTransform()
|
||||
{
|
||||
if(getType() == TRANSFORM_PRIMITIVE)
|
||||
{
|
||||
m_contained.translate(getTranslation());
|
||||
m_contained.rotate(getRotation());
|
||||
m_contained.scale(getScale());
|
||||
}
|
||||
}
|
||||
void applyTransform()
|
||||
{
|
||||
m_contained.revertTransform();
|
||||
evaluateTransform();
|
||||
m_contained.freezeTransform();
|
||||
}
|
||||
typedef MemberCaller<MiscModelInstance, &MiscModelInstance::applyTransform> ApplyTransformCaller;
|
||||
};
|
||||
|
||||
class MiscModelNode :
|
||||
public scene::Node::Symbiot,
|
||||
public scene::Instantiable,
|
||||
public scene::Cloneable,
|
||||
public scene::Traversable::Observer
|
||||
{
|
||||
class TypeCasts
|
||||
{
|
||||
NodeTypeCastTable m_casts;
|
||||
public:
|
||||
TypeCasts()
|
||||
{
|
||||
NodeStaticCast<MiscModelNode, scene::Instantiable>::install(m_casts);
|
||||
NodeStaticCast<MiscModelNode, scene::Cloneable>::install(m_casts);
|
||||
NodeContainedCast<MiscModelNode, scene::Traversable>::install(m_casts);
|
||||
NodeContainedCast<MiscModelNode, Snappable>::install(m_casts);
|
||||
NodeContainedCast<MiscModelNode, TransformNode>::install(m_casts);
|
||||
NodeContainedCast<MiscModelNode, Entity>::install(m_casts);
|
||||
NodeContainedCast<MiscModelNode, Nameable>::install(m_casts);
|
||||
NodeContainedCast<MiscModelNode, Namespaced>::install(m_casts);
|
||||
}
|
||||
NodeTypeCastTable& get()
|
||||
{
|
||||
return m_casts;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
scene::Node m_node;
|
||||
InstanceSet m_instances;
|
||||
MiscModel m_contained;
|
||||
|
||||
void construct()
|
||||
{
|
||||
m_contained.attach(this);
|
||||
}
|
||||
void destroy()
|
||||
{
|
||||
m_contained.detach(this);
|
||||
}
|
||||
|
||||
public:
|
||||
typedef LazyStatic<TypeCasts> StaticTypeCasts;
|
||||
|
||||
scene::Traversable& get(NullType<scene::Traversable>)
|
||||
{
|
||||
return m_contained.getTraversable();
|
||||
}
|
||||
Snappable& get(NullType<Snappable>)
|
||||
{
|
||||
return m_contained;
|
||||
}
|
||||
TransformNode& get(NullType<TransformNode>)
|
||||
{
|
||||
return m_contained.getTransformNode();
|
||||
}
|
||||
Entity& get(NullType<Entity>)
|
||||
{
|
||||
return m_contained.getEntity();
|
||||
}
|
||||
Nameable& get(NullType<Nameable>)
|
||||
{
|
||||
return m_contained.getNameable();
|
||||
}
|
||||
Namespaced& get(NullType<Namespaced>)
|
||||
{
|
||||
return m_contained.getNamespaced();
|
||||
}
|
||||
|
||||
MiscModelNode(EntityClass* eclass) :
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<MiscModelInstance>::Caller(m_instances))
|
||||
{
|
||||
construct();
|
||||
}
|
||||
MiscModelNode(const MiscModelNode& other) :
|
||||
scene::Node::Symbiot(other),
|
||||
scene::Instantiable(other),
|
||||
scene::Cloneable(other),
|
||||
scene::Traversable::Observer(other),
|
||||
m_node(this, this, StaticTypeCasts::instance().get()),
|
||||
m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSetEvaluateTransform<MiscModelInstance>::Caller(m_instances))
|
||||
{
|
||||
construct();
|
||||
}
|
||||
~MiscModelNode()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
scene::Node& node()
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
scene::Node& clone() const
|
||||
{
|
||||
return (new MiscModelNode(*this))->node();
|
||||
}
|
||||
|
||||
void insert(scene::Node& child)
|
||||
{
|
||||
m_instances.insert(child);
|
||||
}
|
||||
void erase(scene::Node& child)
|
||||
{
|
||||
m_instances.erase(child);
|
||||
}
|
||||
|
||||
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
|
||||
{
|
||||
return new MiscModelInstance(path, parent, m_contained);
|
||||
}
|
||||
void forEachInstance(const scene::Instantiable::Visitor& visitor)
|
||||
{
|
||||
m_instances.forEachInstance(visitor);
|
||||
}
|
||||
void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
|
||||
{
|
||||
m_instances.insert(observer, path, instance);
|
||||
}
|
||||
scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
|
||||
{
|
||||
return m_instances.erase(observer, path);
|
||||
}
|
||||
};
|
||||
|
||||
scene::Node& New_MiscModel(EntityClass* eclass)
|
||||
{
|
||||
return (new MiscModelNode(eclass))->node();
|
||||
}
|
||||
|
||||
void MiscModel_construct()
|
||||
{
|
||||
}
|
||||
void MiscModel_destroy()
|
||||
{
|
||||
}
|
||||
29
plugins/entity/miscmodel.h
Normal file
29
plugins/entity/miscmodel.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_MISCMODEL_H)
|
||||
#define INCLUDED_MISCMODEL_H
|
||||
|
||||
scene::Node& New_MiscModel(EntityClass* eclass);
|
||||
void MiscModel_construct();
|
||||
void MiscModel_destroy();
|
||||
|
||||
#endif
|
||||
23
plugins/entity/model.cpp
Normal file
23
plugins/entity/model.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "model.h"
|
||||
|
||||
124
plugins/entity/model.h
Normal file
124
plugins/entity/model.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_MODEL_H)
|
||||
#define INCLUDED_MODEL_H
|
||||
|
||||
#include "entitylib.h"
|
||||
#include "traverselib.h"
|
||||
#include "generic/callback.h"
|
||||
#include "stream/stringstream.h"
|
||||
#include "os/path.h"
|
||||
#include "moduleobserver.h"
|
||||
|
||||
class Model : public ModuleObserver
|
||||
{
|
||||
ResourceReference m_resource;
|
||||
scene::Traversable& m_traverse;
|
||||
scene::Node* m_node;
|
||||
Callback m_modelChanged;
|
||||
|
||||
public:
|
||||
Model(scene::Traversable& traversable, const Callback& modelChanged)
|
||||
: m_resource(""), m_traverse(traversable), m_node(0), m_modelChanged(modelChanged)
|
||||
{
|
||||
m_resource.attach(*this);
|
||||
}
|
||||
~Model()
|
||||
{
|
||||
m_resource.detach(*this);
|
||||
}
|
||||
|
||||
void realise()
|
||||
{
|
||||
m_resource.get()->load();
|
||||
m_node = m_resource.get()->getNode();
|
||||
if(m_node != 0)
|
||||
{
|
||||
m_traverse.insert(*m_node);
|
||||
}
|
||||
}
|
||||
void unrealise()
|
||||
{
|
||||
if(m_node != 0)
|
||||
{
|
||||
m_traverse.erase(*m_node);
|
||||
}
|
||||
}
|
||||
|
||||
void modelChanged(const char* value)
|
||||
{
|
||||
StringOutputStream cleaned(string_length(value));
|
||||
cleaned << PathCleaned(value);
|
||||
m_resource.detach(*this);
|
||||
m_resource.setName(cleaned.c_str());
|
||||
m_resource.attach(*this);
|
||||
m_modelChanged();
|
||||
}
|
||||
typedef MemberCaller1<Model, const char*, &Model::modelChanged> ModelChangedCaller;
|
||||
|
||||
const char* getName() const
|
||||
{
|
||||
return m_resource.getName();
|
||||
}
|
||||
scene::Node* getNode() const
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
};
|
||||
|
||||
class SingletonModel
|
||||
{
|
||||
TraversableNode m_traverse;
|
||||
Model m_model;
|
||||
public:
|
||||
SingletonModel()
|
||||
: m_model(m_traverse, Callback())
|
||||
{
|
||||
}
|
||||
|
||||
void attach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_traverse.attach(observer);
|
||||
}
|
||||
void detach(scene::Traversable::Observer* observer)
|
||||
{
|
||||
m_traverse.detach(observer);
|
||||
}
|
||||
|
||||
scene::Traversable& getTraversable()
|
||||
{
|
||||
return m_traverse;
|
||||
}
|
||||
|
||||
void modelChanged(const char* value)
|
||||
{
|
||||
m_model.modelChanged(value);
|
||||
}
|
||||
typedef MemberCaller1<SingletonModel, const char*, &SingletonModel::modelChanged> ModelChangedCaller;
|
||||
|
||||
scene::Node* getNode() const
|
||||
{
|
||||
return m_model.getNode();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
23
plugins/entity/modelskinkey.cpp
Normal file
23
plugins/entity/modelskinkey.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "modelskinkey.h"
|
||||
|
||||
111
plugins/entity/modelskinkey.h
Normal file
111
plugins/entity/modelskinkey.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_MODELSKINKEY_H)
|
||||
#define INCLUDED_MODELSKINKEY_H
|
||||
|
||||
#include "modelskin.h"
|
||||
|
||||
#include "os/path.h"
|
||||
#include "stream/stringstream.h"
|
||||
#include "moduleobserver.h"
|
||||
#include "entitylib.h"
|
||||
#include "traverselib.h"
|
||||
|
||||
inline void parseTextureName(CopiedString& name, const char* token)
|
||||
{
|
||||
StringOutputStream cleaned(256);
|
||||
cleaned << PathCleaned(token);
|
||||
name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
|
||||
}
|
||||
|
||||
class ModelSkinKey : public ModuleObserver
|
||||
{
|
||||
CopiedString m_name;
|
||||
ModelSkin* m_skin;
|
||||
Callback m_skinChangedCallback;
|
||||
|
||||
ModelSkinKey(const ModelSkinKey&);
|
||||
ModelSkinKey operator=(const ModelSkinKey&);
|
||||
|
||||
void construct()
|
||||
{
|
||||
m_skin = &GlobalModelSkinCache().capture(m_name.c_str());
|
||||
m_skin->attach(*this);
|
||||
}
|
||||
void destroy()
|
||||
{
|
||||
m_skin->detach(*this);
|
||||
GlobalModelSkinCache().release(m_name.c_str());
|
||||
}
|
||||
|
||||
public:
|
||||
ModelSkinKey(const Callback& skinChangedCallback) : m_skinChangedCallback(skinChangedCallback)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
~ModelSkinKey()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
ModelSkin& get() const
|
||||
{
|
||||
return *m_skin;
|
||||
}
|
||||
void skinChanged(const char* value)
|
||||
{
|
||||
destroy();
|
||||
parseTextureName(m_name, value);
|
||||
construct();
|
||||
}
|
||||
typedef MemberCaller1<ModelSkinKey, const char*, &ModelSkinKey::skinChanged> SkinChangedCaller;
|
||||
|
||||
void realise()
|
||||
{
|
||||
m_skinChangedCallback();
|
||||
}
|
||||
void unrealise()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class InstanceSkinChanged : public scene::Instantiable::Visitor
|
||||
{
|
||||
public:
|
||||
void visit(scene::Instance& instance) const
|
||||
{
|
||||
//\todo don't do this for instances that are not children of the entity setting the skin
|
||||
SkinnedModel* skinned = InstanceTypeCast<SkinnedModel>::cast(instance);
|
||||
if(skinned != 0)
|
||||
{
|
||||
skinned->skinChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline void Node_modelSkinChanged(scene::Node& node)
|
||||
{
|
||||
scene::Instantiable* instantiable = Node_getInstantiable(node);
|
||||
ASSERT_NOTNULL(instantiable);
|
||||
instantiable->forEachInstance(InstanceSkinChanged());
|
||||
}
|
||||
|
||||
#endif
|
||||
23
plugins/entity/namedentity.cpp
Normal file
23
plugins/entity/namedentity.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "namedentity.h"
|
||||
|
||||
113
plugins/entity/namedentity.h
Normal file
113
plugins/entity/namedentity.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_NAMEDENTITY_H)
|
||||
#define INCLUDED_NAMEDENTITY_H
|
||||
|
||||
#include "entitylib.h"
|
||||
#include "eclasslib.h"
|
||||
#include "generic/callback.h"
|
||||
#include "nameable.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
class NameCallbackSet
|
||||
{
|
||||
typedef std::set<NameCallback> NameCallbacks;
|
||||
NameCallbacks m_callbacks;
|
||||
public:
|
||||
void insert(const NameCallback& callback)
|
||||
{
|
||||
m_callbacks.insert(callback);
|
||||
}
|
||||
void erase(const NameCallback& callback)
|
||||
{
|
||||
m_callbacks.erase(callback);
|
||||
}
|
||||
void changed(const char* name) const
|
||||
{
|
||||
for(NameCallbacks::const_iterator i = m_callbacks.begin(); i != m_callbacks.end(); ++i)
|
||||
{
|
||||
(*i)(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class NamedEntity : public Nameable
|
||||
{
|
||||
EntityKeyValues& m_entity;
|
||||
NameCallbackSet m_changed;
|
||||
CopiedString m_name;
|
||||
public:
|
||||
NamedEntity(EntityKeyValues& entity) : m_entity(entity)
|
||||
{
|
||||
}
|
||||
const char* name() const
|
||||
{
|
||||
if(string_empty(m_name.c_str()))
|
||||
{
|
||||
return m_entity.getEntityClass().name();
|
||||
}
|
||||
return m_name.c_str();
|
||||
}
|
||||
void attach(const NameCallback& callback)
|
||||
{
|
||||
m_changed.insert(callback);
|
||||
}
|
||||
void detach(const NameCallback& callback)
|
||||
{
|
||||
m_changed.erase(callback);
|
||||
}
|
||||
|
||||
void identifierChanged(const char* value)
|
||||
{
|
||||
if(string_empty(value))
|
||||
{
|
||||
m_changed.changed(m_entity.getEntityClass().name());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_changed.changed(value);
|
||||
}
|
||||
m_name = value;
|
||||
}
|
||||
typedef MemberCaller1<NamedEntity, const char*, &NamedEntity::identifierChanged> IdentifierChangedCaller;
|
||||
};
|
||||
|
||||
class RenderableNamedEntity : public OpenGLRenderable
|
||||
{
|
||||
const NamedEntity& m_named;
|
||||
const Vector3& m_position;
|
||||
public:
|
||||
RenderableNamedEntity(const NamedEntity& named, const Vector3& position)
|
||||
: m_named(named), m_position(position)
|
||||
{
|
||||
}
|
||||
void render(RenderStateFlags state) const
|
||||
{
|
||||
glRasterPos3fv(vector3_to_array(m_position));
|
||||
GlobalOpenGL().drawString(m_named.name());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
23
plugins/entity/namekeys.cpp
Normal file
23
plugins/entity/namekeys.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "namekeys.h"
|
||||
|
||||
148
plugins/entity/namekeys.h
Normal file
148
plugins/entity/namekeys.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_NAMEKEYS_H)
|
||||
#define INCLUDED_NAMEKEYS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <map>
|
||||
#include "generic/static.h"
|
||||
#include "entitylib.h"
|
||||
#include "namespace.h"
|
||||
|
||||
inline bool string_is_integer(const char* string)
|
||||
{
|
||||
strtol(string, const_cast<char**>(&string), 10);
|
||||
return *string == '\0';
|
||||
}
|
||||
|
||||
typedef bool (*KeyIsNameFunc)(const char* key);
|
||||
|
||||
class KeyIsName
|
||||
{
|
||||
public:
|
||||
KeyIsNameFunc m_keyIsName;
|
||||
const char* m_nameKey;
|
||||
|
||||
KeyIsName()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef MemberCaller1<KeyValue, const char*, &KeyValue::assign> KeyValueAssignCaller;
|
||||
typedef MemberCaller1<KeyValue, const KeyObserver&, &KeyValue::attach> KeyValueAttachCaller;
|
||||
typedef MemberCaller1<KeyValue, const KeyObserver&, &KeyValue::detach> KeyValueDetachCaller;
|
||||
|
||||
class NameKeys : public EntityKeyValues::Observer, public Namespaced
|
||||
{
|
||||
Namespace* m_namespace;
|
||||
EntityKeyValues& m_entity;
|
||||
KeyIsNameFunc m_keyIsName;
|
||||
NameKeys(const NameKeys& other);
|
||||
NameKeys& operator=(const NameKeys& other);
|
||||
|
||||
typedef std::map<CopiedString, EntityKeyValues::Value*> KeyValues;
|
||||
KeyValues m_keyValues;
|
||||
|
||||
void insertName(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
if(m_namespace != 0 && m_keyIsName(key))
|
||||
{
|
||||
//globalOutputStream() << "insert " << key << "\n";
|
||||
m_namespace->attach(KeyValueAssignCaller(value), KeyValueAttachCaller(value));
|
||||
}
|
||||
}
|
||||
void eraseName(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
if(m_namespace != 0 && m_keyIsName(key))
|
||||
{
|
||||
//globalOutputStream() << "erase " << key << "\n";
|
||||
m_namespace->detach(KeyValueAssignCaller(value), KeyValueDetachCaller(value));
|
||||
}
|
||||
}
|
||||
void insertAll()
|
||||
{
|
||||
for(KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
|
||||
{
|
||||
insertName((*i).first.c_str(), *(*i).second);
|
||||
}
|
||||
}
|
||||
void eraseAll()
|
||||
{
|
||||
for(KeyValues::iterator i = m_keyValues.begin(); i != m_keyValues.end(); ++i)
|
||||
{
|
||||
eraseName((*i).first.c_str(), *(*i).second);
|
||||
}
|
||||
}
|
||||
public:
|
||||
NameKeys(EntityKeyValues& entity) : m_namespace(0), m_entity(entity), m_keyIsName(Static<KeyIsName>::instance().m_keyIsName)
|
||||
{
|
||||
m_entity.attach(*this);
|
||||
}
|
||||
~NameKeys()
|
||||
{
|
||||
m_entity.detach(*this);
|
||||
}
|
||||
void setNamespace(Namespace& space)
|
||||
{
|
||||
eraseAll();
|
||||
m_namespace = &space;
|
||||
insertAll();
|
||||
}
|
||||
void setKeyIsName(KeyIsNameFunc keyIsName)
|
||||
{
|
||||
eraseAll();
|
||||
m_keyIsName = keyIsName;
|
||||
insertAll();
|
||||
}
|
||||
void insert(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
m_keyValues.insert(KeyValues::value_type(key, &value));
|
||||
insertName(key, value);
|
||||
}
|
||||
void erase(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
eraseName(key, value);
|
||||
m_keyValues.erase(key);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool keyIsNameDoom3(const char* key)
|
||||
{
|
||||
return string_equal(key, "target")
|
||||
|| (string_equal_n(key, "target", 6) && string_is_integer(key + 6))
|
||||
|| string_equal(key, "name");
|
||||
}
|
||||
|
||||
inline bool keyIsNameDoom3Doom3Group(const char* key)
|
||||
{
|
||||
return keyIsNameDoom3(key)
|
||||
|| string_equal(key, "model");
|
||||
}
|
||||
|
||||
inline bool keyIsNameQuake3(const char* key)
|
||||
{
|
||||
return string_equal(key, "target")
|
||||
|| string_equal(key, "targetname");
|
||||
}
|
||||
|
||||
#endif
|
||||
23
plugins/entity/origin.cpp
Normal file
23
plugins/entity/origin.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "origin.h"
|
||||
|
||||
169
plugins/entity/origin.h
Normal file
169
plugins/entity/origin.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_ORIGIN_H)
|
||||
#define INCLUDED_ORIGIN_H
|
||||
|
||||
#include "ientity.h"
|
||||
|
||||
#include "math/matrix.h"
|
||||
#include "generic/callback.h"
|
||||
#include "stringio.h"
|
||||
|
||||
const Vector3 ORIGINKEY_IDENTITY = Vector3(0, 0, 0);
|
||||
|
||||
inline void default_origin(Vector3& origin)
|
||||
{
|
||||
origin = ORIGINKEY_IDENTITY;
|
||||
}
|
||||
inline void read_origin(Vector3& origin, const char* value)
|
||||
{
|
||||
if(!string_parse_vector3(value, origin))
|
||||
{
|
||||
default_origin(origin);
|
||||
}
|
||||
}
|
||||
inline void write_origin(const Vector3& origin, Entity* entity, const char* key)
|
||||
{
|
||||
char value[64];
|
||||
sprintf(value, "%g %g %g", origin[0], origin[1], origin[2]);
|
||||
entity->setKeyValue(key, value);
|
||||
}
|
||||
|
||||
inline Vector3 origin_translated(const Vector3& origin, const Vector3& translation)
|
||||
{
|
||||
return matrix4_get_translation_vec3(
|
||||
matrix4_multiplied_by_matrix4(
|
||||
matrix4_translation_for_vec3(origin),
|
||||
matrix4_translation_for_vec3(translation)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
inline Vector3 origin_snapped(const Vector3& origin, float snap)
|
||||
{
|
||||
return vector3_snapped(origin, snap);
|
||||
}
|
||||
|
||||
class OriginKey
|
||||
{
|
||||
Callback m_originChanged;
|
||||
public:
|
||||
Vector3 m_origin;
|
||||
|
||||
|
||||
OriginKey(const Callback& originChanged)
|
||||
: m_originChanged(originChanged), m_origin(ORIGINKEY_IDENTITY)
|
||||
{
|
||||
}
|
||||
|
||||
void originChanged(const char* value)
|
||||
{
|
||||
read_origin(m_origin, value);
|
||||
m_originChanged();
|
||||
}
|
||||
typedef MemberCaller1<OriginKey, const char*, &OriginKey::originChanged> OriginChangedCaller;
|
||||
|
||||
|
||||
void write(Entity* entity) const
|
||||
{
|
||||
write_origin(m_origin, entity, "origin");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#include "scenelib.h"
|
||||
|
||||
inline BrushDoom3* Node_getBrushDoom3(scene::Node& node)
|
||||
{
|
||||
return NodeTypeCast<BrushDoom3>::cast(node);
|
||||
}
|
||||
|
||||
inline void BrushDoom3_setDoom3GroupOrigin(scene::Node& node, const Vector3& origin)
|
||||
{
|
||||
BrushDoom3* brush = Node_getBrushDoom3(node);
|
||||
if(brush != 0)
|
||||
{
|
||||
brush->setDoom3GroupOrigin(origin);
|
||||
}
|
||||
}
|
||||
|
||||
class SetDoom3GroupOriginWalker : public scene::Traversable::Walker
|
||||
{
|
||||
const Vector3& m_origin;
|
||||
public:
|
||||
SetDoom3GroupOriginWalker(const Vector3& origin) : m_origin(origin)
|
||||
{
|
||||
}
|
||||
bool pre(scene::Node& node) const
|
||||
{
|
||||
BrushDoom3_setDoom3GroupOrigin(node, m_origin);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class Doom3GroupOrigin : public scene::Traversable::Observer
|
||||
{
|
||||
scene::Traversable& m_set;
|
||||
const Vector3& m_origin;
|
||||
bool m_enabled;
|
||||
|
||||
public:
|
||||
Doom3GroupOrigin(scene::Traversable& set, const Vector3& origin) : m_set(set), m_origin(origin), m_enabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
originChanged();
|
||||
}
|
||||
void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
void originChanged()
|
||||
{
|
||||
if(m_enabled)
|
||||
{
|
||||
m_set.traverse(SetDoom3GroupOriginWalker(m_origin));
|
||||
}
|
||||
}
|
||||
|
||||
void insert(scene::Node& node)
|
||||
{
|
||||
if(m_enabled)
|
||||
{
|
||||
BrushDoom3_setDoom3GroupOrigin(node, m_origin);
|
||||
}
|
||||
}
|
||||
void erase(scene::Node& node)
|
||||
{
|
||||
if(m_enabled)
|
||||
{
|
||||
BrushDoom3_setDoom3GroupOrigin(node, Vector3(0, 0, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
163
plugins/entity/plugin.cpp
Normal file
163
plugins/entity/plugin.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
#include "debugging/debugging.h"
|
||||
|
||||
#include "iscenegraph.h"
|
||||
#include "irender.h"
|
||||
#include "iselection.h"
|
||||
#include "ientity.h"
|
||||
#include "iundo.h"
|
||||
#include "ieclass.h"
|
||||
#include "igl.h"
|
||||
#include "ireference.h"
|
||||
#include "ifilter.h"
|
||||
#include "preferencesystem.h"
|
||||
#include "qerplugin.h"
|
||||
#include "namespace.h"
|
||||
#include "modelskin.h"
|
||||
|
||||
#include "typesystem.h"
|
||||
|
||||
#include "entity.h"
|
||||
#include "skincache.h"
|
||||
|
||||
#include "modulesystem/singletonmodule.h"
|
||||
|
||||
class EntityDependencies :
|
||||
public GlobalRadiantModuleRef,
|
||||
public GlobalOpenGLModuleRef,
|
||||
public GlobalUndoModuleRef,
|
||||
public GlobalSceneGraphModuleRef,
|
||||
public GlobalShaderCacheModuleRef,
|
||||
public GlobalSelectionModuleRef,
|
||||
public GlobalReferenceModuleRef,
|
||||
public GlobalFilterModuleRef,
|
||||
public GlobalPreferenceSystemModuleRef,
|
||||
public GlobalNamespaceModuleRef,
|
||||
public GlobalModelSkinCacheModuleRef
|
||||
{
|
||||
};
|
||||
|
||||
class EntityQ3API : public TypeSystemRef
|
||||
{
|
||||
EntityCreator* m_entityq3;
|
||||
public:
|
||||
typedef EntityCreator Type;
|
||||
STRING_CONSTANT(Name, "quake3");
|
||||
|
||||
EntityQ3API()
|
||||
{
|
||||
Entity_Construct();
|
||||
|
||||
m_entityq3 = &GetEntityCreator();
|
||||
|
||||
GlobalReferenceCache().setEntityCreator(*m_entityq3);
|
||||
}
|
||||
~EntityQ3API()
|
||||
{
|
||||
Entity_Destroy();
|
||||
}
|
||||
EntityCreator* getTable()
|
||||
{
|
||||
return m_entityq3;
|
||||
}
|
||||
};
|
||||
|
||||
typedef SingletonModule<EntityQ3API, EntityDependencies> EntityQ3Module;
|
||||
|
||||
EntityQ3Module g_EntityQ3Module;
|
||||
|
||||
|
||||
class EntityWolfAPI : public TypeSystemRef
|
||||
{
|
||||
EntityCreator* m_entitywolf;
|
||||
public:
|
||||
typedef EntityCreator Type;
|
||||
STRING_CONSTANT(Name, "wolf");
|
||||
|
||||
EntityWolfAPI()
|
||||
{
|
||||
Entity_Construct(eGameTypeRTCW);
|
||||
|
||||
m_entitywolf = &GetEntityCreator();
|
||||
|
||||
GlobalReferenceCache().setEntityCreator(*m_entitywolf);
|
||||
}
|
||||
~EntityWolfAPI()
|
||||
{
|
||||
Entity_Destroy();
|
||||
}
|
||||
EntityCreator* getTable()
|
||||
{
|
||||
return m_entitywolf;
|
||||
}
|
||||
};
|
||||
|
||||
typedef SingletonModule<EntityWolfAPI, EntityDependencies> EntityWolfModule;
|
||||
|
||||
EntityWolfModule g_EntityWolfModule;
|
||||
|
||||
|
||||
class EntityDoom3API : public TypeSystemRef
|
||||
{
|
||||
EntityCreator* m_entitydoom3;
|
||||
public:
|
||||
typedef EntityCreator Type;
|
||||
STRING_CONSTANT(Name, "doom3");
|
||||
|
||||
EntityDoom3API()
|
||||
{
|
||||
Entity_Construct(eGameTypeDoom3);
|
||||
|
||||
m_entitydoom3 = &GetEntityCreator();
|
||||
|
||||
GlobalReferenceCache().setEntityCreator(*m_entitydoom3);
|
||||
}
|
||||
~EntityDoom3API()
|
||||
{
|
||||
Entity_Destroy();
|
||||
}
|
||||
EntityCreator* getTable()
|
||||
{
|
||||
return m_entitydoom3;
|
||||
}
|
||||
};
|
||||
|
||||
typedef SingletonModule<EntityDoom3API, EntityDependencies> EntityDoom3Module;
|
||||
|
||||
EntityDoom3Module g_EntityDoom3Module;
|
||||
|
||||
|
||||
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer& server)
|
||||
{
|
||||
GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
|
||||
GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
|
||||
GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
|
||||
GlobalModuleServer::instance().set(server);
|
||||
|
||||
g_EntityQ3Module.selfRegister();
|
||||
g_EntityWolfModule.selfRegister();
|
||||
g_EntityDoom3Module.selfRegister();
|
||||
Doom3ModelSkinCacheModule_selfRegister(server);
|
||||
}
|
||||
25
plugins/entity/plugin.h
Normal file
25
plugins/entity/plugin.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_PLUGIN_H)
|
||||
#define INCLUDED_PLUGIN_H
|
||||
|
||||
#endif
|
||||
23
plugins/entity/rotation.cpp
Normal file
23
plugins/entity/rotation.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "rotation.h"
|
||||
|
||||
199
plugins/entity/rotation.h
Normal file
199
plugins/entity/rotation.h
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_ROTATION_H)
|
||||
#define INCLUDED_ROTATION_H
|
||||
|
||||
#include "ientity.h"
|
||||
|
||||
#include "stream/stringstream.h"
|
||||
#include "math/quaternion.h"
|
||||
#include "generic/callback.h"
|
||||
#include "stringio.h"
|
||||
|
||||
#include "angle.h"
|
||||
|
||||
typedef float Float9[9];
|
||||
|
||||
inline void default_rotation(Float9 rotation)
|
||||
{
|
||||
rotation[0] = 1;
|
||||
rotation[1] = 0;
|
||||
rotation[2] = 0;
|
||||
rotation[3] = 0;
|
||||
rotation[4] = 1;
|
||||
rotation[5] = 0;
|
||||
rotation[6] = 0;
|
||||
rotation[7] = 0;
|
||||
rotation[8] = 1;
|
||||
}
|
||||
inline void write_rotation(const Float9 rotation, Entity* entity, const char* key = "rotation")
|
||||
{
|
||||
if(rotation[0] == 1
|
||||
&& rotation[1] == 0
|
||||
&& rotation[2] == 0
|
||||
&& rotation[3] == 0
|
||||
&& rotation[4] == 1
|
||||
&& rotation[5] == 0
|
||||
&& rotation[6] == 0
|
||||
&& rotation[7] == 0
|
||||
&& rotation[8] == 1)
|
||||
{
|
||||
entity->setKeyValue(key, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
StringOutputStream value(256);
|
||||
value << rotation[0] << ' '
|
||||
<< rotation[1] << ' '
|
||||
<< rotation[2] << ' '
|
||||
<< rotation[3] << ' '
|
||||
<< rotation[4] << ' '
|
||||
<< rotation[5] << ' '
|
||||
<< rotation[6] << ' '
|
||||
<< rotation[7] << ' '
|
||||
<< rotation[8];
|
||||
entity->setKeyValue(key, value.c_str());
|
||||
}
|
||||
}
|
||||
inline void read_rotation(Float9 rotation, const char* value)
|
||||
{
|
||||
if(!string_parse_vector(value, rotation, rotation + 9))
|
||||
{
|
||||
default_rotation(rotation);
|
||||
}
|
||||
}
|
||||
|
||||
inline Matrix4 rotation_toMatrix(const Float9 rotation)
|
||||
{
|
||||
return Matrix4(
|
||||
rotation[0],
|
||||
rotation[1],
|
||||
rotation[2],
|
||||
0,
|
||||
rotation[3],
|
||||
rotation[4],
|
||||
rotation[5],
|
||||
0,
|
||||
rotation[6],
|
||||
rotation[7],
|
||||
rotation[8],
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
inline void rotation_fromMatrix(Float9 rotation, const Matrix4& matrix)
|
||||
{
|
||||
rotation[0] = matrix.xx();
|
||||
rotation[1] = matrix.xy();
|
||||
rotation[2] = matrix.xz();
|
||||
rotation[3] = matrix.yx();
|
||||
rotation[4] = matrix.yy();
|
||||
rotation[5] = matrix.yz();
|
||||
rotation[6] = matrix.zx();
|
||||
rotation[7] = matrix.zy();
|
||||
rotation[8] = matrix.zz();
|
||||
}
|
||||
|
||||
inline void rotation_assign(Float9 rotation, const Float9 other)
|
||||
{
|
||||
rotation[0] = other[0];
|
||||
rotation[1] = other[1];
|
||||
rotation[2] = other[2];
|
||||
rotation[3] = other[3];
|
||||
rotation[4] = other[4];
|
||||
rotation[5] = other[5];
|
||||
rotation[6] = other[6];
|
||||
rotation[7] = other[7];
|
||||
rotation[8] = other[8];
|
||||
}
|
||||
|
||||
inline void rotation_rotate(Float9 rotation, const Quaternion& rotate)
|
||||
{
|
||||
rotation_fromMatrix(rotation,
|
||||
matrix4_multiplied_by_matrix4(
|
||||
rotation_toMatrix(rotation),
|
||||
matrix4_rotation_for_quaternion_quantised(rotate)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
inline void read_angle(Float9 rotation, const char* value)
|
||||
{
|
||||
float angle;
|
||||
if(!string_parse_float(value, angle))
|
||||
{
|
||||
default_rotation(rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
rotation_fromMatrix(rotation, matrix4_rotation_for_z_degrees(angle));
|
||||
}
|
||||
}
|
||||
|
||||
class RotationKey
|
||||
{
|
||||
Callback m_rotationChanged;
|
||||
public:
|
||||
Float9 m_rotation;
|
||||
|
||||
|
||||
RotationKey(const Callback& rotationChanged)
|
||||
: m_rotationChanged(rotationChanged)
|
||||
{
|
||||
default_rotation(m_rotation);
|
||||
}
|
||||
|
||||
void angleChanged(const char* value)
|
||||
{
|
||||
read_angle(m_rotation, value);
|
||||
m_rotationChanged();
|
||||
}
|
||||
typedef MemberCaller1<RotationKey, const char*, &RotationKey::angleChanged> AngleChangedCaller;
|
||||
|
||||
void rotationChanged(const char* value)
|
||||
{
|
||||
read_rotation(m_rotation, value);
|
||||
m_rotationChanged();
|
||||
}
|
||||
typedef MemberCaller1<RotationKey, const char*, &RotationKey::rotationChanged> RotationChangedCaller;
|
||||
|
||||
void write(Entity* entity) const
|
||||
{
|
||||
Vector3 euler = matrix4_get_rotation_euler_xyz_degrees(rotation_toMatrix(m_rotation));
|
||||
if(euler[0] == 0 && euler[1] == 0)
|
||||
{
|
||||
entity->setKeyValue("rotation", "");
|
||||
write_angle(euler[2], entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
entity->setKeyValue("angle", "");
|
||||
write_rotation(m_rotation, entity);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
23
plugins/entity/scale.cpp
Normal file
23
plugins/entity/scale.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "scale.h"
|
||||
|
||||
128
plugins/entity/scale.h
Normal file
128
plugins/entity/scale.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_SCALE_H)
|
||||
#define INCLUDED_SCALE_H
|
||||
|
||||
#include "ientity.h"
|
||||
|
||||
#include "math/matrix.h"
|
||||
#include "generic/callback.h"
|
||||
#include "stringio.h"
|
||||
|
||||
const Vector3 SCALEKEY_IDENTITY = Vector3(1, 1, 1);
|
||||
|
||||
inline void default_scale(Vector3& scale)
|
||||
{
|
||||
scale = SCALEKEY_IDENTITY;
|
||||
}
|
||||
inline void read_scale(Vector3& scalevec, const char* value)
|
||||
{
|
||||
float scale;
|
||||
if(!string_parse_float(value, scale)
|
||||
|| scale == 0)
|
||||
{
|
||||
default_scale(scalevec);
|
||||
}
|
||||
else
|
||||
{
|
||||
scalevec = Vector3(scale, scale, scale);
|
||||
}
|
||||
}
|
||||
inline void read_scalevec(Vector3& scale, const char* value)
|
||||
{
|
||||
if(!string_parse_vector3(value, scale)
|
||||
|| scale[0] == 0
|
||||
|| scale[1] == 0
|
||||
|| scale[2] == 0)
|
||||
default_scale(scale);
|
||||
}
|
||||
inline void write_scale(const Vector3& scale, Entity* entity)
|
||||
{
|
||||
if(scale[0] == 1 && scale[1] == 1 && scale[2] == 1)
|
||||
{
|
||||
entity->setKeyValue("modelscale", "");
|
||||
entity->setKeyValue("modelscale_vec", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
char value[64];
|
||||
|
||||
if(scale[0] == scale[1] && scale[0] == scale[2])
|
||||
{
|
||||
sprintf(value, "%g", scale[0]);
|
||||
entity->setKeyValue("modelscale_vec", "");
|
||||
entity->setKeyValue("modelscale", value);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(value, "%g %g %g", scale[0], scale[1], scale[2]);
|
||||
entity->setKeyValue("modelscale", "");
|
||||
entity->setKeyValue("modelscale_vec", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline Vector3 scale_scaled(const Vector3& scale, const Vector3& scaling)
|
||||
{
|
||||
return matrix4_get_scale_vec3(
|
||||
matrix4_multiplied_by_matrix4(
|
||||
matrix4_scale_for_vec3(scale),
|
||||
matrix4_scale_for_vec3(scaling)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
class ScaleKey
|
||||
{
|
||||
Callback m_scaleChanged;
|
||||
public:
|
||||
Vector3 m_scale;
|
||||
|
||||
|
||||
ScaleKey(const Callback& scaleChanged)
|
||||
: m_scaleChanged(scaleChanged), m_scale(SCALEKEY_IDENTITY)
|
||||
{
|
||||
}
|
||||
|
||||
void uniformScaleChanged(const char* value)
|
||||
{
|
||||
read_scale(m_scale, value);
|
||||
m_scaleChanged();
|
||||
}
|
||||
typedef MemberCaller1<ScaleKey, const char*, &ScaleKey::uniformScaleChanged> UniformScaleChangedCaller;
|
||||
|
||||
void scaleChanged(const char* value)
|
||||
{
|
||||
read_scalevec(m_scale, value);
|
||||
m_scaleChanged();
|
||||
}
|
||||
typedef MemberCaller1<ScaleKey, const char*, &ScaleKey::scaleChanged> ScaleChangedCaller;
|
||||
|
||||
void write(Entity* entity) const
|
||||
{
|
||||
write_scale(m_scale, entity);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
348
plugins/entity/skincache.cpp
Normal file
348
plugins/entity/skincache.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "skincache.h"
|
||||
|
||||
#include "ifilesystem.h"
|
||||
#include "iscriplib.h"
|
||||
#include "iarchive.h"
|
||||
#include "modelskin.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "stream/stringstream.h"
|
||||
#include "generic/callback.h"
|
||||
#include "container/cache.h"
|
||||
#include "container/hashfunc.h"
|
||||
#include "os/path.h"
|
||||
#include "moduleobservers.h"
|
||||
#include "modulesystem/singletonmodule.h"
|
||||
#include "stringio.h"
|
||||
|
||||
void parseShaderName(CopiedString& name, const char* token)
|
||||
{
|
||||
StringOutputStream cleaned(256);
|
||||
cleaned << PathCleaned(token);
|
||||
name = cleaned.c_str();
|
||||
}
|
||||
|
||||
class Doom3ModelSkin
|
||||
{
|
||||
typedef std::map<CopiedString, CopiedString> Remaps;
|
||||
Remaps m_remaps;
|
||||
public:
|
||||
bool parseTokens(Tokeniser& tokeniser)
|
||||
{
|
||||
RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
|
||||
tokeniser.nextLine();
|
||||
for(;;)
|
||||
{
|
||||
const char* token = tokeniser.getToken();
|
||||
if(token == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(string_equal(token, "}"))
|
||||
{
|
||||
tokeniser.nextLine();
|
||||
return true;
|
||||
}
|
||||
else if(string_equal(token, "model"))
|
||||
{
|
||||
//const char* model =
|
||||
tokeniser.getToken();
|
||||
}
|
||||
else
|
||||
{
|
||||
CopiedString from, to;
|
||||
parseShaderName(from, token);
|
||||
|
||||
tokeniser.nextLine(); // hack to handle badly formed skins
|
||||
|
||||
parseShaderName(to, tokeniser.getToken());
|
||||
|
||||
if(!string_equal(from.c_str(), to.c_str()))
|
||||
{
|
||||
m_remaps.insert(Remaps::value_type(from, to));
|
||||
}
|
||||
}
|
||||
tokeniser.nextLine();
|
||||
}
|
||||
}
|
||||
const char* getRemap(const char* name) const
|
||||
{
|
||||
Remaps::const_iterator i = m_remaps.find(name);
|
||||
if(i != m_remaps.end())
|
||||
{
|
||||
return (*i).second.c_str();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
void forEachRemap(const SkinRemapCallback& callback) const
|
||||
{
|
||||
for(Remaps::const_iterator i = m_remaps.begin(); i != m_remaps.end(); ++i)
|
||||
{
|
||||
callback(SkinRemap((*i).first.c_str(), (*i).second.c_str()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class GlobalSkins
|
||||
{
|
||||
public:
|
||||
typedef std::map<CopiedString, Doom3ModelSkin> SkinMap;
|
||||
SkinMap m_skins;
|
||||
Doom3ModelSkin g_nullSkin;
|
||||
|
||||
Doom3ModelSkin& getSkin(const char* name)
|
||||
{
|
||||
SkinMap::iterator i = m_skins.find(name);
|
||||
if(i != m_skins.end())
|
||||
{
|
||||
return (*i).second;
|
||||
}
|
||||
|
||||
return g_nullSkin;
|
||||
}
|
||||
|
||||
bool parseTokens(Tokeniser& tokeniser)
|
||||
{
|
||||
tokeniser.nextLine();
|
||||
for(;;)
|
||||
{
|
||||
const char* token = tokeniser.getToken();
|
||||
if(token == 0)
|
||||
{
|
||||
// end of token stream
|
||||
return true;
|
||||
}
|
||||
if(!string_equal(token, "skin"))
|
||||
{
|
||||
Tokeniser_unexpectedError(tokeniser, token, "skin");
|
||||
return false;
|
||||
}
|
||||
const char* other = tokeniser.getToken();
|
||||
if(other == 0)
|
||||
{
|
||||
Tokeniser_unexpectedError(tokeniser, token, "#string");
|
||||
return false;
|
||||
}
|
||||
CopiedString name;
|
||||
parseShaderName(name, other);
|
||||
Doom3ModelSkin& skin = m_skins[name];
|
||||
RETURN_FALSE_IF_FAIL(skin.parseTokens(tokeniser));
|
||||
}
|
||||
}
|
||||
|
||||
void parseFile(const char* name)
|
||||
{
|
||||
StringOutputStream relativeName(64);
|
||||
relativeName << "skins/" << name;
|
||||
ArchiveTextFile* file = GlobalFileSystem().openTextFile(relativeName.c_str());
|
||||
if(file != 0)
|
||||
{
|
||||
globalOutputStream() << "parsing skins from " << makeQuoted(name) << "\n";
|
||||
{
|
||||
Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewSimpleTokeniser(file->getInputStream());
|
||||
parseTokens(tokeniser);
|
||||
tokeniser.release();
|
||||
}
|
||||
file->release();
|
||||
}
|
||||
else
|
||||
{
|
||||
globalErrorStream() << "failed to open " << makeQuoted(name) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
typedef MemberCaller1<GlobalSkins, const char*, &GlobalSkins::parseFile> ParseFileCaller;
|
||||
|
||||
void construct()
|
||||
{
|
||||
GlobalFileSystem().forEachFile("skins/", "skin", ParseFileCaller(*this));
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
m_skins.clear();
|
||||
}
|
||||
|
||||
void realise()
|
||||
{
|
||||
construct();
|
||||
}
|
||||
void unrealise()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
};
|
||||
|
||||
GlobalSkins g_skins;
|
||||
|
||||
|
||||
class Doom3ModelSkinCacheElement : public ModelSkin
|
||||
{
|
||||
ModuleObservers m_observers;
|
||||
Doom3ModelSkin* m_skin;
|
||||
public:
|
||||
Doom3ModelSkinCacheElement() : m_skin(0)
|
||||
{
|
||||
}
|
||||
void attach(ModuleObserver& observer)
|
||||
{
|
||||
m_observers.attach(observer);
|
||||
if(realised())
|
||||
{
|
||||
observer.realise();
|
||||
}
|
||||
}
|
||||
void detach(ModuleObserver& observer)
|
||||
{
|
||||
if(realised())
|
||||
{
|
||||
observer.unrealise();
|
||||
}
|
||||
m_observers.detach(observer);
|
||||
}
|
||||
bool realised() const
|
||||
{
|
||||
return m_skin != 0;
|
||||
}
|
||||
void realise(const char* name)
|
||||
{
|
||||
ASSERT_MESSAGE(!realised(), "Doom3ModelSkinCacheElement::realise: already realised");
|
||||
m_skin = &g_skins.getSkin(name);
|
||||
m_observers.realise();
|
||||
}
|
||||
void unrealise()
|
||||
{
|
||||
ASSERT_MESSAGE(realised(), "Doom3ModelSkinCacheElement::unrealise: not realised");
|
||||
m_observers.unrealise();
|
||||
m_skin = 0;
|
||||
}
|
||||
const char* getRemap(const char* name) const
|
||||
{
|
||||
ASSERT_MESSAGE(realised(), "Doom3ModelSkinCacheElement::getRemap: not realised");
|
||||
return m_skin->getRemap(name);
|
||||
}
|
||||
void forEachRemap(const SkinRemapCallback& callback) const
|
||||
{
|
||||
ASSERT_MESSAGE(realised(), "Doom3ModelSkinCacheElement::forEachRemap: not realised");
|
||||
m_skin->forEachRemap(callback);
|
||||
}
|
||||
};
|
||||
|
||||
class Doom3ModelSkinCache : public ModelSkinCache, public ModuleObserver
|
||||
{
|
||||
class CreateDoom3ModelSkin
|
||||
{
|
||||
Doom3ModelSkinCache& m_cache;
|
||||
public:
|
||||
explicit CreateDoom3ModelSkin(Doom3ModelSkinCache& cache)
|
||||
: m_cache(cache)
|
||||
{
|
||||
}
|
||||
Doom3ModelSkinCacheElement* construct(const CopiedString& name)
|
||||
{
|
||||
Doom3ModelSkinCacheElement* skin = new Doom3ModelSkinCacheElement;
|
||||
if(m_cache.realised())
|
||||
{
|
||||
skin->realise(name.c_str());
|
||||
}
|
||||
return skin;
|
||||
}
|
||||
void destroy(Doom3ModelSkinCacheElement* skin)
|
||||
{
|
||||
if(m_cache.realised())
|
||||
{
|
||||
skin->unrealise();
|
||||
}
|
||||
delete skin;
|
||||
}
|
||||
};
|
||||
|
||||
typedef HashedCache<CopiedString, Doom3ModelSkinCacheElement, HashString, std::equal_to<CopiedString>, CreateDoom3ModelSkin> Cache;
|
||||
Cache m_cache;
|
||||
bool m_realised;
|
||||
|
||||
public:
|
||||
typedef ModelSkinCache Type;
|
||||
STRING_CONSTANT(Name, "*");
|
||||
ModelSkinCache* getTable()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
Doom3ModelSkinCache() : m_cache(CreateDoom3ModelSkin(*this)), m_realised(false)
|
||||
{
|
||||
GlobalFileSystem().attach(*this);
|
||||
}
|
||||
~Doom3ModelSkinCache()
|
||||
{
|
||||
GlobalFileSystem().detach(*this);
|
||||
}
|
||||
|
||||
ModelSkin& capture(const char* name)
|
||||
{
|
||||
return *m_cache.capture(name);
|
||||
}
|
||||
void release(const char* name)
|
||||
{
|
||||
m_cache.release(name);
|
||||
}
|
||||
|
||||
bool realised() const
|
||||
{
|
||||
return m_realised;
|
||||
}
|
||||
void realise()
|
||||
{
|
||||
g_skins.realise();
|
||||
m_realised = true;
|
||||
for(Cache::iterator i = m_cache.begin(); i != m_cache.end(); ++i)
|
||||
{
|
||||
(*i).value->realise((*i).key.c_str());
|
||||
}
|
||||
}
|
||||
void unrealise()
|
||||
{
|
||||
m_realised = false;
|
||||
for(Cache::iterator i = m_cache.begin(); i != m_cache.end(); ++i)
|
||||
{
|
||||
(*i).value->unrealise();
|
||||
}
|
||||
g_skins.unrealise();
|
||||
}
|
||||
};
|
||||
|
||||
class Doom3ModelSkinCacheDependencies : public GlobalFileSystemModuleRef, public GlobalScripLibModuleRef
|
||||
{
|
||||
};
|
||||
|
||||
typedef SingletonModule<Doom3ModelSkinCache, Doom3ModelSkinCacheDependencies> Doom3ModelSkinCacheModule;
|
||||
|
||||
Doom3ModelSkinCacheModule g_Doom3ModelSkinCacheModule;
|
||||
|
||||
void Doom3ModelSkinCacheModule_selfRegister(ModuleServer& server)
|
||||
{
|
||||
g_Doom3ModelSkinCacheModule.selfRegister();
|
||||
}
|
||||
|
||||
28
plugins/entity/skincache.h
Normal file
28
plugins/entity/skincache.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_SKINCACHE_H)
|
||||
#define INCLUDED_SKINCACHE_H
|
||||
|
||||
class ModuleServer;
|
||||
void Doom3ModelSkinCacheModule_selfRegister(ModuleServer& server);
|
||||
|
||||
#endif
|
||||
37
plugins/entity/targetable.cpp
Normal file
37
plugins/entity/targetable.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "targetable.h"
|
||||
|
||||
typedef std::map<CopiedString, targetables_t> targetnames_t;
|
||||
|
||||
const char* g_targetable_nameKey = "targetname";
|
||||
|
||||
targetnames_t g_targetnames;
|
||||
|
||||
targetables_t* getTargetables(const char* targetname)
|
||||
{
|
||||
if(targetname[0] == '\0')
|
||||
return 0;
|
||||
return &g_targetnames[targetname];
|
||||
}
|
||||
|
||||
Shader* RenderableTargetingEntity::m_state;
|
||||
452
plugins/entity/targetable.h
Normal file
452
plugins/entity/targetable.h
Normal file
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
Copyright (C) 2001-2006, William Joseph.
|
||||
All Rights Reserved.
|
||||
|
||||
This file is part of GtkRadiant.
|
||||
|
||||
GtkRadiant is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GtkRadiant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GtkRadiant; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if !defined(INCLUDED_TARGETABLE_H)
|
||||
#define INCLUDED_TARGETABLE_H
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include "cullable.h"
|
||||
#include "renderable.h"
|
||||
|
||||
#include "math/line.h"
|
||||
#include "render.h"
|
||||
#include "generic/callback.h"
|
||||
#include "selectionlib.h"
|
||||
#include "entitylib.h"
|
||||
#include "eclasslib.h"
|
||||
#include "stringio.h"
|
||||
|
||||
class Targetable
|
||||
{
|
||||
public:
|
||||
virtual const Vector3& world_position() const = 0;
|
||||
};
|
||||
|
||||
typedef std::set<Targetable*> targetables_t;
|
||||
|
||||
extern const char* g_targetable_nameKey;
|
||||
|
||||
targetables_t* getTargetables(const char* targetname);
|
||||
|
||||
class EntityConnectionLine : public OpenGLRenderable
|
||||
{
|
||||
public:
|
||||
Vector3 start;
|
||||
Vector3 end;
|
||||
|
||||
void render(RenderStateFlags state) const
|
||||
{
|
||||
float s1[2], s2[2];
|
||||
Vector3 dir(vector3_subtracted(end, start));
|
||||
double len = vector3_length(dir);
|
||||
vector3_scale(dir, 8.0 * (1.0 / len));
|
||||
s1[0] = dir[0] - dir[1];
|
||||
s1[1] = dir[0] + dir[1];
|
||||
s2[0] = dir[0] + dir[1];
|
||||
s2[1] = -dir[0] + dir[1];
|
||||
|
||||
glBegin(GL_LINES);
|
||||
|
||||
glVertex3fv(vector3_to_array(start));
|
||||
glVertex3fv(vector3_to_array(end));
|
||||
|
||||
len*=0.0625; // half / 8
|
||||
|
||||
Vector3 arrow(start);
|
||||
for (unsigned int i = 0, count = (len<32)? 1 : static_cast<unsigned int>(len*0.0625); i < count; i++)
|
||||
{
|
||||
vector3_add(arrow, vector3_scaled(dir, (len<32)?len:32));
|
||||
glVertex3fv(vector3_to_array(arrow));
|
||||
glVertex3f(arrow[0]+s1[0], arrow[1]+s1[1], arrow[2]+dir[2]);
|
||||
glVertex3fv(vector3_to_array(arrow));
|
||||
glVertex3f(arrow[0]+s2[0], arrow[1]+s2[1], arrow[2]+dir[2]);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
};
|
||||
|
||||
class TargetedEntity
|
||||
{
|
||||
Targetable& m_targetable;
|
||||
targetables_t* m_targets;
|
||||
|
||||
void construct()
|
||||
{
|
||||
if(m_targets != 0)
|
||||
m_targets->insert(&m_targetable);
|
||||
}
|
||||
void destroy()
|
||||
{
|
||||
if(m_targets != 0)
|
||||
m_targets->erase(&m_targetable);
|
||||
}
|
||||
public:
|
||||
TargetedEntity(Targetable& targetable)
|
||||
: m_targetable(targetable), m_targets(getTargetables(""))
|
||||
{
|
||||
construct();
|
||||
}
|
||||
~TargetedEntity()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
void targetnameChanged(const char* name)
|
||||
{
|
||||
destroy();
|
||||
m_targets = getTargetables(name);
|
||||
construct();
|
||||
}
|
||||
typedef MemberCaller1<TargetedEntity, const char*, &TargetedEntity::targetnameChanged> TargetnameChangedCaller;
|
||||
};
|
||||
|
||||
|
||||
class TargetingEntity
|
||||
{
|
||||
targetables_t* m_targets;
|
||||
public:
|
||||
TargetingEntity() :
|
||||
m_targets(getTargetables(""))
|
||||
{
|
||||
}
|
||||
void targetChanged(const char* target)
|
||||
{
|
||||
m_targets = getTargetables(target);
|
||||
}
|
||||
typedef MemberCaller1<TargetingEntity, const char*, &TargetingEntity::targetChanged> TargetChangedCaller;
|
||||
|
||||
typedef targetables_t::iterator iterator;
|
||||
|
||||
iterator begin() const
|
||||
{
|
||||
if(m_targets == 0)
|
||||
{
|
||||
return iterator();
|
||||
}
|
||||
return m_targets->begin();
|
||||
}
|
||||
iterator end() const
|
||||
{
|
||||
if(m_targets == 0)
|
||||
{
|
||||
return iterator();
|
||||
}
|
||||
return m_targets->end();
|
||||
}
|
||||
size_t size() const
|
||||
{
|
||||
if(m_targets == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return m_targets->size();
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return m_targets == 0 || m_targets->empty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Functor>
|
||||
void TargetingEntity_forEach(const TargetingEntity& targets, const Functor& functor)
|
||||
{
|
||||
for(TargetingEntity::iterator i = targets.begin(); i != targets.end(); ++i)
|
||||
{
|
||||
functor((*i)->world_position());
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::map<std::size_t, TargetingEntity> TargetingEntities;
|
||||
|
||||
template<typename Functor>
|
||||
void TargetingEntities_forEach(const TargetingEntities& targetingEntities, const Functor& functor)
|
||||
{
|
||||
for(TargetingEntities::const_iterator i = targetingEntities.begin(); i != targetingEntities.end(); ++i)
|
||||
{
|
||||
TargetingEntity_forEach((*i).second, functor);
|
||||
}
|
||||
}
|
||||
|
||||
class TargetLinesPushBack
|
||||
{
|
||||
RenderablePointVector& m_targetLines;
|
||||
const Vector3& m_worldPosition;
|
||||
const VolumeTest& m_volume;
|
||||
public:
|
||||
TargetLinesPushBack(RenderablePointVector& targetLines, const Vector3& worldPosition, const VolumeTest& volume) :
|
||||
m_targetLines(targetLines), m_worldPosition(worldPosition), m_volume(volume)
|
||||
{
|
||||
}
|
||||
void operator()(const Vector3& worldPosition) const
|
||||
{
|
||||
if(m_volume.TestLine(segment_for_startend(m_worldPosition, worldPosition)))
|
||||
{
|
||||
m_targetLines.push_back(PointVertex(reinterpret_cast<const Vertex3f&>(m_worldPosition)));
|
||||
m_targetLines.push_back(PointVertex(reinterpret_cast<const Vertex3f&>(worldPosition)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class TargetKeys : public EntityKeyValues::Observer
|
||||
{
|
||||
TargetingEntities m_targetingEntities;
|
||||
Callback m_targetsChanged;
|
||||
|
||||
bool readTargetKey(const char* key, std::size_t& index)
|
||||
{
|
||||
if(string_equal_n(key, "target", 6))
|
||||
{
|
||||
index = 0;
|
||||
if(string_empty(key + 6) || string_parse_size(key + 6, index))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
void setTargetsChanged(const Callback& targetsChanged)
|
||||
{
|
||||
m_targetsChanged = targetsChanged;
|
||||
}
|
||||
void targetsChanged()
|
||||
{
|
||||
m_targetsChanged();
|
||||
}
|
||||
|
||||
void insert(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
std::size_t index;
|
||||
if(readTargetKey(key, index))
|
||||
{
|
||||
TargetingEntities::iterator i = m_targetingEntities.insert(TargetingEntities::value_type(index, TargetingEntity())).first;
|
||||
value.attach(TargetingEntity::TargetChangedCaller((*i).second));
|
||||
targetsChanged();
|
||||
}
|
||||
}
|
||||
void erase(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
std::size_t index;
|
||||
if(readTargetKey(key, index))
|
||||
{
|
||||
TargetingEntities::iterator i = m_targetingEntities.find(index);
|
||||
value.detach(TargetingEntity::TargetChangedCaller((*i).second));
|
||||
m_targetingEntities.erase(i);
|
||||
targetsChanged();
|
||||
}
|
||||
}
|
||||
const TargetingEntities& get() const
|
||||
{
|
||||
return m_targetingEntities;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class RenderableTargetingEntity
|
||||
{
|
||||
TargetingEntity& m_targets;
|
||||
mutable RenderablePointVector m_target_lines;
|
||||
public:
|
||||
static Shader* m_state;
|
||||
|
||||
RenderableTargetingEntity(TargetingEntity& targets)
|
||||
: m_targets(targets), m_target_lines(GL_LINES)
|
||||
{
|
||||
}
|
||||
void compile(const VolumeTest& volume, const Vector3& world_position) const
|
||||
{
|
||||
m_target_lines.clear();
|
||||
m_target_lines.reserve(m_targets.size() * 2);
|
||||
TargetingEntity_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
|
||||
}
|
||||
void render(Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
|
||||
{
|
||||
if(!m_targets.empty())
|
||||
{
|
||||
compile(volume, world_position);
|
||||
if(!m_target_lines.empty())
|
||||
{
|
||||
renderer.addRenderable(m_target_lines, g_matrix4_identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class RenderableTargetingEntities
|
||||
{
|
||||
const TargetingEntities& m_targets;
|
||||
mutable RenderablePointVector m_target_lines;
|
||||
public:
|
||||
static Shader* m_state;
|
||||
|
||||
RenderableTargetingEntities(const TargetingEntities& targets)
|
||||
: m_targets(targets), m_target_lines(GL_LINES)
|
||||
{
|
||||
}
|
||||
void compile(const VolumeTest& volume, const Vector3& world_position) const
|
||||
{
|
||||
m_target_lines.clear();
|
||||
TargetingEntities_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
|
||||
}
|
||||
void render(Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
|
||||
{
|
||||
if(!m_targets.empty())
|
||||
{
|
||||
compile(volume, world_position);
|
||||
if(!m_target_lines.empty())
|
||||
{
|
||||
renderer.addRenderable(m_target_lines, g_matrix4_identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TargetableInstance :
|
||||
public SelectableInstance,
|
||||
public Targetable,
|
||||
public EntityKeyValues::Observer
|
||||
{
|
||||
mutable Vertex3f m_position;
|
||||
EntityKeyValues& m_entity;
|
||||
TargetKeys m_targeting;
|
||||
TargetedEntity m_targeted;
|
||||
RenderableTargetingEntities m_renderable;
|
||||
public:
|
||||
|
||||
TargetableInstance(
|
||||
const scene::Path& path,
|
||||
scene::Instance* parent,
|
||||
void* instance,
|
||||
InstanceTypeCastTable& casts,
|
||||
EntityKeyValues& entity,
|
||||
Targetable& targetable
|
||||
) :
|
||||
SelectableInstance(path, parent, instance, casts),
|
||||
m_entity(entity),
|
||||
m_targeted(targetable),
|
||||
m_renderable(m_targeting.get())
|
||||
{
|
||||
m_entity.attach(*this);
|
||||
m_entity.attach(m_targeting);
|
||||
}
|
||||
~TargetableInstance()
|
||||
{
|
||||
m_entity.detach(m_targeting);
|
||||
m_entity.detach(*this);
|
||||
}
|
||||
|
||||
void setTargetsChanged(const Callback& targetsChanged)
|
||||
{
|
||||
m_targeting.setTargetsChanged(targetsChanged);
|
||||
}
|
||||
void targetsChanged()
|
||||
{
|
||||
m_targeting.targetsChanged();
|
||||
}
|
||||
|
||||
void insert(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
if(string_equal(key, g_targetable_nameKey))
|
||||
{
|
||||
value.attach(TargetedEntity::TargetnameChangedCaller(m_targeted));
|
||||
}
|
||||
}
|
||||
void erase(const char* key, EntityKeyValues::Value& value)
|
||||
{
|
||||
if(string_equal(key, g_targetable_nameKey))
|
||||
{
|
||||
value.detach(TargetedEntity::TargetnameChangedCaller(m_targeted));
|
||||
}
|
||||
}
|
||||
|
||||
const Vector3& world_position() const
|
||||
{
|
||||
#if 1
|
||||
const AABB& bounds = Instance::worldAABB();
|
||||
if(aabb_valid(bounds))
|
||||
{
|
||||
return bounds.origin;
|
||||
}
|
||||
#else
|
||||
const AABB& childBounds = Instance::childBounds();
|
||||
if(aabb_valid(childBounds))
|
||||
{
|
||||
return childBounds.origin;
|
||||
}
|
||||
#endif
|
||||
return localToWorld().t();
|
||||
}
|
||||
|
||||
void render(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
|
||||
renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials);
|
||||
m_renderable.render(renderer, volume, world_position());
|
||||
}
|
||||
|
||||
const TargetingEntities& getTargeting() const
|
||||
{
|
||||
return m_targeting.get();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class RenderableConnectionLines : public Renderable
|
||||
{
|
||||
typedef std::set<TargetableInstance*> TargetableInstances;
|
||||
TargetableInstances m_instances;
|
||||
public:
|
||||
void attach(TargetableInstance& instance)
|
||||
{
|
||||
ASSERT_MESSAGE(m_instances.find(&instance) == m_instances.end(), "cannot attach instance");
|
||||
m_instances.insert(&instance);
|
||||
}
|
||||
void detach(TargetableInstance& instance)
|
||||
{
|
||||
ASSERT_MESSAGE(m_instances.find(&instance) != m_instances.end(), "cannot detach instance");
|
||||
m_instances.erase(&instance);
|
||||
}
|
||||
|
||||
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
for(TargetableInstances::const_iterator i = m_instances.begin(); i != m_instances.end(); ++i)
|
||||
{
|
||||
if((*i)->path().top().get().visible())
|
||||
{
|
||||
(*i)->render(renderer, volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
|
||||
{
|
||||
renderSolid(renderer, volume);
|
||||
}
|
||||
};
|
||||
|
||||
typedef Static<RenderableConnectionLines> StaticRenderableConnectionLines;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user