Ticket #914: selection_bbox_07oct11.patch
File selection_bbox_07oct11.patch, 87.9 KB (added by , 13 years ago) |
---|
-
binaries/data/mods/public/gui/session/session.xml
diff --git a/binaries/data/mods/public/gui/session/session.xml b/binaries/data/mods/public/gui/session/session.xml index bbf24cb..39e2b5c 100644
a b 89 89 /> 90 90 91 91 <!-- Dev/cheat commands --> 92 <object name="devCommands" size="100%-156 50%-8 0 100%-8 50%+80" type="image" sprite="devCommandsBackground"92 <object name="devCommands" size="100%-156 50%-88 100%-8 50%+88" type="image" sprite="devCommandsBackground" 93 93 hidden="true" hotkey="session.devcommands.toggle"> 94 94 <action on="Press"> 95 95 toggleDeveloperOverlay(); … … 126 126 <action on="Press">Engine.GuiInterfaceCall("SetRangeDebugOverlay", this.checked);</action> 127 127 </object> 128 128 129 <object size="0 96 100%-18 112" type="text" style="devCommandsText">Restrict camera</object> 130 <object size="100%-16 96 100% 112" type="checkbox" style="StoneCrossBox" checked="true"> 129 <object size="0 96 100%-18 112" type="text" style="devCommandsText">Bounding box overlay</object> 130 <object size="100%-16 96 100% 112" type="checkbox" style="StoneCrossBox"> 131 <action on="Press">Engine.SetBoundingBoxDebugOverlay(this.checked);</action> 132 </object> 133 134 <object size="0 112 100%-18 128" type="text" style="devCommandsText">Restrict camera</object> 135 <object size="100%-16 112 100% 128" type="checkbox" style="StoneCrossBox" checked="true"> 131 136 <action on="Press">gameView.constrainCamera = this.checked;</action> 132 137 </object> 133 138 134 <object size="0 1 12 100%-18 128" type="text" style="devCommandsText">Reveal map</object>135 <object name="devCommandsRevealMap" size="100%-16 112 100% 128" type="checkbox" style="StoneCrossBox">139 <object size="0 128 100%-18 144" type="text" style="devCommandsText">Reveal map</object> 140 <object size="100%-16 128 100% 144" type="checkbox" name="devCommandsRevealMap" style="StoneCrossBox"> 136 141 <action on="Press">Engine.PostNetworkCommand({"type": "reveal-map", "enable": this.checked});</action> 137 142 </object> 138 143 139 <object size="0 1 28 100%-18 144" type="text" style="devCommandsText">Enable time warp</object>140 <object size="100%-16 1 28 100% 144" type="checkbox" name="devTimeWarp" style="StoneCrossBox">144 <object size="0 144 100%-18 160" type="text" style="devCommandsText">Enable time warp</object> 145 <object size="100%-16 144 100% 160" type="checkbox" name="devTimeWarp" style="StoneCrossBox"> 141 146 <action on="Press">Engine.EnableTimeWarpRecording(this.checked ? 10 : 0);</action> 142 147 </object> 143 148 144 <object size="0 1 44 100%-18 160" type="text" style="devCommandsText">Promote selected units</object>145 <object size="100%-16 1 44 100% 160" type="button" style="StoneCrossBox">149 <object size="0 160 100%-18 176" type="text" style="devCommandsText">Promote selected units</object> 150 <object size="100%-16 160 100% 176" type="button" style="StoneCrossBox"> 146 151 <action on="Press">Engine.PostNetworkCommand({"type": "promote", "entities": g_Selection.toList()});</action> 147 152 </object> 148 153 </object> -
binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml b/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml index 1ca7667..12874de 100644
a b 16 16 <Type>wood.tree</Type> 17 17 </ResourceSupply> 18 18 <Selectable/> 19 <VisualActor> 20 <SelectionShape type="footprint" /> 21 </VisualActor> 19 22 </Entity> -
source/graphics/Decal.cpp
diff --git a/source/graphics/Decal.cpp b/source/graphics/Decal.cpp index 85b6ef9..06258eb 100644
a b void CModelDecal::CalcBounds() 55 55 { 56 56 ssize_t i0, j0, i1, j1; 57 57 CalcVertexExtents(i0, j0, i1, j1); 58 m_ Bounds = m_Terrain->GetVertexesBound(i0, j0, i1, j1);58 m_WorldBounds = m_Terrain->GetVertexesBound(i0, j0, i1, j1); 59 59 } 60 60 61 61 void CModelDecal::SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1) -
source/graphics/GameView.cpp
diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 7e17a4a..4e8205c 100644
a b void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c) 493 493 CPatch* patch=pTerrain->GetPatch(i,j); // can't fail 494 494 495 495 // If the patch is underwater, calculate a bounding box that also contains the water plane 496 CBound bounds = patch->Get Bounds();496 CBound bounds = patch->GetWorldBounds(); 497 497 float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight + 0.001f; 498 498 if(bounds[1].Y < waterHeight) { 499 499 bounds[1].Y = waterHeight; -
source/graphics/Model.cpp
diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index 704e2b2..a6031c6 100644
a b 33 33 #include "lib/res/graphics/ogl_tex.h" 34 34 #include "lib/res/h_mgr.h" 35 35 #include "ps/Profile.h" 36 37 36 #include "ps/CLogger.h" 38 37 39 38 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// … … void CModel::CalcBounds() 116 115 if (! (m_Anim && m_Anim->m_AnimDef)) 117 116 { 118 117 if (m_ObjectBounds.IsEmpty()) 119 Calc ObjectBounds();118 CalcStaticObjectBounds(); 120 119 } 121 120 else 122 121 { 123 122 if (m_Anim->m_ObjectBounds.IsEmpty()) 124 CalcAnimatedObjectBound (m_Anim->m_AnimDef, m_Anim->m_ObjectBounds);123 CalcAnimatedObjectBounds(m_Anim->m_AnimDef, m_Anim->m_ObjectBounds); 125 124 ENSURE(! m_Anim->m_ObjectBounds.IsEmpty()); // (if this happens, it'll be recalculating the bounds every time) 126 125 m_ObjectBounds = m_Anim->m_ObjectBounds; 127 126 } … … void CModel::CalcBounds() 129 128 // Ensure the transform is set correctly before we use it 130 129 ValidatePosition(); 131 130 132 m_ObjectBounds.Transform(GetTransform(), m_Bounds); 131 // Now transform the object-space bounds to world-space bounds 132 m_ObjectBounds.Transform(GetTransform(), m_WorldBounds); 133 133 } 134 134 135 135 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 136 136 // CalcObjectBounds: calculate object space bounds of this model, based solely on vertex positions 137 void CModel::Calc ObjectBounds()137 void CModel::CalcStaticObjectBounds() 138 138 { 139 139 m_ObjectBounds.SetEmpty(); 140 140 … … void CModel::CalcObjectBounds() 148 148 149 149 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 150 150 // CalcAnimatedObjectBound: calculate bounds encompassing all vertex positions for given animation 151 void CModel::CalcAnimatedObjectBound (CSkeletonAnimDef* anim,CBound& result)151 void CModel::CalcAnimatedObjectBounds(CSkeletonAnimDef* anim, CBound& result) 152 152 { 153 153 result.SetEmpty(); 154 154 … … void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result) 199 199 } 200 200 201 201 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 202 const CBound CModel::Get BoundsRec()202 const CBound CModel::GetWorldBoundsRec() 203 203 { 204 CBound bounds = Get Bounds();204 CBound bounds = GetWorldBounds(); 205 205 for (size_t i = 0; i < m_Props.size(); ++i) 206 bounds += m_Props[i].m_Model->Get BoundsRec();206 bounds += m_Props[i].m_Model->GetWorldBoundsRec(); 207 207 return bounds; 208 208 } 209 209 210 const CBound CModel::GetObjectSelectionBoundsRec() 211 { 212 CBound objBounds = GetObjectBounds(); // updates the (children-not-included) object-space bounds if necessary 213 214 // now extend these bounds to include the props' selection bounds (if any) 215 for (size_t i = 0; i < m_Props.size(); ++i) 216 { 217 const Prop& prop = m_Props[i]; 218 if (prop.m_Hidden) 219 continue; // prop is hidden from rendering, so it also shouldn't be used for selection 220 221 CBound propSelectionBounds = prop.m_Model->GetObjectSelectionBoundsRec(); 222 if (propSelectionBounds.IsEmpty()) 223 continue; // submodel does not wish to participate in selection box, exclude it 224 225 // We have the prop's bounds in its own object-space; now we need to transform them into this coordinate space so 226 // they can be properly added to our object-space. For that, we need the object-space transform of the prop 227 // attachment point. 228 // 229 // We have the prop point information; however, it's not trivial to compute its exact location in our object-space 230 // since it may or may not be attached to a bone (see SPropPoint), which in turn may or may not be in the middle of 231 // an animation. The bone matrices might be of interest, but they're really only meant to be used for the animation 232 // system and are quite opaque to use from the outside (see @ref ValidatePosition). 233 // 234 // However, a nice side effect of ValidatePosition is that it also computes the absolute world-space transform of 235 // our props and sets it on their respective models. In particular, @ref ValidatePosition will compute the prop's 236 // world-space transform as either 237 // 238 // T' = T x B x O 239 // or 240 // T' = T x O 241 // 242 // where T' is the prop's world-space transform, T is our world-space transform, O is the prop's local 243 // offset/rotation matrix, and B is an optional transformation matrix of the bone the prop is attached to 244 // (taking into account animation and everything). 245 // 246 // From this, it is clear that either O or B x O is the object-space transformation matrix of the prop. So, 247 // all we need to do is apply our own inverse world-transform T^(-1) to T' to get our desired result. Luckily, 248 // this is precomputed upon setting the transform matrix (see @ref SetTransform), so it is free to fetch. 249 250 CMatrix3D propObjectTransform = prop.m_Model->GetTransform(); // T' 251 propObjectTransform.Concatenate(GetInvTransform()); // T^(-1) x T' 252 253 // Transform the prop's bounds into our object coordinate space 254 CBound transformedPropSelectionBounds; 255 propSelectionBounds.Transform(propObjectTransform, transformedPropSelectionBounds); 256 257 objBounds += transformedPropSelectionBounds; 258 } 259 260 return objBounds; 261 } 262 210 263 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 211 264 // BuildAnimation: load raw animation frame animation from given file, and build a 212 265 // animation specific to this model … … void CModel::ValidatePosition() 293 346 294 347 m_Anim->m_AnimDef->BuildBoneMatrices(m_AnimTime, m_BoneMatrices, !(m_Flags & MODELFLAG_NOLOOPANIMATION)); 295 348 349 // add world-space transformation to m_BoneMatrices 296 350 const CMatrix3D& transform = GetTransform(); 297 351 for (size_t i = 0; i < m_pModelDef->GetNumBones(); i++) 298 352 m_BoneMatrices[i].Concatenate(transform); … … void CModel::ValidatePosition() 312 366 } 313 367 } 314 368 369 // our own position is now valid; now we can safely update our props' positions without fearing 370 // that doing so will cause a revalidation of this model (see recursion above). 315 371 m_PositionValid = true; 316 372 317 373 // re-position and validate all props … … void CModel::ValidatePosition() 321 377 322 378 CMatrix3D proptransform = prop.m_Point->m_Transform;; 323 379 if (prop.m_Point->m_BoneIndex != 0xff) 380 { 381 // m_BoneMatrices[i] already have world transform pre-applied (see above) 324 382 proptransform.Concatenate(m_BoneMatrices[prop.m_Point->m_BoneIndex]); 383 } 325 384 else 385 { 386 // not relative to any bone; just apply world-space transformation (i.e. relative to object-space origin) 326 387 proptransform.Concatenate(m_Transform); 388 } 327 389 328 390 prop.m_Model->SetTransform(proptransform); 329 391 prop.m_Model->ValidatePosition(); … … void CModel::CopyAnimationFrom(CModel* source) 409 471 void CModel::AddProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry) 410 472 { 411 473 // position model according to prop point position 474 475 // this next call will invalidate the bounds of "model", which will in turn also invalidate the selection box 412 476 model->SetTransform(point->m_Transform); 413 477 model->m_Parent = this; 414 478 … … void CModel::AddAmmoProp(const SPropPoint* point, CModelAbstract* model, CObject 425 489 m_AmmoPropPoint = point; 426 490 m_AmmoLoadedProp = m_Props.size() - 1; 427 491 m_Props[m_AmmoLoadedProp].m_Hidden = true; 492 493 // we only need to invalidate the selection box here if it is based on props and their visibilities 494 if (!m_CustomSelectionShape) 495 m_SelectionBoxValid = false; 428 496 } 429 497 430 498 void CModel::ShowAmmoProp() … … void CModel::ShowAmmoProp() 436 504 for (size_t i = 0; i < m_Props.size(); ++i) 437 505 if (m_Props[i].m_Point == m_AmmoPropPoint) 438 506 m_Props[i].m_Hidden = (i != m_AmmoLoadedProp); 507 508 // we only need to invalidate the selection box here if it is based on props and their visibilities 509 if (!m_CustomSelectionShape) 510 m_SelectionBoxValid = false; 439 511 } 440 512 441 513 void CModel::HideAmmoProp() … … void CModel::HideAmmoProp() 447 519 for (size_t i = 0; i < m_Props.size(); ++i) 448 520 if (m_Props[i].m_Point == m_AmmoPropPoint) 449 521 m_Props[i].m_Hidden = (i == m_AmmoLoadedProp); 522 523 // we only need to invalidate here if the selection box is based on props and their visibilities 524 if (!m_CustomSelectionShape) 525 m_SelectionBoxValid = false; 450 526 } 451 527 452 528 CModelAbstract* CModel::FindFirstAmmoProp() -
source/graphics/Model.h
diff --git a/source/graphics/Model.h b/source/graphics/Model.h index 84efeb6..f75843a 100644
a b public: 54 54 { 55 55 Prop() : m_Point(0), m_Model(0), m_ObjectEntry(0), m_Hidden(false) {} 56 56 57 /** 58 * Location of the prop point within its parent model, relative to either a bone in the parent model or to the 59 * parent model's origin. See the documentation for @ref SPropPoint for more details. 60 * @see SPropPoint 61 */ 57 62 const SPropPoint* m_Point; 63 64 /** 65 * Pointer to the model associated with this prop. Note that the transform matrix held by this model is the full object-to-world 66 * space transform, taking into account all parent model positioning (see @ref CModel::ValidatePosition for positioning logic). 67 * @see CModel::ValidatePosition 68 */ 58 69 CModelAbstract* m_Model; 59 70 CObjectEntry* m_ObjectEntry; 60 71 61 bool m_Hidden; // temporarily removed from rendering72 bool m_Hidden; ///< Should this prop be temporarily removed from rendering? 62 73 }; 63 74 64 75 public: … … public: 75 86 76 87 // setup model from given geometry 77 88 bool InitModel(const CModelDefPtr& modeldef); 78 // calculate the world space bounds of this model79 virtual void CalcBounds();80 89 // update this model's state; 'time' is the absolute time since the start of the animation, in MS 81 90 void UpdateTo(float time); 82 91 … … public: 133 142 m_Props[i].m_Model->SetEntityVariable(name, value); 134 143 } 135 144 136 // calculate object space bounds of this model, based solely on vertex positions 137 void CalcObjectBounds(); 138 // calculate bounds encompassing all vertex positions for given animation 139 void CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result); 145 // --- WORLD/OBJECT SPACE BOUNDS ----------------------------------------------------------------- 146 147 /// Overridden to calculate both the world-space and object-space bounds of this model, and stores the result in 148 /// m_Bounds and m_ObjectBounds, respectively. 149 virtual void CalcBounds(); 140 150 141 virtual const CBound GetBoundsRec(); 151 /// Returns the object-space bounds for this model, excluding its children. 152 const CBound& GetObjectBounds() 153 { 154 RecalculateBoundsIfNecessary(); // recalculates both object-space and world-space bounds if necessary 155 return m_ObjectBounds; 156 } 157 158 virtual const CBound GetWorldBoundsRec(); // reimplemented here 159 160 /// Auxiliary method; calculates object space bounds of this model, based solely on vertex positions, and stores 161 /// the result in m_ObjectBounds. Called by CalcBounds (instead of CalcAnimatedObjectBounds) if it has been determined 162 /// that the object-space bounds are static. 163 void CalcStaticObjectBounds(); 164 165 /// Auxiliary method; calculate object-space bounds encompassing all vertex positions for given animation, and stores 166 /// the result in m_ObjectBounds. Called by CalcBounds (instead of CalcStaticBounds) if it has been determined that the 167 /// object-space bounds need to take animations into account. 168 void CalcAnimatedObjectBounds(CSkeletonAnimDef* anim,CBound& result); 169 170 // --- SELECTION BOX/BOUNDS ---------------------------------------------------------------------- 171 172 /// Reimplemented here since proper models should participate in selection boxes. 173 virtual const CBound GetObjectSelectionBoundsRec(); 142 174 143 175 /** 144 176 * Set transform of this object. … … private: 240 272 CSkeletonAnim* m_Anim; 241 273 // time (in MS) into the current animation 242 274 float m_AnimTime; 243 // current state of all bones on this model; null if associated modeldef isn't skeletal 275 276 /** 277 * Current state of all bones on this model; null if associated modeldef isn't skeletal. 278 * Props may attach to these bones by means of the SPropPoint::m_BoneIndex field; in this case their 279 * transformation matrix held is relative to the bone transformation (see @ref SPropPoint and 280 * @ref CModel::ValidatePosition). 281 * 282 * @see SPropPoint 283 */ 244 284 CMatrix3D* m_BoneMatrices; 245 285 // inverse matrices for the bind pose's bones; null if not skeletal 246 286 CMatrix3D* m_InverseBindBoneMatrices; -
new file source/graphics/ModelAbstract.cpp
diff --git a/source/graphics/ModelAbstract.cpp b/source/graphics/ModelAbstract.cpp new file mode 100644 index 0000000..8995029
- + 1 /* Copyright (C) 2011 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 #include "precompiled.h" 19 20 #include "ModelAbstract.h" 21 22 #include "ps/CLogger.h" 23 24 const CBox& CModelAbstract::GetSelectionBox() 25 { 26 if (!m_SelectionBoxValid) 27 { 28 CalcSelectionBox(); 29 m_SelectionBoxValid = true; 30 } 31 return m_SelectionBox; 32 } 33 34 void CModelAbstract::CalcSelectionBox() 35 { 36 if (m_CustomSelectionShape) 37 { 38 // custom shape 39 switch(m_CustomSelectionShape->m_Type) 40 { 41 case CustomSelectionShape::BOX: 42 { 43 // create object-space bounds according to the information in the descriptor, and transform them to world-space. 44 // the box is centered on the X and Z axes, but extends from 0 to its height on the Y axis. 45 const float width = m_CustomSelectionShape->m_Size0; 46 const float depth = m_CustomSelectionShape->m_Size1; 47 const float height = m_CustomSelectionShape->m_Height; 48 49 CBound bounds; 50 bounds += CVector3D(-width/2.f, 0, -depth/2.f); 51 bounds += CVector3D( width/2.f, height, depth/2.f); 52 53 bounds.Transform(GetTransform(), m_SelectionBox); 54 } 55 break; 56 case CustomSelectionShape::CYLINDER: 57 { 58 // TODO: unimplemented 59 m_SelectionBox.SetEmpty(); 60 LOGWARNING(L"[ModelAbstract] TODO: Cylinder selection boxes are not yet implemented. Use BOX or BOUNDS instead."); 61 } 62 default: 63 { 64 m_SelectionBox.SetEmpty(); 65 LOGWARNING(L"[ModelAbstract] Unrecognized selection shape type: %ld", m_CustomSelectionShape->m_Type); 66 } 67 break; 68 } 69 } 70 else 71 { 72 // standard method 73 74 // Get the object-space bounds that should be used to construct this model (and its children)'s selection box 75 CBound objBounds = GetObjectSelectionBoundsRec(); 76 if (objBounds.IsEmpty()) 77 { 78 m_SelectionBox.SetEmpty(); // model does not wish to participate in selection 79 return; 80 } 81 82 // Prevent the bounding box from extending through the terrain; clip the lower plane at Y=0 in object space. 83 if (objBounds[1].Y > 0.f) // should always be the case, unless the models are defined really weirdly 84 objBounds[0].Y = std::max(0.f, objBounds[0].Y); 85 //objBounds[0].Y = 0; 86 87 // transform object-space axis-aligned bounds to world-space arbitrary-aligned box 88 objBounds.Transform(GetTransform(), m_SelectionBox); 89 } 90 91 } 92 No newline at end of file -
source/graphics/ModelAbstract.h
diff --git a/source/graphics/ModelAbstract.h b/source/graphics/ModelAbstract.h index 2c01968..85ecb68 100644
a b 18 18 #ifndef INCLUDED_MODELABSTRACT 19 19 #define INCLUDED_MODELABSTRACT 20 20 21 #include "maths/Box.h" 21 22 #include "graphics/RenderableObject.h" 22 23 #include "ps/Overlay.h" 23 24 #include "simulation2/helpers/Player.h" … … class CModelAbstract : public CRenderableObject 37 38 NONCOPYABLE(CModelAbstract); 38 39 39 40 public: 40 CModelAbstract() : 41 m_Parent(NULL), m_PositionValid(false), 42 m_ShadingColor(1, 1, 1, 1), m_PlayerID(INVALID_PLAYER) 41 42 /** 43 * Describes a custom selection shape to be used for a model's selection box instead of the default 44 * recursive bounding boxes. 45 */ 46 struct CustomSelectionShape 47 { 48 enum EType { 49 /// The selection shape is determined by an oriented box of custom, user-specified size. 50 BOX, 51 /// The selection shape is determined by a cylinder of custom, user-specified size. 52 CYLINDER 53 }; 54 55 EType m_Type; ///< Type of shape. @see ESource 56 float m_Size0; ///< Box width if @ref BOX, or radius if @ref CYLINDER 57 float m_Size1; ///< Box depth if @ref BOX, or radius if @ref CYLINDER 58 float m_Height; ///< Box height if @ref BOX, cylinder height if @ref CYLINDER 59 }; 60 61 public: 62 63 CModelAbstract() 64 : m_Parent(NULL), m_PositionValid(false), m_ShadingColor(1, 1, 1, 1), m_PlayerID(INVALID_PLAYER), 65 m_SelectionBoxValid(false), m_CustomSelectionShape(NULL) 43 66 { 67 m_SelectionBox.SetEmpty(); 68 } 69 70 ~CModelAbstract() 71 { 72 if (m_CustomSelectionShape) // allocated and set externally by CCmpVisualActor, but our responsibility to clean up 73 delete m_CustomSelectionShape; 44 74 } 45 75 46 76 virtual CModelAbstract* Clone() const = 0; … … public: 58 88 // and this seems the easiest way to integrate with other code that wants 59 89 // type-specific processing) 60 90 91 /// Calls SetDirty on this model and all child objects. 92 virtual void SetDirtyRec(int dirtyflags) = 0; 93 94 /// Returns world space bounds of this object and all child objects. 95 virtual const CBound GetWorldBoundsRec() { return GetWorldBounds(); } 96 61 97 /** 62 * Calls SetDirty on this model and all child objects. 98 * Returns the world-space selection box of this model. Used primarily for hittesting against against a selection ray. The 99 * returned selection box may be empty to indicate that it does not wish to participate in the selection process. 63 100 */ 64 virtual void SetDirtyRec(int dirtyflags) = 0; 101 virtual const CBox& GetSelectionBox(); 102 103 virtual void InvalidateBounds() 104 { 105 m_BoundsValid = false; 106 // 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 107 // want to update the selection box accordingly regardless of the shape it is built from. 108 m_SelectionBoxValid = false; 109 } 110 111 /// Sets a custom selection shape as described by a @p descriptor. Argument may be NULL 112 /// if you wish to keep the default behaviour of using the recursively-calculated bounding boxes. 113 void SetCustomSelectionShape(CustomSelectionShape* descriptor) 114 { 115 if (m_CustomSelectionShape != descriptor) 116 { 117 m_CustomSelectionShape = descriptor; 118 m_SelectionBoxValid = false; // update the selection box when it is next requested 119 } 120 } 65 121 66 122 /** 67 * Returns world space bounds of this object and all child objects. 123 * Returns the (object-space) bounds that should be used to construct a selection box for this model and its children. 124 * May return an empty bound to indicate that this model and its children should not be selectable themselves, or should 125 * not be included in its parent model's selection box. This method is used for constructing the default selection boxes, 126 * as opposed to any boxes of custom shape specified by @ref m_CustomSelectionShape. 127 * 128 * If you wish your model type to be included in selection boxes, override this method and have it return the object-space 129 * bounds of itself, augmented recursively (via this method) with the object-space selection bounds of its children. 68 130 */ 69 virtual const CBound Get BoundsRec() { return GetBounds(); }131 virtual const CBound GetObjectSelectionBoundsRec() { return CBound::EMPTY; } 70 132 71 133 /** 72 134 * Called when terrain has changed in the given inclusive bounds. … … public: 81 143 virtual void SetEntityVariable(const std::string& UNUSED(name), float UNUSED(value)) { } 82 144 83 145 /** 84 * Ensure that both the transformation and the bone 85 * matrices are correct for this model and all its props. 146 * Ensure that both the transformation and the bone matrices are correct for this model and all its props. 86 147 */ 87 148 virtual void ValidatePosition() = 0; 88 149 89 150 /** 90 * Mark this model's position and bone matrices, 91 * and all props' positions as invalid. 151 * Mark this model's position and bone matrices, and all props' positions as invalid. 92 152 */ 93 153 virtual void InvalidatePosition() = 0; 94 154 … … public: 100 160 virtual void SetShadingColor(const CColor& colour) { m_ShadingColor = colour; } 101 161 virtual CColor GetShadingColor() const { return m_ShadingColor; } 102 162 103 /// If non-null points to the model that we are attached to. 163 protected: 164 void CalcSelectionBox(); 165 166 public: 167 /// If non-null, points to the model that we are attached to. 104 168 CModelAbstract* m_Parent; 105 169 106 170 /// True if both transform and and bone matrices are valid. … … public: 108 172 109 173 player_id_t m_PlayerID; 110 174 111 // modulating color175 /// Modulating color 112 176 CColor m_ShadingColor; 177 178 protected: 179 180 /// Selection box for this model. 181 CBox m_SelectionBox; 182 183 /// Is the current selection box valid? 184 bool m_SelectionBoxValid; 185 186 /// Pointer to a descriptor for a custom-defined selection box shape. If no custom selection box is required, this is NULL 187 /// and the standard recursive-bounding-box-based selection box is used. Otherwise, a custom selection box described by this 188 /// field will be used. 189 /// @see SetCustomSelectionShape 190 CustomSelectionShape* m_CustomSelectionShape; 191 113 192 }; 114 193 115 194 #endif // INCLUDED_MODELABSTRACT -
source/graphics/ModelDef.h
diff --git a/source/graphics/ModelDef.h b/source/graphics/ModelDef.h index e7ce494..64f509b 100644
a b 32 32 33 33 class CBoneState; 34 34 35 /////////////////////////////////////////////////////////////////////////////// 36 // SPropPoint: structure describing a prop point 35 /** 36 * Describes the position of a prop point within its parent model. A prop point is the location within a parent model 37 * where the prop's origin will be attached. 38 * 39 * A prop point is specified by its transformation matrix (or separately by its position and rotation), which 40 * can be relative to either the parent model's origin, or one of the parent's bones. If the parent model is boned, 41 * then the @ref m_BoneIndex field may specify a bone to which the transformation matrix is relative (see 42 * @ref CModel::m_BoneMatrices). Otherwise, the transformation matrix is assumed to be relative to the parent model's 43 * origin. 44 * 45 * @see CModel::m_BoneMatrices 46 */ 37 47 struct SPropPoint 38 48 { 39 // name of the prop point49 /// Name of the prop point 40 50 CStr m_Name; 41 // position of the point 51 52 /** 53 * Position of the point within the parent model, relative to either the parent model's origin or one of the parent 54 * model's bones if applicable. Also specified as part of @ref m_Transform. 55 * @see m_Transform 56 */ 42 57 CVector3D m_Position; 43 // rotation of the point 58 59 /** 60 * Rotation of the prop model that will be attached at this point. Also specified as part of @ref m_Transform. 61 * @see m_Transform 62 */ 44 63 CQuaternion m_Rotation; 45 // object to parent space transformation 64 65 /** 66 * Object to parent space transformation. Combines both @ref m_Position and @ref m_Rotation in a single 67 * transformation matrix. This transformation is relative to either the parent model's origin, or one of its 68 * bones, depending on whether it is skeletal. If relative to a bone, then the bone in the parent model to 69 * which this transformation is relative may be found by m_BoneIndex. 70 * @see m_Position, m_Rotation 71 */ 46 72 CMatrix3D m_Transform; 47 // index of parent bone; 0xff if unboned 73 74 /** 75 * Index of parent bone to which this prop point is relative, if any. The value 0xFF specifies that either the parent 76 * model is unboned, or that this prop point is relative to the parent model's origin rather than one if its bones. 77 */ 48 78 u8 m_BoneIndex; 49 79 }; 50 80 … … private: 233 263 }; 234 264 235 265 #endif 266 267 No newline at end of file -
source/graphics/ObjectEntry.cpp
diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index 25054ab..069ea31 100644
a b bool CObjectEntry::BuildVariation(const std::vector<std::set<CStr> >& selections 129 129 model->SetTexture(texture); 130 130 131 131 // calculate initial object space bounds, based on vertex positions 132 model->Calc ObjectBounds();132 model->CalcStaticObjectBounds(); 133 133 134 134 // load the animations 135 135 for (std::multimap<CStr, CObjectBase::Anim>::iterator it = variation.anims.begin(); it != variation.anims.end(); ++it) -
source/graphics/Overlay.h
diff --git a/source/graphics/Overlay.h b/source/graphics/Overlay.h index e07b13b..da47d19 100644
a b struct SOverlayLine 36 36 CColor m_Color; 37 37 std::vector<float> m_Coords; // (x, y, z) vertex coordinate triples; shape is not automatically closed 38 38 u8 m_Thickness; // pixels 39 40 /// Utility function; pushes three vertex coordinates at once onto the coordinates array 41 void PushCoords(const float x, const float y, const float z) { m_Coords.push_back(x); m_Coords.push_back(y); m_Coords.push_back(z); } 42 /// Utility function; pushes a vertex location onto the coordinates array 43 void PushCoords(const CVector3D& v) { PushCoords(v.X, v.Y, v.Z); } 39 44 }; 40 45 41 46 /** -
source/graphics/ParticleEmitter.cpp
diff --git a/source/graphics/ParticleEmitter.cpp b/source/graphics/ParticleEmitter.cpp index ab18c17..866b97b 100644
a b void CModelParticleEmitter::CalcBounds() 232 232 // current computed particle positions plus the emitter type's largest 233 233 // potential bounding box at the current position 234 234 235 m_ Bounds = m_Type->CalculateBounds(m_Emitter->GetPosition(), m_Emitter->GetParticleBounds());235 m_WorldBounds = m_Type->CalculateBounds(m_Emitter->GetPosition(), m_Emitter->GetParticleBounds()); 236 236 } 237 237 238 238 void CModelParticleEmitter::ValidatePosition() -
source/graphics/Patch.cpp
diff --git a/source/graphics/Patch.cpp b/source/graphics/Patch.cpp index 38fbf90..e8a1e9c 100644
a b void CPatch::Initialize(CTerrain* parent,ssize_t x,ssize_t z) 57 57 // CalcBounds: calculating the bounds of this patch 58 58 void CPatch::CalcBounds() 59 59 { 60 m_ Bounds.SetEmpty();60 m_WorldBounds.SetEmpty(); 61 61 62 62 for (ssize_t j=0;j<PATCH_SIZE+1;j++) 63 63 { … … void CPatch::CalcBounds() 65 65 { 66 66 CVector3D pos; 67 67 m_Parent->CalcPosition(m_X*PATCH_SIZE+i,m_Z*PATCH_SIZE+j,pos); 68 m_ Bounds+=pos;68 m_WorldBounds+=pos; 69 69 } 70 70 } 71 71 72 72 // If this a side patch, the sides go down to height 0, so add them 73 73 // into the bounds 74 74 if (GetSideFlags()) 75 m_ Bounds[0].Y = std::min(m_Bounds[0].Y, 0.f);75 m_WorldBounds[0].Y = std::min(m_WorldBounds[0].Y, 0.f); 76 76 } 77 77 78 78 int CPatch::GetSideFlags() -
source/graphics/RenderableObject.h
diff --git a/source/graphics/RenderableObject.h b/source/graphics/RenderableObject.h index 1b642f8..338eed5 100644
a b public: 86 86 if (m_RenderData) m_RenderData->m_UpdateFlags|=dirtyflags; 87 87 } 88 88 89 // calculate (and store in m_Bounds) the world space bounds of this object 90 // - must be implemented by all concrete subclasses 89 /** 90 * (Re)calculates and stores any bounds or bound-dependent data for this object. At this level, this is only the world-space bounds stored 91 * in @ref m_WorldBounds; subclasses may use this method to (re)compute additional bounds if necessary, or any data that depends on the 92 * bounds. Whenever bound-dependent data is requested through a public interface, @ref RecalculateBoundsIfNecessary should be called 93 * first to ensure bound correctness, which will in turn call this method if it turns out that they're outdated. 94 * 95 * @see m_BoundsValid 96 * @see RecalculateBoundsIfNecessary 97 */ 91 98 virtual void CalcBounds() = 0; 92 99 93 // return world space bounds of this object 94 const CBound& GetBounds() { 95 if (! m_BoundsValid) { 96 CalcBounds(); 97 m_BoundsValid = true; 98 } 99 return m_Bounds; 100 /// Returns the world-space axis-aligned bounds of this object. 101 const CBound& GetWorldBounds() { 102 RecalculateBoundsIfNecessary(); 103 return m_WorldBounds; 100 104 } 101 105 102 void InvalidateBounds() { m_BoundsValid = false; } 106 /** 107 * Marks the bounds as invalid. This will trigger @ref RecalculateBoundsIfNecessary to recompute any bound-related data the next time 108 * any bound-related data is requested through a public interface -- at least, if you've made sure to call it before returning the 109 * stored data. 110 */ 111 virtual void InvalidateBounds() { m_BoundsValid = false; } 103 112 104 113 // Set the object renderdata and free previous renderdata, if any. 105 114 void SetRenderData(CRenderData* renderdata) { … … public: 107 116 m_RenderData = renderdata; 108 117 } 109 118 110 // return object renderdata - can be null if renderer hasn't yet 111 // created the renderdata 119 /// Return object renderdata - can be null if renderer hasn't yet created the renderdata 112 120 CRenderData* GetRenderData() { return m_RenderData; } 113 121 114 122 protected: 115 // object bounds 116 CBound m_Bounds; 123 /// Factored out so subclasses don't need to repeat this if they want to add additional getters for bounds-related methods 124 /// (since they'll have to make sure to recalc the bounds if necessary before they return it). 125 void RecalculateBoundsIfNecessary() 126 { 127 if (!m_BoundsValid) { 128 CalcBounds(); 129 m_BoundsValid = true; 130 } 131 } 132 133 protected: 134 /// World-space bounds of this object 135 CBound m_WorldBounds; 117 136 // local->world space transform 118 137 CMatrix3D m_Transform; 119 138 // world->local space transform … … protected: 121 140 // object renderdata 122 141 CRenderData* m_RenderData; 123 142 124 private: 125 // remembers whether m_bounds needs to be recalculated 143 /** 144 * Remembers whether any bounds need to be recalculated. Subclasses that add any data that depends on the bounds should 145 * take care to consider the validity of the bounds and recalculate their data when necessary -- overriding @ref CalcBounds 146 * to do so would be a good idea, since it's already set up to be called by @ref RecalculateBoundsIfNecessary whenever the 147 * bounds are marked as invalid. The latter should then be called before returning any bounds or bounds-derived data through 148 * a public interface (see the implementation of @ref GetWorldBounds for an example). 149 * 150 * @see CalcBounds 151 * @see InvalidateBounds 152 * @see RecalculateBoundsIfNecessary 153 */ 126 154 bool m_BoundsValid; 127 155 }; 128 156 -
source/graphics/UnitManager.cpp
diff --git a/source/graphics/UnitManager.cpp b/source/graphics/UnitManager.cpp index d8604fe..0e3d7d1 100644
a b CUnit* CUnitManager::PickUnit(const CVector3D& origin, const CVector3D& dir) con 100 100 CUnit* unit = m_Units[i]; 101 101 float tmin, tmax; 102 102 103 if (unit->GetModel().Get Bounds().RayIntersect(origin, dir, tmin, tmax))103 if (unit->GetModel().GetWorldBounds().RayIntersect(origin, dir, tmin, tmax)) 104 104 { 105 105 // Point of closest approach 106 106 CVector3D obj; 107 unit->GetModel().Get Bounds().GetCentre(obj);107 unit->GetModel().GetWorldBounds().GetCentre(obj); 108 108 CVector3D delta = obj - origin; 109 109 float distance = delta.Dot(dir); 110 110 CVector3D closest = origin + dir * distance; -
source/gui/scripting/ScriptFunctions.cpp
diff --git a/source/gui/scripting/ScriptFunctions.cpp b/source/gui/scripting/ScriptFunctions.cpp index 0054246..7df679a 100644
a b 48 48 #include "simulation2/components/ICmpGuiInterface.h" 49 49 #include "simulation2/components/ICmpRangeManager.h" 50 50 #include "simulation2/components/ICmpTemplateManager.h" 51 #include "simulation2/components/ICmpSelectable.h" 51 52 #include "simulation2/helpers/Selection.h" 52 53 53 54 #include "js/jsapi.h" … … void RewindTimeWarp(void* UNUSED(cbdata)) 456 457 g_Game->GetTurnManager()->RewindTimeWarp(); 457 458 } 458 459 460 void SetBoundingBoxDebugOverlay(void* UNUSED(cbdata), bool enabled) 461 { 462 ICmpSelectable::ms_EnableDebugOverlays = enabled; 463 } 464 459 465 } // namespace 460 466 461 467 void GuiScriptingInit(ScriptInterface& scriptInterface) … … void GuiScriptingInit(ScriptInterface& scriptInterface) 520 526 scriptInterface.RegisterFunction<void, &DumpSimState>("DumpSimState"); 521 527 scriptInterface.RegisterFunction<void, unsigned int, &EnableTimeWarpRecording>("EnableTimeWarpRecording"); 522 528 scriptInterface.RegisterFunction<void, &RewindTimeWarp>("RewindTimeWarp"); 529 scriptInterface.RegisterFunction<void, bool, &SetBoundingBoxDebugOverlay>("SetBoundingBoxDebugOverlay"); 523 530 } -
source/maths/Bound.cpp
diff --git a/source/maths/Bound.cpp b/source/maths/Bound.cpp index bf6d798..a9b8886 100644
a b 28 28 #include <float.h> 29 29 30 30 #include "graphics/Frustum.h" 31 #include "maths/Box.h" 31 32 #include "maths/Brush.h" 32 33 #include "maths/Matrix3D.h" 33 34 35 const CBound CBound::EMPTY = CBound(); // initializes to an empty bound 34 36 35 37 /////////////////////////////////////////////////////////////////////////////// 36 38 // RayIntersect: intersect ray with this bound; return true … … bool CBound::IsEmpty() const 136 138 // Transform: transform this bound by given matrix; return transformed bound 137 139 // in 'result' parameter - slightly modified version of code in Graphic Gems 138 140 // (can't remember which one it was, though) 139 void CBound::Transform(const CMatrix3D& m, CBound& result) const141 void CBound::Transform(const CMatrix3D& m, CBound& result) const 140 142 { 141 143 ENSURE(this!=&result); 142 144 … … void CBound::Transform(const CMatrix3D& m,CBound& result) const 161 163 } 162 164 } 163 165 166 void CBound::Transform(const CMatrix3D& transform, CBox& result) const 167 { 168 // The idea is this: compute the corners of this bounding box, transform them according to the specified matrix, 169 // then derive the box center, orientation vectors, and half-sizes. 170 const CVector3D& pMin = m_Data[0]; 171 const CVector3D& pMax = m_Data[1]; 172 173 // Find the corners of these bounds. We only need some of the corners to derive the information we need, so let's 174 // not actually compute all of them. The corners are numbered starting from the minimum position (m_Data[0]), going 175 // counter-clockwise in the bottom plane, and then in the same order for the top plane (starting from the corner 176 // that's directly above the minimum position). Hence, corner0 is pMin and corner6 is pMax, so we don't need to 177 // custom-create those. 178 179 CVector3D corner0; // corner0 is pMin, no need to copy it 180 CVector3D corner1(pMax.X, pMin.Y, pMin.Z); 181 CVector3D corner3(pMin.X, pMin.Y, pMax.Z); 182 CVector3D corner4(pMin.X, pMax.Y, pMin.Z); 183 CVector3D corner6; // corner6 is pMax, no need to copy it 184 185 // transform corners to world space 186 corner0 = transform.Transform(pMin); // = corner0 187 corner1 = transform.Transform(corner1); 188 corner3 = transform.Transform(corner3); 189 corner4 = transform.Transform(corner4); 190 corner6 = transform.Transform(pMax); // = corner6 191 192 // Compute orientation vectors, half-size vector, and box center. We can get the orientation vectors by just taking 193 // the directional vectors from a specific corner point (corner0) to the other corners, once in each direction. The 194 // half-sizes are similarly computed by taking the distances of those sides and dividing them by 2. Finally, the 195 // center is simply the middle between the transformed pMin and pMax corners. 196 197 const CVector3D sideU(corner1 - corner0); 198 const CVector3D sideV(corner4 - corner0); 199 const CVector3D sideW(corner3 - corner0); 200 201 result.m_Basis[0] = sideU.Normalized(); 202 result.m_Basis[1] = sideV.Normalized(); 203 result.m_Basis[2] = sideW.Normalized(); 204 205 result.m_HalfSizes = CVector3D( 206 sideU.Length()/2.f, 207 sideV.Length()/2.f, 208 sideW.Length()/2.f 209 ); 210 211 result.m_Center = (corner0 + corner6) * 0.5f; 212 } 213 164 214 165 215 /////////////////////////////////////////////////////////////////////////////// 166 216 // Intersect with the given frustum in a conservative manner -
source/maths/Bound.h
diff --git a/source/maths/Bound.h b/source/maths/Bound.h index 7a22eee..9a106b2 100644
a b 27 27 28 28 class CFrustum; 29 29 class CMatrix3D; 30 class CBox; 30 31 31 32 /////////////////////////////////////////////////////////////////////////////// 32 33 // CBound: basic axis aligned bounding box class 33 34 class CBound 34 35 { 35 36 public: 37 36 38 CBound() { SetEmpty(); } 37 CBound(const CVector3D& min,const CVector3D& max) { 38 m_Data[0]=min; m_Data[1]=max; 39 CBound(const CVector3D& min, const CVector3D& max) { 40 m_Data[0] = min; 41 m_Data[1] = max; 39 42 } 40 43 41 void Transform(const CMatrix3D& m,CBound& result) const; 44 /** 45 * Transforms these bounds according to the specified transformation matrix @m, and writes the axis-aligned bounds 46 * of that result to @p result. 47 */ 48 void Transform(const CMatrix3D& m, CBound& result) const; 49 50 /** 51 * Transform these bounds using the matrix @p transform, and write out the result as an arbitrarily-aligned box. 52 * The difference with @ref Transform(const CMatrix3D&, CBound&) is that that method is equivalent to first computing 53 * this result, and then taking the axis-aligned bounding boxes again. 54 */ 55 void Transform(const CMatrix3D& m, CBox& result) const; 42 56 43 57 CVector3D& operator[](int index) { return m_Data[index]; } 44 58 const CVector3D& operator[](int index) const { return m_Data[index]; } … … public: 70 84 return *this; 71 85 } 72 86 73 bool RayIntersect(const CVector3D& origin,const CVector3D& dir,float& tmin,float& tmax) const; 87 /** 88 * Returns true if the ray originating in @p origin and with unit direction vector @p dir intersects this AABB, false otherwise. 89 * Additionally, returns the positive distances from the origin of the ray to the entry and exit points in the bounding box in 90 * @p tmin and @p tmax. See also Real-Time Rendering, Third Edition by T. Akenine-Moller, p. 741--742. 91 * @param origin Origin of the ray. 92 * @param dir Direction vector of the ray. Must be of unit length. 93 */ 94 bool RayIntersect(const CVector3D& origin, const CVector3D& dir, float& tmin, float& tmax) const; 74 95 75 96 // return the volume of this bounding box 76 float GetVolume() const { 77 CVector3D v=m_Data[1]-m_Data[0]; 78 return std::max(v.X, 0.0f)*std::max(v.Y, 0.0f)*std::max(v.Z, 0.0f); 97 float GetVolume() const 98 { 99 CVector3D v = m_Data[1] - m_Data[0]; 100 return (std::max(v.X, 0.0f) * std::max(v.Y, 0.0f) * std::max(v.Z, 0.0f)); 79 101 } 80 102 81 103 // return the centre of this bounding box 82 void GetCentre(CVector3D& centre) const { 83 centre=(m_Data[0]+m_Data[1])*0.5f; 104 void GetCentre(CVector3D& centre) const 105 { 106 centre = (m_Data[0] + m_Data[1]) * 0.5f; 84 107 } 85 108 86 109 /** … … public: 109 132 void Render() const; 110 133 111 134 private: 135 // Holds the minimal and maximal coordinate points in m_Data[0] and m_Data[1], respectively. 112 136 CVector3D m_Data[2]; 137 138 public: 139 static const CBound EMPTY; 140 113 141 }; 114 142 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 115 143 -
new file source/maths/Box.cpp
diff --git a/source/maths/Box.cpp b/source/maths/Box.cpp new file mode 100644 index 0000000..799ba48
- + 1 /* Copyright (C) 2011 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 #include "precompiled.h" 19 20 #include "Box.h" 21 #include "maths/Bound.h" 22 23 #include <float.h> 24 25 const CBox CBox::EMPTY = CBox(); 26 27 CBox::CBox(const CBound& bound) 28 { 29 if (bound.IsEmpty()) 30 { 31 SetEmpty(); 32 } 33 else 34 { 35 bound.GetCentre(m_Center); 36 37 // the axes of an AABB are the world-space axes 38 m_Basis[0].X = 1.f; m_Basis[0].Y = 0.f; m_Basis[0].Z = 0.f; 39 m_Basis[1].X = 0.f; m_Basis[1].Y = 1.f; m_Basis[1].Z = 0.f; 40 m_Basis[2].X = 0.f; m_Basis[2].Y = 0.f; m_Basis[2].Z = 1.f; 41 42 // element-wise division by two to get half sizes (remember, [1] and [0] are the max and min coord points) 43 m_HalfSizes = (bound[1] - bound[0]) * 0.5f; 44 } 45 } 46 47 bool CBox::RayIntersect(const CVector3D& origin, const CVector3D& dir, float& tMin_out, float& tMax_out) const 48 { 49 // See Real-Time Rendering, Third Edition, p. 743 50 float tMin = -FLT_MAX; 51 float tMax = FLT_MAX; 52 53 CVector3D p = m_Center - origin; 54 55 for (int i = 0; i < 3; ++i) 56 { 57 float e = m_Basis[i].Dot(p); 58 float f = m_Basis[i].Dot(dir); 59 60 if(fabs(f) > 1e-10f) 61 { 62 float invF = 1.f/f; 63 float t1 = (e + m_HalfSizes[i]) * invF; 64 float t2 = (e - m_HalfSizes[i]) * invF; 65 66 if (t1 > t2) 67 { 68 float tmp = t1; 69 t1 = t2; 70 t2 = tmp; 71 } 72 if (t1 > tMin) tMin = t1; 73 if (t2 < tMax) tMax = t2; 74 if (tMin > tMax) return false; 75 if (tMax < 0) return false; 76 } 77 else 78 { 79 if(-e - m_HalfSizes[i] > 0 || -e + m_HalfSizes[i] < 0) return false; 80 } 81 } 82 83 tMin_out = tMin; 84 tMax_out = tMax; 85 return true; 86 } 87 No newline at end of file -
new file source/maths/Box.h
diff --git a/source/maths/Box.h b/source/maths/Box.h new file mode 100644 index 0000000..6caebbf
- + 1 /* Copyright (C) 2011 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_BOX 19 #define INCLUDED_BOX 20 21 #include "maths/Vector3D.h" 22 23 class CBound; 24 25 /* 26 * Generic oriented box. Originally intended to be used an Oriented Bounding Box (OBB), as opposed to CBound which is always aligned 27 * to the world-space axes (hence axis-aligned bounding box, or AABB). 28 */ 29 class CBox 30 { 31 public: 32 33 /// Empty constructor; creates an empty box 34 CBox() { SetEmpty(); } 35 36 /** 37 * Constructs a new oriented box centered at @p centered and with normalized side vectors @p u, @p v and @p w. These vectors should 38 * be mutually orthonormal for a proper rectangular box. The half-widths of the box in each direction are given by @p hU, @p hV 39 * and @p hW, respectively. 40 */ 41 CBox(const CVector3D& center, const CVector3D& u, const CVector3D& v, const CVector3D& w, const CVector3D& halfSizes) 42 : m_Center(center), m_HalfSizes(halfSizes) 43 { 44 m_Basis[0] = u; 45 m_Basis[1] = v; 46 m_Basis[2] = w; 47 } 48 49 /// Constructs a new box from an axis-aligned bounding box (AABB). 50 explicit CBox(const CBound& bound); 51 52 /** 53 * Returns true if the ray originating in @p origin and with unit direction vector @p dir intersects this box, false otherwise. 54 * Additionally, returns the positive distances from the origin of the ray to the entry and exit points in the box in 55 * @p tmin and @p tmax. See also Real-Time Rendering, Third Edition by T. Akenine-Möller, p. 741--742. 56 * Should not be used if IsEmpty() is true. 57 * 58 * @param origin Origin of the ray. 59 * @param dir Direction vector of the ray. Must be of unit length. 60 */ 61 bool RayIntersect(const CVector3D& origin, const CVector3D& dir, float& tMin, float& tMax) const; 62 63 /** 64 * Returns the corner at coordinate (@p u, @p v, @p w). Each of @p u, @p v and @p w must be exactly 1 or -1. 65 * Should not be used if IsEmpty() is true. 66 */ 67 void GetCorner(int u, int v, int w, CVector3D& out) const 68 { 69 out = m_Center + m_Basis[0]*(u*m_HalfSizes[0]) + m_Basis[1]*(v*m_HalfSizes[1]) + m_Basis[2]*(w*m_HalfSizes[2]); 70 } 71 72 void SetEmpty() 73 { 74 // everything is zero 75 m_Center = CVector3D(); 76 m_Basis[0] = CVector3D(); 77 m_Basis[1] = CVector3D(); 78 m_Basis[2] = CVector3D(); 79 m_HalfSizes = CVector3D(); 80 } 81 82 bool IsEmpty() const 83 { 84 return ( m_Center.X == 0 && m_Center.Y == 0 && m_Center.Z == 0 && 85 m_Basis[0].X == 0 && m_Basis[0].Y == 0 && m_Basis[0].Z == 0 && 86 m_Basis[1].X == 0 && m_Basis[1].Y == 0 && m_Basis[1].Z == 0 && 87 m_Basis[2].X == 0 && m_Basis[2].Y == 0 && m_Basis[2].Z == 0 && 88 m_HalfSizes.X == 0 && m_HalfSizes.Y == 0 && m_HalfSizes.Z == 0); 89 } 90 91 public: 92 CVector3D m_Center; ///< Centroid location of the box 93 CVector3D m_HalfSizes; ///< Half the sizes of the box in each dimension (u,v,w). Positive values are expected. 94 /// Basis vectors (u,v,w) of the sides. Must always be normalized, and should be 95 /// orthogonal for a proper rectangular cuboid. 96 CVector3D m_Basis[3]; 97 98 static const CBox EMPTY; 99 }; 100 101 #endif INCLUDED_BOX 102 No newline at end of file -
source/maths/Matrix3D.h
diff --git a/source/maths/Matrix3D.h b/source/maths/Matrix3D.h index 0a14bd3..84968db 100644
a b class CMatrix3D 35 35 public: 36 36 // the matrix data itself - accessible as either longhand names 37 37 // or via a flat or 2d array 38 // NOTE: _xy means row x, column y, so don't be fooled by the way they're listed below 38 39 union { 39 40 struct { 40 41 float _11, _21, _31, _41; … … public: 155 156 _14 == m._14 && _24 == m._24 && _34 == m._34 && _44 == m._44; 156 157 } 157 158 159 // inequality 160 bool operator!=(const CMatrix3D& m) const 161 { 162 return !(*this == m); 163 } 164 158 165 // set this matrix to the identity matrix 159 166 void SetIdentity(); 160 167 // set this matrix to the zero matrix -
source/renderer/Renderer.cpp
diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index b8308bc..731f53d 100644
a b public: 1041 1041 1042 1042 bool Filter(CModel *model) 1043 1043 { 1044 return m_Frustum.IsBoxVisible(CVector3D(0, 0, 0), model->Get BoundsRec());1044 return m_Frustum.IsBoxVisible(CVector3D(0, 0, 0), model->GetWorldBoundsRec()); 1045 1045 } 1046 1046 1047 1047 private: … … void CRenderer::SubmitNonRecursive(CModel* model) 1753 1753 { 1754 1754 if (model->GetFlags() & MODELFLAG_CASTSHADOWS) { 1755 1755 // PROFILE( "updating shadow bounds" ); 1756 m->shadow->AddShadowedBound(model->Get Bounds());1756 m->shadow->AddShadowedBound(model->GetWorldBounds()); 1757 1757 } 1758 1758 1759 // Tricky: The call to Get Bounds() above can invalidate the position1759 // Tricky: The call to GetWorldBounds() above can invalidate the position 1760 1760 model->ValidatePosition(); 1761 1761 1762 1762 bool canUseInstancing = false; -
source/renderer/TerrainRenderer.cpp
diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index 13b71bc..56b1eca 100644
a b bool TerrainRenderer::CullPatches(const CFrustum* frustum) 173 173 m->filteredPatches.clear(); 174 174 for (std::vector<CPatchRData*>::iterator it = m->visiblePatches.begin(); it != m->visiblePatches.end(); it++) 175 175 { 176 if (frustum->IsBoxVisible(CVector3D(0, 0, 0), (*it)->GetPatch()->Get Bounds()))176 if (frustum->IsBoxVisible(CVector3D(0, 0, 0), (*it)->GetPatch()->GetWorldBounds())) 177 177 m->filteredPatches.push_back(*it); 178 178 } 179 179 180 180 m->filteredDecals.clear(); 181 181 for (std::vector<CDecalRData*>::iterator it = m->visibleDecals.begin(); it != m->visibleDecals.end(); it++) 182 182 { 183 if (frustum->IsBoxVisible(CVector3D(0, 0, 0), (*it)->GetDecal()->Get Bounds()))183 if (frustum->IsBoxVisible(CVector3D(0, 0, 0), (*it)->GetDecal()->GetWorldBounds())) 184 184 m->filteredDecals.push_back(*it); 185 185 } 186 186 -
source/simulation2/TypeList.h
diff --git a/source/simulation2/TypeList.h b/source/simulation2/TypeList.h index a7ac94b..b2c3042 100644
a b COMPONENT(CommandQueue) 71 71 INTERFACE(Decay) 72 72 COMPONENT(Decay) 73 73 74 // Note: The VisualActor component relies on this component being initialized before itself, in order to support using 75 // an entity's footprint shape for the selection boxes. This dependency is not strictly necessary, but it does avoid 76 // some extra plumbing code to set up on-demand initialization. If you find yourself forced to break this dependency, 77 // see VisualActor's Init method for a description of how you can avoid it. 74 78 INTERFACE(Footprint) 75 79 COMPONENT(Footprint) 76 80 … … COMPONENT(UnitMotionScripted) 142 146 INTERFACE(Vision) 143 147 COMPONENT(Vision) 144 148 149 // Note: this component relies on the Footprint component being initialized before itself. See the comments above for 150 // the Footprint component to find out why. 145 151 INTERFACE(Visual) 146 152 COMPONENT(VisualActor) 147 153 -
source/simulation2/components/CCmpProjectileManager.cpp
diff --git a/source/simulation2/components/CCmpProjectileManager.cpp b/source/simulation2/components/CCmpProjectileManager.cpp index e0ac1cc..c7ffccd 100644
a b void CCmpProjectileManager::RenderSubmit(SceneCollector& collector, const CFrust 347 347 348 348 model.ValidatePosition(); 349 349 350 if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), model.Get Bounds()))350 if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), model.GetWorldBounds())) 351 351 continue; 352 352 353 353 // TODO: do something about LOS (copy from CCmpVisualActor) -
source/simulation2/components/CCmpSelectable.cpp
diff --git a/source/simulation2/components/CCmpSelectable.cpp b/source/simulation2/components/CCmpSelectable.cpp index e9aa3d2..d5865e0 100644
a b 22 22 23 23 #include "ICmpPosition.h" 24 24 #include "ICmpFootprint.h" 25 #include "ICmpVisual.h" 25 26 #include "simulation2/MessageTypes.h" 26 27 #include "simulation2/helpers/Render.h" 27 28 … … public: 153 154 void RenderSubmit(SceneCollector& collector) 154 155 { 155 156 // (This is only called if a > 0) 156 157 157 collector.Submit(&m_Overlay); 158 159 if (ICmpSelectable::ms_EnableDebugOverlays) 160 { 161 static SOverlayLine boundOverlayLine; 162 static SOverlayLine selectionOverlayLine; 163 164 CmpPtr<ICmpVisual> cmpVisual(GetSimContext(), GetEntityId()); 165 if (!cmpVisual.null()) 166 { 167 SimRender::ConstructBoxOutline(cmpVisual->GetBounds(), boundOverlayLine); 168 boundOverlayLine.m_Thickness = 2; 169 boundOverlayLine.m_Color = CColor(1.f, 0.f, 0.f, 1.f); 170 171 SimRender::ConstructBoxOutline(cmpVisual->GetSelectionBox(), selectionOverlayLine); 172 selectionOverlayLine.m_Thickness = 2; 173 selectionOverlayLine.m_Color = CColor(0.f, 1.f, 0.f, 1.f); 174 175 collector.Submit(&boundOverlayLine); 176 collector.Submit(&selectionOverlayLine); 177 } 178 } 158 179 } 159 180 }; 160 181 -
source/simulation2/components/CCmpVisualActor.cpp
diff --git a/source/simulation2/components/CCmpVisualActor.cpp b/source/simulation2/components/CCmpVisualActor.cpp index f35cb80..6965af2 100644
a b 24 24 #include "ICmpRangeManager.h" 25 25 #include "ICmpVision.h" 26 26 #include "simulation2/MessageTypes.h" 27 #include "simulation2/components/ICmpFootprint.h" 27 28 28 29 #include "graphics/Frustum.h" 29 30 #include "graphics/Model.h" … … public: 97 98 "</element>" 98 99 "<element name='SilhouetteOccluder'>" 99 100 "<data type='boolean'/>" 100 "</element>"; 101 "</element>" 102 "<optional>" 103 "<element name='SelectionShape'>" 104 "<choice>" 105 "<attribute name='type'>" 106 "<choice>" 107 "<value>bounds</value>" 108 "<value>footprint</value>" 109 "</choice>" 110 "</attribute>" 111 "<group>" 112 "<attribute name='type'>" 113 "<text/>" 114 "</attribute>" 115 "<attribute name='width'>" 116 "<data type='decimal' />" 117 "</attribute>" 118 "<attribute name='height'>" 119 "<data type='decimal' />" 120 "</attribute>" 121 "<attribute name='depth'>" 122 "<data type='decimal' />" 123 "</attribute>" 124 "</group>" 125 "<group>" 126 "<attribute name='type'>" 127 "<text/>" 128 "</attribute>" 129 "<attribute name='radius'>" 130 "<data type='decimal' />" 131 "</attribute>" 132 "<attribute name='height'>" 133 "<data type='decimal' />" 134 "</attribute>" 135 "</group>" 136 "</choice>" 137 "</element>" 138 "</optional>"; 101 139 } 102 140 103 141 virtual void Init(const CParamNode& paramNode) … … public: 130 168 if (paramNode.GetChild("SilhouetteOccluder").ToBool()) 131 169 modelFlags |= MODELFLAG_SILHOUETTE_OCCLUDER; 132 170 133 if (m_Unit->GetModel().ToCModel()) 134 m_Unit->GetModel().ToCModel()->AddFlagsRec(modelFlags); 171 CModelAbstract& model = m_Unit->GetModel(); 172 if (model.ToCModel()) 173 model.ToCModel()->AddFlagsRec(modelFlags); 174 175 // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the 176 // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint 177 // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in 178 // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just 179 // initialize the selection shape descriptor on-demand. 180 InitSelectionShapeDescriptor(model, paramNode); 135 181 136 182 m_Unit->SetID(GetEntityId()); 137 183 … … public: 223 269 virtual CBound GetBounds() 224 270 { 225 271 if (!m_Unit) 226 return CBound(); 227 return m_Unit->GetModel().GetBounds(); 272 return CBound::EMPTY; 273 return m_Unit->GetModel().GetWorldBounds(); 274 } 275 276 virtual CBox GetSelectionBox() 277 { 278 if (!m_Unit) 279 return CBox::EMPTY; 280 return m_Unit->GetModel().GetSelectionBox(); 228 281 } 229 282 230 283 virtual CVector3D GetPosition() … … private: 381 434 return GetEntityId(); 382 435 } 383 436 437 /// Helper method; initializes the model selection shape descriptor from XML. Factored out for readability of @ref Init. 438 /// The @p model argument is technically not really necessary since naturally this method is intended to initialize this 439 /// visual actor's model (I wouldn't know which other one you'd pass), but it's included here to enforce that the 440 /// component's model must have been created before using this method (i.e. to prevent accidentally calls to this method 441 /// before the model was constructed). 442 void InitSelectionShapeDescriptor(CModelAbstract& model, const CParamNode& paramNode); 443 384 444 void Update(fixed turnLength); 385 445 void Interpolate(float frameTime, float frameOffset); 386 446 void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling); … … private: 388 448 389 449 REGISTER_COMPONENT_TYPE(VisualActor) 390 450 451 // ------------------------------------------------------------------------------------------------------------------ 452 453 void CCmpVisualActor::InitSelectionShapeDescriptor(CModelAbstract& model, const CParamNode& paramNode) 454 { 455 // by default, we don't need a custom selection shape and we can just keep the default behaviour 456 CModelAbstract::CustomSelectionShape* shapeDescriptor = NULL; 457 458 const CParamNode& xmlSelectionShapeNode = paramNode.GetChild("SelectionShape"); 459 if (xmlSelectionShapeNode.IsOk()) 460 { 461 const std::wstring& selectionShapeType = xmlSelectionShapeNode.GetChild("@type").ToString(); // source attribute should always exist 462 if (selectionShapeType == L"bounds") 463 { 464 // default; no need to take action 465 } 466 else 467 { 468 shapeDescriptor = new CModelAbstract::CustomSelectionShape; 469 if (selectionShapeType == L"footprint") 470 { 471 CmpPtr<ICmpFootprint> cmpFootprint(GetSimContext(), GetEntityId()); 472 if (!cmpFootprint.null()) 473 { 474 ICmpFootprint::EShape fpShape; // fp stands for "footprint" 475 entity_pos_t fpSize0, fpSize1, fpHeight; // fp stands for "footprint" 476 cmpFootprint->GetShape(fpShape, fpSize0, fpSize1, fpHeight); 477 478 float size0 = fpSize0.ToFloat(); 479 float size1 = fpSize1.ToFloat(); 480 481 // TODO: we should properly distinguish between CIRCLE and SQUARE footprint shapes here, but since cylinders 482 // aren't implemented yet (and they're almost indistinguishable from boxes for small enough sizes anyway), so 483 // we'll just use boxes for either case. Although, as a basic measure, for circle footprints the size0 and size1 484 // represent the radius, so we do adjust that to match the (full-size) sizes of the square footprints. 485 if (fpShape == ICmpFootprint::CIRCLE) 486 { 487 size0 *= 2; 488 size1 *= 2; 489 } 490 491 shapeDescriptor->m_Type = CModelAbstract::CustomSelectionShape::BOX; 492 shapeDescriptor->m_Size0 = size0; 493 shapeDescriptor->m_Size1 = size1; 494 shapeDescriptor->m_Height = fpHeight.ToFloat(); 495 } 496 else 497 { 498 LOGWARNING(L"Footprint component not yet initialized; cannot apply footprint-based SelectionShape in VisualActor"); 499 } 500 } 501 else if (selectionShapeType == L"box") 502 { 503 shapeDescriptor->m_Type = CModelAbstract::CustomSelectionShape::BOX; 504 shapeDescriptor->m_Size0 = xmlSelectionShapeNode.GetChild("@width").ToFixed().ToFloat(); 505 shapeDescriptor->m_Size1 = xmlSelectionShapeNode.GetChild("@depth").ToFixed().ToFloat(); 506 shapeDescriptor->m_Height = xmlSelectionShapeNode.GetChild("@height").ToFixed().ToFloat(); 507 // TODO: we might need to support the ability to specify a different box center 508 } 509 else if (selectionShapeType == L"cylinder") 510 { 511 LOGWARNING(L"[VisualActor] TODO: cylinder selection shapes are not yet implemented; defaulting to recursive bounding boxes"); 512 } 513 514 } 515 } 516 517 // the model is now responsible for cleaning up the descriptor 518 model.SetCustomSelectionShape(shapeDescriptor); 519 } 520 391 521 void CCmpVisualActor::Update(fixed turnLength) 392 522 { 393 523 if (m_Unit == NULL) … … void CCmpVisualActor::RenderSubmit(SceneCollector& collector, const CFrustum& fr 482 612 483 613 CModelAbstract& model = m_Unit->GetModel(); 484 614 485 if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), model.Get BoundsRec()))615 if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), model.GetWorldBoundsRec())) 486 616 return; 487 617 488 618 collector.SubmitRecursive(&model); -
source/simulation2/components/ICmpSelectable.cpp
diff --git a/source/simulation2/components/ICmpSelectable.cpp b/source/simulation2/components/ICmpSelectable.cpp index 20f0b09..dc959ea 100644
a b 26 26 BEGIN_INTERFACE_WRAPPER(Selectable) 27 27 DEFINE_INTERFACE_METHOD_1("SetSelectionHighlight", void, ICmpSelectable, SetSelectionHighlight, CColor) 28 28 END_INTERFACE_WRAPPER(Selectable) 29 30 bool ICmpSelectable::ms_EnableDebugOverlays = false; 31 No newline at end of file -
source/simulation2/components/ICmpSelectable.h
diff --git a/source/simulation2/components/ICmpSelectable.h b/source/simulation2/components/ICmpSelectable.h index eadd554..0ada93a 100644
a b public: 32 32 virtual void SetSelectionHighlight(CColor color) = 0; 33 33 34 34 DECLARE_INTERFACE_TYPE(Selectable) 35 36 static bool ms_EnableDebugOverlays; 35 37 }; 36 38 37 39 #endif // INCLUDED_ICMPSELECTABLE -
source/simulation2/components/ICmpVisual.h
diff --git a/source/simulation2/components/ICmpVisual.h b/source/simulation2/components/ICmpVisual.h index 68f1108..4d7a12a 100644
a b 20 20 21 21 #include "simulation2/system/Interface.h" 22 22 23 #include "maths/Box.h" 23 24 #include "maths/Bound.h" 24 25 #include "maths/Fixed.h" 25 26 #include "lib/file/vfs/vfs_path.h" … … public: 37 38 virtual CBound GetBounds() = 0; 38 39 39 40 /** 41 * Get the oriented world-space bounding box of the object's visual representation, clipped at the Y=0 plane in object space 42 * to prevent it from extending into the terrain. The primary difference with GetBounds is that this bounding box is not aligned 43 * to the world axes, but arbitrarily rotated according to the model transform. 44 */ 45 virtual CBox GetSelectionBox() = 0; 46 47 /** 40 48 * Get the world-space position of the base point of the object's visual representation. 41 49 * (Not safe for use in simulation code.) 42 50 */ -
source/simulation2/helpers/Render.cpp
diff --git a/source/simulation2/helpers/Render.cpp b/source/simulation2/helpers/Render.cpp index db63115..67e55df 100644
a b 24 24 #include "simulation2/components/ICmpWaterManager.h" 25 25 #include "graphics/Overlay.h" 26 26 #include "graphics/Terrain.h" 27 #include "maths/Bound.h" 28 #include "maths/Box.h" 27 29 #include "maths/MathUtil.h" 28 30 #include "maths/Vector2D.h" 29 31 #include "ps/Profile.h" 32 #include "maths/Quaternion.h" 30 33 31 34 void SimRender::ConstructLineOnGround(const CSimContext& context, const std::vector<float>& xz, 32 35 SOverlayLine& overlay, bool floating, float heightOffset) … … void SimRender::ConstructSquareOnGround(const CSimContext& context, float x, flo 159 162 } 160 163 } 161 164 165 void SimRender::ConstructBoxOutline(const CBound& bound, SOverlayLine& overlayLine) 166 { 167 overlayLine.m_Coords.clear(); 168 169 if (bound.IsEmpty()) 170 return; 171 172 const CVector3D& pMin = bound[0]; 173 const CVector3D& pMax = bound[1]; 174 175 // floor square 176 overlayLine.PushCoords(pMin.X, pMin.Y, pMin.Z); 177 overlayLine.PushCoords(pMax.X, pMin.Y, pMin.Z); 178 overlayLine.PushCoords(pMax.X, pMin.Y, pMax.Z); 179 overlayLine.PushCoords(pMin.X, pMin.Y, pMax.Z); 180 overlayLine.PushCoords(pMin.X, pMin.Y, pMin.Z); 181 // roof square 182 overlayLine.PushCoords(pMin.X, pMax.Y, pMin.Z); 183 overlayLine.PushCoords(pMax.X, pMax.Y, pMin.Z); 184 overlayLine.PushCoords(pMax.X, pMax.Y, pMax.Z); 185 overlayLine.PushCoords(pMin.X, pMax.Y, pMax.Z); 186 overlayLine.PushCoords(pMin.X, pMax.Y, pMin.Z); 187 } 188 189 void SimRender::ConstructBoxOutline(const CBox& box, SOverlayLine& overlayLine) 190 { 191 overlayLine.m_Coords.clear(); 192 193 if (box.IsEmpty()) 194 return; 195 196 CVector3D corners[8]; 197 box.GetCorner(-1, -1, -1, corners[0]); 198 box.GetCorner( 1, -1, -1, corners[1]); 199 box.GetCorner( 1, -1, 1, corners[2]); 200 box.GetCorner(-1, -1, 1, corners[3]); 201 box.GetCorner(-1, 1, -1, corners[4]); 202 box.GetCorner( 1, 1, -1, corners[5]); 203 box.GetCorner( 1, 1, 1, corners[6]); 204 box.GetCorner(-1, 1, 1, corners[7]); 205 206 overlayLine.PushCoords(corners[0]); 207 overlayLine.PushCoords(corners[1]); 208 overlayLine.PushCoords(corners[2]); 209 overlayLine.PushCoords(corners[3]); 210 overlayLine.PushCoords(corners[0]); 211 212 overlayLine.PushCoords(corners[4]); 213 overlayLine.PushCoords(corners[5]); 214 overlayLine.PushCoords(corners[6]); 215 overlayLine.PushCoords(corners[7]); 216 overlayLine.PushCoords(corners[4]); 217 } 218 219 void SimRender::ConstructGimbal(const CVector3D& center, float radius, SOverlayLine& out, size_t numSteps) 220 { 221 ENSURE(numSteps > 0 && numSteps % 4 == 0); // must be a positive multiple of 4 222 223 out.m_Coords.clear(); 224 225 size_t fullCircleSteps = numSteps; 226 const float angleIncrement = 2.f*M_PI/fullCircleSteps; 227 228 const CVector3D X_UNIT(1, 0, 0); 229 const CVector3D Y_UNIT(0, 1, 0); 230 const CVector3D Z_UNIT(0, 0, 1); 231 CVector3D rotationVector(0, 0, radius); // directional vector based in the center that we will be rotating to get the gimbal points 232 233 // first draw a quarter of XZ gimbal; then complete the XY gimbal; then continue the XZ gimbal and finally add the YZ gimbal 234 // (that way we can keep a single continuous line) 235 236 // -- XZ GIMBAL (PART 1/2) ----------------------------------------------- 237 238 CQuaternion xzRotation; 239 xzRotation.FromAxisAngle(Y_UNIT, angleIncrement); 240 241 for (size_t i = 0; i < fullCircleSteps/4; ++i) // complete only a quarter of the way 242 { 243 out.PushCoords(center + rotationVector); 244 rotationVector = xzRotation.Rotate(rotationVector); 245 } 246 247 // -- XY GIMBAL ---------------------------------------------------------- 248 249 // now complete the XY gimbal while the XZ gimbal is interrupted 250 CQuaternion xyRotation; 251 xyRotation.FromAxisAngle(Z_UNIT, angleIncrement); 252 253 for (size_t i = 0; i < fullCircleSteps; ++i) // note the <; the last point of the XY gimbal isn't added, because the XZ gimbal will add it 254 { 255 out.PushCoords(center + rotationVector); 256 rotationVector = xyRotation.Rotate(rotationVector); 257 } 258 259 // -- XZ GIMBAL (PART 2/2) ----------------------------------------------- 260 261 // resume the XZ gimbal to completion 262 for (size_t i = fullCircleSteps/4; i < fullCircleSteps; ++i) // exclude the last point of the circle so the YZ gimbal can add it 263 { 264 out.PushCoords(center + rotationVector); 265 rotationVector = xzRotation.Rotate(rotationVector); 266 } 267 268 // -- YZ GIMBAL ---------------------------------------------------------- 269 270 CQuaternion yzRotation; 271 yzRotation.FromAxisAngle(X_UNIT, angleIncrement); 272 273 for (size_t i = 0; i <= fullCircleSteps; ++i) 274 { 275 out.PushCoords(center + rotationVector); 276 rotationVector = yzRotation.Rotate(rotationVector); 277 } 278 } 279 162 280 void SimRender::SmoothPointsAverage(std::vector<CVector2D>& points, bool closed) 163 281 { 164 282 PROFILE("SmoothPointsAverage"); -
source/simulation2/helpers/Render.h
diff --git a/source/simulation2/helpers/Render.h b/source/simulation2/helpers/Render.h index 0129b01..a8c0a97 100644
a b 25 25 26 26 class CSimContext; 27 27 class CVector2D; 28 class CVector3D; 29 class CBound; 30 class CBox; 28 31 struct SOverlayLine; 29 32 30 33 namespace SimRender … … void ConstructSquareOnGround(const CSimContext& context, float x, float z, float 54 57 bool floating, float heightOffset = 0.25f); 55 58 56 59 /** 60 * Constructs a solid outline of an arbitrarily-aligned box. 61 */ 62 void ConstructBoxOutline(const CBox& box, SOverlayLine& overlayLine); 63 64 /** 65 * Constructs a solid outline of an axis-aligned bounding box. 66 */ 67 void ConstructBoxOutline(const CBound& bound, SOverlayLine& overlayLine); 68 69 /** 70 * Constructs a simple gimbal outline of radius @p radius at @p center in @p out. 71 * @param numSteps The amount of steps to trace a circle's complete outline. Must be a (strictly) positive multiple of four. 72 * For small radii, you can get away with small values; setting this to 4 will create a diamond shape. 73 */ 74 void ConstructGimbal(const CVector3D& center, float radius, SOverlayLine& out, size_t numSteps = 16); 75 76 /** 57 77 * Updates @p points so each point is averaged with its neighbours, resulting in 58 78 * a somewhat smoother curve, assuming the points are roughly equally spaced. 59 79 * If @p closed then the points are treated as a closed path (the last is connected -
source/simulation2/helpers/Selection.cpp
diff --git a/source/simulation2/helpers/Selection.cpp b/source/simulation2/helpers/Selection.cpp index 0405894..d0c02e5 100644
a b std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simu 51 51 if (cmpVisual.null()) 52 52 continue; 53 53 54 CBound bounds = cmpVisual->GetBounds(); 54 CBox selectionBox = cmpVisual->GetSelectionBox(); 55 if (selectionBox.IsEmpty()) 56 continue; 55 57 56 58 float tmin, tmax; 57 if (! bounds.RayIntersect(origin, dir, tmin, tmax))59 if (!selectionBox.RayIntersect(origin, dir, tmin, tmax)) 58 60 continue; 59 61 60 62 // Find the perpendicular distance from the object's centre to the picker ray 61 63 62 CVector3D centre; 63 bounds.GetCentre(centre); 64 65 CVector3D closest = origin + dir * (centre - origin).Dot(dir); 66 float dist2 = (closest - centre).LengthSquared(); 64 CVector3D closest = origin + dir * (selectionBox.m_Center - origin).Dot(dir); 65 float dist2 = (closest - selectionBox.m_Center).LengthSquared(); 67 66 68 67 hits.push_back(std::make_pair(dist2, ent)); 69 68 } -
source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp index 15f46ae..b7d3064 100644
a b enum 44 44 ID_ViewerShadows, 45 45 ID_ViewerPolyCount, 46 46 ID_ViewerAnimation, 47 ID_ViewerBoundingBox, 48 ID_ViewerAxesMarker, 47 49 ID_ViewerPlay, 48 50 ID_ViewerPause, 49 51 ID_ViewerSlow … … static wxWindow* Tooltipped(wxWindow* window, const wxString& tip) 59 61 class ObjectBottomBar : public wxPanel 60 62 { 61 63 public: 62 ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEditor, Observable<ObjectSettings>& objectSettings, Observable<AtObj>& mapSettings, ObjectSidebarImpl* p); 64 ObjectBottomBar( 65 wxWindow* parent, 66 ScenarioEditor& scenarioEditor, 67 Observable<ObjectSettings>& objectSettings, 68 Observable<AtObj>& mapSettings, 69 ObjectSidebarImpl* p 70 ); 63 71 64 72 void OnFirstDisplay(); 65 66 73 void ShowActorViewer(bool show); 67 74 68 75 private: … … private: 75 82 bool m_ViewerGround; 76 83 bool m_ViewerShadows; 77 84 bool m_ViewerPolyCount; 85 bool m_ViewerBoundingBox; 86 bool m_ViewerAxesMarker; 78 87 79 88 wxPanel* m_ViewerPanel; 80 89 81 90 ObjectSidebarImpl* p; 82 83 91 ScenarioEditor& m_ScenarioEditor; 84 92 85 93 DECLARE_EVENT_TABLE(); … … struct ObjectSidebarImpl 108 116 } 109 117 }; 110 118 111 ObjectSidebar::ObjectSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) 112 : Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), p(new ObjectSidebarImpl()) 119 ObjectSidebar::ObjectSidebar( 120 ScenarioEditor& scenarioEditor, 121 wxWindow* sidebarContainer, 122 wxWindow* bottomBarContainer 123 ) 124 : Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), 125 p(new ObjectSidebarImpl()) 113 126 { 114 127 wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); 115 128 sizer->Add(new wxStaticText(this, wxID_ANY, _("Filter")), wxSizerFlags().Align(wxALIGN_CENTER)); 116 sizer->Add(Tooltipped(new wxTextCtrl(this, ID_ObjectFilter), 117 _("Enter text to filter object list")), wxSizerFlags().Expand().Proportion(1)); 129 sizer->Add( 130 Tooltipped( 131 new wxTextCtrl(this, ID_ObjectFilter), 132 _("Enter text to filter object list") 133 ), 134 wxSizerFlags().Expand().Proportion(1) 135 ); 118 136 m_MainSizer->Add(sizer, wxSizerFlags().Expand()); 137 m_MainSizer->AddSpacer(3); 138 139 // ------------------------------------------------------------------------------------------ 119 140 120 141 wxArrayString strings; 121 142 strings.Add(_("Entities")); … … ObjectSidebar::ObjectSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarCo 123 144 wxChoice* objectType = new wxChoice(this, ID_ObjectType, wxDefaultPosition, wxDefaultSize, strings); 124 145 objectType->SetSelection(0); 125 146 m_MainSizer->Add(objectType, wxSizerFlags().Expand()); 147 m_MainSizer->AddSpacer(3); 148 149 // ------------------------------------------------------------------------------------------ 126 150 127 151 p->m_ObjectListBox = new wxListBox(this, ID_SelectObject, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE|wxLB_HSCROLL); 128 152 m_MainSizer->Add(p->m_ObjectListBox, wxSizerFlags().Proportion(1).Expand()); 153 m_MainSizer->AddSpacer(3); 154 155 // ------------------------------------------------------------------------------------------ 129 156 130 157 m_MainSizer->Add(new wxButton(this, ID_ToggleViewer, _("Switch to Actor Viewer")), wxSizerFlags().Expand()); 131 158 132 m_BottomBar = new ObjectBottomBar(bottomBarContainer, scenarioEditor, scenarioEditor.GetObjectSettings(), scenarioEditor.GetMapSettings(), p); 159 // ------------------------------------------------------------------------------------------ 160 161 m_BottomBar = new ObjectBottomBar( 162 bottomBarContainer, 163 scenarioEditor, 164 scenarioEditor.GetObjectSettings(), 165 scenarioEditor.GetMapSettings(), 166 p 167 ); 133 168 134 169 p->m_ToolConn = scenarioEditor.GetToolManager().GetCurrentTool().RegisterObserver(0, &ObjectSidebar::OnToolChange, this); 135 170 } … … END_EVENT_TABLE(); 312 347 313 348 ////////////////////////////////////////////////////////////////////////// 314 349 315 ObjectBottomBar::ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEditor, Observable<ObjectSettings>& objectSettings, Observable<AtObj>& mapSettings, ObjectSidebarImpl* p) 350 ObjectBottomBar::ObjectBottomBar( 351 wxWindow* parent, 352 ScenarioEditor& scenarioEditor, 353 Observable<ObjectSettings>& objectSettings, 354 Observable<AtObj>& mapSettings, 355 ObjectSidebarImpl* p 356 ) 316 357 : wxPanel(parent, wxID_ANY), p(p), m_ScenarioEditor(scenarioEditor) 317 358 { 318 359 m_ViewerWireframe = false; … … ObjectBottomBar::ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEdito 320 361 m_ViewerGround = true; 321 362 m_ViewerShadows = true; 322 363 m_ViewerPolyCount = false; 364 m_ViewerBoundingBox = false; 365 m_ViewerAxesMarker = false; 323 366 324 wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);367 wxSizer* mainSizer = new wxBoxSizer(wxHORIZONTAL); 325 368 369 // --- viewer options panel ------------------------------------------------------------------------------- 326 370 327 371 m_ViewerPanel = new wxPanel(this, wxID_ANY); 328 372 wxSizer* viewerSizer = new wxBoxSizer(wxHORIZONTAL); 329 373 330 wxSizer* viewerButtonsSizer = new wxStaticBoxSizer(wxVERTICAL, m_ViewerPanel, _("Display settings")); 331 viewerButtonsSizer->SetMinSize(140, -1); 332 viewerButtonsSizer->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerWireframe, _("Wireframe")), _("Toggle wireframe / solid rendering")), wxSizerFlags().Expand()); 333 viewerButtonsSizer->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerMove, _("Move")), _("Toggle movement along ground when playing walk/run animations")), wxSizerFlags().Expand()); 334 viewerButtonsSizer->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerGround, _("Ground")), _("Toggle the ground plane")), wxSizerFlags().Expand()); 335 viewerButtonsSizer->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerShadows, _("Shadows")), _("Toggle shadow rendering")), wxSizerFlags().Expand()); 336 viewerButtonsSizer->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerPolyCount, _("Poly count")), _("Toggle polygon-count statistics - turn off ground and shadows for more useful data")), wxSizerFlags().Expand()); 374 wxSizer* viewerButtonsSizer = new wxStaticBoxSizer(wxHORIZONTAL, m_ViewerPanel, _("Display settings")); 375 { 376 wxSizer* viewerButtonsLeft = new wxBoxSizer(wxVERTICAL); 377 viewerButtonsLeft->SetMinSize(110, -1); 378 viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerWireframe, _("Wireframe")), _("Toggle wireframe / solid rendering")), wxSizerFlags().Expand()); 379 viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerMove, _("Move")), _("Toggle movement along ground when playing walk/run animations")), wxSizerFlags().Expand()); 380 viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerGround, _("Ground")), _("Toggle the ground plane")), wxSizerFlags().Expand()); 381 viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerShadows, _("Shadows")), _("Toggle shadow rendering")), wxSizerFlags().Expand()); 382 viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerPolyCount, _("Poly count")), _("Toggle polygon-count statistics - turn off ground and shadows for more useful data")), wxSizerFlags().Expand()); 383 viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerBoundingBox, _("Bounding Boxes")), _("Toggle bounding boxes")), wxSizerFlags().Expand()); 384 385 wxSizer* viewerButtonsRight = new wxBoxSizer(wxVERTICAL); 386 viewerButtonsRight->SetMinSize(110,-1); 387 viewerButtonsRight->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerAxesMarker, _("Axes Marker")), _("Toggle the axes marker (R=X, G=Y, B=Z)")), wxSizerFlags().Expand()); 388 389 viewerButtonsSizer->Add(viewerButtonsLeft, wxSizerFlags().Expand()); 390 viewerButtonsSizer->Add(viewerButtonsRight, wxSizerFlags().Expand()); 391 } 392 337 393 viewerSizer->Add(viewerButtonsSizer, wxSizerFlags().Expand()); 394 viewerSizer->AddSpacer(3); 395 396 // --- animations panel ------------------------------------------------------------------------------- 338 397 339 398 wxSizer* viewerAnimSizer = new wxStaticBoxSizer(wxVERTICAL, m_ViewerPanel, _("Animation")); 340 399 … … ObjectBottomBar::ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEdito 357 416 358 417 viewerSizer->Add(viewerAnimSizer, wxSizerFlags().Expand()); 359 418 419 // --- add viewer-specific options ------------------------------------------------------------------------------- 420 360 421 m_ViewerPanel->SetSizer(viewerSizer); 361 sizer->Add(m_ViewerPanel, wxSizerFlags().Expand());422 mainSizer->Add(m_ViewerPanel, wxSizerFlags().Expand()); 362 423 424 m_ViewerPanel->Layout(); // prevents strange visibility glitch of the animation buttons on my machine (Vista 32-bit SP1) -- vtsj 363 425 m_ViewerPanel->Show(false); 364 426 427 // --- add player/variation selection ------------------------------------------------------------------------------- 365 428 429 wxSizer* playerSelectionSizer = new wxBoxSizer(wxHORIZONTAL); 366 430 wxSizer* playerVariationSizer = new wxBoxSizer(wxVERTICAL); 367 431 368 432 // TODO: make this a wxChoice instead 369 433 wxComboBox* playerSelect = new PlayerComboBox(this, objectSettings, mapSettings); 370 playerVariationSizer->Add(playerSelect); 434 playerSelectionSizer->Add(new wxStaticText(this, wxID_ANY, _("Player:")), wxSizerFlags().Align(wxALIGN_CENTER)); 435 playerSelectionSizer->AddSpacer(3); 436 playerSelectionSizer->Add(playerSelect); 437 438 playerVariationSizer->Add(playerSelectionSizer); 439 playerVariationSizer->AddSpacer(3); 440 371 441 372 442 wxWindow* variationSelect = new VariationControl(this, objectSettings); 373 443 variationSelect->SetMinSize(wxSize(160, -1)); … … ObjectBottomBar::ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEdito 375 445 variationSizer->Add(variationSelect, wxSizerFlags().Proportion(1).Expand()); 376 446 playerVariationSizer->Add(variationSizer, wxSizerFlags().Proportion(1)); 377 447 378 sizer->Add(playerVariationSizer, wxSizerFlags().Expand()); 448 mainSizer->AddSpacer(3); 449 mainSizer->Add(playerVariationSizer, wxSizerFlags().Expand()); 450 451 // ---------------------------------------------------------------------------------- 379 452 380 SetSizer( sizer);453 SetSizer(mainSizer); 381 454 } 382 455 383 456 void ObjectBottomBar::OnFirstDisplay() … … void ObjectBottomBar::OnFirstDisplay() 402 475 POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"ground", m_ViewerGround)); 403 476 POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"shadows", m_ViewerShadows)); 404 477 POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"stats", m_ViewerPolyCount)); 478 POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"bounding_box", m_ViewerBoundingBox)); 405 479 } 406 480 407 481 void ObjectBottomBar::ShowActorViewer(bool show) … … void ObjectBottomBar::OnViewerSetting(wxCommandEvent& evt) 434 508 m_ViewerPolyCount = !m_ViewerPolyCount; 435 509 POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"stats", m_ViewerPolyCount)); 436 510 break; 511 case ID_ViewerBoundingBox: 512 m_ViewerBoundingBox = !m_ViewerBoundingBox; 513 POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"bounding_box", m_ViewerBoundingBox)); 514 break; 515 case ID_ViewerAxesMarker: 516 m_ViewerAxesMarker = !m_ViewerAxesMarker; 517 POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"axes_marker", m_ViewerAxesMarker)); 518 break; 437 519 } 438 520 } 439 521 … … BEGIN_EVENT_TABLE(ObjectBottomBar, wxPanel) 464 546 EVT_BUTTON(ID_ViewerPlay, ObjectBottomBar::OnSpeed) 465 547 EVT_BUTTON(ID_ViewerPause, ObjectBottomBar::OnSpeed) 466 548 EVT_BUTTON(ID_ViewerSlow, ObjectBottomBar::OnSpeed) 549 EVT_BUTTON(ID_ViewerBoundingBox, ObjectBottomBar::OnViewerSetting) 550 EVT_BUTTON(ID_ViewerAxesMarker, ObjectBottomBar::OnViewerSetting) 467 551 END_EVENT_TABLE(); -
source/tools/atlas/GameInterface/ActorViewer.cpp
diff --git a/source/tools/atlas/GameInterface/ActorViewer.cpp b/source/tools/atlas/GameInterface/ActorViewer.cpp index 0a010aa..3c05af2 100644
a b 33 33 #include "graphics/TerrainTextureManager.h" 34 34 #include "graphics/TerritoryTexture.h" 35 35 #include "graphics/UnitManager.h" 36 #include "graphics/Overlay.h" 36 37 #include "maths/MathUtil.h" 37 38 #include "ps/Font.h" 38 39 #include "ps/GameSetup/Config.h" … … 48 49 #include "simulation2/components/ICmpTerrain.h" 49 50 #include "simulation2/components/ICmpUnitMotion.h" 50 51 #include "simulation2/components/ICmpVisual.h" 52 #include "simulation2/helpers/Render.h" 51 53 52 54 struct ActorViewerImpl : public Scene 53 55 { … … public: 75 77 bool WalkEnabled; 76 78 bool GroundEnabled; 77 79 bool ShadowsEnabled; 80 bool SelectionBoxEnabled; 81 bool AxesMarkerEnabled; 78 82 79 83 SColor4ub Background; 80 84 … … public: 89 93 CLOSTexture LOSTexture; 90 94 CTerritoryTexture TerritoryTexture; 91 95 96 SOverlayLine SelectionBoxOverlay; 97 SOverlayLine AxesMarkerOverlays[3]; 98 92 99 // Simplistic implementation of the Scene interface 93 100 virtual void EnumerateObjects(const CFrustum& frustum, SceneCollector* c) 94 101 { … … public: 99 106 c->Submit(Terrain.GetPatch(pi, pj)); 100 107 } 101 108 109 CmpPtr<ICmpVisual> cmpVisual(Simulation2, Entity); 110 111 // add selection box outlines manually 112 if (SelectionBoxEnabled && !cmpVisual.null()) 113 { 114 SelectionBoxOverlay.m_Color = CColor(35/255.f, 86/255.f, 188/255.f, .75f); // pretty blue 115 SelectionBoxOverlay.m_Thickness = 2; 116 117 SimRender::ConstructBoxOutline(cmpVisual->GetSelectionBox(), SelectionBoxOverlay); 118 c->Submit(&SelectionBoxOverlay); 119 } 120 121 // add origin axis thingy 122 if (AxesMarkerEnabled && !cmpVisual.null()) 123 { 124 AxesMarkerOverlays[0].m_Color = CColor(1, 0, 0, .5f); // X axis; red 125 AxesMarkerOverlays[1].m_Color = CColor(0, 1, 0, .5f); // Y axis; green 126 AxesMarkerOverlays[2].m_Color = CColor(0, 0, 1, .5f); // Z axis; blue 127 128 AxesMarkerOverlays[0].m_Thickness = 2; 129 AxesMarkerOverlays[1].m_Thickness = 2; 130 AxesMarkerOverlays[2].m_Thickness = 2; 131 132 AxesMarkerOverlays[0].m_Coords.clear(); 133 AxesMarkerOverlays[1].m_Coords.clear(); 134 AxesMarkerOverlays[2].m_Coords.clear(); 135 136 CVector3D origin = cmpVisual->GetPosition() + CVector3D(0, 0.02f, 0); // offset from the ground a little bit to prevent fighting with the floor texture 137 AxesMarkerOverlays[0].PushCoords(origin); 138 AxesMarkerOverlays[1].PushCoords(origin); 139 AxesMarkerOverlays[2].PushCoords(origin); 140 141 AxesMarkerOverlays[0].PushCoords(origin + CVector3D(1, 0, 0)); 142 AxesMarkerOverlays[1].PushCoords(origin + CVector3D(0, 1, 0)); 143 AxesMarkerOverlays[2].PushCoords(origin + CVector3D(0, 0, 1)); 144 145 c->Submit(&AxesMarkerOverlays[0]); 146 c->Submit(&AxesMarkerOverlays[1]); 147 c->Submit(&AxesMarkerOverlays[2]); 148 } 149 150 // send a RenderSubmit message so the components can submit their visuals to the renderer 102 151 Simulation2.RenderSubmit(*c, frustum, false); 103 152 } 104 153 … … public: 114 163 }; 115 164 116 165 ActorViewer::ActorViewer() 117 : m(*new ActorViewerImpl())166 : m(*new ActorViewerImpl()) 118 167 { 119 168 m.WalkEnabled = false; 120 169 m.GroundEnabled = true; 121 170 m.ShadowsEnabled = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS); 171 m.SelectionBoxEnabled = false; 172 m.AxesMarkerEnabled = false; 122 173 m.Background = SColor4ub(0, 0, 0, 255); 123 174 124 175 // Create a tiny empty piece of terrain, just so we can put shadows … … void ActorViewer::SetBackgroundColour(const SColor4ub& colour) 304 355 void ActorViewer::SetWalkEnabled(bool enabled) { m.WalkEnabled = enabled; } 305 356 void ActorViewer::SetGroundEnabled(bool enabled) { m.GroundEnabled = enabled; } 306 357 void ActorViewer::SetShadowsEnabled(bool enabled) { m.ShadowsEnabled = enabled; } 358 void ActorViewer::SetBoundingBoxesEnabled(bool enabled) { m.SelectionBoxEnabled = enabled; } 359 void ActorViewer::SetAxesMarkerEnabled(bool enabled) { m.AxesMarkerEnabled = enabled; } 307 360 308 361 void ActorViewer::SetStatsEnabled(bool enabled) 309 362 { -
source/tools/atlas/GameInterface/ActorViewer.h
diff --git a/source/tools/atlas/GameInterface/ActorViewer.h b/source/tools/atlas/GameInterface/ActorViewer.h index 7297260..365e4e0 100644
a b public: 41 41 void SetGroundEnabled(bool enabled); 42 42 void SetShadowsEnabled(bool enabled); 43 43 void SetStatsEnabled(bool enabled); 44 void SetBoundingBoxesEnabled(bool enabled); 45 void SetAxesMarkerEnabled(bool enabled); 44 46 void Render(); 45 47 void Update(float dt); 46 48 -
source/tools/atlas/GameInterface/View.cpp
diff --git a/source/tools/atlas/GameInterface/View.cpp b/source/tools/atlas/GameInterface/View.cpp index 03a71a6..55841da 100644
a b void ViewActor::SetParam(const std::wstring& name, bool value) 132 132 m_ActorViewer->SetShadowsEnabled(value); 133 133 else if (name == L"stats") 134 134 m_ActorViewer->SetStatsEnabled(value); 135 else if (name == L"bounding_box") 136 m_ActorViewer->SetBoundingBoxesEnabled(value); 137 else if (name == L"axes_marker") 138 m_ActorViewer->SetAxesMarkerEnabled(value); 135 139 } 136 140 137 141 void ViewActor::SetParam(const std::wstring& name, const AtlasMessage::Colour& value)