Line data Source code
1 : /* Copyright (C) 2022 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #ifndef INCLUDED_MODELABSTRACT
19 : #define INCLUDED_MODELABSTRACT
20 :
21 : #include "graphics/Color.h"
22 : #include "graphics/RenderableObject.h"
23 : #include "maths/BoundingBoxOriented.h"
24 : #include "simulation2/helpers/Player.h"
25 :
26 : class CModelDummy;
27 : class CModel;
28 : class CModelDecal;
29 : class CModelParticleEmitter;
30 :
31 : /**
32 : * Abstract base class for graphical objects that are used by units,
33 : * or as props attached to other CModelAbstract objects.
34 : * This includes meshes, terrain decals, and sprites.
35 : * These objects exist in a tree hierarchy.
36 : */
37 : class CModelAbstract : public CRenderableObject
38 : {
39 : NONCOPYABLE(CModelAbstract);
40 :
41 : public:
42 :
43 : /**
44 : * Describes a custom selection shape to be used for a model's selection box instead of the default
45 : * recursive bounding boxes.
46 : */
47 : struct CustomSelectionShape
48 : {
49 : enum EType {
50 : /// The selection shape is determined by an oriented box of custom, user-specified size.
51 : BOX,
52 : /// The selection shape is determined by a cylinder of custom, user-specified size.
53 : CYLINDER
54 : };
55 :
56 : EType m_Type; ///< Type of shape.
57 : float m_Size0; ///< Box width if @ref BOX, or radius if @ref CYLINDER
58 : float m_Size1; ///< Box depth if @ref BOX, or radius if @ref CYLINDER
59 : float m_Height; ///< Box height if @ref BOX, cylinder height if @ref CYLINDER
60 : };
61 :
62 : public:
63 :
64 0 : CModelAbstract()
65 0 : : m_Parent(NULL), m_PositionValid(false), m_ShadingColor(1, 1, 1, 1), m_PlayerID(INVALID_PLAYER),
66 0 : m_SelectionBoxValid(false), m_CustomSelectionShape(NULL)
67 0 : { }
68 :
69 0 : ~CModelAbstract()
70 0 : {
71 0 : delete m_CustomSelectionShape; // allocated and set externally by CCmpVisualActor, but our responsibility to clean up
72 0 : }
73 :
74 : virtual CModelAbstract* Clone() const = 0;
75 :
76 : /// Dynamic cast
77 0 : virtual CModelDummy* ToCModelDummy() { return nullptr; }
78 :
79 : /// Dynamic cast
80 0 : virtual CModel* ToCModel() { return nullptr; }
81 :
82 : /// Dynamic cast
83 0 : virtual CModelDecal* ToCModelDecal() { return nullptr; }
84 :
85 : /// Dynamic cast
86 0 : virtual CModelParticleEmitter* ToCModelParticleEmitter() { return nullptr; }
87 :
88 : // (This dynamic casting is a bit ugly, but we won't have many subclasses
89 : // and this seems the easiest way to integrate with other code that wants
90 : // type-specific processing)
91 :
92 : /// Returns world space bounds of this object and all child objects.
93 0 : virtual const CBoundingBoxAligned GetWorldBoundsRec() { return GetWorldBounds(); } // default implementation
94 :
95 : /**
96 : * Returns the world-space selection box of this model. Used primarily for hittesting against against a selection ray. The
97 : * returned selection box may be empty to indicate that it does not wish to participate in the selection process.
98 : */
99 : virtual const CBoundingBoxOriented& GetSelectionBox();
100 :
101 0 : virtual void InvalidateBounds()
102 : {
103 0 : m_BoundsValid = false;
104 : // a call to this method usually means that the model's transform has changed, i.e. it has moved or rotated, so we'll also
105 : // want to update the selection box accordingly regardless of the shape it is built from.
106 0 : m_SelectionBoxValid = false;
107 0 : }
108 :
109 : /// Sets a custom selection shape as described by a @p descriptor. Argument may be NULL
110 : /// if you wish to keep the default behaviour of using the recursively-calculated bounding boxes.
111 0 : void SetCustomSelectionShape(CustomSelectionShape* descriptor)
112 : {
113 0 : if (m_CustomSelectionShape != descriptor)
114 : {
115 0 : m_CustomSelectionShape = descriptor;
116 0 : m_SelectionBoxValid = false; // update the selection box when it is next requested
117 : }
118 0 : }
119 :
120 : /**
121 : * Returns the (object-space) bounds that should be used to construct a selection box for this model and its children.
122 : * May return an empty bound to indicate that this model and its children should not be selectable themselves, or should
123 : * not be included in its parent model's selection box. This method is used for constructing the default selection boxes,
124 : * as opposed to any boxes of custom shape specified by @ref m_CustomSelectionShape.
125 : *
126 : * If you wish your model type to be included in selection boxes, override this method and have it return the object-space
127 : * bounds of itself, augmented recursively (via this method) with the object-space selection bounds of its children.
128 : */
129 0 : virtual const CBoundingBoxAligned GetObjectSelectionBoundsRec() { return CBoundingBoxAligned::EMPTY; }
130 :
131 : /**
132 : * Called when terrain has changed in the given inclusive bounds.
133 : * Might call SetDirty if the change affects this model.
134 : */
135 : virtual void SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1) = 0;
136 :
137 : /**
138 : * Called when the entity tries to set some variable to affect the display of this model
139 : * and/or its child objects.
140 : */
141 0 : virtual void SetEntityVariable(const std::string& UNUSED(name), float UNUSED(value)) { }
142 :
143 : /**
144 : * Ensure that both the transformation and the bone matrices are correct for this model and all its props.
145 : */
146 : virtual void ValidatePosition() = 0;
147 :
148 : /**
149 : * Mark this model's position and bone matrices, and all props' positions as invalid.
150 : */
151 : virtual void InvalidatePosition() = 0;
152 :
153 0 : virtual void SetPlayerID(player_id_t id) { m_PlayerID = id; }
154 :
155 : // get the model's player ID; initial default is INVALID_PLAYER
156 0 : virtual player_id_t GetPlayerID() const { return m_PlayerID; }
157 :
158 0 : virtual void SetShadingColor(const CColor& color) { m_ShadingColor = color; }
159 0 : virtual const CColor& GetShadingColor() const { return m_ShadingColor; }
160 :
161 : protected:
162 : void CalcSelectionBox();
163 :
164 : public:
165 : /// If non-null, points to the model that we are attached to.
166 : CModelAbstract* m_Parent;
167 :
168 : /// True if both transform and and bone matrices are valid.
169 : bool m_PositionValid;
170 :
171 : player_id_t m_PlayerID;
172 :
173 : /// Modulating color
174 : CColor m_ShadingColor;
175 :
176 : protected:
177 :
178 : /// Selection box for this model.
179 : CBoundingBoxOriented m_SelectionBox;
180 :
181 : /// Is the current selection box valid?
182 : bool m_SelectionBoxValid;
183 :
184 : /// Pointer to a descriptor for a custom-defined selection box shape. If no custom selection box is required, this is NULL
185 : /// and the standard recursive-bounding-box-based selection box is used. Otherwise, a custom selection box described by this
186 : /// field will be used.
187 : /// @see SetCustomSelectionShape
188 : CustomSelectionShape* m_CustomSelectionShape;
189 :
190 : };
191 :
192 : #endif // INCLUDED_MODELABSTRACT
|