| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921 |
- #include <algorithm>
- #include "DAESceneEncoder.h"
- #include "DAEOptimizer.h"
- //#define ENCODER_PRINT_TIME 1
- using namespace gameplay;
- DAESceneEncoder::DAESceneEncoder()
- : _collada(NULL), _dom(NULL), file(NULL), _vertexBlendWeights(NULL), _vertexBlendIndices(NULL)
- {
- }
- DAESceneEncoder::~DAESceneEncoder()
- {
- }
- unsigned int getMaxOffset(domInputLocalOffset_Array& inputArray)
- {
- unsigned int maxOffset = 0;
- for (unsigned int i = 0; i < (int)inputArray.getCount(); ++i)
- {
- if ( inputArray[i]->getOffset() > maxOffset )
- {
- maxOffset = (unsigned int)inputArray[i]->getOffset();
- }
- }
- return maxOffset;
- }
- void DAESceneEncoder::optimizeCOLLADA(const EncoderArguments& arguments, domCOLLADA* dom)
- {
- DAEOptimizer optimizer(dom);
- const std::vector<std::string>& groupAnimatioNodeIds = arguments.getGroupAnimationNodeId();
- const std::vector<std::string>& groupAnimatioIds = arguments.getGroupAnimationAnimationId();
- assert(groupAnimatioNodeIds.size() == groupAnimatioIds.size());
- size_t size = groupAnimatioNodeIds.size();
- if (size > 0)
- {
- begin();
- for (size_t i = 0; i < size; ++i)
- {
- optimizer.combineAnimations(groupAnimatioNodeIds[i], groupAnimatioIds[i]);
- }
- end("groupAnimation");
- }
- if (arguments.DAEOutputEnabled())
- {
- if (!_collada->writeTo(arguments.getFilePath(), arguments.getDAEOutputPath()))
- {
- fprintf(stderr,"Error: COLLADA failed to write the dom for file:%s\n", arguments.getDAEOutputPath().c_str());
- }
- }
- }
- void DAESceneEncoder::triangulate(DAE* dae)
- {
- daeDatabase* dataBase = dae->getDatabase();
- int geometryCount = (int)(dataBase->getElementCount(0, "geometry"));
- for (int i = 0; i < geometryCount; ++i)
- {
- // Find the next geometry element.
- domGeometry* domGeometry;
- dataBase->getElement((daeElement**)&domGeometry, i, 0, "geometry");
- // Get the mesh out of the geometry.
- const domMeshRef domMesh = domGeometry->getMesh();
- if (!domMesh)
- {
- continue;
- }
- // Loop over all the polygons elements.
- int polygonsCount = (int)(domMesh->getPolygons_array().getCount());
- for (int j = 0; j < polygonsCount; ++j)
- {
- // Get the polygons out of the mesh.
- domPolygons* domPolygons = domMesh->getPolygons_array()[j];
- // Create the triangles from the polygons
- createTrianglesFromPolygons(domMesh, domPolygons);
- }
- while (domMesh->getPolygons_array().getCount() > 0)
- {
- domPolygons* domPolygons = domMesh->getPolygons_array().get(0);
- // Remove the polygons from the mesh.
- domMesh->removeChildElement(domPolygons);
- }
- // Loop over all the polylist elements.
- int polylistCount = (int)(domMesh->getPolylist_array().getCount());
- for (int j = 0; j < polylistCount; ++j)
- {
- // Get the polylist out of the mesh.
- domPolylist* domPolylist = domMesh->getPolylist_array()[j];
- // Create the triangles from the polygon list
- createTrianglesFromPolylist(domMesh, domPolylist);
- }
- while (domMesh->getPolylist_array().getCount() > 0)
- {
- domPolylist* domPolylist = domMesh->getPolylist_array().get(0);
- // Remove the polylist from the mesh.
- domMesh->removeChildElement(domPolylist);
- }
- }
- }
- void DAESceneEncoder::createTrianglesFromPolygons(domMesh* domMesh, domPolygons* domPolygons)
- {
- // Create a new <triangles> inside the mesh that has the same material as the <polygons>.
- domTriangles* triangles = (domTriangles*)domMesh->createAndPlace("triangles");
- triangles->setCount(0);
- triangles->setMaterial(domPolygons->getMaterial());
- domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
-
- // Give the new <triangles> the same <_dae> and <parameters> as the old <polygons>.
- for (unsigned int i = 0; i < domPolygons->getInput_array().getCount(); ++i)
- {
- triangles->placeElement(domPolygons->getInput_array()[i]->clone());
- }
-
- // Get the number of inputs and primitives for the polygons array.
- unsigned int inputCount = getMaxOffset(domPolygons->getInput_array()) + 1;
- unsigned int primitiveCount = domPolygons->getP_array().getCount();
-
- // Triangulate all the primitives, this generates all the triangles in a single <p> element.
- for (unsigned int j = 0; j < primitiveCount; ++j)
- {
- // Check the polygons for consistancy (some exported files have had the wrong number of indices).
- domP* domCurrentP = domPolygons->getP_array()[j];
- int elementCount = (int)(domCurrentP->getValue().getCount());
- if ( (elementCount % inputCount) != 0 )
- {
- // Skip this case.
- }
- else
- {
- unsigned int triangleCount = (elementCount / inputCount) - 2;
-
- // Write out the primitives as triangles, just fan using the first element as the base.
- unsigned int index = inputCount;
- for (unsigned int k = 0; k < triangleCount; ++k)
- {
- // First vertex.
- for (unsigned int l = 0; l < inputCount; ++l)
- {
- domTrianglesP->getValue().append(domCurrentP->getValue()[l]);
- }
- // Second vertex.
- for (unsigned int l = 0; l < inputCount; ++l)
- {
- domTrianglesP->getValue().append(domCurrentP->getValue()[index + l]);
- }
- // Third vertex.
- index += inputCount;
- for (unsigned int l = 0; l < inputCount; ++l)
- {
- domTrianglesP->getValue().append(domCurrentP->getValue()[index + l]);
- }
- triangles->setCount(triangles->getCount() + 1);
- }
- }
- }
- }
- void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist* domPolylist)
- {
- // Create a new <triangles> inside the mesh that has the same material as the <polylist>.
- domTriangles* triangles = (domTriangles*)domMesh->createAndPlace("triangles");
- triangles->setMaterial(domPolylist->getMaterial());
- domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
-
- // Give the new <triangles> the same <_dae> and <parameters> as the old <polylist>.
- for (int i = 0; i < (int)(domPolylist->getInput_array().getCount()); ++i)
- {
- triangles->placeElement(domPolylist->getInput_array()[i]->clone());
- }
-
- // Get the number of inputs and primitives for the polygons array.
- unsigned int inputCount = getMaxOffset(domPolylist->getInput_array()) + 1;
- unsigned int primitiveCount = domPolylist->getVcount()->getValue().getCount();
-
- unsigned int offset = 0;
- unsigned int trianglesProcessed = 0;
-
- // Triangulate all the primitives, this generates all the triangles in a single <p> element.
- for (unsigned int j = 0; j < primitiveCount; ++j)
- {
- unsigned int triangleCount = (unsigned int)domPolylist->getVcount()->getValue()[j] - 2;
-
- // Write out the primitives as triangles, just fan using the first element as the base.
- int index = inputCount;
- for (unsigned int k = 0; k < triangleCount; ++k)
- {
- // First vertex.
- for (unsigned int l = 0; l < inputCount; ++l)
- {
- domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + l]);
- }
- // Second vertex.
- for (unsigned int l = 0; l < inputCount; ++l)
- {
- domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + index + l]);
- }
- // Third vertex.
- index += inputCount;
- for (unsigned int l = 0; l < inputCount; ++l)
- {
- domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + index + l]);
- }
-
- trianglesProcessed++;
- }
-
- offset += (unsigned int)domPolylist->getVcount()->getValue()[j] * inputCount;
- }
- triangles->setCount(trianglesProcessed);
- }
- void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments& arguments)
- {
- _begin = std::clock();
- const char* nodeId = arguments.getNodeId();
- bool text = arguments.textOutputEnabled();
- std::string filenameOnly = getFilenameFromFilePath(filepath);
- std::string dstPath = filepath.substr(0, filepath.find_last_of('/'));
-
- // Load the collada document
- _collada = new DAE();
- begin();
- _dom = _collada->open(filepath);
- end("Open file");
- if (!_dom)
- {
- fprintf(stderr,"Error: COLLADA failed to open file:%s\n", filepath.c_str());
- if (_collada)
- {
- delete _collada;
- _collada = NULL;
- }
- return;
- }
-
- // Run collada conditioners
- begin();
- triangulate(_collada);
- end("triangulate");
- // Optimize the dom before encoding
- optimizeCOLLADA(arguments, _dom);
- // Find the <visual_scene> element within the <scene>
- const domCOLLADA::domSceneRef& domScene = _dom->getScene();
- daeElement* scene = NULL;
- if (domScene && domScene->getInstance_visual_scene())
- {
- scene = domScene->getInstance_visual_scene()->getUrl().getElement();
- if (scene->getElementType() != COLLADA_TYPE::VISUAL_SCENE)
- {
- // This occured once where Maya exported a Node and Scene element with the same ID.
- fprintf(stderr,"Error: instance_visual_scene does not reference visual_scene for file:%s\n", filepath.c_str());
- return;
- }
- if (scene)
- {
- if (nodeId == NULL)
- {
- // If the -n <node_id> parameter was not passed then write out the entire scene.
- begin();
- loadScene((domVisual_scene*)scene);
- end("load scene");
- }
- else
- {
- // Resolve/Search for the node the user specified with the -n <node_id> parameter.
- daeSIDResolver resolver(scene, nodeId);
- const domNode* node = daeSafeCast<domNode>(resolver.getElement());
- if (node)
- {
- //createNode(node, NULL);
- }
- else
- {
- fprintf(stderr,"COLLADA File loaded to the dom, but node was not found with -n%s.\n", nodeId);
- }
- }
- }
- else
- {
- fprintf(stderr,"COLLADA File loaded to the dom, but query for the dom assets failed.\n");
- }
- }
- else
- {
- fprintf(stderr, "COLLADA File loaded to the dom, but missing <visual_scene>.\n");
- }
-
- // The animations should be loaded last
- begin();
- loadAnimations(_dom);
- end("loadAnimations");
- std::string dstFilename = dstPath;
- dstFilename.append(1, '/');
- dstFilename.append(getFilenameNoExt(filenameOnly));
- _gamePlayFile.adjust();
- if (text)
- {
- std::string outFile = dstFilename + ".xml";
- fprintf(stderr, "Saving debug file: %s\n", outFile.c_str());
- _gamePlayFile.saveText(outFile);
- }
- else
- {
- std::string outFile = dstFilename + ".gpb";
- fprintf(stderr, "Saving binary file: %s\n", outFile.c_str());
- begin();
- _gamePlayFile.saveBinary(outFile);
- end("save binary");
- }
-
- // Cleanup
- if (file)
- {
- fclose(file);
- }
- if (_collada)
- {
- delete _collada;
- _collada = NULL;
- }
- }
- void DAESceneEncoder::loadAnimations(const domCOLLADA* dom)
- {
- // Call loadAnimation on all <animation> elements in all <library_animations>
- const domLibrary_animations_Array& animationLibrarys = dom->getLibrary_animations_array();
- size_t animationLibrarysCount = animationLibrarys.getCount();
- for (size_t i = 0; i < animationLibrarysCount; ++i)
- {
- const domLibrary_animationsRef& libraryAnimation = animationLibrarys.get(i);
- const domAnimation_Array& animationArray = libraryAnimation->getAnimation_array();
- size_t animationCount = animationArray.getCount();
- for (size_t j = 0; j < animationCount; ++j)
- {
- const domAnimationRef& animationRef = animationArray.get(j);
- loadAnimation(animationRef);
- }
- }
- }
- void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
- {
- // <channel> points to one <sampler>
- // <sampler> points to multiple <input> elements
- Animation* animation = new Animation();
- const char* str = animationRef->getId();
- if (str)
- {
- animation->setId(str);
- }
- // <channel>
- const domChannel_Array& channelArray = animationRef->getChannel_array();
- size_t channelArrayCount = channelArray.getCount();
- for (size_t i = 0; i < channelArrayCount; ++i)
- {
- AnimationChannel* animationChannel = new AnimationChannel();
- const domChannelRef& channelRef = channelArray.get(i);
- // <sampler>
- const domSamplerRef sampler = getSampler(channelRef);
- assert(sampler);
- // <input>
- const domInputLocal_Array& inputArray = sampler->getInput_array();
- size_t inputArrayCount = inputArray.getCount();
- for (size_t j = 0; j < inputArrayCount; ++j)
- {
- const domInputLocalRef& inputLocal = inputArray.get(j);
- // <source>
- const domSourceRef source = getSource(inputLocal, animationRef);
- std::string semantic = inputLocal->getSemantic();
- if (equals(semantic, "INTERPOLATION"))
- {
- // Interpolation source is a list of strings
- loadInterpolation(source, animationChannel);
- }
- else
- {
- // The other sources are lists of floats.
- std::vector<float> floats;
- copyFloats(source->getFloat_array(), &floats);
- if (equals(semantic, "INPUT"))
- {
- // TODO: Ensure param name is TIME?
- for (std::vector<float>::iterator k = floats.begin(); k != floats.end(); ++k)
- {
- // Convert seconds to milliseconds
- *k = *k * 1000.0f;
- }
- animationChannel->setKeyTimes(floats);
- }
- else if (equals(semantic, "OUTPUT"))
- {
- animationChannel->setKeyValues(floats);
- }
- else if (equals(semantic, "IN_TANGENT"))
- {
- animationChannel->setTangentsIn(floats);
- }
- else if (equals(semantic, "OUT_TANGENT"))
- {
- animationChannel->setTangentsOut(floats);
- }
- }
- }
- // get target attribute enum value
- if (loadTarget(channelRef, animationChannel))
- {
- animation->add(animationChannel);
- }
- }
- if (animation->getAnimationChannelCount() > 0)
- {
- _gamePlayFile.addAnimation(animation);
- }
- else
- {
- delete animation;
- }
- }
- void DAESceneEncoder::loadInterpolation(const domSourceRef source, AnimationChannel* animationChannel)
- {
- // COLLADA stores the interpolations as a list of strings while GBP uses unsigned int
- std::vector<unsigned int> values;
- const domName_arrayRef nameArray = getSourceNameArray(source);
- assert(nameArray);
- const domListOfNames& names = nameArray->getValue();
- size_t count = (size_t)names.getCount();
- values.resize(count);
- if (count > 0)
- {
- for (size_t i = 0; i < count; ++i)
- {
- values[i] = AnimationChannel::getInterpolationType(names.get(i));
- }
- // If all of the interpolation types are the same then only store the interpolation once
- // instead of storing the same type for each key frame.
- unsigned int firstType = values[0];
- bool allEqual = true;
- for (size_t i = 1; i < count; ++i)
- {
- if (firstType != values[i])
- {
- allEqual = false;
- break;
- }
- }
- if (allEqual)
- {
- values.resize(1);
- }
- }
- animationChannel->setInterpolations(values);
- }
- bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChannel* animationChannel)
- {
- // GamePlay requires that animations are baked. Use "Bake Transforms" in your 3D modeling tool.
- // If the target of an animation is not a matrix then an error will be printed.
- const static char* TRANSFORM_WARNING_FORMAT = "Warning: Node \"%s\":\n %s %s\n";
- const static char* TRANSFORM_MESSAGE = "transform found but not supported.\n Use \"Bake Transforms\" option when exporting.";
- unsigned int targetProperty = 0;
- DAEChannelTarget channelTarget(channelRef);
- const char* targetId = channelTarget.getTargetId().c_str();
- // TODO: Do we want to support more than one? If yes then this needs to be fixed.
- for (size_t i = 0; i < channelTarget.getTargetAttributeCount(); ++i)
- {
- std::string prop;
- channelTarget.getPropertyName(i, &prop);
- daeElement* attributeElement = channelTarget.getTargetAttribute(i);
- if (attributeElement)
- {
- daeInt type = attributeElement->typeID();
- if (type == domRotate::ID())
- {
- printf(TRANSFORM_WARNING_FORMAT, targetId, "Rotate", TRANSFORM_MESSAGE);
- return false;
- /*
- // <rotate>
- const domRotate* rotate = daeSafeCast<domRotate>(attributeElement);
- if (prop.size() > 0)
- {
- if (equalsIgnoreCase(prop, "ANGLE"))
- {
- targetProperty = Transform::ANIMATE_ROTATE;
- // get the rotation axis
- const domFloat4& f = rotate->getValue();
- float x = (float)f.get(0);
- float y = (float)f.get(1);
- float z = (float)f.get(2);
-
- // Get the angle values that were already read
- const std::vector<float>& keyValues = animationChannel->getKeyValues();
- size_t size = keyValues.size();
- assert(size > 0);
- // COLLADA only targeted a single prop but GBP requires all 4 rotate values.
- // Convert (ANGLE ANGLE ANGLE) to (X Y Z ANGLE X Y Z ANGLE X Y Z ANGLE)
- std::vector<float> floats(size * 4);
- // Duplicate rotation axis. We will replace only the angle that COLLADA is targeting.
- for (size_t j = 0; j < size; ++j)
- {
- size_t k = j * 4;
- floats[k+0] = x;
- floats[k+1] = y;
- floats[k+2] = z;
- floats[k+3] = keyValues[j]; // angle
- }
- animationChannel->setKeyValues(floats);
- }
- }
- */
- }
- else if (type == domScale::ID())
- {
- printf(TRANSFORM_WARNING_FORMAT, targetId, "Scale", TRANSFORM_MESSAGE);
- return false;
- /*
- // <scale>
- //const domScale* scale = daeSafeCast<domScale>(attributeElement);
- if (equalsIgnoreCase(prop, "X"))
- {
- targetProperty = Transform::ANIMATE_SCALE_X;
- }
- else if (equalsIgnoreCase(prop, "Y"))
- {
- targetProperty = Transform::ANIMATE_SCALE_Y;
- }
- else if (equalsIgnoreCase(prop, "Z"))
- {
- targetProperty = Transform::ANIMATE_SCALE_Z;
- }
- else
- {
- targetProperty = Transform::ANIMATE_SCALE;
- }
- */
- }
- else if (type == domTranslate::ID())
- {
- printf(TRANSFORM_WARNING_FORMAT, targetId, "Translate", TRANSFORM_MESSAGE);
- return false;
- /*
- // <translate>
- //const domTranslate* translate = daeSafeCast<domTranslate>(attributeElement);
- if (equalsIgnoreCase(prop, "X"))
- {
- targetProperty = Transform::ANIMATE_TRANSLATE_X;
- }
- else if (equalsIgnoreCase(prop, "Y"))
- {
- targetProperty = Transform::ANIMATE_TRANSLATE_Y;
- }
- else if (equalsIgnoreCase(prop, "Z"))
- {
- targetProperty = Transform::ANIMATE_TRANSLATE_Z;
- }
- else
- {
- targetProperty = Transform::ANIMATE_TRANSLATE;
- }
- */
- }
- else if (type == domMatrix::ID())
- {
- // If the animation is targetting a matrix then convert it into
- // a scale, rotate, translate animation by decomposing the matrix.
- targetProperty = Transform::ANIMATE_SCALE_ROTATE_TRANSLATE;
- const std::vector<float>& keyValues = animationChannel->getKeyValues();
- assert(keyValues.size() % 16 == 0);
- // The matrix was 16 floats and the new values will be 10 floats
- size_t newSize = keyValues.size() / 16 * 10;
- std::vector<float> floats(newSize);
- size_t matrixCount = keyValues.size() / 16;
- for (size_t i = 0; i < matrixCount; ++i)
- {
- size_t j = i * 16;
- // COLLADA used row-major but the Matrix class uses column-major
- Matrix matrix(
- keyValues[j+0], keyValues[j+4], keyValues[j+8], keyValues[j+12],
- keyValues[j+1], keyValues[j+5], keyValues[j+9], keyValues[j+13],
- keyValues[j+2], keyValues[j+6], keyValues[j+10], keyValues[j+14],
- keyValues[j+3], keyValues[j+7], keyValues[j+11], keyValues[j+15]);
- Vector3 scale;
- Quaternion rotation;
- Vector3 translation;
- matrix.decompose(&scale, &rotation, &translation);
- size_t k = i * 10;
- floats[k+0] = scale.x;
- floats[k+1] = scale.y;
- floats[k+2] = scale.z;
- floats[k+3] = rotation.x;
- floats[k+4] = rotation.y;
- floats[k+5] = rotation.z;
- floats[k+6] = rotation.w;
- floats[k+7] = translation.x;
- floats[k+8] = translation.y;
- floats[k+9] = translation.z;
- }
- animationChannel->setKeyValues(floats);
- }
- }
- }
- animationChannel->setTargetAttribute(targetProperty);
- animationChannel->setTargetId(channelTarget.getTargetId());
- //animationChannel->removeDuplicates();
- return true;
- }
- void DAESceneEncoder::begin()
- {
- #ifdef ENCODER_PRINT_TIME
- _begin = std::clock();
- #endif
- }
- void DAESceneEncoder::end(const char* str)
- {
- #ifdef ENCODER_PRINT_TIME
- clock_t time = std::clock() - _begin;
- fprintf(stderr,"%5d %s\n", time, str);
- #endif
- }
- void DAESceneEncoder::copyFloats(const domFloat_array* source, std::vector<float>* target)
- {
- std::vector<float>& t = *target;
- size_t count = (size_t)source->getCount();
- t.resize(count);
- const domListOfFloats& listOfFloats = source->getValue();
- for (size_t i = 0; i < count; ++i)
- {
- t[i] = (float)listOfFloats.get(i);
- }
- }
- void DAESceneEncoder::loadScene(const domVisual_scene* visualScene)
- {
- Scene* scene = new Scene();
- const domNode_Array& nodes = visualScene->getNode_array();
- scene->setId(visualScene->getId());
- size_t childCount = nodes.getCount();
- for (size_t i = 0; i < childCount; ++i)
- {
- scene->add(loadNode(nodes[i], NULL));
- }
-
- Node* activeCameraNode = findSceneActiveCameraNode(visualScene, scene);
- if (activeCameraNode)
- {
- scene->setActiveCameraNode(activeCameraNode);
- }
- _gamePlayFile.addScene(scene);
- }
- Node* DAESceneEncoder::findSceneActiveCameraNode(const domVisual_scene* visualScene, Scene* scene)
- {
- // Loops through each evaluate_scene's render until an active camera node is found.
- // Returns the first one found.
- // Find the active camera
- const domVisual_scene::domEvaluate_scene_Array& evaluateScenes = visualScene->getEvaluate_scene_array();
- size_t evaluateSceneCount = evaluateScenes.getCount();
- for (size_t i = 0; i < evaluateSceneCount; ++i)
- {
- const domVisual_scene::domEvaluate_scene::domRender_Array& renders = evaluateScenes[i]->getRender_array();
- size_t renderCount = renders.getCount();
- for (size_t j = 0; j < renderCount; ++j)
- {
- xsAnyURI cameraNodeURI = renders[i]->getCamera_node();
- domNode* nodeRef = daeSafeCast<domNode>(cameraNodeURI.getElement());
- if (nodeRef)
- {
- std::string id = nodeRef->getId();
- Node* node = _gamePlayFile.getNode(id.c_str());
- if (node)
- {
- return node;
- }
- }
- }
- }
- // Find the first node in the scene that contains a camera.
- return scene->getFirstCameraNode();
- }
- Node* DAESceneEncoder::loadNode(domNode* n, Node* parent)
- {
- Node* node = NULL;
- // Check if this node has already been loaded
- const char* id = n->getID();
- if (id && strlen(id) > 0)
- {
- node = _gamePlayFile.getNode(n->getID());
- if (node)
- {
- return node;
- }
- }
-
- // Load the node
- node = new Node();
- if (parent)
- {
- parent->addChild(node);
- }
-
- if (n->getType() == NODETYPE_JOINT)
- {
- node->setIsJoint(true);
- }
- // Set node id
- node->setId(n->getId());
- // If this node has an id then add it to the ref table
- _gamePlayFile.addNode(node);
- transformNode(n, node);
- loadControllerInstance(n, node);
- loadCameraInstance(n, node);
- loadLightInstance(n, node);
- loadGeometryInstance(n, node);
-
- // Load child nodes
- const domNode_Array& childNodes = n->getNode_array();
- size_t childCount = childNodes.getCount();
- for (size_t i = 0; i < childCount; ++i)
- {
- loadNode(childNodes.get(i), node);
- }
- return node;
- }
- void DAESceneEncoder::transformNode(domNode* domNode, Node* node)
- {
- // Apply the transform.
- // Note that we only honor the first matrix transform specified for the DOM node.
- const domMatrix_Array& matrixArray = domNode->getMatrix_array();
- if (matrixArray.getCount() > 0)
- {
- const domMatrixRef& matrix = matrixArray.get(0);
- if (!matrix)
- {
- return;
- }
- const domFloat4x4& tx = matrix->getValue();
- float transform[] = {(float)tx.get(0), (float)tx.get(4), (float)tx.get(8), (float)tx.get(12),
- (float)tx.get(1), (float)tx.get(5), (float)tx.get(9), (float)tx.get(13),
- (float)tx.get(2), (float)tx.get(6), (float)tx.get(10), (float)tx.get(14),
- (float)tx.get(3), (float)tx.get(7), (float)tx.get(11), (float)tx.get(15)};
- node->setTransformMatrix(transform);
- }
- else
- {
- Matrix transform;
- calcTransform(domNode, transform);
- node->setTransformMatrix(transform.m);
- }
- // TODO: Handle transforming by other types (SRT, etc) (see "Node" child elements spec)
- /*Vector3 scale;
- Quaternion rotation;
- Vector3 translation;
- localTransform.Decompose(&scale, &rotation, &translation);
- node->SetScale(scale);
- node->SetRotation(rotation);
- node->SetTranslation(translation);*/
- }
- void DAESceneEncoder::calcTransform(domNode* domNode, Matrix& dstTransform)
- {
- daeTArray<daeSmartRef<daeElement> > children;
- domNode->getChildren(children);
- size_t childCount = children.getCount();
- for (size_t i = 0; i < childCount; ++i)
- {
- daeElementRef childElement = children[i];
- switch (childElement->getElementType())
- {
- case COLLADA_TYPE::TRANSLATE:
- {
- domTranslateRef translateNode = daeSafeCast<domTranslate>(childElement);
- float x = (float)translateNode->getValue().get(0);
- float y = (float)translateNode->getValue().get(1);
- float z = (float)translateNode->getValue().get(2);
- dstTransform.translate(x, y, z);
- break;
- }
- case COLLADA_TYPE::ROTATE:
- {
- domRotateRef rotateNode = daeSafeCast<domRotate>(childElement);
- float x = (float)rotateNode->getValue().get(0);
- float y = (float)rotateNode->getValue().get(1);
- float z = (float)rotateNode->getValue().get(2);
- float angle = MATH_DEG_TO_RAD((float)rotateNode->getValue().get(3)); // COLLADA uses degrees, gameplay uses radians
- if (x == 1.0f && y == 0.0f && z == 0.0f)
- {
- dstTransform.rotateX(angle);
- }
- else if (x == 0.0f && y == 1.0f && z == 0.0f)
- {
- dstTransform.rotateY(angle);
- }
- else if (x == 0.0f && y == 0.0f && z == 1.0f)
- {
- dstTransform.rotateZ(angle);
- }
- else
- {
- dstTransform.rotate(x, y, z, angle);
- }
- break;
- }
- case COLLADA_TYPE::SCALE:
- {
- domScaleRef scaleNode = daeSafeCast<domScale>(childElement);
- float x = (float)scaleNode->getValue().get(0);
- float y = (float)scaleNode->getValue().get(1);
- float z = (float)scaleNode->getValue().get(2);
- dstTransform.scale(x, y, z);
- break;
- }
- case COLLADA_TYPE::SKEW:
- warning("Skew transform found but not supported.");
- break;
- case COLLADA_TYPE::LOOKAT:
- warning("Lookat transform found but not supported.");
- break;
- default:
- break;
- }
- }
- }
- void DAESceneEncoder::loadCameraInstance(const domNode* n, Node* node)
- {
- // Does this node have any camera instances?
- const domInstance_camera_Array& instanceCameras = n->getInstance_camera_array();
- size_t instanceCameraCount = instanceCameras.getCount();
- for (size_t i = 0; i < instanceCameraCount; ++i)
- {
- // Get the camrea object
- const domInstance_camera* cameraInstanceRef = instanceCameras.get(i);
- xsAnyURI cameraURI = cameraInstanceRef->getUrl();
- domCamera* cameraRef = daeSafeCast<domCamera>(cameraURI.getElement());
- if (cameraRef)
- {
- CameraInstance* cameraInstance = loadCamera(cameraRef);
- if (cameraInstance)
- {
- node->setCameraInstance(cameraInstance);
- }
- }
- else
- {
- // warning
- }
- }
- }
- void DAESceneEncoder::loadLightInstance(const domNode* n, Node* node)
- {
- // Does this node have any light instances?
- const domInstance_light_Array& instanceLights = n->getInstance_light_array();
- size_t instanceLightCount = instanceLights.getCount();
- for (size_t i = 0; i < instanceLightCount; ++i)
- {
- // Get the camrea object
- const domInstance_light* lightInstanceRef = instanceLights.get(i);
- xsAnyURI lightURI = lightInstanceRef->getUrl();
- domLight* lightRef = daeSafeCast<domLight>(lightURI.getElement());
- if (lightRef)
- {
- LightInstance* lightInstance = loadLight(lightRef);
- if (lightInstance)
- {
- node->setLightInstance(lightInstance);
- }
- }
- else
- {
- // warning
- }
- }
- }
- void DAESceneEncoder::loadGeometryInstance(const domNode* n, Node* node)
- {
- // Does this node have any geometry instances?
- const domInstance_geometry_Array& instanceGeometries = n->getInstance_geometry_array();
- size_t instanceGeometryCount = instanceGeometries.getCount();
- for (size_t i = 0; i < instanceGeometryCount; ++i)
- {
- // Get the geometry object
- const domInstance_geometryRef geometryInstanceRef = instanceGeometries.get(i);
- xsAnyURI geometryURI = geometryInstanceRef->getUrl();
- domGeometry* geometry = daeSafeCast<domGeometry>(geometryURI.getElement());
- // Load the model from this geometry
- if (geometry)
- {
- Model* model = loadGeometry(geometry, geometryInstanceRef->getBind_material());
- if (model)
- {
- node->setModel(model);
- }
- }
- else
- {
- warning(std::string("Failed to resolve geometry url: ") + geometryURI.getURI());
- }
- }
- }
- void DAESceneEncoder::loadControllerInstance(const domNode* n, Node* node)
- {
- // Does this node have any controller instances?
- const domInstance_controller_Array& instanceControllers = n->getInstance_controller_array();
- size_t instanceControllerCount = instanceControllers.getCount();
- for (size_t i = 0; i < instanceControllerCount; ++i)
- {
- const domInstance_controllerRef instanceControllerRef = instanceControllers.get(i);
- xsAnyURI controllerURI = instanceControllerRef->getUrl();
- domController* controllerRef = daeSafeCast<domController>(controllerURI.getElement());
- if (controllerRef)
- {
- const domSkin* skinElement = controllerRef->getSkin();
- if (skinElement)
- {
- Model* model = loadSkin(skinElement);
- if (model)
- {
- domInstance_controller::domSkeleton_Array& skeletons = instanceControllerRef->getSkeleton_array();
- if (skeletons.getCount() == 0)
- {
- warning("No skeletons found for instance controller: ");
- delete model;
- continue;
- }
- // Load the skeleton for this skin
- domInstance_controller::domSkeletonRef skeleton = getSkeleton(instanceControllerRef);
- assert(skeleton);
- loadSkeleton(skeleton, model->getSkin());
- node->setModel(model);
- }
- }
- }
- else
- {
- // warning
- }
- _jointLookupTable.clear();
- _jointInverseBindPoseMatrices.clear();
- }
- }
- CameraInstance* DAESceneEncoder::loadCamera(const domCamera* cameraRef)
- {
- ///////////////////////////// CAMERA
- // check if camera is already added to gamePlayFile
- const char* id = cameraRef->getId();
- Camera* camera = _gamePlayFile.getCamera(id);
- if (camera == NULL)
- {
- camera = new Camera();
- camera->setId(id);
- // Optics
- const domCamera::domOpticsRef opticsRef = cameraRef->getOptics();
- if (opticsRef.cast())
- {
- const domCamera::domOptics::domTechnique_commonRef techRef = opticsRef->getTechnique_common();
- // Orthographics
- const domCamera::domOptics::domTechnique_common::domOrthographicRef orthographicRef = techRef->getOrthographic();
- if (orthographicRef.cast())
- {
- camera->setOrthographic();
- camera->setAspectRatio((float)orthographicRef->getAspect_ratio()->getValue());
- camera->setNearPlane((float)orthographicRef->getZnear()->getValue());
- camera->setFarPlane((float)orthographicRef->getZfar()->getValue());
- const domTargetableFloatRef xmag = orthographicRef->getXmag();
- const domTargetableFloatRef ymag = orthographicRef->getYmag();
- // Viewport width
- if (xmag.cast())
- {
- camera->setViewportWidth((float)xmag->getValue());
- }
- // Viewport height
- if (ymag.cast())
- {
- camera->setViewportHeight((float)ymag->getValue());
- }
- // TODO: Viewport x and y?
- }
- // Perspective
- const domCamera::domOptics::domTechnique_common::domPerspectiveRef perspectiveRef = techRef->getPerspective();
- if (perspectiveRef.cast())
- {
- camera->setPerspective();
- camera->setNearPlane((float)perspectiveRef->getZnear()->getValue());
- camera->setFarPlane((float)perspectiveRef->getZfar()->getValue());
- float aspectRatio = -1.0f;
- if (perspectiveRef->getAspect_ratio().cast())
- {
- aspectRatio = (float)perspectiveRef->getAspect_ratio()->getValue();
- camera->setAspectRatio(aspectRatio);
- }
- if (perspectiveRef->getYfov().cast())
- {
- camera->setFieldOfView((float)perspectiveRef->getYfov()->getValue());
- }
- else if (perspectiveRef->getXfov().cast() && aspectRatio > 0.0f)
- {
- // The gameplaybinary stores the yfov but collada might have specified
- // an xfov and an aspect ratio. So use those to calculate the yfov.
- float xfov = (float)perspectiveRef->getXfov()->getValue();
- float yfov = xfov / aspectRatio;
- camera->setFieldOfView(yfov);
- }
- }
- }
- _gamePlayFile.addCamera(camera);
- }
- CameraInstance* cameraInstance = new CameraInstance();
- cameraInstance->setCamera(camera);
- return cameraInstance;
- }
- LightInstance* DAESceneEncoder::loadLight(const domLight* lightRef)
- {
- ///////////////////////////// LIGHT
- // check if light is already added to gamePlayFile
- const char* id = lightRef->getId();
- Light* light = _gamePlayFile.getLight(id);
- if (light == NULL)
- {
- light = new Light();
- light->setId(lightRef->getId());
- const domLight::domTechnique_commonRef techRef = lightRef->getTechnique_common();
- // Ambient light
- {
- const domLight::domTechnique_common::domAmbientRef ambientRef = techRef->getAmbient();
- if (ambientRef.cast())
- {
- light->setAmbientLight();
- // color
- const domTargetableFloat3Ref float3Ref = ambientRef->getColor();
- const domFloat3& color3 = float3Ref->getValue();
- light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
- }
- }
- // Directional light
- {
- const domLight::domTechnique_common::domDirectionalRef direcitonalRef = techRef->getDirectional();
- if (direcitonalRef.cast())
- {
- light->setDirectionalLight();
- // color
- const domTargetableFloat3Ref float3Ref = direcitonalRef->getColor();
- const domFloat3& color3 = float3Ref->getValue();
- light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
- }
- }
- // Spot light
- {
- const domLight::domTechnique_common::domSpotRef spotRef = techRef->getSpot();
- if (spotRef.cast())
- {
- light->setSpotLight();
- // color
- const domTargetableFloat3Ref float3Ref = spotRef->getColor();
- const domFloat3& color3 = float3Ref->getValue();
- light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
-
- const domTargetableFloatRef& constAtt = spotRef->getConstant_attenuation();
- if (constAtt.cast())
- {
- light->setConstantAttenuation((float)constAtt->getValue());
- }
- const domTargetableFloatRef& linearAtt = spotRef->getLinear_attenuation();
- if (linearAtt.cast())
- {
- light->setLinearAttenuation((float)linearAtt->getValue());
- }
- const domTargetableFloatRef& quadAtt = spotRef->getQuadratic_attenuation();
- if (quadAtt.cast())
- {
- light->setQuadraticAttenuation((float)quadAtt->getValue());
- }
- const domTargetableFloatRef& falloffAngle = spotRef->getFalloff_angle();
- if (falloffAngle.cast())
- {
- light->setFalloffAngle((float)falloffAngle->getValue());
- }
- const domTargetableFloatRef& falloffExp = spotRef->getFalloff_exponent();
- if (falloffExp.cast())
- {
- light->setFalloffExponent((float)falloffExp->getValue());
- }
- }
- }
- // Point light
- {
- const domLight::domTechnique_common::domPointRef pointRef = techRef->getPoint();
- if (pointRef.cast())
- {
- light->setPointLight();
- // color
- const domTargetableFloat3Ref float3Ref = pointRef->getColor();
- const domFloat3& color3 = float3Ref->getValue();
- light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
- const domTargetableFloatRef& constAtt = pointRef->getConstant_attenuation();
- if (constAtt.cast())
- {
- light->setConstantAttenuation((float)constAtt->getValue());
- }
- const domTargetableFloatRef& linearAtt = pointRef->getLinear_attenuation();
- if (linearAtt.cast())
- {
- light->setLinearAttenuation((float)linearAtt->getValue());
- }
- const domTargetableFloatRef& quadAtt = pointRef->getQuadratic_attenuation();
- if (quadAtt.cast())
- {
- light->setQuadraticAttenuation((float)quadAtt->getValue());
- }
- }
- }
- _gamePlayFile.addLight(light);
- }
- LightInstance* lightInstance = new LightInstance();
- lightInstance->setLight(light);
- return lightInstance;
- }
- void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeletonElement, MeshSkin* skin)
- {
- xsAnyURI skeletonUri = skeletonElement->getValue();
- daeString skeletonId = skeletonUri.getID();
- daeSIDResolver resolver(skeletonUri.getElement(), skeletonId);
- domNode* rootNode = daeSafeCast<domNode>(resolver.getElement());
-
- // Get the lookup scene id (sid) and joint index.
- std::string id = std::string(skeletonId);
- // Has the skeleton (root joint) been loaded yet?
- Node* skeleton = (Node*)_gamePlayFile.getFromRefTable(id);
- // The skeleton node is not loaded yet, so let's load it now
- if (skeleton == NULL)
- {
- // Find the top most parent of rootNode that has not yet been loaded
- domNode* topLevelParent = rootNode;
- while (
- topLevelParent->getParent() &&
- topLevelParent->getParent()->getElementType() == COLLADA_TYPE::NODE &&
- _gamePlayFile.getFromRefTable(topLevelParent->getParent()->getID()) == NULL)
- {
- topLevelParent = (domNode*)topLevelParent->getParent();
- }
- // Is the parent of this node loaded yet?
- Node* parentNode = NULL;
- if (topLevelParent->getParent() &&
- topLevelParent->getParent()->getElementType() == COLLADA_TYPE::NODE &&
- _gamePlayFile.getFromRefTable(topLevelParent->getParent()->getID()) != NULL)
- {
- parentNode = (Node*)_gamePlayFile.getFromRefTable(topLevelParent->getParent()->getID());
- }
- // Finally, load the node hierarchy that includes the skeleton
- skeleton = loadNode(topLevelParent, parentNode);
- }
- if (skeleton == NULL)
- {
- // This shouldn't really happen..
- skeleton = new Node();
- skeleton->setId(id);
- _gamePlayFile.addNode(skeleton);
- }
- // Resolve and set joints array for skin
- std::list<Node*> _joints;
- const std::list<std::string>& jointNames = skin->getJointNames();
- for (std::list<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); ++i)
- {
- Object* obj = _gamePlayFile.getFromRefTable(*i);
- if (obj)
- {
- Node* node = (Node*)obj;
- _joints.push_back(node);
- }
- }
- skin->setJoints(_joints);
- }
- Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
- {
- ///////////////////////////// SKIN
- Model* model = new Model();
- MeshSkin* skin = new MeshSkin();
- // Bind Shape Matrix
- const domSkin::domBind_shape_matrix* bindShapeMatrix = skinElement->getBind_shape_matrix();
- if (bindShapeMatrix)
- {
- const domFloat4x4& m = bindShapeMatrix->getValue();
- float transform[] = {(float)m.get(0), (float)m.get(4), (float)m.get(8), (float)m.get(12),
- (float)m.get(1), (float)m.get(5), (float)m.get(9), (float)m.get(13),
- (float)m.get(2), (float)m.get(6), (float)m.get(10), (float)m.get(14),
- (float)m.get(3), (float)m.get(7), (float)m.get(11), (float)m.get(15)};
- skin->setBindShape(transform);
- }
- // Read and set our joints
- domSkin::domJointsRef _joints = skinElement->getJoints();
- domInputLocal_Array& jointInputs = _joints->getInput_array();
- // Process "JOINT" input semantic first (we need to do this to set the joint count)
- unsigned int jointCount = 0;
- for (unsigned int i = 0; i < jointInputs.getCount(); ++i)
- {
- domInputLocalRef input = jointInputs.get(i);
- std::string inputSemantic = std::string(input->getSemantic());
- domURIFragmentType* sourceURI = &input->getSource();
- sourceURI->resolveElement();
- const domSourceRef source = (domSource*)(daeElement*)sourceURI->getElement();
- if (equals(inputSemantic, "JOINT"))
- {
- // Get the joint Ids's
- std::list<std::string> list;
- getJointNames(source, list);
- // Go through the joint list and conver them from sid to id because the sid information is
- // lost when converting to the gameplay binary format.
- for (std::list<std::string>::iterator i = list.begin(); i != list.end(); ++i)
- {
- daeSIDResolver resolver(source->getDocument()->getDomRoot(), i->c_str());
- daeElement* element = resolver.getElement();
- if (element && element->getElementType() == COLLADA_TYPE::NODE)
- {
- domNodeRef node = daeSafeCast<domNode>(element);
- const char* nodeId = node->getId();
- if (nodeId && !equals(*i, nodeId))
- {
- *i = nodeId;
- }
- }
- }
- // Get the joint count and set the capacities for both the
- jointCount = list.size();
- _jointInverseBindPoseMatrices.reserve(jointCount);
- unsigned int j = 0;
- for (std::list<std::string>::const_iterator i = list.begin(); i != list.end(); ++i)
- {
- _jointLookupTable[*i] = j++;
- }
- skin->setJointNames(list);
- }
- }
- // Make sure we have some joints
- if (jointCount == 0)
- {
- warning("No joints found for skin: ");
- return NULL;
- }
- // Process "INV_BIND_MATRIX" next
- for (unsigned int i = 0; i < jointInputs.getCount(); ++i)
- {
- domInputLocalRef input = jointInputs.get(i);
- std::string inputSemantic = std::string(input->getSemantic());
- domURIFragmentType* sourceURI = &input->getSource();
- sourceURI->resolveElement();
- domSource* source = (domSource*)(daeElement*)sourceURI->getElement();
- if (equals(inputSemantic, "INV_BIND_MATRIX"))
- {
- domListOfFloats& matrixFloats = source->getFloat_array()->getValue();
- //unsigned int matrixFloatsCount = (unsigned int)source->getFloat_array()->getCount();
- unsigned int jointIndex = 0;
- for (unsigned int j = 0; j < jointCount; ++j)
- {
- Matrix matrix((float)matrixFloats.get(jointIndex + 0), (float)matrixFloats.get(jointIndex + 4), (float)matrixFloats.get(jointIndex + 8), (float)matrixFloats.get(jointIndex + 12),
- (float)matrixFloats.get(jointIndex + 1), (float)matrixFloats.get(jointIndex + 5), (float)matrixFloats.get(jointIndex + 9), (float)matrixFloats.get(jointIndex + 13),
- (float)matrixFloats.get(jointIndex + 2), (float)matrixFloats.get(jointIndex + 6), (float)matrixFloats.get(jointIndex + 10), (float)matrixFloats.get(jointIndex + 14),
- (float)matrixFloats.get(jointIndex + 3), (float)matrixFloats.get(jointIndex + 7), (float)matrixFloats.get(jointIndex + 11), (float)matrixFloats.get(jointIndex + 15));
- _jointInverseBindPoseMatrices.push_back(matrix);
- jointIndex += 16;
- }
- }
- }
- skin->setBindPoses(_jointInverseBindPoseMatrices);
- // Get the vertex weights inputs
- domSkin::domVertex_weights* vertexWeights = skinElement->getVertex_weights();
- domInputLocalOffset_Array& vertexWeightsInputs = vertexWeights->getInput_array();
- unsigned int vertexWeightsCount = (unsigned int)vertexWeights->getCount();
- domListOfFloats jointWeights;
- for (unsigned int i = 0; i < jointInputs.getCount(); ++i)
- {
- domInputLocalOffsetRef input = vertexWeightsInputs.get(i);
- std::string inputSemantic = std::string(input->getSemantic());
- domURIFragmentType* sourceURI = &input->getSource();
- sourceURI->resolveElement();
- domSource* source = (domSource*)(daeElement*)sourceURI->getElement();
- if (equals(inputSemantic, "WEIGHT"))
- {
- domFloat_array* weights = source->getFloat_array();
- if (weights)
- {
- jointWeights = weights->getValue();
- }
- }
- }
-
- // Get the number of joint influences per vertex
- domSkin::domVertex_weights::domVcount* vCountElement = vertexWeights->getVcount();
- domListOfUInts skinVertexInfluenceCounts = vCountElement->getValue();
- // Get the joint/weight pair data.
- domSkin::domVertex_weights::domV* vElement = vertexWeights->getV();
- domListOfInts skinVertexJointWeightPairIndices = vElement->getValue();
-
- // Get the vertex influence count for any given vertex (up to max of 4)
- unsigned int maxVertexInfluencesCount = SCENE_SKIN_VERTEXINFLUENCES_MAX;
- skin->setVertexInfluenceCount(maxVertexInfluencesCount);
- // Get the vertex blend weights and joint indices and
- // allocate our vertex blend weights and blend indices arrays.
- // These will be used and cleaned up later in LoadMesh
- int skinVertexInfluenceCountTotal = skinVertexInfluenceCounts.getCount();
- int totalVertexInfluencesCount = vertexWeightsCount * maxVertexInfluencesCount;
- _vertexBlendWeights = new float[totalVertexInfluencesCount];
- _vertexBlendIndices = new unsigned int[totalVertexInfluencesCount];
- // Preset the default blend weights to 0.0f (no effect) and blend indices to 0 (uses the first which when multiplied
- // will have no effect anyhow.
- memset(_vertexBlendWeights, 0, totalVertexInfluencesCount * sizeof(float));
- memset(_vertexBlendIndices , 0, totalVertexInfluencesCount * sizeof(unsigned int));
-
- int vOffset = 0;
- int weightOffset = 0;
- // Go through all the skin vertex influence weights from the indexed data.
- for (int i = 0; i < skinVertexInfluenceCountTotal; ++i)
- {
- // Get the influence count and directly get the vertext blend weights and indices.
- unsigned int vertexInfluenceCount = (unsigned int)skinVertexInfluenceCounts.get(i);
- float vertexInfluencesTotalWeights = 0.0f;
- std::vector<SkinnedVertexWeightPair> vertexInfluences;
- //vertexInfluences.SetCapacity(vertexInfluenceCount);
- // Get the index/weight pairs and some the weight totals while at it.
- for (unsigned int j = 0; j < vertexInfluenceCount; ++j)
- {
- float weight = (float)jointWeights.get((unsigned int)skinVertexJointWeightPairIndices[vOffset + 1]);
- int index = (int)skinVertexJointWeightPairIndices[vOffset];
-
- // Set invalid index corresponding weights to zero
- if (index < 0 || index > (int)vertexWeightsCount)
- {
- weight = 0.0f;
- index = 0;
- }
- SkinnedVertexWeightPair pair(weight, index);
- vertexInfluences.push_back(pair);
- vertexInfluencesTotalWeights += weight;
- vOffset+=2;
- }
- // Get up the the maximum vertex weight influence count.
- for (unsigned int j = 0; j < maxVertexInfluencesCount; ++j)
- {
- if (j < vertexInfluenceCount)
- {
- SkinnedVertexWeightPair pair = vertexInfluences[j];
- _vertexBlendIndices[weightOffset] = pair.BlendIndex;
-
- if (vertexInfluencesTotalWeights > 0.0f)
- {
- _vertexBlendWeights[weightOffset] = pair.BlendWeight;
- }
- else
- {
- if (j == 0)
- {
- _vertexBlendWeights[weightOffset] = 1.0f;
- }
- else
- {
- _vertexBlendWeights[weightOffset] = 0.0f;
- }
- }
- }
- weightOffset++;
- }
- }
- model->setSkin(skin);
- ///////////////////////////////////////////////////////////
- // get geometry
- xsAnyURI geometryURI = skinElement->getSource();
- domGeometry* geometry = daeSafeCast<domGeometry>(geometryURI.getElement());
- if (geometry)
- {
- const domMesh* meshElement = geometry->getMesh();
- if (meshElement)
- {
- Mesh* mesh = loadMesh(meshElement, geometry->getId());
- if (mesh)
- {
- model->setMesh(mesh);
- }
- }
- }
- ///////////////////////////////////////////////////////////
- return model;
- }
- Model* DAESceneEncoder::loadGeometry(const domGeometry* geometry, const domBind_materialRef bindMaterial)
- {
- // Does this geometry have a valid mesh?
- // Get the mesh for the geometry (if it has one)
- const domMesh* meshElement = geometry->getMesh();
- if (meshElement == NULL)
- {
- warning(std::string("No mesh found for geometry: ") + geometry->getId());
- return NULL;
- }
- ///////////////////////////// GEOMETRY
- // Load the mesh for this model
- Mesh* mesh = loadMesh(meshElement, geometry->getId());
- if (mesh == NULL)
- {
- return NULL;
- }
- // Mesh instance
- Model* model = new Model();
- model->setMesh(mesh);
- return model;
- }
- Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& geometryId)
- {
- const domTriangles_Array& trianglesArray = meshElement->getTriangles_array();
- unsigned int trianglesArrayCount = (unsigned int)trianglesArray.getCount();
- // Ensure the data is exported as triangles.
- if (trianglesArrayCount == 0)
- {
- warning(std::string("Geometry mesh has no triangles: ") + geometryId);
- return NULL;
- }
- // Check if this mesh already exists
- Mesh* mesh = _gamePlayFile.getMesh(geometryId.c_str());
- if (mesh)
- {
- return mesh;
- }
- mesh = new Mesh();
- mesh->setId(geometryId.c_str());
-
- std::vector<DAEPolygonInput*> polygonInputs;
- // Quickly just go through each triangles array and make sure they have the same number of inputs
- // with the same layout.
- // const domSource_Array& sourceArray = meshElement->getSource_array();
- const domInputLocal_Array& vertexArray = meshElement->getVertices()->getInput_array();
- unsigned int inputCount = (unsigned int)-1;
- // Loop through our set of triangle lists (each list of triangles corresponds to a single MeshPart)
- for (unsigned int i = 0; i < trianglesArrayCount; ++i)
- {
- const domTrianglesRef& triangles = trianglesArray.get(i);
- const domInputLocalOffset_Array& inputArray = triangles->getInput_array();
- // If not set then determine the number of input for all the triangles.
- if (inputCount == -1)
- {
- inputCount = (unsigned int)inputArray.getCount();
- int texCoordCount = 0;
- for (unsigned int j = 0; j < inputCount; ++j)
- {
- const domInputLocalOffsetRef& input = inputArray.get(j);
- std::string inputSemantic = input->getSemantic();
- // If its a vertex first do an extra lookup for the inclusive inputs
- if (equals(inputSemantic, "VERTEX"))
- {
- unsigned int vertexArrayCount = (unsigned int)vertexArray.getCount();
- for (unsigned int k = 0; k < vertexArrayCount; ++k)
- {
- const domInputLocalRef& vertexInput = vertexArray.get(k);
-
- std::string semantic = std::string(vertexInput->getSemantic());
- int type = getVertexUsageType(semantic);
- if (type == -1)
- {
- warning(std::string("Vertex semantic (") + semantic + ") is invalid/unsupported for geometry mesh: " + geometryId);
- }
- DAEPolygonInput* polygonInput = new DAEPolygonInput();
- domURIFragmentType& sourceURI = vertexInput->getSource();
- sourceURI.resolveElement();
- domSource* source = (domSource*)(daeElement*)sourceURI.getElement();
- polygonInput->offset = 0;
- polygonInput->sourceValues = source->getFloat_array()->getValue();
- polygonInput->type = type;
- polygonInputs.push_back(polygonInput);
- }
- }
- else
- {
- std::string semantic = input->getSemantic();
- int type = getVertexUsageType(semantic);
- if (type == -1)
- {
- warning(std::string("Semantic (") + semantic + ") is invalid/unsupported for geometry mesh: " + geometryId);
- break;
- }
- if (type == TEXCOORD0)
- {
- // Some meshes have multiple texture coordinates
- assert(texCoordCount <= 7);
- type += texCoordCount;
- ++texCoordCount;
- }
- DAEPolygonInput* polygonInput = new DAEPolygonInput();
- domURIFragmentType& sourceURI = input->getSource();
- sourceURI.resolveElement();
- domSource* source = (domSource*)(daeElement*)sourceURI.getElement();
- polygonInput->offset = (unsigned int)input->getOffset();
- polygonInput->sourceValues = source->getFloat_array()->getValue();
- polygonInput->type = type;
- // Get the accessor info
- const domSource::domTechnique_commonRef& technique = source->getTechnique_common();
- if (technique.cast())
- {
- const domAccessorRef& accessor = technique->getAccessor();
- polygonInput->accessor = accessor;
- }
- polygonInputs.push_back(polygonInput);
- }
- }
- }
- else
- {
- // If there is a triangle array with a different number of inputs, this is not supported.
- if (inputCount != (unsigned int)inputArray.getCount())
- {
- for (size_t j = 0; j < polygonInputs.size(); ++j)
- {
- delete polygonInputs[j];
- }
- warning(std::string("Triangles do not all have the same number of input sources for geometry mesh: ") + geometryId);
- return NULL;
- }
- else
- {
- // TODO: Check if they are in the same order...
- }
- }
- }
-
- // Now we have validated that all input in all triangles are the same and in the same input layout.
- // Lets start to read them and build our subsets.
- for (unsigned int i = 0; i < trianglesArrayCount; ++i)
- {
- // Subset to be built.
- MeshPart* subset = new MeshPart();
- // All of the information about the triangles and the sources to access the data from.
- domTriangles* triangles = daeSafeCast<domTriangles>(trianglesArray.get(i));
- // Parse the material for this subset
- //std::string materialName = triangles->getMaterial() == NULL ? _T("") : triangles->getMaterial();
- //if (materialName.size() > 0)
- /// subset->material = ParseMaterial(bindMaterial, materialName);
- //const domInputLocalOffset_Array& inputArray = triangles->getInput_array();
- const domListOfUInts& polyInts = triangles->getP()->getValue();
- unsigned int polyIntsCount = (unsigned int)polyInts.getCount();
- unsigned int poly = 0;
- unsigned int inputSourceCount = (unsigned int)polygonInputs.size();
- unsigned int maxOffset = 0;
- // Go through the polygon indices for each input source retrieve the values
- // and iterate by its offset.
- Vertex vertex;
- for (unsigned int k = 0; k < inputSourceCount && poly < polyIntsCount;)
- {
- const domListOfFloats& source = polygonInputs[k]->sourceValues;
- unsigned int offset = polygonInputs[k]->offset;
- if (offset > maxOffset)
- {
- maxOffset = offset;
- }
- int type = polygonInputs[k]->type;
- unsigned int polyIndex = (unsigned int) polyInts.get(poly + offset);
- switch (type)
- {
- case POSITION:
- vertex = Vertex(); // TODO
- if (_vertexBlendWeights && _vertexBlendIndices)
- {
- vertex.hasWeights = true;
- vertex.blendWeights.x = _vertexBlendWeights[polyIndex * 4];
- vertex.blendWeights.y = _vertexBlendWeights[polyIndex * 4 + 1];
- vertex.blendWeights.z = _vertexBlendWeights[polyIndex * 4 + 2];
- vertex.blendWeights.w = _vertexBlendWeights[polyIndex * 4 + 3];
- vertex.blendIndices.x = (float)_vertexBlendIndices[polyIndex * 4];
- vertex.blendIndices.y = (float)_vertexBlendIndices[polyIndex * 4 + 1];
- vertex.blendIndices.z = (float)_vertexBlendIndices[polyIndex * 4 + 2];
- vertex.blendIndices.w = (float)_vertexBlendIndices[polyIndex * 4 + 3];
- }
- vertex.position.x = (float)source.get(polyIndex * 3);
- vertex.position.y = (float)source.get(polyIndex * 3 + 1);
- vertex.position.z = (float)source.get(polyIndex * 3 + 2);
- break;
-
- case NORMAL:
- vertex.hasNormal = true;
- vertex.normal.x = (float)source.get(polyIndex * 3);
- vertex.normal.y = (float)source.get(polyIndex * 3 + 1);
- vertex.normal.z = (float)source.get(polyIndex * 3 + 2);
- break;
- // TODO: Handle reading of per-vertex colors.
- // HOW do we know how many color components to read?
- // We must examine the Collada input accessor and read the stride/count to verify this - not ONLY for Color, but we should be doing this for ALL components (i.e. Position, Normal, etc).
- // case Color:
- // vertex.hasColor = true;
- // vertex.Diffuse.R = (float)source.get(polyIndex * 3);
- // vertex.Diffuse.G = (float)source.get(polyIndex * 3 + 1);
- // vertex.Diffuse.B = (float)source.get(polyIndex * 3 + 2);
- // vertex.Diffuse.A = (float)source.get(polyIndex * 3 + 3);
- // break;
- case TANGENT:
- vertex.hasTangent = true;
- vertex.tangent.x = (float)source.get(polyIndex * 3);
- vertex.tangent.y = (float)source.get(polyIndex * 3 + 1);
- vertex.tangent.z = (float)source.get(polyIndex * 3 + 2);
- break;
- case BINORMAL:
- vertex.hasBinormal = true;
- vertex.binormal.x = (float)source.get(polyIndex * 3);
- vertex.binormal.y = (float)source.get(polyIndex * 3 + 1);
- vertex.binormal.z = (float)source.get(polyIndex * 3 + 2);
- break;
- case TEXCOORD0:
- vertex.hasTexCoord = true;
- if (polygonInputs[k]->accessor)
- {
- // TODO: This assumes (s, t) are first
- unsigned int stride = (unsigned int)polygonInputs[k]->accessor->getStride();
- vertex.texCoord.x = (float)source.get(polyIndex * stride);
- vertex.texCoord.y = (float)source.get(polyIndex * stride + 1);
- }
- else
- {
- vertex.texCoord.x = (float)source.get(polyIndex * 2);
- vertex.texCoord.y = (float)source.get(polyIndex * 2 + 1);
- }
- break;
- case TEXCOORD1:
- // TODO
- break;
- default:
- break;
- }
- // On the last input source attempt to add the vertex or index an existing one.
- if (k == (inputSourceCount - 1))
- {
- // Only add unique vertices, use a hashtable and compare the hash functions of the
- // vertices. If they exist simply lookup the index of the existing ones.
- // otherwise add and new one and index it.
- unsigned int index;
- if (mesh->contains(vertex))
- {
- index = mesh->getVertexIndex(vertex);
- }
- else
- {
- index = mesh->addVertex(vertex);
- }
- subset->addIndex(index);
- poly += (maxOffset+1);
- k = 0;
- }
- else
- {
- k++;
- }
- }
- // Add our new subset for the mesh.
- mesh->addMeshPart(subset);
- }
-
- bool hasNormals = mesh->vertices[0].hasNormal;
- bool hasColors = mesh->vertices[0].hasColor;
- bool hasTangents = mesh->vertices[0].hasTangent;
- bool hasBinormals = mesh->vertices[0].hasBinormal;
- bool hasTexCoords = mesh->vertices[0].hasTexCoord;
- bool hasWeights = mesh->vertices[0].hasWeights;
- // The order that the vertex elements are add to the list matters.
- // It should be the same order as how the Vertex data is written.
- // Position
- mesh->addVetexAttribute(POSITION, 3);
-
- // Normals
- if (hasNormals)
- {
- mesh->addVetexAttribute(NORMAL, 3);
- }
- // Tangents
- if (hasTangents)
- {
- mesh->addVetexAttribute(TANGENT, 3);
- }
- // Binormals
- if (hasBinormals)
- {
- mesh->addVetexAttribute(BINORMAL, 3);
- }
- // Texture Coordinates
- if (hasTexCoords)
- {
- mesh->addVetexAttribute(TEXCOORD0, 2);
- }
- // Diffuse Color
- if (hasColors)
- {
- mesh->addVetexAttribute(COLOR, 3);
- }
- // Skinning BlendWeights BlendIndices
- if (hasWeights /*_vertexBlendWeights && _vertexBlendIndices*/)
- {
- mesh->addVetexAttribute(BLENDWEIGHTS, 4);
- mesh->addVetexAttribute(BLENDINDICES, 4);
- }
- _gamePlayFile.addMesh(mesh);
- return mesh;
- }
- void DAESceneEncoder::warning(const std::string& message)
- {
- printf("Warning: %s\n", message.c_str());
- }
- void DAESceneEncoder::warning(const char* message)
- {
- printf("Warning: %s\n", message);
- }
- int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
- {
- int type = -1;
- if (semantic.length() > 0)
- {
- switch (semantic[0])
- {
- case 'P':
- if (equals(semantic, "POSITION"))
- {
- type = POSITION;
- }
- break;
- case 'N':
- if (equals(semantic, "NORMAL"))
- {
- type = NORMAL;
- }
- case 'C':
- if (equals(semantic, "COLOR"))
- {
- type = COLOR;
- }
- case 'T':
- if (equals(semantic, "TANGENT"))
- {
- type = TANGENT;
- }
- else if (equals(semantic, "TEXCOORD"))
- {
- type = TEXCOORD0;
- }
- else if (equals(semantic, "TEXTANGENT"))
- {
- // Treat TEXTANGENT as TANGENT
- type = TANGENT;
- }
- else if (equals(semantic, "TEXBINORMAL"))
- {
- // Treat TEXBINORMAL as BINORMAL
- type = BINORMAL;
- }
- case 'B':
- if (equals(semantic, "BINORMAL"))
- {
- type = BINORMAL;
- }
- default:
- break;
- }
- }
- return type;
- }
- DAESceneEncoder::DAEPolygonInput::DAEPolygonInput(void) :
- offset(0),
- type(0),
- accessor(NULL)
- {
- }
- DAESceneEncoder::DAEPolygonInput::~DAEPolygonInput(void)
- {
- }
|