BGE patch: approve patch #17312: Multiple material IPOs per mesh in BGE.
authorBenoit Bolsee <benoit.bolsee@online.be>
Fri, 25 Jul 2008 13:45:57 +0000 (13:45 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Fri, 25 Jul 2008 13:45:57 +0000 (13:45 +0000)
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Converter/KX_IpoConvert.cpp
source/gameengine/Converter/KX_IpoConvert.h
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_MaterialIpoController.cpp
source/gameengine/Ketsji/KX_MaterialIpoController.h
source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
source/gameengine/Rasterizer/RAS_IPolygonMaterial.h
source/gameengine/Rasterizer/RAS_MeshObject.cpp
source/gameengine/Rasterizer/RAS_MeshObject.h

index 1f1ac6da1193bbfa8b60c93807ad3a1defe41c46..ce37ea5907faaf9b48fb1fcc10ccedc3a844c7f0 100644 (file)
@@ -1989,10 +1989,8 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                        gameobj->NodeUpdateGS(0,true);
                        
                        BL_ConvertIpos(blenderobject,gameobj,converter);
-                       // TODO: expand to multiple ipos per mesh
-                       Material *mat = give_current_material(blenderobject, 1);
-                       if(mat) BL_ConvertMaterialIpos(mat, gameobj, converter);        
-       
+                       BL_ConvertMaterialIpos(blenderobject, gameobj, converter);
+                       
                        sumolist->Add(gameobj->AddRef());
                        
                        BL_ConvertProperties(blenderobject,gameobj,timemgr,kxscene,isInActiveLayer);
@@ -2171,9 +2169,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                                                        gameobj->NodeUpdateGS(0,true);
                                                        
                                                        BL_ConvertIpos(blenderobject,gameobj,converter);
-                                                       // TODO: expand to multiple ipos per mesh
-                                                       Material *mat = give_current_material(blenderobject, 1);
-                                                       if(mat) BL_ConvertMaterialIpos(mat, gameobj, converter);        
+                                                       BL_ConvertMaterialIpos(blenderobject,gameobj, converter);       
                                        
                                                        sumolist->Add(gameobj->AddRef());
                                                        
index 75ca59d01e771b0eb25213d041a40773e6cdcb67..7410beecaf4ea963c2116ac9736da87da405d652 100644 (file)
@@ -36,6 +36,7 @@
 #pragma warning (disable:4786)
 #endif
 
+#include "BKE_material.h" /* give_current_material */
 
 #include "KX_GameObject.h"
 #include "KX_IpoConvert.h"
@@ -68,6 +69,8 @@
 
 #include "SG_Node.h"
 
+#include "STR_HashedString.h"
+
 static BL_InterpolatorList *GetIpoList(struct Ipo *for_ipo, KX_BlenderSceneConverter *converter) {
        BL_InterpolatorList *ipoList= converter->FindInterpolatorList(for_ipo);
 
@@ -560,16 +563,15 @@ void BL_ConvertWorldIpos(struct World* blenderworld,KX_BlenderSceneConverter *co
        }
 }
 
-
-void BL_ConvertMaterialIpos(
-       Material* blendermaterial, 
+static void ConvertMaterialIpos(
+       Material* blendermaterial,
+       dword matname_hash,
        KX_GameObject* gameobj,  
        KX_BlenderSceneConverter *converter
        )
 {
        if (blendermaterial->ipo) {
-       
-               KX_MaterialIpoController* ipocontr = new KX_MaterialIpoController();
+               KX_MaterialIpoController* ipocontr = new KX_MaterialIpoController(matname_hash);
                gameobj->GetSGNode()->AddSGController(ipocontr);
                ipocontr->SetObject(gameobj->GetSGNode());
                
@@ -596,7 +598,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_COL_R);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -610,7 +612,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_COL_G);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -624,7 +626,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_COL_B);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -638,7 +640,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_ALPHA);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -653,7 +655,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_SPEC_R );
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -667,7 +669,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_SPEC_G);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -681,7 +683,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_SPEC_B);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -696,7 +698,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_HARD);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -710,7 +712,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_SPEC);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -725,7 +727,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_REF);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -739,7 +741,7 @@ void BL_ConvertMaterialIpos(
                ipo = ipoList->GetScalarInterpolator(MA_EMIT);
                if (ipo) {
                        if (!ipocontr) {
-                               ipocontr = new KX_MaterialIpoController();
+                               ipocontr = new KX_MaterialIpoController(matname_hash);
                                gameobj->GetSGNode()->AddSGController(ipocontr);
                                ipocontr->SetObject(gameobj->GetSGNode());
                        }
@@ -752,3 +754,28 @@ void BL_ConvertMaterialIpos(
        }               
 }
 
+void BL_ConvertMaterialIpos(
+       struct Object* blenderobject,
+       KX_GameObject* gameobj,  
+       KX_BlenderSceneConverter *converter
+       )
+{
+       if (blenderobject->totcol==1)
+       {
+               Material *mat = give_current_material(blenderobject, 1);
+               // if there is only one material attached to the mesh then set material_index in BL_ConvertMaterialIpos to NULL
+               // --> this makes the UpdateMaterialData function in KX_GameObject.cpp use the old hack of using SetObjectColor
+               // because this yields a better performance as not all the vertex colors need to be edited
+               if(mat) ConvertMaterialIpos(mat, NULL, gameobj, converter);
+       }
+       else
+       {
+               for (int material_index=1; material_index <= blenderobject->totcol; material_index++)
+               {
+                       Material *mat = give_current_material(blenderobject, material_index);
+                       STR_HashedString matname = mat->id.name;
+                       if(mat) ConvertMaterialIpos(mat, matname.hash(), gameobj, converter);
+               }
+       }
+}
+
index afcb1b228214051eda97fea9eb55c0336f8d470d..4ec9bd31062157a7cb85de792e3d21f2d83523ae 100644 (file)
@@ -46,7 +46,7 @@ void BL_ConvertCameraIpos(struct Camera* blendercamera,
        class KX_GameObject* cameraobj, 
        class KX_BlenderSceneConverter *converter);
 
-void BL_ConvertMaterialIpos(struct Material* blendermaterial,
+void BL_ConvertMaterialIpos(struct Object* blenderobject,
        class KX_GameObject* materialobj, 
        class KX_BlenderSceneConverter *converter);
 
index 6c8b32b6d2461867aa5ba654c3a428d6a4d53c6c..3d9c7aafd70f1183479b117b680e13f6a2157d52 100644 (file)
@@ -442,6 +442,7 @@ void KX_GameObject::UpdateIPO(float curframetime,
 // IPO update
 void 
 KX_GameObject::UpdateMaterialData(
+               dword matname_hash,
                MT_Vector4 rgba,
                MT_Vector3 specrgb,
                MT_Scalar hard,
@@ -460,9 +461,26 @@ KX_GameObject::UpdateMaterialData(
                        RAS_IPolyMaterial* poly = (*mit)->GetPolyMaterial();
                        if(poly->GetFlag() & RAS_BLENDERMAT )
                        {
-                               SetObjectColor(rgba);
                                KX_BlenderMaterial *m =  static_cast<KX_BlenderMaterial*>(poly);
-                               m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha);
+                               
+                               if (matname_hash == NULL)
+                               {
+                                       m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha);
+                                       // if mesh has only one material attached to it then use original hack with no need to edit vertices (better performance)
+                                       SetObjectColor(rgba);
+                               }
+                               else
+                               {
+                                       if (matname_hash == poly->GetMaterialNameHash())
+                                       {
+                                               m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha);
+                                               m_meshes[mesh]->SetVertexColor(poly,rgba);
+                                               
+                                               // no break here, because one blender material can be split into several game engine materials
+                                               // (e.g. one uvsphere material is split into one material at poles with ras_mode TRIANGLE and one material for the body
+                                               // if here was a break then would miss some vertices if material was split
+                                       }
+                               }
                        }
                }
        }
