/* Copyright (C) 2012 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 . */ /* * 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) #define RENDERDATA_UPDATE_COLOR (1<<4) /////////////////////////////////////////////////////////////////////////////// // 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