1
0
forked from 0ad/0ad
0ad/source/graphics/RenderableObject.h

163 lines
5.5 KiB
C++

/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 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
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Base class for renderable objects
*/
#ifndef INCLUDED_RENDERABLEOBJECT
#define INCLUDED_RENDERABLEOBJECT
#include "maths/BoundingBoxAligned.h"
#include "maths/Matrix3D.h"
// dirty flags - used as notification to the renderer that some bit of data
// need updating
#define RENDERDATA_UPDATE_VERTICES (1<<1)
#define RENDERDATA_UPDATE_INDICES (1<<2)
///////////////////////////////////////////////////////////////////////////////
// CRenderData: base class of all the renderer's renderdata classes - the
// derived class stores necessary information for rendering an object of a
// particular type
class CRenderData
{
public:
CRenderData() : m_UpdateFlags(0) {}
virtual ~CRenderData() {}
int m_UpdateFlags;
};
///////////////////////////////////////////////////////////////////////////////
// CRenderableObject: base class of all renderable objects - patches, models,
// sprites, etc; stores position and bound information, and a pointer to
// some renderdata necessary for the renderer to actually render it
class CRenderableObject
{
NONCOPYABLE(CRenderableObject);
public:
// constructor
CRenderableObject() : m_RenderData(0), m_BoundsValid(false)
{
m_Transform.SetIdentity();
}
// destructor
virtual ~CRenderableObject() { delete m_RenderData; }
// set object transform
virtual void SetTransform(const CMatrix3D& transform)
{
if (m_Transform == transform)
return;
// store transform, calculate inverse
m_Transform=transform;
m_Transform.GetInverse(m_InvTransform);
// normal recalculation likely required on transform change; flag it
SetDirty(RENDERDATA_UPDATE_VERTICES);
// need to rebuild world space bounds
InvalidateBounds();
}
// get object to world space transform
const CMatrix3D& GetTransform() const { return m_Transform; }
// get world to object space transform
const CMatrix3D& GetInvTransform() const { return m_InvTransform; }
// mark some part of the renderdata as dirty, and requiring
// an update on next render
void SetDirty(u32 dirtyflags)
{
if (m_RenderData)
m_RenderData->m_UpdateFlags |= dirtyflags;
}
/**
* (Re)calculates and stores any bounds or bound-dependent data for this object. At this abstraction level, this is only the world-space
* bounds stored in @ref m_WorldBounds; subclasses may use this method to (re)compute additional bounds if necessary, or any data that
* depends on the bounds. Whenever bound-dependent data is requested through a public interface, @ref RecalculateBoundsIfNecessary should
* be called first to ensure bound correctness, which will in turn call this method if it turns out that they're outdated.
*
* @see m_BoundsValid
* @see RecalculateBoundsIfNecessary
*/
virtual void CalcBounds() = 0;
/// Returns the world-space axis-aligned bounds of this object.
const CBoundingBoxAligned& GetWorldBounds()
{
RecalculateBoundsIfNecessary();
return m_WorldBounds;
}
/**
* Marks the bounds as invalid. This will trigger @ref RecalculateBoundsIfNecessary to recompute any bound-related data the next time
* any bound-related data is requested through a public interface -- at least, if you've made sure to call it before returning the
* stored data.
*/
virtual void InvalidateBounds() { m_BoundsValid = false; }
// Set the object renderdata and free previous renderdata, if any.
void SetRenderData(CRenderData* renderdata)
{
delete m_RenderData;
m_RenderData = renderdata;
}
/// Return object renderdata - can be null if renderer hasn't yet created the renderdata
CRenderData* GetRenderData() { return m_RenderData; }
protected:
/// Factored out so subclasses don't need to repeat this if they want to add additional getters for bounds-related methods
/// (since they'll have to make sure to recalc the bounds if necessary before they return it).
void RecalculateBoundsIfNecessary()
{
if (!m_BoundsValid) {
CalcBounds();
m_BoundsValid = true;
}
}
protected:
/// World-space bounds of this object
CBoundingBoxAligned m_WorldBounds;
// local->world space transform
CMatrix3D m_Transform;
// world->local space transform
CMatrix3D m_InvTransform;
// object renderdata
CRenderData* m_RenderData;
/**
* Remembers whether any bounds need to be recalculated. Subclasses that add any data that depends on the bounds should
* take care to consider the validity of the bounds and recalculate their data when necessary -- overriding @ref CalcBounds
* to do so would be a good idea, since it's already set up to be called by @ref RecalculateBoundsIfNecessary whenever the
* bounds are marked as invalid. The latter should then be called before returning any bounds or bounds-derived data through
* a public interface (see the implementation of @ref GetWorldBounds for an example).
*
* @see CalcBounds
* @see InvalidateBounds
* @see RecalculateBoundsIfNecessary
*/
bool m_BoundsValid;
};
#endif