# Changeset View

Changeset View

# Standalone View

Standalone View

# source/graphics/ModelAbstract.cpp

/* Copyright (C) 2011 Wildfire Games. | /* Copyright (C) 2022 Wildfire Games. | ||||

* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||

* | * | ||||

* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||

* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||

* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||

* (at your option) any later version. | * (at your option) any later version. | ||||

* | * | ||||

* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||

* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||

* GNU General Public License for more details. | * GNU General Public License for more details. | ||||

* | * | ||||

* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||

* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||

*/ | */ | ||||

#include "precompiled.h" | #include "precompiled.h" | ||||

#include "ModelAbstract.h" | #include "ModelAbstract.h" | ||||

#include "graphics/PropPoint.h" | |||||

#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||

const CBoundingBoxOriented& CModelAbstract::GetSelectionBox() | void CModelAbstract::Clone(CModelAbstract& o) const | ||||

{ | |||||

for (const Prop& prop : m_Props) | |||||

o.AddProp(prop.m_Point, prop.m_Model->Clone(), prop.m_ObjectEntry, prop.m_MinHeight, prop.m_MaxHeight, prop.m_Selectable); | |||||

} | |||||

void CModelAbstract::AddProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry, float minHeight, float maxHeight, bool selectable) | |||||

{ | |||||

// this next call will invalidate the bounds of "model", which will in turn also invalidate the selection box | |||||

model->m_Parent = this; | |||||

model->SetParentRelativeTransform(point->m_Transform); | |||||

Prop prop; | |||||

prop.m_Point = point; | |||||

prop.m_Model = model; | |||||

prop.m_ObjectEntry = objectentry; | |||||

prop.m_MinHeight = minHeight; | |||||

prop.m_MaxHeight = maxHeight; | |||||

prop.m_Selectable = selectable; | |||||

m_Props.push_back(prop); | |||||

} | |||||

const CBoundingBoxAligned CModelAbstract::GetObjectBounds() | |||||

{ | |||||

CBoundingBoxAligned objBounds = CSelectableObject::GetObjectBounds(); // updates the (children-not-included) object-space bounds if necessary | |||||

// now extend these bounds to include the props' selection bounds (if any) | |||||

for (size_t i = 0; i < m_Props.size(); ++i) | |||||

{ | |||||

const Prop& prop = m_Props[i]; | |||||

if (prop.m_Hidden || !prop.m_Selectable) | |||||

continue; // prop is hidden from rendering, so it also shouldn't be used for selection | |||||

CBoundingBoxAligned propSelectionBounds = prop.m_Model->GetObjectBounds(); | |||||

if (propSelectionBounds.IsEmpty()) | |||||

continue; // submodel does not wish to participate in selection box, exclude it | |||||

// We have the prop's bounds in its own object-space; now we need to transform them so they can be properly added | |||||

// to the bounds in our object-space. For that, we need the transform of the prop attachment point. | |||||

// | |||||

// We have the prop point information; however, it's not trivial to compute its exact location in our object-space | |||||

// 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 | |||||

// an animation. The bone matrices might be of interest, but they're really only meant to be used for the animation | |||||

// system and are quite opaque to use from the outside (see @ref ValidatePosition). | |||||

// | |||||

// However, a nice side effect of ValidatePosition is that it also computes the absolute world-space transform of | |||||

// our props and sets it on their respective models. In particular, @ref ValidatePosition will compute the prop's | |||||

// world-space transform as either | |||||

// | |||||

// T' = T x B x O | |||||

// or | |||||

// T' = T x O | |||||

// | |||||

// where T' is the prop's world-space transform, T is our world-space transform, O is the prop's local | |||||

// offset/rotation matrix, and B is an optional transformation matrix of the bone the prop is attached to | |||||

// (taking into account animation and everything). | |||||

// | |||||

// From this, it is clear that either O or B x O is the object-space transformation matrix of the prop. So, | |||||

// all we need to do is apply our own inverse world-transform T^(-1) to T' to get our desired result. Luckily, | |||||

// this is precomputed upon setting the transform matrix (see @ref SetTransform), so it is free to fetch. | |||||

CMatrix3D propObjectTransform = prop.m_Model->m_ParentRelativeTransform; // T' | |||||

//propObjectTransform.Concatenate(GetInvTransform()); // T^(-1) x T' | |||||

// Transform the prop's bounds into our object coordinate space | |||||

CBoundingBoxAligned transformedPropSelectionBounds; | |||||

propSelectionBounds.Transform(propObjectTransform, transformedPropSelectionBounds); | |||||

objBounds += transformedPropSelectionBounds; | |||||

} | |||||

return objBounds; | |||||

} | |||||

const CBoundingBoxOriented& CSelectableObject::GetSelectionBox() | |||||

{ | { | ||||

if (!m_SelectionBoxValid) | if (!m_SelectionBoxValid) | ||||

{ | { | ||||

CalcSelectionBox(); | CalcSelectionBox(); | ||||

m_SelectionBoxValid = true; | m_SelectionBoxValid = true; | ||||

} | } | ||||

return m_SelectionBox; | return m_SelectionBox; | ||||

} | } | ||||

void CModelAbstract::CalcSelectionBox() | void CSelectableObject::CalcSelectionBox() | ||||

{ | { | ||||

if (m_CustomSelectionShape) | if (m_CustomSelectionShape) | ||||

{ | { | ||||

// custom shape | // custom shape | ||||

switch(m_CustomSelectionShape->m_Type) | switch(m_CustomSelectionShape->m_Type) | ||||

{ | { | ||||

case CustomSelectionShape::BOX: | case CustomSelectionShape::BOX: | ||||

{ | { | ||||

Show All 26 Lines | default: | ||||

break; | break; | ||||

} | } | ||||

} | } | ||||

else | else | ||||

{ | { | ||||

// standard method | // standard method | ||||

// Get the object-space bounds that should be used to construct this model (and its children)'s selection box | // Get the object-space bounds that should be used to construct this model (and its children)'s selection box | ||||

CBoundingBoxAligned objBounds = GetObjectSelectionBoundsRec(); | CBoundingBoxAligned objBounds = GetObjectBounds(); | ||||

if (objBounds.IsEmpty()) | if (objBounds.IsEmpty()) | ||||

{ | { | ||||

m_SelectionBox.SetEmpty(); // model does not wish to participate in selection | m_SelectionBox.SetEmpty(); // model does not wish to participate in selection | ||||

return; | return; | ||||

} | } | ||||

// Prevent the bounding box from extending through the terrain; clip the lower plane at Y=0 in object space. | // Prevent the bounding box from extending through the terrain; clip the lower plane at Y=0 in object space. | ||||

if (objBounds[1].Y > 0.f) // should always be the case, unless the models are defined really weirdly | if (objBounds[1].Y > 0.f) // should always be the case, unless the models are defined really weirdly | ||||

objBounds[0].Y = std::max(0.f, objBounds[0].Y); | objBounds[0].Y = std::max(0.f, objBounds[0].Y); | ||||

// transform object-space axis-aligned bounds to world-space arbitrary-aligned box | // transform object-space axis-aligned bounds to world-space arbitrary-aligned box | ||||

objBounds.Transform(GetTransform(), m_SelectionBox); | objBounds.Transform(GetTransform(), m_SelectionBox); | ||||

} | } | ||||

} | } |

Wildfire Games · Phabricator