#include "precompiled.h" #include #include "MathUtil.h" #include "lib/res/graphics/ogl_tex.h" #include "Renderer.h" #include "TransparencyRenderer.h" #include "PlayerRenderer.h" #include "ModelRData.h" #include "Model.h" #include "ModelDef.h" #include "MaterialManager.h" #include "Profile.h" #include "renderer/ModelDefRData.h" /////////////////////////////////////////////////////////////////// // CModelRData constructor CModelRData::CModelRData(CModel* model) : m_Model(model), m_Normals(0), m_DynamicArray(true), m_Indices(0), m_Flags(0) { debug_assert(model); // build all data now Build(); } /////////////////////////////////////////////////////////////////// // CModelRData destructor CModelRData::~CModelRData() { // clean up system copies of data delete[] m_Indices; delete[] m_Normals; } void CModelRData::Build() { CModelDefPtr mdef = m_Model->GetModelDef(); if (!mdef->GetRenderData()) { mdef->SetRenderData(new CModelDefRData(&*mdef)); } m_Position.type = GL_FLOAT; m_Position.elems = 3; m_DynamicArray.AddAttribute(&m_Position); /* m_UV.type = GL_FLOAT; m_UV.elems = 2; m_DynamicArray.AddAttribute(&m_UV); */ m_Color.type = GL_UNSIGNED_BYTE; m_Color.elems = 3; m_DynamicArray.AddAttribute(&m_Color); m_DynamicArray.SetNumVertices(mdef->GetNumVertices()); m_DynamicArray.Layout(); // build data BuildStaticVertices(); BuildVertices(); BuildIndices(); // force a texture load on model's texture g_Renderer.LoadTexture(m_Model->GetTexture(),GL_CLAMP_TO_EDGE); // setup model render flags /*if (g_Renderer.IsTextureTransparent(m_Model->GetTexture())) { m_Flags|=MODELRDATA_FLAG_TRANSPARENT; }*/ if(m_Model->GetMaterial().IsPlayer()) { m_Flags |= MODELRDATA_FLAG_PLAYERCOLOR; } else if(m_Model->GetMaterial().UsesAlpha()) { m_Flags |= MODELRDATA_FLAG_TRANSPARENT; } } void CModelRData::BuildIndices() { CModelDefPtr mdef=m_Model->GetModelDef(); debug_assert(mdef); // allocate indices if we haven't got any already if (!m_Indices) { m_Indices=new u16[mdef->GetNumFaces()*3]; } // build indices u32 indices=0; SModelFace* faces=mdef->GetFaces(); for (size_t j=0; jGetNumFaces(); j++) { SModelFace& face=faces[j]; m_Indices[indices++]=face.m_Verts[0]; m_Indices[indices++]=face.m_Verts[1]; m_Indices[indices++]=face.m_Verts[2]; } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // SkinPoint: skin the vertex position using it's blend data and given bone matrices static void SkinPoint(const SModelVertex& vertex,const CMatrix3D* matrices,CVector3D& result) { CVector3D tmp; const SVertexBlend& blend=vertex.m_Blend; // must have at least one valid bone if we're using SkinPoint debug_assert(blend.m_Bone[0]!=0xff); const CMatrix3D& m=matrices[blend.m_Bone[0]]; m.Transform(vertex.m_Coords,result); result*=blend.m_Weight[0]; for (u32 i=1; iGetModelDef(); size_t numVertices = mdef->GetNumVertices(); SModelVertex* vertices = mdef->GetVertices(); VertexArrayIterator UVit = m_UV.GetIterator(); for (uint j=0; j < numVertices; ++j, ++UVit) { (*UVit)[0] = vertices[j].m_U; (*UVit)[1] = 1.0-vertices[j].m_V; } */ } void CModelRData::BuildVertices() { CModelDefPtr mdef=m_Model->GetModelDef(); size_t numVertices=mdef->GetNumVertices(); SModelVertex* vertices=mdef->GetVertices(); // allocate vertices if we haven't got any already and // fill in data that never changes if (!m_Normals) m_Normals=new CVector3D[mdef->GetNumVertices()]; // build vertices VertexArrayIterator Position = m_Position.GetIterator(); VertexArrayIterator Color = m_Color.GetIterator(); const CMatrix3D* bonematrices=m_Model->GetBoneMatrices(); if (bonematrices) { // boned model - calculate skinned vertex positions/normals PROFILE( "skinning bones" ); const CMatrix3D* invbonematrices=m_Model->GetInvBoneMatrices(); for (size_t j=0; jGetTransform(); const CMatrix3D& invtransform=m_Model->GetInvTransform(); for (uint j=0; jGetShadingColor(); RGBColor shadingcolor(sc.r, sc.g, sc.b); RGBColor tempcolor; for (uint j=0; jGetModelDef(); if (streamflags & STREAM_UV0) { if(!isplayer) m_Model->GetMaterial().Bind(); else g_Renderer.SetTexture(1,m_Model->GetTexture()); g_Renderer.SetTexture(0,m_Model->GetTexture()); } ((CModelDefRData*)mdldef->GetRenderData())->PrepareStream(streamflags); u8* base = m_DynamicArray.Bind(); size_t stride = m_DynamicArray.GetStride(); glVertexPointer(3, GL_FLOAT, stride, base + m_Position.offset); if (streamflags & STREAM_COLOR) glColorPointer(3, m_Color.type, stride, base + m_Color.offset); #if 0 { uint a = (uint)this; uint b = (uint)m_Model->GetTexture(); uint hash = ((a >> 16) ^ (b & 0xffff)) | ((a & 0xffff0000) ^ (b << 16)); hash = (hash * 65537) + 17; hash |= 0xff000000; glColor4ubv((GLubyte*)&hash); glDisableClientState(GL_COLOR_ARRAY); } #endif // render the lot size_t numFaces=mdldef->GetNumFaces(); glDrawRangeElements(GL_TRIANGLES,0,mdldef->GetNumVertices(),numFaces*3,GL_UNSIGNED_SHORT,m_Indices); if(streamflags & STREAM_UV0 & !isplayer) m_Model->GetMaterial().Unbind(); // bump stats g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_ModelTris+=numFaces; } void CModelRData::Update() { if (m_UpdateFlags!=0) { // renderdata changed : rebuild necessary portions if (m_UpdateFlags & RENDERDATA_UPDATE_VERTICES) { BuildVertices(); } if (m_UpdateFlags & RENDERDATA_UPDATE_INDICES) { BuildIndices(); } m_UpdateFlags=0; } } typedef std::pair IntFloatPair; static std::vector IndexSorter; struct SortFacesByDist { bool operator()(const IntFloatPair& lhs,const IntFloatPair& rhs) { return lhs.second>rhs.second ? true : false; } }; float CModelRData::BackToFrontIndexSort(CMatrix3D& objToCam) { float mindist=1.0e30f; CVector3D osvtx,csvtx; CModelDefPtr mdldef=m_Model->GetModelDef(); SModelVertex* vtxs=mdldef->GetVertices(); size_t numFaces=mdldef->GetNumFaces(); SModelFace* faces=mdldef->GetFaces(); IndexSorter.reserve(numFaces); SModelFace* facePtr=faces; u32 i; for (i=0;im_Verts[0]].m_Coords; osvtx+=vtxs[facePtr->m_Verts[1]].m_Coords; osvtx+=vtxs[facePtr->m_Verts[2]].m_Coords; osvtx*=1.0f/3.0f; csvtx=objToCam.Transform(osvtx); float distsqrd=SQR(csvtx.X)+SQR(csvtx.Y)+SQR(csvtx.Z); if (distsqrdm_SubmissionNext) { mdefdata->PrepareStream(streamflags); for(uint idx = 0; idx < mdefdata->m_SubmissionSlots; ++idx) { CModelRData* modeldata = mdefdata->m_SubmissionModels[idx]; if (streamflags & STREAM_UV0) g_Renderer.SetTexture(0, modeldata->GetModel()->GetTexture()); for(; modeldata; modeldata = modeldata->m_SubmissionNext) { if (flags && !(modeldata->GetModel()->GetFlags()&flags)) continue; CModelDefPtr mdldef = modeldata->GetModel()->GetModelDef(); u8* base = modeldata->m_DynamicArray.Bind(); size_t stride = modeldata->m_DynamicArray.GetStride(); glVertexPointer(3, GL_FLOAT, stride, base + modeldata->m_Position.offset); if (streamflags & STREAM_COLOR) glColorPointer(3, modeldata->m_Color.type, stride, base + modeldata->m_Color.offset); // render the lot size_t numFaces=mdldef->GetNumFaces(); glDrawRangeElements(GL_TRIANGLES, 0, mdldef->GetNumVertices(), numFaces*3, GL_UNSIGNED_SHORT, modeldata->m_Indices); // bump stats g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_ModelTris+=numFaces; } } } } ///////////////////////////////////////////////////////////////////////////////////////////// // Submit: submit a model to render this frame void CModelRData::Submit(CModel* model) { CModelRData* data=(CModelRData*) model->GetRenderData(); if (data==0) { // no renderdata for model, create it now PROFILE( "create render data" ); data=new CModelRData(model); model->SetRenderData(data); } else { PROFILE( "update render data" ); data->Update(); } if (data->GetFlags() & MODELRDATA_FLAG_TRANSPARENT) { // add this mode to the transparency renderer for later processing - calculate // transform matrix g_TransparencyRenderer.Add(model); } else if (data->GetFlags() & MODELRDATA_FLAG_PLAYERCOLOR) { // add this model to the player renderer g_PlayerRenderer.Add(model); } else { CModelDefPtr mdldef = model->GetModelDef(); CModelDefRData* mdefdata = (CModelDefRData*)mdldef->GetRenderData(); debug_assert(mdefdata != 0); mdefdata->Submit(data); } } ///////////////////////////////////////////////////////////////////////////////////////////// // ClearSubmissions: Clear the submissions list // TODO: This is asymmetrical: It only clears CModelRData lists, but no player/transparency renderer lists void CModelRData::ClearSubmissions() { for(CModelDefRData* mdefdata = CModelDefRData::m_Submissions; mdefdata; mdefdata = mdefdata->m_SubmissionNext) { mdefdata->ClearSubmissions(); } CModelDefRData::m_Submissions = 0; }