index 6051cf850b5f2bfbd94c8d39cd97f089370086d0..1d36798b12fffae31d456cbba6a9623e615fad8c 100644 (file)
@@ -521,6 +521,7 @@ public:
         */
                void 
        UpdateMaterialData(
+               dword matname_hash,
                MT_Vector4 rgba,
                MT_Vector3 specrgb,
                MT_Scalar hard,
index c0757a32b9c1d00f633fa281020631a922708a7f..2ce5d4693807f578c1f1611db6bdd06c50ff3df6 100644 (file)
@@ -37,6 +37,7 @@ bool KX_MaterialIpoController::Update(double currentTime)
 
                //kxgameobj->SetObjectColor(m_rgba);
                kxgameobj->UpdateMaterialData( 
+                       m_matname_hash,
                        m_rgba, 
                        m_specrgb, 
                        m_hard, 
index e76ddeefb044f03f961710f27575e76d1a6ab9d3..4d2e258bf94cdd0399ebb9da4f782604f23cfb2e 100644 (file)
@@ -7,6 +7,8 @@
 #include "SG_Spatial.h"
 #include "KX_IInterpolator.h"
 
+#include "STR_String.h" //typedef dword
+
 class KX_MaterialIpoController : public SG_Controller
 {
 public:
@@ -23,10 +25,12 @@ private:
        bool                            m_modified;
 
        double                  m_ipotime;
+       dword                           m_matname_hash;
 public:
-       KX_MaterialIpoController() : 
+       KX_MaterialIpoController(dword matname_hash) : 
                                m_modified(true),
-                               m_ipotime(0.0)
+                               m_ipotime(0.0),
+                               m_matname_hash(matname_hash)
                {}
        virtual ~KX_MaterialIpoController();
        virtual SG_Controller*  GetReplica(class SG_Node* destnode);
index cb10ba6bf379b9a1eddd2db5b91c41722d339b64..31bdd8638c273153f2959f5dd3843ce99f63fc0f 100644 (file)
@@ -139,6 +139,11 @@ const STR_String& RAS_IPolyMaterial::GetMaterialName() const
        return m_materialname;
 }
 
+dword RAS_IPolyMaterial::GetMaterialNameHash() const
+{
+       return m_materialname.hash();
+}
+
 const STR_String& RAS_IPolyMaterial::GetTextureName() const
 {
        return m_texturename;
index d2d1dba99d981a61a23b866b56debc9ddbd2fbac..6d90d260a231ae3094f0a0cb67b00a148dafd70a 100644 (file)
@@ -138,6 +138,7 @@ public:
        unsigned int            hash() const;
        int                                     GetDrawingMode() const;
        const STR_String&       GetMaterialName() const;
+       dword                           GetMaterialNameHash() const;
        const STR_String&       GetTextureName() const;
        const unsigned int      GetFlag() const;
 
index 4420f16c56d63c146696fd7d8ce809e62575ffd2..5087f62500eea037c46ba895729db1edea1822d7 100644 (file)
@@ -201,7 +201,20 @@ void RAS_MeshObject::DebugColor(unsigned int abgr)
        m_debugcolor = abgr;    
 }
 
-
+void RAS_MeshObject::SetVertexColor(RAS_IPolyMaterial* mat,MT_Vector4 rgba)
+{
+       RAS_TexVert* vertex = NULL;
+       const vecVertexArray & vertexvec = GetVertexCache(mat);
+                       
+       for (vector<KX_VertexArray*>::const_iterator it = vertexvec.begin(); it != vertexvec.end(); ++it)
+       {
+               KX_VertexArray::iterator vit;
+               for (vit=(*it)->begin(); vit != (*it)->end(); vit++)
+               {
+                       vit->SetRGBA(rgba);
+               }
+       }       
+}
 
 void RAS_MeshObject::SchedulePoly(const KX_VertexIndex& idx,
                                                                  int numverts,
index 0d06748f91ffc5aeea9dafc0ba38a27365c7dda5..44ad508d1e8fc900a765cbf3184c78fc23425552 100644 (file)
@@ -189,6 +189,7 @@ public:
                                                );
 
        void                            DebugColor(unsigned int abgr);
+       void                            SetVertexColor(RAS_IPolyMaterial* mat,MT_Vector4 rgba);
        
        /**
         *  Sorts the polygons by their transformed z values.