Ticket #1012: collada_alternate_fix-01222012.patch

File collada_alternate_fix-01222012.patch, 12.5 KB (added by historic_bruno, 12 years ago)

alternative solution - extra bone added by the DAE converters

  • source/collada/DLL.h

     
    1 /* Copyright (C) 2011 Wildfire Games.
     1/* Copyright (C) 2012 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    4141
    4242/* This version number should be bumped whenever incompatible changes
    4343 * are made, to invalidate old caches. */
    44 #define COLLADA_CONVERTER_VERSION 3
     44#define COLLADA_CONVERTER_VERSION 4
    4545
    4646EXPORT void set_logger(LogFn logger, void* cb_data);
    4747EXPORT int set_skeleton_definitions(const char* xml, int length);
  • source/collada/PMDConvert.cpp

     
    1 /* Copyright (C) 2011 Wildfire Games.
     1/* Copyright (C) 2012 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    252252                    // guaranteed by ReduceInfluences; necessary for avoiding
    253253                    // out-of-bounds writes to the VertexBlend
    254254
     255                if (vertexInfluences[i].GetPairCount() == 0)
     256                {
     257                    // Blender exports some models with vertices that have no influences,
     258                    //  which I've not found details about in the COLLADA spec, however,
     259                    //  it seems to work OK to treat these vertices the same as if they
     260                    //  were only influenced by the bind-shape matrix (see comment below),
     261                    //  so we use the same special case here.
     262                    influences.bones[0] = (uint8)jointCount;
     263                    influences.weights[0] = 1.0f;
     264                }
     265
    255266                for (size_t j = 0; j < vertexInfluences[i].GetPairCount(); ++j)
    256267                {
    257                     uint32 jointIdx = vertexInfluences[i].GetPair(j)->jointIndex;
    258                     REQUIRE(jointIdx <= 0xFF, "sensible number of joints (<256)"); // because we only have a u8 to store them in
     268                    if (vertexInfluences[i].GetPair(j)->jointIndex == -1)
     269                    {
     270                        // This is a special case we must handle, according to the COLLADA spec:
     271                        //  "An index of -1 into the array of joints refers to the bind shape"
     272                        //  which basically means when skinning the vertex it's relative to the
     273                        //  bind-shape transform instead of an animated bone. Since our skinning
     274                        //  is in world space, we will have already applied the bind-shape transform,
     275                        //  so we don't have to worry about that, though we DO have to apply the
     276                        //  world space transform of the model for the indicated vertex.
     277                        //
     278                        //  To handle this special case, we add a zero translation, identity
     279                        //  rotation bone to all models, with a bone ID equal to the number of
     280                        //  real bones in the COLLADA model.
     281                        //  (see http://trac.wildfiregames.com/ticket/1012)
     282                        influences.bones[j] = (uint8)jointCount;
     283                        influences.weights[j] = vertexInfluences[i].GetPair(j)->weight;
     284                    }
     285                    else
     286                    {
     287                        // Check for less than 255 joints because we store them in a u8
     288                        //  and 0xFF is a reserved value
     289                        uint32 jointIdx = vertexInfluences[i].GetPair(j)->jointIndex;
     290                        REQUIRE(jointIdx < 0xFF, "sensible number of joints (<255)");
    259291
    260                     // Find the joint on the skeleton, after checking it really exists
    261                     FCDSceneNode* joint = NULL;
    262                     if (jointIdx < controllerInstance.GetJointCount())
    263                         joint = controllerInstance.GetJoint(jointIdx);
     292                        // Find the joint on the skeleton, after checking it really exists
     293                        FCDSceneNode* joint = NULL;
     294                        if (jointIdx < controllerInstance.GetJointCount())
     295                            joint = controllerInstance.GetJoint(jointIdx);
    264296
    265                     // Complain on error
    266                     if (! joint)
    267                     {
    268                         if (! hasComplainedAboutNonexistentJoints)
     297                        // Complain on error
     298                        if (! joint)
    269299                        {
    270                             Log(LOG_WARNING, "Vertexes influenced by nonexistent joint");
    271                             hasComplainedAboutNonexistentJoints = true;
     300                            if (! hasComplainedAboutNonexistentJoints)
     301                            {
     302                                Log(LOG_WARNING, "Vertexes influenced by nonexistent joint");
     303                                hasComplainedAboutNonexistentJoints = true;
     304                            }
     305                            continue;
    272306                        }
    273                         continue;
    274                     }
    275307
    276                     // Store into the VertexBlend
    277                     int boneId = skeleton.GetBoneID(joint->GetName().c_str());
    278                     if (boneId < 0)
    279                     {
    280                         // The relevant joint does exist, but it's not a recognised
    281                         // bone in our chosen skeleton structure
    282                         Log(LOG_ERROR, "Vertex influenced by unrecognised bone '%s'", joint->GetName().c_str());
    283                         continue;
     308                        // Store into the VertexBlend
     309                        int boneId = skeleton.GetBoneID(joint->GetName().c_str());
     310                        if (boneId < 0)
     311                        {
     312                            // The relevant joint does exist, but it's not a recognised
     313                            // bone in our chosen skeleton structure
     314                            Log(LOG_ERROR, "Vertex influenced by unrecognised bone '%s'", joint->GetName().c_str());
     315                            continue;
     316                        }
     317
     318                        influences.bones[j] = (uint8)boneId;
     319                        influences.weights[j] = vertexInfluences[i].GetPair(j)->weight;
    284320                    }
    285 
    286                     influences.bones[j] = (uint8)boneId;
    287                     influences.weights[j] = vertexInfluences[i].GetPair(j)->weight;
    288321                }
    289322
    290323                boneWeights.push_back(influences);
     
    292325
    293326            // Convert the bind pose into BoneTransform structures for the PMD:
    294327
     328            // Add a special zero translation, identity bone (see comments above)
     329
    295330            BoneTransform boneDefault  = { { 0, 0, 0 }, { 0, 0, 0, 1 } }; // identity transform
    296             std::vector<BoneTransform> boneTransforms (skeleton.GetBoneCount(), boneDefault);
     331            std::vector<BoneTransform> boneTransforms (skeleton.GetBoneCount()+1, boneDefault);
    297332
    298333            for (size_t i = 0; i < jointCount; ++i)
    299334            {
     
    454489        }
    455490
    456491        output("PSMD", 4);  // magic number
    457         write(output, (uint32)3); // version number
     492        write(output, (uint32)4); // version number
    458493        write(output, (uint32)(
    459494            4 + 13*4*vertexCount + // vertices
    460495            4 + 6*faceCount + // faces
     
    522557    /**
    523558     * Applies world-space transform to vertex data and transforms Collada's right-handed
    524559     *  Y-up / Z-up coordinates to the game's left-handed Y-up coordinate system
     560     *
     561     * TODO: Maybe we should use FCDocumentTools::StandardizeUpAxisAndLength in addition
     562     *      to this, so we'd only have one up-axis case to worry about, but it doesn't seem to
     563     *      correctly adjust the prop points in Y_UP models.
    525564     */
    526565    static void TransformStaticModel(float* position, float* normal, size_t vertexCount,
    527566        const FMMatrix44& transform, bool yUp)
     
    563602    /**
    564603     * Applies world-space transform to vertex data and transforms Collada's right-handed
    565604     *  Y-up / Z-up coordinates to the game's left-handed Y-up coordinate system
     605     *
     606     * TODO: Maybe we should use FCDocumentTools::StandardizeUpAxisAndLength in addition
     607     *      to this, so we'd only have one up-axis case to worry about, but it doesn't seem to
     608     *      correctly adjust the prop points in Y_UP models.
    566609     */
    567610    static void TransformSkinnedModel(float* position, float* normal, size_t vertexCount,
    568611        std::vector<BoneTransform>& bones, std::vector<PropPoint>& propPoints,
  • source/collada/PSAConvert.cpp

     
    1 /* Copyright (C) 2009 Wildfire Games.
     1/* Copyright (C) 2012 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    8686            size_t frameCount = (size_t)((timeEnd - timeStart) / frameLength - 0.5f);
    8787            // (TODO: sort out the timing/looping problems)
    8888
    89             size_t boneCount = skeleton.GetBoneCount();
     89            // Add a special zero translation, identity bone state (see comments in PMDConvert.cpp)
     90            size_t boneCount = skeleton.GetBoneCount()+1;
    9091
    9192            std::vector<BoneTransform> boneTransforms;
    9293
     
    150151    static void WritePSA(OutputCB& output, size_t frameCount, size_t boneCount, const std::vector<BoneTransform>& boneTransforms)
    151152    {
    152153        output("PSSA", 4);  // magic number
    153         write(output, (uint32)1); // version number
     154        write(output, (uint32)2); // version number
    154155        write(output, (uint32)(
    155156            4 + 0 + // name
    156157            4 + // frameLength
  • source/graphics/ModelDef.cpp

     
    1 /* Copyright (C) 2011 Wildfire Games.
     1/* Copyright (C) 2012 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    259259    unpacker.Read(filename,"PSMD");
    260260           
    261261    // check version
    262     if (unpacker.GetVersion()<FILE_READ_VERSION) {
     262    if (unpacker.GetVersion() < FILE_READ_VERSION)
     263    {
    263264        throw PSERROR_File_InvalidVersion();
    264265    }
    265266
     
    269270    // now unpack everything
    270271    mdef->m_NumVertices = unpacker.UnpackSize();
    271272    mdef->m_pVertices=new SModelVertex[mdef->m_NumVertices];
    272     unpacker.UnpackRaw(mdef->m_pVertices,sizeof(SModelVertex)*mdef->m_NumVertices);
     273    unpacker.UnpackRaw(mdef->m_pVertices, sizeof(SModelVertex)*mdef->m_NumVertices);
    273274   
    274275    mdef->m_NumFaces = unpacker.UnpackSize();
    275276    mdef->m_pFaces=new SModelFace[mdef->m_NumFaces];
    276     unpacker.UnpackRaw(mdef->m_pFaces,sizeof(SModelFace)*mdef->m_NumFaces);
     277    unpacker.UnpackRaw(mdef->m_pFaces, sizeof(SModelFace)*mdef->m_NumFaces);
    277278   
    278279    mdef->m_NumBones = unpacker.UnpackSize();
    279280    if (mdef->m_NumBones)
    280281    {
     282        size_t numPackedBones = mdef->m_NumBones;
     283
     284        if (unpacker.GetVersion() < 4)
     285        {
     286            // For older versions we need to add an extra identity bone
     287            // (see http://trac.wildfiregames.com/ticket/1012)
     288            mdef->m_NumBones++;
     289        }
     290
    281291        mdef->m_Bones=new CBoneState[mdef->m_NumBones];
    282         unpacker.UnpackRaw(mdef->m_Bones,mdef->m_NumBones*sizeof(CBoneState));
     292        unpacker.UnpackRaw(mdef->m_Bones, numPackedBones*sizeof(CBoneState));
    283293
     294        if (unpacker.GetVersion() < 4)
     295        {
     296            // see above comment
     297            CBoneState identityBone;
     298            identityBone.m_Rotation = CQuaternion(0.0f, 0.0f, 0.0f, 1.0f);
     299            identityBone.m_Translation = CVector3D(0.0f, 0.0f, 0.0f);
     300            mdef->m_Bones[mdef->m_NumBones - 1] = identityBone;
     301        }
     302
    284303        mdef->m_pBlendIndices = new size_t[mdef->m_NumVertices];
    285304        std::vector<SVertexBlend> blends;
    286305        for (size_t i = 0; i < mdef->m_NumVertices; i++)
  • source/graphics/SkeletonAnimDef.cpp

     
    1 /* Copyright (C) 2009 Wildfire Games.
     1/* Copyright (C) 2012 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    9393    unpacker.Read(filename,"PSSA");
    9494           
    9595    // check version
    96     if (unpacker.GetVersion()<FILE_READ_VERSION) {
     96    if (unpacker.GetVersion() < FILE_READ_VERSION)
     97    {
    9798        throw PSERROR_File_InvalidVersion();
    9899    }
    99100
    100101    // unpack the data
    101     CSkeletonAnimDef* anim=new CSkeletonAnimDef;
    102     try {
     102    CSkeletonAnimDef* anim = new CSkeletonAnimDef;
     103    try
     104    {
    103105        CStr name; // unused - just here to maintain compatibility with the animation files
    104106        unpacker.UnpackString(name);
    105         unpacker.UnpackRaw(&anim->m_FrameTime,sizeof(anim->m_FrameTime));
     107        unpacker.UnpackRaw(&anim->m_FrameTime, sizeof(anim->m_FrameTime));
    106108        anim->m_NumKeys = unpacker.UnpackSize();
    107109        anim->m_NumFrames = unpacker.UnpackSize();
    108         anim->m_Keys=new Key[anim->m_NumKeys*anim->m_NumFrames];
    109         unpacker.UnpackRaw(anim->m_Keys,anim->m_NumKeys*anim->m_NumFrames*sizeof(Key));
    110     } catch (PSERROR_File&) {
     110
     111        anim->m_Keys = new Key[anim->m_NumKeys * anim->m_NumFrames];
     112        unpacker.UnpackRaw(anim->m_Keys, anim->m_NumKeys * anim->m_NumFrames * sizeof(Key));
     113
     114        if (unpacker.GetVersion() < 2)
     115        {
     116            // For old versions, we need to add an identity bone state in each frame,
     117            // to maintain compatibility with new models
     118            // (see http://trac.wildfiregames.com/ticket/1012)
     119
     120            Key specialKey;
     121            specialKey.m_Rotation = CQuaternion(0.0f, 0.0f, 0.0f, 1.0f);
     122            specialKey.m_Translation = CVector3D(0.0f, 0.0f, 0.0f);
     123
     124            size_t oldKeysNum = anim->m_NumKeys;
     125            size_t newKeysNum = oldKeysNum + 1;
     126           
     127            Key* newKeys = new Key[newKeysNum * anim->m_NumFrames];
     128           
     129            for (size_t f = 0; f < anim->m_NumFrames; ++f)
     130            {
     131                memcpy(&newKeys[f*newKeysNum], &anim->m_Keys[f*oldKeysNum], oldKeysNum*sizeof(Key));
     132                newKeys[f*newKeysNum + oldKeysNum] = specialKey;
     133            }
     134
     135            delete anim->m_Keys;
     136            anim->m_NumKeys = newKeysNum;
     137            anim->m_Keys = newKeys;
     138        }
     139
     140    }
     141    catch (PSERROR_File&)
     142    {
    111143        delete anim;
    112144        throw;
    113145    }