From d24c93237c4abecd17fbb5878d9d401113765591 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Sun, 13 Mar 2011 19:22:05 +0000 Subject: [PATCH] # Initial version of terrain decal textures. Rejig CModel to support non-mesh-based props. Avoid redundant recomputation for non-moving CRenderableObjects. This was SVN commit r9055. --- source/graphics/Decal.cpp | 107 ++++++++++ source/graphics/Decal.h | 88 +++++++++ source/graphics/GameView.cpp | 16 +- source/graphics/Model.cpp | 58 ++---- source/graphics/Model.h | 80 ++++---- source/graphics/ObjectBase.cpp | 32 ++- source/graphics/ObjectBase.h | 20 +- source/graphics/ObjectEntry.cpp | 114 +++++------ source/graphics/ObjectEntry.h | 6 +- source/graphics/RenderableObject.h | 4 + source/graphics/Terrain.cpp | 29 +++ source/graphics/Terrain.h | 8 +- source/graphics/Unit.cpp | 25 ++- source/graphics/Unit.h | 8 +- source/graphics/UnitAnimation.cpp | 29 +-- source/graphics/UnitAnimation.h | 15 +- source/maths/Bound.cpp | 50 ++--- source/maths/Bound.h | 2 +- source/maths/Matrix3D.cpp | 8 + source/maths/Matrix3D.h | 3 + source/renderer/DecalRData.cpp | 185 ++++++++++++++++++ source/renderer/DecalRData.h | 48 +++++ source/renderer/PatchRData.h | 2 + source/renderer/Renderer.cpp | 5 + source/renderer/Renderer.h | 2 + source/renderer/Scene.cpp | 25 ++- source/renderer/Scene.h | 9 +- source/renderer/TerrainRenderer.cpp | 111 ++++++----- source/renderer/TerrainRenderer.h | 14 +- .../components/CCmpProjectileManager.cpp | 2 +- .../components/CCmpVisualActor.cpp | 68 +++++-- 31 files changed, 862 insertions(+), 311 deletions(-) create mode 100644 source/graphics/Decal.cpp create mode 100644 source/graphics/Decal.h create mode 100644 source/renderer/DecalRData.cpp create mode 100644 source/renderer/DecalRData.h diff --git a/source/graphics/Decal.cpp b/source/graphics/Decal.cpp new file mode 100644 index 0000000000..30e6fc5fb8 --- /dev/null +++ b/source/graphics/Decal.cpp @@ -0,0 +1,107 @@ +/* Copyright (C) 2011 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 . + */ + +#include "precompiled.h" + +#include "Decal.h" + +#include "graphics/Terrain.h" +#include "maths/MathUtil.h" + +CModelAbstract* CModelDecal::Clone() const +{ + CModelDecal* clone = new CModelDecal(m_Terrain, m_Decal); + return clone; +} + +void CModelDecal::CalcVertexExtents(ssize_t& i0, ssize_t& j0, ssize_t& i1, ssize_t& j1) +{ + CVector3D corner0(m_Decal.m_OffsetX + m_Decal.m_SizeX/2, 0, m_Decal.m_OffsetZ + m_Decal.m_SizeZ/2); + CVector3D corner1(m_Decal.m_OffsetX + m_Decal.m_SizeX/2, 0, m_Decal.m_OffsetZ - m_Decal.m_SizeZ/2); + CVector3D corner2(m_Decal.m_OffsetX - m_Decal.m_SizeX/2, 0, m_Decal.m_OffsetZ - m_Decal.m_SizeZ/2); + CVector3D corner3(m_Decal.m_OffsetX - m_Decal.m_SizeX/2, 0, m_Decal.m_OffsetZ + m_Decal.m_SizeZ/2); + + corner0 = GetTransform().Transform(corner0); + corner1 = GetTransform().Transform(corner1); + corner2 = GetTransform().Transform(corner2); + corner3 = GetTransform().Transform(corner3); + + i0 = floor(std::min(std::min(corner0.X, corner1.X), std::min(corner2.X, corner3.X)) / CELL_SIZE); + j0 = floor(std::min(std::min(corner0.Z, corner1.Z), std::min(corner2.Z, corner3.Z)) / CELL_SIZE); + i1 = ceil(std::max(std::max(corner0.X, corner1.X), std::max(corner2.X, corner3.X)) / CELL_SIZE); + j1 = ceil(std::max(std::max(corner0.Z, corner1.Z), std::max(corner2.Z, corner3.Z)) / CELL_SIZE); + + i0 = clamp(i0, (ssize_t)0, m_Terrain->GetVerticesPerSide()-1); + j0 = clamp(j0, (ssize_t)0, m_Terrain->GetVerticesPerSide()-1); + i1 = clamp(i1, (ssize_t)0, m_Terrain->GetVerticesPerSide()-1); + j1 = clamp(j1, (ssize_t)0, m_Terrain->GetVerticesPerSide()-1); +} + +void CModelDecal::CalcBounds() +{ + ssize_t i0, j0, i1, j1; + CalcVertexExtents(i0, j0, i1, j1); + m_Bounds = m_Terrain->GetVertexesBound(i0, j0, i1, j1); +} + +void CModelDecal::SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1) +{ + // Check if there's no intersection between the dirty range and this decal + ssize_t bi0, bj0, bi1, bj1; + CalcVertexExtents(bi0, bj0, bi1, bj1); + if (bi1 < i0 || bi0 > i1 || bj1 < j0 || bj0 > j1) + return; + + SetDirty(RENDERDATA_UPDATE_VERTICES); +} + +void CModelDecal::InvalidatePosition() +{ + m_PositionValid = false; +} + +void CModelDecal::ValidatePosition() +{ + if (m_PositionValid) + { + debug_assert(!m_Parent || m_Parent->m_PositionValid); + return; + } + + if (m_Parent && !m_Parent->m_PositionValid) + { + // Make sure we don't base our calculations on + // a parent animation state that is out of date. + m_Parent->ValidatePosition(); + + // Parent will recursively call our validation. + debug_assert(m_PositionValid); + return; + } + + m_PositionValid = true; +} + +void CModelDecal::SetTransform(const CMatrix3D& transform) +{ + CMatrix3D newTransform = transform; + newTransform.SetYRotation(m_Decal.m_Angle); + newTransform.Concatenate(transform); + + CRenderableObject::SetTransform(newTransform); + InvalidatePosition(); +} diff --git a/source/graphics/Decal.h b/source/graphics/Decal.h new file mode 100644 index 0000000000..311d098112 --- /dev/null +++ b/source/graphics/Decal.h @@ -0,0 +1,88 @@ +/* Copyright (C) 2011 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 . + */ + +#ifndef INCLUDED_DECAL +#define INCLUDED_DECAL + +#include "graphics/ModelAbstract.h" +#include "graphics/Texture.h" + +class CTerrain; + +/** + * Terrain decal definition. + * Decals are rectangular textures that are projected vertically downwards + * onto the terrain. + */ +struct SDecal +{ + SDecal(const CTexturePtr& texture, float sizeX, float sizeZ, float angle, + float offsetX, float offsetZ, bool floating) + : m_Texture(texture), m_SizeX(sizeX), m_SizeZ(sizeZ), m_Angle(angle), + m_OffsetX(offsetX), m_OffsetZ(offsetZ), m_Floating(floating) + { + } + + CTexturePtr m_Texture; + float m_SizeX; + float m_SizeZ; + float m_Angle; + float m_OffsetX; + float m_OffsetZ; + bool m_Floating; +}; + +class CModelDecal : public CModelAbstract +{ +public: + CModelDecal(CTerrain* terrain, const SDecal& decal) + : m_Terrain(terrain), m_Decal(decal) + { + } + + /// Dynamic cast + virtual CModelDecal* ToCModelDecal() + { + return this; + } + + virtual CModelAbstract* Clone() const; + + virtual void SetDirtyRec(int dirtyflags) + { + SetDirty(dirtyflags); + } + + virtual void SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1); + + virtual void CalcBounds(); + virtual void ValidatePosition(); + virtual void InvalidatePosition(); + virtual void SetTransform(const CMatrix3D& transform); + + /** + * Compute the terrain vertex indexes that bound the decal's + * projection onto the terrain. + * The returned indexes are clamped to the terrain size. + */ + void CalcVertexExtents(ssize_t& i0, ssize_t& j0, ssize_t& i1, ssize_t& j1); + + CTerrain* m_Terrain; + SDecal m_Decal; +}; + +#endif // INCLUDED_DECAL diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index b54b645863..f1f2f6b596 100644 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -543,17 +543,6 @@ void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c) } -static void MarkUpdateColorRecursive(CModel& model) -{ - model.SetDirty(RENDERDATA_UPDATE_COLOR); - - const std::vector& props = model.GetProps(); - for(size_t i = 0; i < props.size(); ++i) { - debug_assert(props[i].m_Model); - MarkUpdateColorRecursive(*props[i].m_Model); - } -} - void CGameView::CheckLightEnv() { if (m->CachedLightEnv == g_LightEnv) @@ -569,9 +558,8 @@ void CGameView::CheckLightEnv() pTerrain->MakeDirty(RENDERDATA_UPDATE_COLOR); const std::vector& units = m->Game->GetWorld()->GetUnitManager().GetUnits(); - for(size_t i = 0; i < units.size(); ++i) { - MarkUpdateColorRecursive(units[i]->GetModel()); - } + for (size_t i = 0; i < units.size(); ++i) + units[i]->GetModel().SetDirtyRec(RENDERDATA_UPDATE_COLOR); } diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index 5192d2e073..423cc03dd9 100644 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -39,10 +39,9 @@ ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // Constructor CModel::CModel(CSkeletonAnimManager& skeletonAnimManager) - : m_Parent(NULL), m_Flags(0), m_Anim(NULL), m_AnimTime(0), + : m_Flags(0), m_Anim(NULL), m_AnimTime(0), m_BoneMatrices(NULL), m_InverseBindBoneMatrices(NULL), m_AmmoPropPoint(NULL), m_AmmoLoadedProp(0), - m_PositionValid(false), m_ShadingColor(1,1,1,1), m_PlayerID((size_t)-1), m_SkeletonAnimManager(skeletonAnimManager) { } @@ -51,23 +50,6 @@ CModel::CModel(CSkeletonAnimManager& skeletonAnimManager) // Destructor CModel::~CModel() { - // Detach us from our parent - if (m_Parent) - { - for(std::vector::iterator iter = m_Parent->m_Props.begin(); - iter != m_Parent->m_Props.end(); - ++iter) - { - if (iter->m_Model == this) - { - m_Parent->m_Props.erase(iter); - break; - } - } - - m_Parent = 0; - } - ReleaseData(); } @@ -77,12 +59,11 @@ void CModel::ReleaseData() { delete[] m_BoneMatrices; delete[] m_InverseBindBoneMatrices; + for (size_t i = 0; i < m_Props.size(); ++i) - { - m_Props[i].m_Model->m_Parent = 0; delete m_Props[i].m_Model; - } m_Props.clear(); + m_pModelDef = CModelDefPtr(); m_Texture.reset(); @@ -177,7 +158,7 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result) // at the origin. The box is later re-transformed onto the object, without // having to recalculate the size of the box. CMatrix3D transform, oldtransform = GetTransform(); - CModel* oldparent = m_Parent; + CModelAbstract* oldparent = m_Parent; m_Parent = 0; transform.SetIdentity(); @@ -384,7 +365,7 @@ void CModel::CopyAnimationFrom(CModel* source) ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // AddProp: add a prop to the model on the given point -void CModel::AddProp(const SPropPoint* point, CModel* model, CObjectEntry* objectentry) +void CModel::AddProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry) { // position model according to prop point position model->SetTransform(point->m_Transform); @@ -397,7 +378,7 @@ void CModel::AddProp(const SPropPoint* point, CModel* model, CObjectEntry* objec m_Props.push_back(prop); } -void CModel::AddAmmoProp(const SPropPoint* point, CModel* model, CObjectEntry* objectentry) +void CModel::AddAmmoProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry) { AddProp(point, model, objectentry); m_AmmoPropPoint = point; @@ -427,16 +408,20 @@ void CModel::HideAmmoProp() m_Props[i].m_Hidden = (i == m_AmmoLoadedProp); } -CModel* CModel::FindFirstAmmoProp() +CModelAbstract* CModel::FindFirstAmmoProp() { if (m_AmmoPropPoint) return m_Props[m_AmmoLoadedProp].m_Model; for (size_t i = 0; i < m_Props.size(); ++i) { - CModel* model = m_Props[i].m_Model->FindFirstAmmoProp(); - if (model) - return model; + CModel* propModel = m_Props[i].m_Model->ToCModel(); + if (propModel) + { + CModelAbstract* model = propModel->FindFirstAmmoProp(); + if (model) + return model; + } } return NULL; @@ -444,7 +429,7 @@ CModel* CModel::FindFirstAmmoProp() ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // Clone: return a clone of this model -CModel* CModel::Clone() const +CModelAbstract* CModel::Clone() const { CModel* clone = new CModel(m_SkeletonAnimManager); clone->m_ObjectBounds = m_ObjectBounds; @@ -473,7 +458,6 @@ void CModel::SetTransform(const CMatrix3D& transform) { // call base class to set transform on this object CRenderableObject::SetTransform(transform); - InvalidateBounds(); InvalidatePosition(); } @@ -486,7 +470,7 @@ void CModel::SetMaterial(const CMaterial &material) void CModel::SetPlayerID(size_t id) { - m_PlayerID = id; + CModelAbstract::SetPlayerID(id); if (id != (size_t)-1) m_Material.SetPlayerColor(id); @@ -495,11 +479,6 @@ void CModel::SetPlayerID(size_t id) it->m_Model->SetPlayerID(id); } -size_t CModel::GetPlayerID() -{ - return m_PlayerID; -} - void CModel::SetPlayerColor(const CColor& colour) { m_Material.SetPlayerColor(colour); @@ -507,7 +486,8 @@ void CModel::SetPlayerColor(const CColor& colour) void CModel::SetShadingColor(const CColor& colour) { - m_ShadingColor = colour; + CModelAbstract::SetShadingColor(colour); + for (std::vector::iterator it = m_Props.begin(); it != m_Props.end(); ++it) it->m_Model->SetShadingColor(colour); } diff --git a/source/graphics/Model.h b/source/graphics/Model.h index a69f1a4ea9..a06a0eede0 100644 --- a/source/graphics/Model.h +++ b/source/graphics/Model.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,10 +24,10 @@ #include -#include "Texture.h" -#include "MeshManager.h" -#include "RenderableObject.h" -#include "Material.h" +#include "graphics/Texture.h" +#include "graphics/Material.h" +#include "graphics/MeshManager.h" +#include "graphics/ModelAbstract.h" #include "ps/Overlay.h" struct SPropPoint; @@ -42,7 +42,7 @@ class CSkeletonAnimManager; /////////////////////////////////////////////////////////////////////////////// // CModel: basically, a mesh object - holds the texturing and skinning // information for a model in game -class CModel : public CRenderableObject +class CModel : public CModelAbstract { NONCOPYABLE(CModel); @@ -52,7 +52,7 @@ public: Prop() : m_Point(0), m_Model(0), m_ObjectEntry(0), m_Hidden(false) {} const SPropPoint* m_Point; - CModel* m_Model; + CModelAbstract* m_Model; CObjectEntry* m_ObjectEntry; bool m_Hidden; // temporarily removed from rendering @@ -64,10 +64,16 @@ public: // destructor ~CModel(); + /// Dynamic cast + virtual CModel* ToCModel() + { + return this; + } + // setup model from given geometry bool InitModel(const CModelDefPtr& modeldef); // calculate the world space bounds of this model - void CalcBounds(); + virtual void CalcBounds(); // update this model's state; 'time' is the absolute time since the start of the animation, in MS void UpdateTo(float time); @@ -80,18 +86,14 @@ public: void SetMaterial(const CMaterial &material); // set the model's player ID, recursively through props void SetPlayerID(size_t id); - // get the model's player ID, recursively through props; initial default is (size_t)-1 - size_t GetPlayerID(); // set the model's player colour - void SetPlayerColor(const CColor& colour); + virtual void SetPlayerColor(const CColor& colour); // set the models mod color - void SetShadingColor(const CColor& colour); + virtual void SetShadingColor(const CColor& colour); // get the model's texture CTexturePtr& GetTexture() { return m_Texture; } // get the model's material CMaterial& GetMaterial() { return m_Material; } - // get the model's shading color - CColor GetShadingColor() { return m_ShadingColor; } // set the given animation as the current animation on this model bool SetAnimation(CSkeletonAnim* anim, bool once = false); @@ -109,13 +111,19 @@ public: int GetFlags() const { return m_Flags; } // recurse down tree setting dirty bits - void SetDirtyRec(int dirtyflags) { + virtual void SetDirtyRec(int dirtyflags) { SetDirty(dirtyflags); for (size_t i=0;iSetDirtyRec(dirtyflags); } } + virtual void SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1) + { + for (size_t i = 0; i < m_Props.size(); ++i) + m_Props[i].m_Model->SetTerrainDirty(i0, j0, i1, j1); + } + // calculate object space bounds of this model, based solely on vertex positions void CalcObjectBounds(); // calculate bounds encompassing all vertex positions for given animation @@ -123,12 +131,12 @@ public: /** * Set transform of this object. - * + * * @note In order to ensure that all child props are updated properly, * you must call ValidatePosition(). */ - void SetTransform(const CMatrix3D& transform); - + virtual void SetTransform(const CMatrix3D& transform); + /** * Return whether this is a skinned/skeletal model. If it is, Get*BoneMatrices() * will return valid non-NULL arrays. @@ -159,13 +167,13 @@ public: /** * Add a prop to the model on the given point. */ - void AddProp(const SPropPoint* point, CModel* model, CObjectEntry* objectentry); + void AddProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry); /** * Add a prop to the model on the given point, and treat it as the ammo prop. * The prop will be hidden by default. */ - void AddAmmoProp(const SPropPoint* point, CModel* model, CObjectEntry* objectentry); + void AddAmmoProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry); /** * Show the ammo prop (if any), and hide any other props on that prop point. @@ -180,36 +188,30 @@ public: /** * Find the first prop used for ammo, by this model or its own props. */ - CModel* FindFirstAmmoProp(); + CModelAbstract* FindFirstAmmoProp(); // return prop list std::vector& GetProps() { return m_Props; } const std::vector& GetProps() const { return m_Props; } // return a clone of this model - CModel* Clone() const; + virtual CModelAbstract* Clone() const; /** * Ensure that both the transformation and the bone * matrices are correct for this model and all its props. */ - void ValidatePosition(); - -private: - // delete anything allocated by the model - void ReleaseData(); + virtual void ValidatePosition(); /** * Mark this model's position and bone matrices, * and all props' positions as invalid. */ - void InvalidatePosition(); - - /** - * If non-null, m_Parent points to the model that we - * are attached to. - */ - CModel* m_Parent; + virtual void InvalidatePosition(); + +private: + // delete anything allocated by the model + void ReleaseData(); // object flags int m_Flags; @@ -244,16 +246,6 @@ private: */ size_t m_AmmoLoadedProp; - /** - * true if both transform and and bone matrices are valid. - */ - bool m_PositionValid; - - // modulating color - CColor m_ShadingColor; - - size_t m_PlayerID; - // manager object which can load animations for us CSkeletonAnimManager& m_SkeletonAnimManager; }; diff --git a/source/graphics/ObjectBase.cpp b/source/graphics/ObjectBase.cpp index e7862b330b..a6f158b388 100644 --- a/source/graphics/ObjectBase.cpp +++ b/source/graphics/ObjectBase.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -61,6 +61,7 @@ bool CObjectBase::Load(const VfsPath& pathname) EL(mesh); EL(texture); EL(colour); + EL(decal); AT(file); AT(name); AT(speed); @@ -69,6 +70,11 @@ bool CObjectBase::Load(const VfsPath& pathname) AT(attachpoint); AT(actor); AT(frequency); + AT(width); + AT(depth); + AT(angle); + AT(offsetx); + AT(offsetz); #undef AT #undef EL @@ -130,20 +136,33 @@ bool CObjectBase::Load(const VfsPath& pathname) currentVariant->m_Frequency = attr.Value.ToInt(); } - XERO_ITER_EL(variant, option) { int option_name = option.GetNodeName(); if (option_name == el_mesh) + { currentVariant->m_ModelFilename = VfsPath(L"art/meshes")/(std::wstring)option.GetText().FromUTF8(); - + } else if (option_name == el_texture) + { currentVariant->m_TextureFilename = VfsPath(L"art/textures/skins")/(std::wstring)option.GetText().FromUTF8(); - + } + else if (option_name == el_decal) + { + XMBAttributeList attrs = option.GetAttributes(); + Decal decal; + decal.m_SizeX = attrs.GetNamedItem(at_width).ToFloat(); + decal.m_SizeZ = attrs.GetNamedItem(at_depth).ToFloat(); + decal.m_Angle = DEGTORAD(attrs.GetNamedItem(at_angle).ToFloat()); + decal.m_OffsetX = attrs.GetNamedItem(at_offsetx).ToFloat(); + decal.m_OffsetZ = attrs.GetNamedItem(at_offsetz).ToFloat(); + currentVariant->m_Decal = decal; + } else if (option_name == el_colour) + { currentVariant->m_Color = option.GetText(); - + } else if (option_name == el_animations) { XERO_ITER_EL(option, anim_element) @@ -362,6 +381,9 @@ const CObjectBase::Variation CObjectBase::BuildVariation(const std::vector& if (! var.m_ModelFilename.empty()) variation.model = var.m_ModelFilename; + if (var.m_Decal.m_SizeX && var.m_Decal.m_SizeZ) + variation.decal = var.m_Decal; + if (! var.m_Color.empty()) variation.color = var.m_Color; diff --git a/source/graphics/ObjectBase.h b/source/graphics/ObjectBase.h index 693446f325..143ed5f9c1 100644 --- a/source/graphics/ObjectBase.h +++ b/source/graphics/ObjectBase.h @@ -33,7 +33,8 @@ class CObjectBase NONCOPYABLE(CObjectBase); public: - struct Anim { + struct Anim + { // constructor Anim() : m_Speed(1.f), m_ActionPos(-1.f), m_ActionPos2(-1.f) {} @@ -49,20 +50,34 @@ public: float m_ActionPos2; }; - struct Prop { + struct Prop + { // name of the prop point to attach to - "Prop01", "Prop02", "Head", "LeftHand", etc .. CStr m_PropPointName; // name of the model file - art/actors/props/sword.xml or whatever VfsPath m_ModelName; }; + struct Decal + { + Decal() : m_SizeX(0.f), m_SizeZ(0.f), m_Angle(0.f), m_OffsetX(0.f), m_OffsetZ(0.f) {} + + float m_SizeX; + float m_SizeZ; + float m_Angle; + float m_OffsetX; + float m_OffsetZ; + }; + struct Variant { Variant() : m_Frequency(0) {} + CStr m_VariantName; // lowercase name int m_Frequency; VfsPath m_ModelFilename; VfsPath m_TextureFilename; + Decal m_Decal; CStr m_Color; std::vector m_Anims; @@ -73,6 +88,7 @@ public: { VfsPath texture; VfsPath model; + Decal decal; CStr color; std::multimap props; std::multimap anims; diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index 3fdb7ae958..ea3b023a65 100644 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,18 +18,21 @@ #include "precompiled.h" #include "ObjectEntry.h" -#include "ObjectManager.h" -#include "ObjectBase.h" -#include "Model.h" -#include "ModelDef.h" -#include "ps/CLogger.h" -#include "MaterialManager.h" -#include "MeshManager.h" -#include "SkeletonAnim.h" -#include "TextureManager.h" -#include "renderer/Renderer.h" +#include "graphics/Decal.h" +#include "graphics/MaterialManager.h" +#include "graphics/MeshManager.h" +#include "graphics/Model.h" +#include "graphics/ModelDef.h" +#include "graphics/ObjectBase.h" +#include "graphics/ObjectManager.h" +#include "graphics/SkeletonAnim.h" +#include "graphics/TextureManager.h" #include "lib/rand.h" +#include "ps/CLogger.h" +#include "ps/Game.h" +#include "ps/World.h" +#include "renderer/Renderer.h" #include @@ -70,6 +73,25 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections m_Color = CColor(r/255.0f, g/255.0f, b/255.0f, 1.0f); } + if (variation.decal.m_SizeX && variation.decal.m_SizeZ) + { + CTextureProperties textureProps(m_TextureName); + + // Decals should be transparent, so clamp to the border (default 0,0,0,0) + textureProps.SetWrap(GL_CLAMP_TO_BORDER); + + CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); + texture->Prefetch(); // if we've loaded this model we're probably going to render it soon, so prefetch its texture + + SDecal decal(texture, + variation.decal.m_SizeX, variation.decal.m_SizeZ, + variation.decal.m_Angle, variation.decal.m_OffsetX, variation.decal.m_OffsetZ, + m_Base->m_Properties.m_FloatOnWater); + m_Model = new CModelDecal(g_Game->GetWorld()->GetTerrain(), decal); + + return true; + } + std::vector props; for (std::multimap::iterator it = variation.props.begin(); it != variation.props.end(); ++it) @@ -77,11 +99,6 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections // Build the model: -/* - // remember the old model so we can replace any models using it later on - CModelDefPtr oldmodeldef = m_Model ? m_Model->GetModelDef() : CModelDefPtr(); -*/ - // try and create a model CModelDefPtr modeldef (objectManager.GetMeshManager().GetMesh(m_ModelName)); if (!modeldef) @@ -91,20 +108,21 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections } // delete old model, create new + CModel* model = new CModel(objectManager.GetSkeletonAnimManager()); delete m_Model; - m_Model = new CModel(objectManager.GetSkeletonAnimManager()); - m_Model->SetMaterial(g_MaterialManager.LoadMaterial(m_Base->m_Material)); - m_Model->InitModel(modeldef); - m_Model->SetPlayerColor(m_Color); + m_Model = model; + model->SetMaterial(g_MaterialManager.LoadMaterial(m_Base->m_Material)); + model->InitModel(modeldef); + model->SetPlayerColor(m_Color); CTextureProperties textureProps(m_TextureName); textureProps.SetWrap(GL_CLAMP_TO_EDGE); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); // if we've loaded this model we're probably going to render it soon, so prefetch its texture - m_Model->SetTexture(texture); + model->SetTexture(texture); // calculate initial object space bounds, based on vertex positions - m_Model->CalcObjectBounds(); + model->CalcObjectBounds(); // load the animations for (std::multimap::iterator it = variation.anims.begin(); it != variation.anims.end(); ++it) @@ -119,7 +137,7 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections if (! it->second.m_FileName.empty()) { - CSkeletonAnim* anim = m_Model->BuildAnimation(it->second.m_FileName, name, it->second.m_Speed, it->second.m_ActionPos, it->second.m_ActionPos2); + CSkeletonAnim* anim = model->BuildAnimation(it->second.m_FileName, name, it->second.m_Speed, it->second.m_ActionPos, it->second.m_ActionPos2); if (anim) m_Animations.insert(std::make_pair(name, anim)); } @@ -137,12 +155,12 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections m_Animations.insert(std::make_pair("idle", anim)); // Ignore errors, since they're probably saying this is a non-animated model - m_Model->SetAnimation(anim); + model->SetAnimation(anim); } else { // start up idling - if (!m_Model->SetAnimation(GetRandomAnimation("idle"))) + if (!model->SetAnimation(GetRandomAnimation("idle"))) LOGERROR(L"Failed to set idle animation in model \"%ls\"", m_ModelName.string().c_str()); } @@ -184,12 +202,13 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections const SPropPoint* proppoint = modeldef->FindPropPoint(ppn.c_str()); if (proppoint) { - CModel* propmodel = oe->m_Model->Clone(); + CModelAbstract* propmodel = oe->m_Model->Clone(); if (isAmmo) - m_Model->AddAmmoProp(proppoint, propmodel, oe); + model->AddAmmoProp(proppoint, propmodel, oe); else - m_Model->AddProp(proppoint, propmodel, oe); - propmodel->SetAnimation(oe->GetRandomAnimation("idle")); + model->AddProp(proppoint, propmodel, oe); + if (propmodel->ToCModel()) + propmodel->ToCModel()->SetAnimation(oe->GetRandomAnimation("idle")); } else LOGERROR(L"Failed to find matching prop point called \"%hs\" in model \"%ls\" for actor \"%ls\"", ppn.c_str(), m_ModelName.string().c_str(), m_Base->m_ShortName.c_str()); @@ -198,44 +217,9 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections // setup flags if (m_Base->m_Properties.m_CastShadows) { - m_Model->SetFlags(m_Model->GetFlags()|MODELFLAG_CASTSHADOWS); + model->SetFlags(model->GetFlags()|MODELFLAG_CASTSHADOWS); } - // replace any units using old model to now use new model; also reprop models, if necessary - // FIXME, RC - ugh, doesn't recurse correctly through props -/* - // (PT: Removed this, since I'm not entirely sure what it's useful for, and it - // gets a bit confusing with randomised actors) - - const std::vector& units = g_UnitMan.GetUnits(); - for (size_t i = 0; i < units.size(); ++i) - { - CModel* unitmodel=units[i]->GetModel(); - if (unitmodel->GetModelDef() == oldmodeldef) - { - unitmodel->InitModel(m_Model->GetModelDef()); - unitmodel->SetFlags(m_Model->GetFlags()); - - const std::vector& newprops = m_Model->GetProps(); - for (size_t j = 0; j < newprops.size(); j++) - unitmodel->AddProp(newprops[j].m_Point, newprops[j].m_Model->Clone()); - } - - std::vector& mdlprops = unitmodel->GetProps(); - for (size_t j = 0; j < mdlprops.size(); j++) - { - CModel::Prop& prop = mdlprops[j]; - if (prop.m_Model) - { - if (prop.m_Model->GetModelDef() == oldmodeldef) - { - delete prop.m_Model; - prop.m_Model = m_Model->Clone(); - } - } - } - } -*/ return true; } diff --git a/source/graphics/ObjectEntry.h b/source/graphics/ObjectEntry.h index 1e721c7756..ca31abde78 100644 --- a/source/graphics/ObjectEntry.h +++ b/source/graphics/ObjectEntry.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,7 +18,7 @@ #ifndef INCLUDED_OBJECTENTRY #define INCLUDED_OBJECTENTRY -class CModel; +class CModelAbstract; class CSkeletonAnim; class CObjectBase; class CObjectManager; @@ -65,7 +65,7 @@ public: std::vector GetAnimations(const CStr& animationName) const; // corresponding model - CModel* m_Model; + CModelAbstract* m_Model; private: typedef std::multimap SkeletonAnimMap; diff --git a/source/graphics/RenderableObject.h b/source/graphics/RenderableObject.h index 3d0a5240bc..1b642f8f18 100644 --- a/source/graphics/RenderableObject.h +++ b/source/graphics/RenderableObject.h @@ -53,6 +53,8 @@ public: // some renderdata necessary for the renderer to actually render it class CRenderableObject { + NONCOPYABLE(CRenderableObject); + public: // constructor CRenderableObject() : m_RenderData(0), m_BoundsValid(false) { @@ -63,6 +65,8 @@ public: // 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); diff --git a/source/graphics/Terrain.cpp b/source/graphics/Terrain.cpp index 2b7d828a95..3f05de6722 100644 --- a/source/graphics/Terrain.cpp +++ b/source/graphics/Terrain.cpp @@ -550,3 +550,32 @@ void CTerrain::MakeDirty(int dirtyFlags) } } } + +CBound CTerrain::GetVertexesBound(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1) +{ + i0 = clamp(i0, (ssize_t)0, m_MapSize-1); + j0 = clamp(j0, (ssize_t)0, m_MapSize-1); + i1 = clamp(i1, (ssize_t)0, m_MapSize-1); + j1 = clamp(j1, (ssize_t)0, m_MapSize-1); + + u16 minH = 65535; + u16 maxH = 0; + + for (ssize_t j = j0; j <= j1; ++j) + { + for (ssize_t i = i0; i <= i1; ++i) + { + minH = std::min(minH, m_Heightmap[j*m_MapSize + i]); + maxH = std::max(maxH, m_Heightmap[j*m_MapSize + i]); + } + } + + CBound bound; + bound[0].X = (float)(i0*CELL_SIZE); + bound[0].Y = (float)(minH*HEIGHT_SCALE); + bound[0].Z = (float)(j0*CELL_SIZE); + bound[1].X = (float)(i1*CELL_SIZE); + bound[1].Y = (float)(maxH*HEIGHT_SCALE); + bound[1].Z = (float)(j1*CELL_SIZE); + return bound; +} diff --git a/source/graphics/Terrain.h b/source/graphics/Terrain.h index 1b1112ea75..98445fc72a 100644 --- a/source/graphics/Terrain.h +++ b/source/graphics/Terrain.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,6 +30,7 @@ class CPatch; class CMiniPatch; class CFixedVector3D; class CStr8; +class CBound; /////////////////////////////////////////////////////////////////////////////// // Terrain Constants: @@ -134,6 +135,11 @@ public: // mark the entire map as dirty void MakeDirty(int dirtyFlags); + /** + * Returns a 3D bounding box encompassing the given vertex range (inclusive) + */ + CBound GetVertexesBound(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1); + // get the base colour for the terrain (typically pure white - other colours // will interact badly with LOS - but used by the Actor Viewer tool) SColor4ub GetBaseColour() const { return m_BaseColour; } diff --git a/source/graphics/Unit.cpp b/source/graphics/Unit.cpp index d6a395923c..6ca874855a 100644 --- a/source/graphics/Unit.cpp +++ b/source/graphics/Unit.cpp @@ -32,7 +32,10 @@ CUnit::CUnit(CObjectEntry* object, CObjectManager& objectManager, m_ID(INVALID_ENTITY), m_ActorSelections(actorSelections), m_ObjectManager(objectManager) { - m_Animation = new CUnitAnimation(*this); + if (m_Model->ToCModel()) + m_Animation = new CUnitAnimation(m_ID, m_Model->ToCModel(), m_Object); + else + m_Animation = NULL; } CUnit::~CUnit() @@ -63,7 +66,8 @@ CUnit* CUnit::Create(const CStrW& actorName, const std::set& selections, C void CUnit::UpdateModel(float frameTime) { - m_Animation->Update(frameTime*1000.0f); + if (m_Animation) + m_Animation->Update(frameTime*1000.0f); } void CUnit::SetEntitySelection(const CStr& selection) @@ -99,17 +103,28 @@ void CUnit::ReloadObject() if (newObject && newObject != m_Object) { // Clone the new object's base (non-instance) model - CModel* newModel = newObject->m_Model->Clone(); + CModelAbstract* newModel = newObject->m_Model->Clone(); // Copy the old instance-specific settings from the old model to the new instance newModel->SetTransform(m_Model->GetTransform()); newModel->SetPlayerID(m_Model->GetPlayerID()); - newModel->CopyAnimationFrom(m_Model); + if (newModel->ToCModel() && m_Model->ToCModel()) + newModel->ToCModel()->CopyAnimationFrom(m_Model->ToCModel()); delete m_Model; m_Model = newModel; m_Object = newObject; - m_Animation->ReloadUnit(); // TODO: maybe this should try to preserve animation state? + if (m_Model->ToCModel()) + { + if (m_Animation) + m_Animation->ReloadUnit(m_Model->ToCModel(), m_Object); // TODO: maybe this should try to preserve animation state? + else + m_Animation = new CUnitAnimation(m_ID, m_Model->ToCModel(), m_Object); + } + else + { + SAFE_DELETE(m_Animation); + } } } diff --git a/source/graphics/Unit.h b/source/graphics/Unit.h index 889c04b01c..ddec350470 100644 --- a/source/graphics/Unit.h +++ b/source/graphics/Unit.h @@ -23,7 +23,7 @@ #include "ps/CStr.h" #include "simulation2/system/Entity.h" // entity_id_t -class CModel; +class CModelAbstract; class CObjectEntry; class CObjectManager; class CSkeletonAnim; @@ -52,9 +52,9 @@ public: // get unit's template object const CObjectEntry& GetObject() const { return *m_Object; } // get unit's model data - CModel& GetModel() const { return *m_Model; } + CModelAbstract& GetModel() const { return *m_Model; } - CUnitAnimation& GetAnimation() { return *m_Animation; } + CUnitAnimation* GetAnimation() { return m_Animation; } /** * Update the model's animation. @@ -80,7 +80,7 @@ private: // object from which unit was created; never NULL CObjectEntry* m_Object; // object model representation; never NULL - CModel* m_Model; + CModelAbstract* m_Model; CUnitAnimation* m_Animation; diff --git a/source/graphics/UnitAnimation.cpp b/source/graphics/UnitAnimation.cpp index 9e38e87b66..7d7d000a8d 100644 --- a/source/graphics/UnitAnimation.cpp +++ b/source/graphics/UnitAnimation.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -40,10 +40,11 @@ static float DesyncSpeed(float speed, float desync) return speed * (1.f - desync + 2.f*desync*(rand(0, 256)/255.f)); } -CUnitAnimation::CUnitAnimation(CUnit& unit) -: m_Unit(unit), m_State("idle"), m_Looping(true), m_Speed(1.f), m_SyncRepeatTime(0.f), m_OriginalSpeed(1.f), m_Desync(0.f) +CUnitAnimation::CUnitAnimation(entity_id_t ent, CModel* model, CObjectEntry* object) + : m_Entity(ent), m_State("idle"), m_Looping(true), + m_Speed(1.f), m_SyncRepeatTime(0.f), m_OriginalSpeed(1.f), m_Desync(0.f) { - ReloadUnit(); + ReloadUnit(model, object); } void CUnitAnimation::AddModel(CModel* model, const CObjectEntry* object) @@ -70,17 +71,22 @@ void CUnitAnimation::AddModel(CModel* model, const CObjectEntry* object) const std::vector& props = model->GetProps(); for (std::vector::const_iterator it = props.begin(); it != props.end(); ++it) { - AddModel(it->m_Model, it->m_ObjectEntry); + CModel* propModel = it->m_Model->ToCModel(); + if (propModel) + AddModel(propModel, it->m_ObjectEntry); } } -void CUnitAnimation::ReloadUnit() +void CUnitAnimation::ReloadUnit(CModel* model, const CObjectEntry* object) { + m_Model = model; + m_Object = object; + m_AnimStates.clear(); - AddModel(&m_Unit.GetModel(), &m_Unit.GetObject()); + AddModel(m_Model, m_Object); } -void CUnitAnimation::SetAnimationState(const CStr& name, bool once, float speed, float desync, bool keepSelection, const CStrW& actionSound) +void CUnitAnimation::SetAnimationState(const CStr& name, bool once, float speed, float desync, const CStrW& actionSound) { m_Looping = !once; m_OriginalSpeed = speed; @@ -94,10 +100,7 @@ void CUnitAnimation::SetAnimationState(const CStr& name, bool once, float speed, { m_State = name; - if (! keepSelection) - m_Unit.SetEntitySelection(name); - - ReloadUnit(); + ReloadUnit(m_Model, m_Object); } } @@ -179,7 +182,7 @@ void CUnitAnimation::Update(float time) { CmpPtr cmpSoundManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY); if (!cmpSoundManager.null()) - cmpSoundManager->PlaySoundGroup(m_ActionSound, m_Unit.GetID()); + cmpSoundManager->PlaySoundGroup(m_ActionSound, m_Entity); } it->pastActionPos = true; diff --git a/source/graphics/UnitAnimation.h b/source/graphics/UnitAnimation.h index 1330b1d986..4190a969d9 100644 --- a/source/graphics/UnitAnimation.h +++ b/source/graphics/UnitAnimation.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,6 +20,8 @@ #include "ps/CStr.h" +#include "simulation2/system/Entity.h" + class CUnit; class CModel; class CSkeletonAnim; @@ -37,7 +39,7 @@ public: /** * Construct for a given unit, defaulting to the "idle" animation. */ - CUnitAnimation(CUnit& unit); + CUnitAnimation(entity_id_t ent, CModel* model, CObjectEntry* object); /** * Start playing an animation. @@ -52,10 +54,9 @@ public: * @param once if true then the animation freezes on its last frame; otherwise it loops * @param speed fraction of actor-defined speed to play back at (should typically be 1.0) * @param desync maximum fraction of length/speed to randomly adjust timings (or 0.0 for no desyncing) - * @param keepSelection if false then the random actor variation will have the selection @p name added * @param actionSound sound group name to be played at the 'action' point in the animation, or empty string */ - void SetAnimationState(const CStr& name, bool once, float speed, float desync, bool keepSelection, const CStrW& actionSound); + void SetAnimationState(const CStr& name, bool once, float speed, float desync, const CStrW& actionSound); /** * Adjust the speed of the current animation, so that Update(repeatTime) will do a @@ -82,7 +83,7 @@ public: * Regenerate internal animation state from the models in the current unit. * This should be called whenever the unit is changed externally, to keep this in sync. */ - void ReloadUnit(); + void ReloadUnit(CModel* model, const CObjectEntry* object); private: struct SModelAnimState @@ -99,7 +100,9 @@ private: void AddModel(CModel* model, const CObjectEntry* object); - CUnit& m_Unit; + entity_id_t m_Entity; + CModel* m_Model; + const CObjectEntry* m_Object; CStr m_State; bool m_Looping; float m_OriginalSpeed; diff --git a/source/maths/Bound.cpp b/source/maths/Bound.cpp index 757962937f..2da01b5816 100644 --- a/source/maths/Bound.cpp +++ b/source/maths/Bound.cpp @@ -206,37 +206,37 @@ void CBound::IntersectFrustumConservative(const CFrustum& frustum) /////////////////////////////////////////////////////////////////////////////// // Render the bounding box -void CBound::Render() +void CBound::Render() const { glBegin(GL_QUADS); - glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z); - glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z); - glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z); - glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z); + glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z); + glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z); + glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z); + glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z); - glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z); - glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z); - glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z); - glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z); + glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z); + glTexCoord2f(1, 0); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z); + glTexCoord2f(1, 1); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z); + glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z); - glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z); - glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z); - glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z); - glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z); + glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z); + glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z); + glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z); + glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z); - glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z); - glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z); - glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z); - glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z); + glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z); + glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z); + glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z); + glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z); - glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z); - glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z); - glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z); - glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z); + glTexCoord2f(0, 0); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z); + glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z); + glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z); + glTexCoord2f(0, 1); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z); - glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z); - glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z); - glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z); - glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z); + glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z); + glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z); + glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z); + glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z); glEnd(); } diff --git a/source/maths/Bound.h b/source/maths/Bound.h index 38b3642a79..7247acfafe 100644 --- a/source/maths/Bound.h +++ b/source/maths/Bound.h @@ -80,7 +80,7 @@ public: /** * Render: Render the surfaces of the bound object as polygons. */ - void Render(); + void Render() const; private: CVector3D m_Data[2]; diff --git a/source/maths/Matrix3D.cpp b/source/maths/Matrix3D.cpp index a60411c2f2..6dfac6aa8b 100644 --- a/source/maths/Matrix3D.cpp +++ b/source/maths/Matrix3D.cpp @@ -134,6 +134,14 @@ CMatrix3D& CMatrix3D::operator+=(const CMatrix3D& m) return *this; } +bool CMatrix3D::operator==(const CMatrix3D &matrix) const +{ + for (int i = 0; i < 16; ++i) + if (matrix._data[i] != _data[i]) + return false; + return true; +} + //Sets the identity matrix void CMatrix3D::SetIdentity () { diff --git a/source/maths/Matrix3D.h b/source/maths/Matrix3D.h index 2388b6a9fc..3d23262c7c 100644 --- a/source/maths/Matrix3D.h +++ b/source/maths/Matrix3D.h @@ -75,6 +75,9 @@ public: // matrix addition/assignment CMatrix3D& operator+=(const CMatrix3D &matrix); + // equality + bool operator==(const CMatrix3D &matrix) const; + // set this matrix to the identity matrix void SetIdentity(); // set this matrix to the zero matrix diff --git a/source/renderer/DecalRData.cpp b/source/renderer/DecalRData.cpp new file mode 100644 index 0000000000..dde2d1066f --- /dev/null +++ b/source/renderer/DecalRData.cpp @@ -0,0 +1,185 @@ +/* Copyright (C) 2011 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 . + */ + +#include "precompiled.h" + +#include "DecalRData.h" + +#include "graphics/Decal.h" +#include "graphics/Model.h" +#include "graphics/Terrain.h" +#include "graphics/TextureManager.h" +#include "ps/Game.h" +#include "ps/Profile.h" +#include "renderer/Renderer.h" +#include "simulation2/Simulation2.h" +#include "simulation2/components/ICmpWaterManager.h" + +// TODO: Currently each decal is a separate CDecalRData. We might want to use +// lots of decals for special effects like shadows, footprints, etc, in which +// case we should probably redesign this to batch them all together for more +// efficient rendering. + +CDecalRData::CDecalRData(CModelDecal* decal) + : m_Decal(decal), m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW) +{ + m_Position.type = GL_FLOAT; + m_Position.elems = 3; + m_Array.AddAttribute(&m_Position); + + m_UV.type = GL_FLOAT; + m_UV.elems = 2; + m_Array.AddAttribute(&m_UV); + + BuildArrays(); +} + +CDecalRData::~CDecalRData() +{ +} + +void CDecalRData::Update() +{ + if (m_UpdateFlags != 0) + { + BuildArrays(); + m_UpdateFlags = 0; + } +} + +void CDecalRData::Render() +{ + m_Decal->m_Decal.m_Texture->Bind(0); + + // TODO: Need to handle floating decals correctly. In particular, we need + // to render non-floating before water and floating after water (to get + // the blending right), and we also need to apply the correct lighting in + // each case, which doesn't really seem possible with the current + // TerrainRenderer. + // Also, need to mark the decals as dirty when water height changes. + +// glDisable(GL_TEXTURE_2D); +// m_Decal->GetBounds().Render(); +// glEnable(GL_TEXTURE_2D); + + u8* base = m_Array.Bind(); + GLsizei stride = (GLsizei)m_Array.GetStride(); + + u8* indexBase = m_IndexArray.Bind(); + + glColor3fv(m_Decal->GetShadingColor().FloatArray()); + + glVertexPointer(3, GL_FLOAT, stride, base + m_Position.offset); + glTexCoordPointer(2, GL_FLOAT, stride, base + m_UV.offset); + + if (!g_Renderer.m_SkipSubmit) + { + glDrawElements(GL_TRIANGLES, (GLsizei)m_IndexArray.GetNumVertices(), GL_UNSIGNED_SHORT, indexBase); + } + + // bump stats + g_Renderer.m_Stats.m_DrawCalls++; + g_Renderer.m_Stats.m_TerrainTris += m_IndexArray.GetNumVertices() / 3; + + CVertexBuffer::Unbind(); +} + +void CDecalRData::BuildArrays() +{ + PROFILE("decal build"); + + const SDecal& decal = m_Decal->m_Decal; + + // TODO: Currently this constructs an axis-aligned bounding rectangle around + // the decal. It would be more efficient for rendering if we excluded tiles + // that are outside the (non-axis-aligned) decal rectangle. + + ssize_t i0, j0, i1, j1; + m_Decal->CalcVertexExtents(i0, j0, i1, j1); + + // Construct vertex data arrays + + CmpPtr cmpWaterManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY); + + m_Array.SetNumVertices((i1-i0+1)*(j1-j0+1)); + m_Array.Layout(); + VertexArrayIterator Position = m_Position.GetIterator(); + VertexArrayIterator UV = m_UV.GetIterator(); + + for (ssize_t j = j0; j <= j1; ++j) + { + for (ssize_t i = i0; i <= i1; ++i) + { + CVector3D pos; + m_Decal->m_Terrain->CalcPosition(i, j, pos); + + if (decal.m_Floating && !cmpWaterManager.null()) + pos.Y = std::max(pos.Y, cmpWaterManager->GetExactWaterLevel(pos.X, pos.Z)); + + *Position = pos; + ++Position; + + // Map from world space back into decal texture space + CVector3D inv = m_Decal->GetInvTransform().Transform(pos); + (*UV)[0] = 0.5f + (inv.X - decal.m_OffsetX) / decal.m_SizeX; + (*UV)[1] = 0.5f - (inv.Z - decal.m_OffsetZ) / decal.m_SizeZ; // flip V to match our texture convention + ++UV; + } + } + + m_Array.Upload(); + m_Array.FreeBackingStore(); + + // Construct index arrays for each terrain tile + + m_IndexArray.SetNumVertices((i1-i0)*(j1-j0)*6); + m_IndexArray.Layout(); + VertexArrayIterator Index = m_IndexArray.GetIterator(); + + u16 base = 0; + ssize_t w = i1-i0+1; + for (ssize_t dj = 0; dj < j1-j0; ++dj) + { + for (ssize_t di = 0; di < i1-i0; ++di) + { + bool dir = m_Decal->m_Terrain->GetTriangulationDir(i0+di, j0+dj); + if (dir) + { + *Index++ = u16(((dj+0)*w+(di+0))+base); + *Index++ = u16(((dj+0)*w+(di+1))+base); + *Index++ = u16(((dj+1)*w+(di+0))+base); + + *Index++ = u16(((dj+0)*w+(di+1))+base); + *Index++ = u16(((dj+1)*w+(di+1))+base); + *Index++ = u16(((dj+1)*w+(di+0))+base); + } + else + { + *Index++ = u16(((dj+0)*w+(di+0))+base); + *Index++ = u16(((dj+0)*w+(di+1))+base); + *Index++ = u16(((dj+1)*w+(di+1))+base); + + *Index++ = u16(((dj+1)*w+(di+1))+base); + *Index++ = u16(((dj+1)*w+(di+0))+base); + *Index++ = u16(((dj+0)*w+(di+0))+base); + } + } + } + + m_IndexArray.Upload(); + m_IndexArray.FreeBackingStore(); +} diff --git a/source/renderer/DecalRData.h b/source/renderer/DecalRData.h new file mode 100644 index 0000000000..e0dd13cb9f --- /dev/null +++ b/source/renderer/DecalRData.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2011 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 . + */ + +#ifndef INCLUDED_DECALRDATA +#define INCLUDED_DECALRDATA + +#include "graphics/RenderableObject.h" +#include "renderer/VertexArray.h" + +class CModelDecal; + +class CDecalRData : public CRenderData +{ +public: + CDecalRData(CModelDecal* decal); + ~CDecalRData(); + + void Update(); + + void Render(); + +private: + void BuildArrays(); + + VertexIndexArray m_IndexArray; + + VertexArray m_Array; + VertexArray::Attribute m_Position; + VertexArray::Attribute m_UV; + + CModelDecal* m_Decal; +}; + +#endif // INCLUDED_DECALRDATA diff --git a/source/renderer/PatchRData.h b/source/renderer/PatchRData.h index 79bb697a39..da0eece5c1 100644 --- a/source/renderer/PatchRData.h +++ b/source/renderer/PatchRData.h @@ -45,6 +45,8 @@ public: static void RenderBlends(const std::vector& patches); static void RenderStreams(const std::vector& patches, int streamflags); + CPatch* GetPatch() { return m_Patch; } + private: struct SSplat { SSplat() : m_Texture(0), m_IndexCount(0) {} diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index b16f94a96a..e86f95115d 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -1410,6 +1410,11 @@ void CRenderer::Submit(SOverlaySprite* overlay) m->overlayRenderer.Submit(overlay); } +void CRenderer::Submit(CModelDecal* decal) +{ + m->terrainRenderer->Submit(decal); +} + void CRenderer::SubmitNonRecursive(CModel* model) { if (model->GetFlags() & MODELFLAG_CASTSHADOWS) { diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index 9ad2861321..e37123d869 100644 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -303,6 +303,7 @@ protected: friend struct CRendererInternals; friend class CVertexBuffer; friend class CPatchRData; + friend class CDecalRData; friend class FixedFunctionModelRenderer; friend class ModelRenderer; friend class PolygonSortModelRenderer; @@ -332,6 +333,7 @@ protected: void Submit(CPatch* patch); void Submit(SOverlayLine* overlay); void Submit(SOverlaySprite* overlay); + void Submit(CModelDecal* decal); void SubmitNonRecursive(CModel* model); //END: Implementation of SceneCollector diff --git a/source/renderer/Scene.cpp b/source/renderer/Scene.cpp index a1c88a238b..49245c176e 100644 --- a/source/renderer/Scene.cpp +++ b/source/renderer/Scene.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -34,14 +34,23 @@ /////////////////////////////////////////////////////////// // Default implementation traverses the model recursively and uses // SubmitNonRecursive for the actual work. -void SceneCollector::SubmitRecursive(CModel* model) +void SceneCollector::SubmitRecursive(CModelAbstract* model) { - SubmitNonRecursive(model); - - const std::vector& props = model->GetProps(); - for (size_t i = 0; i < props.size(); i++) + if (model->ToCModel()) { - if (!props[i].m_Hidden) - SubmitRecursive(props[i].m_Model); + SubmitNonRecursive(model->ToCModel()); + + const std::vector& props = model->ToCModel()->GetProps(); + for (size_t i = 0; i < props.size(); i++) + { + if (!props[i].m_Hidden) + SubmitRecursive(props[i].m_Model); + } } + else if (model->ToCModelDecal()) + { + Submit(model->ToCModelDecal()); + } + else + debug_warn(L"unknown model type"); } diff --git a/source/renderer/Scene.h b/source/renderer/Scene.h index 356a52b136..a51dd95b37 100644 --- a/source/renderer/Scene.h +++ b/source/renderer/Scene.h @@ -30,6 +30,8 @@ class CFrustum; class CModel; +class CModelAbstract; +class CModelDecal; class CPatch; struct SOverlayLine; struct SOverlaySprite; @@ -82,6 +84,11 @@ public: */ virtual void Submit(SOverlaySprite* overlay) = 0; + /** + * Submit a terrain decal. + */ + virtual void Submit(CModelDecal* decal) = 0; + /** * Submit a model that is part of the scene, * without submitting attached models. @@ -95,7 +102,7 @@ public: * @note This function is implemented using SubmitNonRecursive, * so you shouldn't have to reimplement it. */ - virtual void SubmitRecursive(CModel* model); + virtual void SubmitRecursive(CModelAbstract* model); }; diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index 9e7c9c4fa1..3816313806 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -23,11 +23,13 @@ #include "precompiled.h" #include "graphics/Camera.h" +#include "graphics/Decal.h" #include "graphics/LightEnv.h" #include "graphics/LOSTexture.h" #include "graphics/Patch.h" #include "graphics/Terrain.h" #include "graphics/GameView.h" +#include "graphics/Model.h" #include "maths/MathUtil.h" @@ -38,10 +40,12 @@ #include "ps/Profile.h" #include "ps/World.h" +#include "renderer/DecalRData.h" #include "renderer/PatchRData.h" #include "renderer/Renderer.h" #include "renderer/ShadowMap.h" #include "renderer/TerrainRenderer.h" +#include "renderer/VertexArray.h" #include "renderer/WaterManager.h" #include "lib/res/graphics/ogl_shader.h" @@ -69,12 +73,11 @@ struct TerrainRendererInternals /// Which phase (submitting or rendering patches) are we in right now? Phase phase; - /** - * VisiblePatches: Patches that were submitted for this frame - * - * @todo Merge this list with CPatchRData list - */ - std::vector visiblePatches; + /// Patches that were submitted for this frame + std::vector visiblePatches; + + /// Decals that were submitted for this frame + std::vector visibleDecals; /// Fancy water shader Handle fancyWaterShader; @@ -107,7 +110,7 @@ void TerrainRenderer::Submit(CPatch* patch) { debug_assert(m->phase == Phase_Submit); - CPatchRData* data=(CPatchRData*) patch->GetRenderData(); + CPatchRData* data = (CPatchRData*)patch->GetRenderData(); if (data == 0) { // no renderdata for patch, create it now @@ -116,9 +119,26 @@ void TerrainRenderer::Submit(CPatch* patch) } data->Update(); - m->visiblePatches.push_back(patch); + m->visiblePatches.push_back(data); } +/////////////////////////////////////////////////////////////////// +// Submit a decal for rendering +void TerrainRenderer::Submit(CModelDecal* decal) +{ + debug_assert(m->phase == Phase_Submit); + + CDecalRData* data = (CDecalRData*)decal->GetRenderData(); + if (data == 0) + { + // no renderdata for decal, create it now + data = new CDecalRData(decal); + decal->SetRenderData(data); + } + data->Update(); + + m->visibleDecals.push_back(data); +} /////////////////////////////////////////////////////////////////// // Prepare for rendering @@ -136,40 +156,25 @@ void TerrainRenderer::EndFrame() debug_assert(m->phase == Phase_Render || m->phase == Phase_Submit); m->visiblePatches.clear(); + m->visibleDecals.clear(); m->phase = Phase_Submit; } -/////////////////////////////////////////////////////////////////// -// Query if patches have been submitted this frame -bool TerrainRenderer::HaveSubmissions() -{ - return !m->visiblePatches.empty(); -} - - /////////////////////////////////////////////////////////////////// // Full-featured terrain rendering with blending and everything void TerrainRenderer::RenderTerrain(ShadowMap* shadow) { debug_assert(m->phase == Phase_Render); - std::vector patchRDatas; - patchRDatas.reserve(m->visiblePatches.size()); - for (size_t i = 0; i < m->visiblePatches.size(); ++i) - patchRDatas.push_back(static_cast(m->visiblePatches[i]->GetRenderData())); - // render the solid black sides of the map first g_Renderer.BindTexture(0, 0); glEnableClientState(GL_VERTEX_ARRAY); glColor3f(0, 0, 0); PROFILE_START("render terrain sides"); for (size_t i = 0; i < m->visiblePatches.size(); ++i) - { - CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData(); - patchdata->RenderSides(); - } + m->visiblePatches[i]->RenderSides(); PROFILE_END("render terrain sides"); // switch on required client states @@ -192,7 +197,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow) glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, one); PROFILE_START("render terrain base"); - CPatchRData::RenderBases(patchRDatas); + CPatchRData::RenderBases(m->visiblePatches); PROFILE_END("render terrain base"); // render blends @@ -222,13 +227,35 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow) // render blend passes for each patch PROFILE_START("render terrain blends"); - CPatchRData::RenderBlends(patchRDatas); + CPatchRData::RenderBlends(m->visiblePatches); PROFILE_END("render terrain blends"); // Disable second texcoord array pglClientActiveTextureARB(GL_TEXTURE1); glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + // Render terrain decals + + g_Renderer.BindTexture(1, 0); + pglActiveTextureARB(GL_TEXTURE0); + pglClientActiveTextureARB(GL_TEXTURE0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + + PROFILE_START("render terrain decals"); + for (size_t i = 0; i < m->visibleDecals.size(); ++i) + m->visibleDecals[i]->Render(); + PROFILE_END("render terrain decals"); + + // Now apply lighting const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); @@ -292,15 +319,16 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow) } else { - const CMatrix3D& texturematrix = shadow->GetTextureMatrix(); + losTexture.BindTexture(1); + g_Renderer.BindTexture(0, shadow->GetTexture()); + + const CMatrix3D& texturematrix = shadow->GetTextureMatrix(); pglActiveTextureARB(GL_TEXTURE0); glMatrixMode(GL_TEXTURE); glLoadMatrixf(&texturematrix._11); glMatrixMode(GL_MODELVIEW); - glBindTexture(GL_TEXTURE_2D, shadow->GetTexture()); - if (shadow->GetUseDepthTexture()) { // (Ambient + ShTranslucency * Diffuse * (1 - Shadow) + Diffuse * Shadow) * LOS @@ -416,7 +444,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow) pglClientActiveTextureARB(GL_TEXTURE0); PROFILE_START("render terrain streams"); - CPatchRData::RenderStreams(patchRDatas, streamflags); + CPatchRData::RenderStreams(m->visiblePatches, streamflags); PROFILE_END("render terrain streams"); glMatrixMode(GL_TEXTURE); @@ -475,13 +503,8 @@ void TerrainRenderer::RenderPatches() { debug_assert(m->phase == Phase_Render); - std::vector patchRDatas; - patchRDatas.reserve(m->visiblePatches.size()); - for (size_t i = 0; i < m->visiblePatches.size(); ++i) - patchRDatas.push_back(static_cast(m->visiblePatches[i]->GetRenderData())); - glEnableClientState(GL_VERTEX_ARRAY); - CPatchRData::RenderStreams(patchRDatas, STREAM_POS); + CPatchRData::RenderStreams(m->visiblePatches, STREAM_POS); glDisableClientState(GL_VERTEX_ARRAY); } @@ -493,11 +516,8 @@ void TerrainRenderer::RenderOutlines() debug_assert(m->phase == Phase_Render); glEnableClientState(GL_VERTEX_ARRAY); - for(size_t i = 0; i < m->visiblePatches.size(); ++i) - { - CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData(); - patchdata->RenderOutline(); - } + for (size_t i = 0; i < m->visiblePatches.size(); ++i) + m->visiblePatches[i]->RenderOutline(); glDisableClientState(GL_VERTEX_ARRAY); } @@ -665,7 +685,7 @@ void TerrainRenderer::RenderWater() for(size_t i=0; ivisiblePatches.size(); i++) { - CPatch* patch = m->visiblePatches[i]; + CPatch* patch = m->visiblePatches[i]->GetPatch(); for(ssize_t dx=0; dxvisiblePatches.size(); ++i) - { - CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData(); - patchdata->RenderPriorities(); - } + m->visiblePatches[i]->RenderPriorities(); } diff --git a/source/renderer/TerrainRenderer.h b/source/renderer/TerrainRenderer.h index 1708c45c64..9db03087fe 100644 --- a/source/renderer/TerrainRenderer.h +++ b/source/renderer/TerrainRenderer.h @@ -51,6 +51,11 @@ public: */ void Submit(CPatch* patch); + /** + * Submit: Add a terrain decal for rendering in this frame. + */ + void Submit(CModelDecal* decal); + /** * PrepareForRendering: Prepare internal data structures like vertex * buffers for rendering. @@ -66,15 +71,6 @@ public: */ void EndFrame(); - /** - * HaveSubmissions: Query whether any patches have been submitted - * for this frame. - * - * @return @c true if a patch has been submitted for this frame, - * @c false otherwise. - */ - bool HaveSubmissions(); - /** * RenderTerrain: Render textured terrain (including blends between * different terrain types). diff --git a/source/simulation2/components/CCmpProjectileManager.cpp b/source/simulation2/components/CCmpProjectileManager.cpp index e525537e3d..e640359a90 100644 --- a/source/simulation2/components/CCmpProjectileManager.cpp +++ b/source/simulation2/components/CCmpProjectileManager.cpp @@ -337,7 +337,7 @@ void CCmpProjectileManager::RenderSubmit(SceneCollector& collector, const CFrust if (!losRevealAll && !los.IsVisible(posi, posj)) continue; - CModel& model = m_Projectiles[i].unit->GetModel(); + CModelAbstract& model = m_Projectiles[i].unit->GetModel(); model.ValidatePosition(); diff --git a/source/simulation2/components/CCmpVisualActor.cpp b/source/simulation2/components/CCmpVisualActor.cpp index 1fcdb33859..a5a1dbc1bf 100644 --- a/source/simulation2/components/CCmpVisualActor.cpp +++ b/source/simulation2/components/CCmpVisualActor.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2011 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -47,6 +47,7 @@ public: componentManager.SubscribeToMessageType(MT_Interpolate); componentManager.SubscribeToMessageType(MT_RenderSubmit); componentManager.SubscribeToMessageType(MT_OwnershipChanged); + componentManager.SubscribeGloballyToMessageType(MT_TerrainChanged); } DEFAULT_COMPONENT_ALLOCATOR(VisualActor) @@ -196,6 +197,12 @@ public: m_Unit->GetModel().SetPlayerID(msgData.to); break; } + case MT_TerrainChanged: + { + const CMessageTerrainChanged& msgData = static_cast (msg); + m_Unit->GetModel().SetTerrainDirty(msgData.i0, msgData.j0, msgData.i1, msgData.j1); + break; + } } } @@ -232,13 +239,17 @@ public: if (!m_Unit) return CVector3D(); - // Ensure the prop transforms are correct - m_Unit->GetModel().ValidatePosition(); + if (m_Unit->GetModel().ToCModel()) + { + // Ensure the prop transforms are correct + m_Unit->GetModel().ValidatePosition(); - CModel* ammo = m_Unit->GetModel().FindFirstAmmoProp(); - if (!ammo) - return CVector3D(); - return ammo->GetTransform().GetTranslation(); + CModelAbstract* ammo = m_Unit->GetModel().ToCModel()->FindFirstAmmoProp(); + if (ammo) + return ammo->GetTransform().GetTranslation(); + } + + return CVector3D(); } virtual void SelectAnimation(std::string name, bool once, float speed, std::wstring soundgroup) @@ -257,7 +268,9 @@ public: m_AnimDesync = 0.05f; // TODO: make this an argument m_AnimSyncRepeatTime = 0.0f; - m_Unit->GetAnimation().SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, false, m_SoundGroup.c_str()); + m_Unit->SetEntitySelection(m_AnimName); + if (m_Unit->GetAnimation()) + m_Unit->GetAnimation()->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, m_SoundGroup.c_str()); } virtual void SelectMovementAnimation(float runThreshold) @@ -267,7 +280,9 @@ public: m_AnimRunThreshold = runThreshold; - m_Unit->GetAnimation().SetAnimationState("walk", false, 1.f, 0.f, false, L""); + m_Unit->SetEntitySelection("walk"); + if (m_Unit->GetAnimation()) + m_Unit->GetAnimation()->SetAnimationState("walk", false, 1.f, 0.f, L""); } virtual void SetAnimationSyncRepeat(float repeattime) @@ -277,7 +292,8 @@ public: m_AnimSyncRepeatTime = repeattime; - m_Unit->GetAnimation().SetAnimationSyncRepeat(m_AnimSyncRepeatTime); + if (m_Unit->GetAnimation()) + m_Unit->GetAnimation()->SetAnimationSyncRepeat(m_AnimSyncRepeatTime); } virtual void SetAnimationSyncOffset(float actiontime) @@ -285,7 +301,8 @@ public: if (!m_Unit) return; - m_Unit->GetAnimation().SetAnimationSyncOffset(actiontime); + if (m_Unit->GetAnimation()) + m_Unit->GetAnimation()->SetAnimationSyncOffset(actiontime); } virtual void SetShadingColour(fixed r, fixed g, fixed b, fixed a) @@ -320,11 +337,14 @@ public: m_Unit->SetID(GetEntityId()); - m_Unit->GetAnimation().SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, false, m_SoundGroup.c_str()); + m_Unit->SetEntitySelection(m_AnimName); + if (m_Unit->GetAnimation()) + m_Unit->GetAnimation()->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, m_SoundGroup.c_str()); // We'll lose the exact synchronisation but we should at least make sure it's going at the correct rate if (m_AnimSyncRepeatTime != 0.0f) - m_Unit->GetAnimation().SetAnimationSyncRepeat(m_AnimSyncRepeatTime); + if (m_Unit->GetAnimation()) + m_Unit->GetAnimation()->SetAnimationSyncRepeat(m_AnimSyncRepeatTime); m_Unit->GetModel().SetShadingColor(shading); @@ -354,11 +374,23 @@ void CCmpVisualActor::Update(fixed turnLength) float speed = cmpPosition->GetDistanceTravelled().ToFloat() / turnLength.ToFloat(); if (speed == 0.0f) - m_Unit->GetAnimation().SetAnimationState("idle", false, 1.f, 0.f, false, L""); + { + m_Unit->SetEntitySelection("idle"); + if (m_Unit->GetAnimation()) + m_Unit->GetAnimation()->SetAnimationState("idle", false, 1.f, 0.f, L""); + } else if (speed < m_AnimRunThreshold) - m_Unit->GetAnimation().SetAnimationState("walk", false, speed, 0.f, false, L""); + { + m_Unit->SetEntitySelection("walk"); + if (m_Unit->GetAnimation()) + m_Unit->GetAnimation()->SetAnimationState("walk", false, speed, 0.f, L""); + } else - m_Unit->GetAnimation().SetAnimationState("run", false, speed, 0.f, false, L""); + { + m_Unit->SetEntitySelection("run"); + if (m_Unit->GetAnimation()) + m_Unit->GetAnimation()->SetAnimationState("run", false, speed, 0.f, L""); + } } } @@ -398,7 +430,7 @@ void CCmpVisualActor::Interpolate(float frameTime, float frameOffset) CMatrix3D transform(cmpPosition->GetInterpolatedTransform(frameOffset, floating)); - CModel& model = m_Unit->GetModel(); + CModelAbstract& model = m_Unit->GetModel(); model.SetTransform(transform); m_Unit->UpdateModel(frameTime); @@ -423,7 +455,7 @@ void CCmpVisualActor::RenderSubmit(SceneCollector& collector, const CFrustum& fr if (m_Visibility == ICmpRangeManager::VIS_HIDDEN) return; - CModel& model = m_Unit->GetModel(); + CModelAbstract& model = m_Unit->GetModel(); if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), model.GetBounds())) return;