/* Copyright (C) 2009 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/Bound.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;
	}

	// calculate (and store in m_Bounds) the world space bounds of this object
	// - must be implemented by all concrete subclasses
	virtual void CalcBounds() = 0;

	// return world space bounds of this object
	const CBound& GetBounds() {
		if (! m_BoundsValid) {
			CalcBounds();
			m_BoundsValid = true;
		}
		return m_Bounds;
	}

	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:
	// object bounds
	CBound m_Bounds;
	// local->world space transform
	CMatrix3D m_Transform;
	// world->local space transform
	CMatrix3D m_InvTransform;
	// object renderdata
	CRenderData* m_RenderData;

private:
	// remembers whether m_bounds needs to be recalculated
	bool m_BoundsValid;
};

#endif
