1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include <algorithm>
- #include "console/console.h"
- #include "gfx/bitmap/gBitmap.h"
- #include "ts/collada/colladaUtils.h"
- #include "materials/matInstance.h"
- //special handling for export classes
- #include "persistence/taml/fsTinyXml.h"
- #include "T3D/convexShape.h"
- using namespace ColladaUtils;
- #define MAX_PATH_LENGTH 256
- // Helper macro to create Collada elements
- #define CREATE_ELEMENT(container, name, type) \
- type* name = daeSafeCast<type>(container->createAndPlace(#name));
- ColladaUtils::ImportOptions& ColladaUtils::getOptions()
- {
- static ImportOptions options;
- return options;
- }
- //------------------------------------------------------------------------------
- // Utility functions
- // Convert a transform from the Collada model coordinate system to the DTS coordinate
- // system
- void ColladaUtils::convertTransform(MatrixF& mat)
- {
- MatrixF rot(true);
- switch (ColladaUtils::getOptions().upAxis)
- {
- case UPAXISTYPE_X_UP:
- // rotate 90 around Y-axis, then 90 around Z-axis
- rot(0,0) = 0.0f; rot(1,0) = 1.0f;
- rot(1,1) = 0.0f; rot(2,1) = 1.0f;
- rot(0,2) = 1.0f; rot(2,2) = 0.0f;
- // pre-multiply the transform by the rotation matrix
- mat.mulL(rot);
- break;
- case UPAXISTYPE_Y_UP:
- // rotate 180 around Y-axis, then 90 around X-axis
- rot(0,0) = -1.0f;
- rot(1,1) = 0.0f; rot(2,1) = 1.0f;
- rot(1,2) = 1.0f; rot(2,2) = 0.0f;
- // pre-multiply the transform by the rotation matrix
- mat.mulL(rot);
- break;
- case UPAXISTYPE_Z_UP:
- default:
- // nothing to do
- break;
- }
- }
- /// Find the COMMON profile element in an effect
- const domProfile_COMMON* ColladaUtils::findEffectCommonProfile(const domEffect* effect)
- {
- if (effect) {
- // Find the COMMON profile
- const domFx_profile_abstract_Array& profiles = effect->getFx_profile_abstract_array();
- for (S32 iProfile = 0; iProfile < profiles.getCount(); iProfile++) {
- if (profiles[iProfile]->getElementType() == COLLADA_TYPE::PROFILE_COMMON)
- return daeSafeCast<domProfile_COMMON>(profiles[iProfile]);
- }
- }
- return NULL;
- }
- /// Find the <diffuse> element in the COMMON profile of an effect
- const domCommon_color_or_texture_type_complexType* ColladaUtils::findEffectDiffuse(const domEffect* effect)
- {
- const domProfile_COMMON* profile = findEffectCommonProfile(effect);
- if (profile) {
- if (profile->getTechnique()->getLambert())
- return profile->getTechnique()->getLambert()->getDiffuse();
- else if (profile->getTechnique()->getPhong())
- return profile->getTechnique()->getPhong()->getDiffuse();
- else if (profile->getTechnique()->getBlinn())
- return profile->getTechnique()->getBlinn()->getDiffuse();
- }
- return NULL;
- }
- /// Find the <specular> element in the COMMON profile of an effect
- const domCommon_color_or_texture_type_complexType* ColladaUtils::findEffectSpecular(const domEffect* effect)
- {
- const domProfile_COMMON* profile = findEffectCommonProfile(effect);
- if (profile) {
- if (profile->getTechnique()->getLambert())
- return NULL; // no <specular> element for Lambert shader
- else if (profile->getTechnique()->getPhong())
- return profile->getTechnique()->getPhong()->getSpecular();
- else if (profile->getTechnique()->getBlinn())
- return profile->getTechnique()->getBlinn()->getSpecular();
- }
- return NULL;
- }
- const domFx_sampler2D_common_complexType* ColladaUtils::getTextureSampler(const domEffect* effect,
- const domCommon_color_or_texture_type_complexType* texture)
- {
- // <texture texture="new_param_SID">.<newparam>.<sampler2D>
- if (texture) {
- const domCommon_color_or_texture_type_complexType::domTexture* domTex = texture->getTexture();
- if (domTex && domTex->getTexture()) {
- daeSIDResolver resolver(const_cast<domEffect*>(effect), domTex->getTexture());
- const domCommon_newparam_type* param = daeSafeCast<domCommon_newparam_type>(resolver.getElement());
- if (param)
- return param->getSampler2D();
- }
- }
- return NULL;
- }
- String ColladaUtils::getSamplerImagePath(const domEffect* effect,
- const domFx_sampler2D_common_complexType* sampler2D)
- {
- // <sampler2D>.<source>.<newparam>.<surface>.<init_from>.<image>.<init_from>
- const domProfile_COMMON* profile = findEffectCommonProfile(effect);
- if (profile && sampler2D && sampler2D->getSource()) {
- // Resolve the SID to get the <surface> param
- daeSIDResolver resolver(const_cast<domProfile_COMMON*>(profile), sampler2D->getSource()->getValue());
- domCommon_newparam_type* surfaceParam = daeSafeCast<domCommon_newparam_type>(resolver.getElement());
- // Get the surface <init_from> element
- if (surfaceParam && surfaceParam->getSurface()) {
- const domFx_surface_init_common* surfaceInit = surfaceParam->getSurface()->getFx_surface_init_common();
- if (surfaceInit && surfaceInit->getInit_from_array().getCount()) {
- // Resolve the ID to get the <image>, then read the texture path
- xsIDREF& idRef = surfaceInit->getInit_from_array()[0]->getValue();
- const domImage* image = daeSafeCast<domImage>(idRef.getElement());
- if (image && image->getInit_from())
- return resolveImagePath(image);
- }
- }
- }
- return "";
- }
- // Resolve image path into something we can use.
- String ColladaUtils::resolveImagePath(const domImage* image)
- {
- // 1. If the URI string contains an absolute path, use it if
- // it is inside the Torque folder, otherwise force textures
- // to be in the same folder as the shape.
- // 2. If the URI string contains a relative path, append it
- // to the shape path (since materials.tscript cannot handle
- // relative paths).
- Torque::Path imagePath;
- String imageStr(image->getInit_from()->getValue().originalStr().c_str());
- // Trim leading "file://"
- if (imageStr.compare("file://", 7) == 0)
- imageStr.erase(0, 7);
- // Trim leading slash from absolute windows paths. eg. /D:/
- if ((imageStr.compare("/", 1) == 0) && (imageStr.find(':') == 2))
- imageStr.erase(0, 1);
- // Replace %20 with space
- imageStr.replace("%20", " ");
- if (Platform::isFullPath(imageStr))
- {
- // Absolute path => check for outside the Torque game folder
- imagePath = String( Platform::makeRelativePathName(imageStr, Platform::getMainDotCsDir()) );
- if ( !imagePath.getRoot().isEmpty() || // different drive (eg. C:/ vs D:/)
- (imagePath.getPath().find("/") == 0) || // different OS (eg. /home vs C:/home)
- (imagePath.getPath().find("../") == 0) ) // same drive, outside Torque game folder
- {
- // Force these to the shape folder
- imagePath.setRoot("");
- imagePath.setPath("");
- }
- }
- else
- {
- // Relative path => prepend with shape path
- Torque::Path tempPath(imageStr);
- imagePath = TSShapeLoader::getShapePath();
- imagePath.appendPath(tempPath);
- imagePath.setFileName(tempPath.getFileName());
- }
- // No need to specify the path if it is in the same folder as the model
- if (imagePath.getPath() == TSShapeLoader::getShapePath().getPath())
- imagePath.setPath("");
- // Don't care about the extension
- imagePath.setExtension("");
- return imagePath.getFullPath();
- }
- //-----------------------------------------------------------------------------
- // Construct the appropriate child class
- BasePrimitive* BasePrimitive::get(const daeElement* element)
- {
- switch (element->getElementType()) {
- case COLLADA_TYPE::TRIANGLES: return new ColladaPrimitive<domTriangles>(element);
- case COLLADA_TYPE::TRISTRIPS: return new ColladaPrimitive<domTristrips>(element);
- case COLLADA_TYPE::TRIFANS: return new ColladaPrimitive<domTrifans>(element);
- case COLLADA_TYPE::POLYGONS: return new ColladaPrimitive<domPolygons>(element);
- case COLLADA_TYPE::POLYLIST: return new ColladaPrimitive<domPolylist>(element);
- default: return 0;
- }
- }
- //------------------------------------------------------------------------------
- // Collada animation curves
- /// Determine which elements are being targeted
- void AnimData::parseTargetString(const char* target, S32 fullCount, const char* elements[])
- {
- // Assume targeting all elements at offset 0
- targetValueCount = fullCount;
- targetValueOffset = 0;
- // Check for array syntax: (n) or (n)(m)
- if (const char* p = dStrchr(target, '(')) {
- S32 indN, indM;
- if (dSscanf(p, "(%d)(%d)", &indN, &indM) == 2) {
- targetValueOffset = (indN * 4) + indM; // @todo: 4x4 matrix only
- targetValueCount = 1;
- }
- else if (dSscanf(p, "(%d)", &indN) == 1) {
- targetValueOffset = indN;
- targetValueCount = 1;
- }
- }
- else if (const char* p2 = dStrrchr(target, '.')) {
- // Check for named elements
- for (S32 iElem = 0; elements[iElem][0] != 0; iElem++) {
- if (!String::compare(p2, elements[iElem])) {
- targetValueOffset = iElem;
- targetValueCount = 1;
- break;
- }
- }
- }
- }
- /// Solve the cubic spline B(s) = param for s
- F32 AnimData::invertParamCubic(F32 param, F32 x0, F32 x1, F32 x2, F32 x3) const
- {
- const F64 INVERTPARAMCUBIC_TOL = 1.0e-09;
- const F64 INVERTPARAMCUBIC_SMALLERTOL = 1.0e-20;
- const F64 INVERTPARAMCUBIC_MAXIT = 100;
- // check input value for outside range
- if ((param - x0) < INVERTPARAMCUBIC_SMALLERTOL)
- return 0.0f;
- else if ((x3 - param) < INVERTPARAMCUBIC_SMALLERTOL)
- return 1.0f;
- U32 iterations = 0;
- // de Casteljau Subdivision.
- F32 u = 0.0f;
- F32 v = 1.0f;
- while (iterations < INVERTPARAMCUBIC_MAXIT) {
- F64 a = (x0 + x1)*0.5f;
- F64 b = (x1 + x2)*0.5f;
- F64 c = (x2 + x3)*0.5f;
- F64 d = (a + b)*0.5f;
- F64 e = (b + c)*0.5f;
- F64 f = (d + e)*0.5f;
- if (mFabs(f - param) < INVERTPARAMCUBIC_TOL)
- break;
- if (f < param) {
- x0 = f;
- x1 = e;
- x2 = c;
- u = (u + v)*0.5f;
- }
- else {
- x1 = a;
- x2 = d;
- x3 = f;
- v = (u + v)*0.5f;
- }
- iterations++;
- }
- return mClampF((u+v)*0.5f, 0.0f, 1.0f);
- }
- /// Get the interpolated value at time 't'
- void AnimData::interpValue(F32 t, U32 offset, double* value) const
- {
- // handle degenerate animation data
- if (input.size() == 0)
- {
- *value = 0.0f;
- return;
- }
- else if (input.size() == 1)
- {
- *value = output.getStringArrayData(0)[offset];
- return;
- }
- // clamp time to valid range
- F32 curveStart = input.getFloatValue(0);
- F32 curveEnd = input.getFloatValue(input.size()-1);
- t = mClampF(t, curveStart, curveEnd);
- // find the index of the input keyframe BEFORE 't'
- S32 index;
- for (index = 0; index < input.size()-2; index++) {
- if (input.getFloatValue(index + 1) > t)
- break;
- }
- // get the data for the two control points either side of 't'
- Point2F v0;
- v0.x = input.getFloatValue(index);
- v0.y = output.getStringArrayData(index)[offset];
- Point2F v3;
- v3.x = input.getFloatValue(index + 1);
- v3.y = output.getStringArrayData(index + 1)[offset];
- // If spline interpolation is specified but the tangents are not available,
- // default to LINEAR.
- const char* interp_method = interpolation.getStringValue(index);
- if (dStrEqual(interp_method, "BEZIER") ||
- dStrEqual(interp_method, "HERMITE") ||
- dStrEqual(interp_method, "CARDINAL")) {
- const double* inArray = inTangent.getStringArrayData(index + 1);
- const double* outArray = outTangent.getStringArrayData(index);
- if (!inArray || !outArray)
- interp_method = "LINEAR";
- }
- if (dStrEqual(interp_method, "STEP")) {
- // STEP interpolation
- *value = v0.y;
- }
- else if (dStrEqual(interp_method, "BEZIER") ||
- dStrEqual(interp_method, "HERMITE") ||
- dStrEqual(interp_method, "CARDINAL") ||
- dStrEqual(interp_method, "BSPLINE"))
- {
- // Cubic spline interpolation. The only difference between the 4 supported
- // forms is in the calculation of the other 2 control points:
- // BEZIER: control points are specified explicitly
- // HERMITE: tangents are specified, need to offset to get the control points
- // CARDINAL: (baked) tangents are specified, need to offset to get the control points
- // BSPLINE: control points are based on previous and next points
- // Get the 2 extra control points
- Point2F v1, v2;
- if (dStrEqual(interp_method, "BSPLINE")) {
- // v0 and v3 are the center points => need to
- // get the control points before and after them
- v1 = v0;
- v2 = v3;
- if (index > 0) {
- v0.x = input.getFloatValue(index-1);
- v0.y = output.getStringArrayData(index-1)[offset];
- }
- else {
- // mirror P1 through P0
- v0 = v1 + (v1 - v2);
- }
- if (index < (input.size()-2)) {
- v3.x = input.getFloatValue(index+2);
- v3.y = output.getStringArrayData(index+2)[offset];
- }
- else {
- // mirror P0 through P1
- v3 = v2 + (v2 - v1);
- }
- }
- else {
- const double* inArray = inTangent.getStringArrayData(index + 1);
- const double* outArray = outTangent.getStringArrayData(index);
- if (output.stride() == inTangent.stride()) {
- // This degenerate form (1D control points) does 2 things wrong:
- // 1) it does not specify the key (time) value
- // 2) the control point is specified as a tangent for both bezier and hermite
- // => interpolate to get the key values, and offset the tangent values
- v1.set((v0.x*2 + v3.x)/3, v0.y + outArray[offset]);
- v2.set((v0.x + v3.x*2)/3, v3.y - inArray[offset]);
- }
- else {
- // the expected form (2D control points)
- v1.set(outArray[offset*2], outArray[offset*2+1]);
- v2.set(inArray[offset*2], inArray[offset*2+1]);
- // if this is a hermite or cardinal spline, treat the values as tangents
- if (dStrEqual(interp_method, "HERMITE") || dStrEqual(interp_method, "CARDINAL")) {
- v1.set(v0.x + v1.x, v3.y - v1.y);
- v2.set(v0.x + v2.x, v3.x - v2.y);
- }
- }
- }
- // find 's' that gives the desired 't' value
- F32 s = invertParamCubic(t, v0.x, v1.x, v2.x, v3.x);
- // Calculate the output value using Bernstein evaluation and the
- // computed 's' value
- F32 c = 3.0f*(v1.y - v0.y);
- F32 e = 3.0f*(v2.y - v1.y);
- *value = (((v3.y - v0.y - e)*s + e - c)*s + c)*s + v0.y;
- }
- else {
- // default to LINEAR interpolation
- F32 s = mClampF((t - v0.x) / (v3.x - v0.x), 0.0f, 1.0f);
- *value = v0.y + (v3.y - v0.y) * s;
- }
- }
- void AnimData::interpValue(F32 t, U32 offset, const char** value) const
- {
- if (input.size() == 0)
- *value = "";
- else if (input.size() == 1)
- *value = output.getStringValue(0);
- else
- {
- // clamp time to valid range
- F32 curveStart = input.getFloatValue(0);
- F32 curveEnd = input.getFloatValue(input.size()-1);
- t = mClampF(t, curveStart, curveEnd);
- // find the index of the input keyframe BEFORE 't'
- S32 index;
- for (index = 0; index < input.size()-2; index++) {
- if (input.getFloatValue(index + 1) > t)
- break;
- }
- // String values only support STEP interpolation, so just get the
- // value at the input keyframe
- *value = output.getStringValue(index);
- }
- }
- //------------------------------------------------------------------------------
- // Collada document conditioners
- static void conditioner_fixupTextureSIDs(domCOLLADA* root)
- {
- for (S32 iLib = 0; iLib < root->getLibrary_effects_array().getCount(); iLib++) {
- domLibrary_effects* lib = root->getLibrary_effects_array()[iLib];
- for (S32 iEffect = 0; iEffect < lib->getEffect_array().getCount(); iEffect++) {
- domEffect* effect = lib->getEffect_array()[iEffect];
- const domCommon_color_or_texture_type_complexType* diffuse = findEffectDiffuse(effect);
- if (!diffuse || !diffuse->getTexture())
- continue;
- // Resolve the SID => if it is an <image>, add <sampler2D> and
- // <surface> elements to conform to the Collada spec.
- const char *image_sid = diffuse->getTexture()->getTexture();
- daeSIDResolver resolver(effect, image_sid);
- if (!daeSafeCast<domImage>(resolver.getElement()))
- continue;
- daeErrorHandler::get()->handleWarning(avar("Fixup %s <diffuse>.<texture> "
- "pointing at <image> instead of <sampler2D>", effect->getID()));
- // Generate SIDs for the new sampler2D and surface elements
- std::string sampler_sid(std::string(image_sid) + "-sampler");
- std::string surface_sid(std::string(image_sid) + "-surface");
- domProfile_COMMON* profile = const_cast<domProfile_COMMON*>(findEffectCommonProfile(effect));
- // Create <newparam>.<sampler2D>.<source>
- {
- CREATE_ELEMENT(profile, newparam, domCommon_newparam_type)
- CREATE_ELEMENT(newparam, sampler2D, domFx_sampler2D_common)
- CREATE_ELEMENT(sampler2D, source, domFx_sampler2D_common_complexType::domSource)
- newparam->setSid(sampler_sid.c_str());
- source->setValue(surface_sid.c_str());
- }
- // Create <newparam>.<surface>.<init_from>
- {
- CREATE_ELEMENT(profile, newparam, domCommon_newparam_type)
- CREATE_ELEMENT(newparam, surface, domFx_surface_common)
- CREATE_ELEMENT(surface, init_from, domFx_surface_init_from_common)
- CREATE_ELEMENT(surface, format, domFx_surface_common_complexType::domFormat)
- newparam->setSid(surface_sid.c_str());
- surface->setType(FX_SURFACE_TYPE_ENUM_2D);
- format->setValue("A8R8G8B8");
- init_from->setValue(image_sid);
- }
- // Store sampler2D sid in the <diffuse>.<texture> "texture" attribute
- diffuse->getTexture()->setTexture(sampler_sid.c_str());
- }
- }
- }
- static void conditioner_fixupImageURIs(domCOLLADA* root)
- {
- for (S32 iLib = 0; iLib < root->getLibrary_images_array().getCount(); iLib++) {
- domLibrary_images* lib = root->getLibrary_images_array()[iLib];
- for (S32 iImage = 0; iImage < lib->getImage_array().getCount(); iImage++) {
- domImage* image = lib->getImage_array()[iImage];
- if (image->getInit_from()) {
- xsAnyURI& uri = image->getInit_from()->getValue();
- // Replace '\' with '/'
- if (uri.originalStr().find("\\") != std::string::npos) {
- daeErrorHandler::get()->handleWarning(avar("Fixup invalid URI "
- "in %s: \"%s\"", image->getID(), uri.originalStr().c_str()));
- std::string str(uri.originalStr());
- std::replace(str.begin(), str.end(), '\\', '/');
- uri.set(str);
- }
- // Detect file://texture.jpg => this is an invalid URI and will
- // not be parsed correctly
- if (uri.scheme() == "file" &&
- uri.pathFile().empty() &&
- !uri.authority().empty()) {
- daeErrorHandler::get()->handleWarning(avar("Fixup invalid URI "
- "in %s: \"%s\"", image->getID(), uri.originalStr().c_str()));
- uri.set(uri.authority());
- }
- }
- }
- }
- }
- static void conditioner_fixupTransparency(domCOLLADA* root)
- {
- // Transparency is another example of something simple made complicated by
- // Collada. There are two (optional) elements that determine transparency:
- //
- // <transparent>: a color
- // <transparency>: a percentage applied to the color values
- //
- // Additionally, <transparent> has an optional "opaque" attribute that changes
- // the way transparency is determined. If set to A_ONE (the default), only the
- // alpha value of the transparent color is used, and a value of "1" means fully
- // opaque. If set to RGB_ZERO, only the RGB values of transparent are used, and
- // a value of "0" means fully opaque.
- //
- // To further complicate matters, Google Sketchup (all versions) and FeelingSoftware
- // ColladaMax (pre 3.03) export materials with the transparency element inverted
- // (1-transparency)
- // Get the <authoring_tool> string
- const char *authoringTool = "";
- if (const domAsset* asset = root->getAsset()) {
- for (S32 iContrib = 0; iContrib < asset->getContributor_array().getCount(); iContrib++) {
- const domAsset::domContributor* contrib = asset->getContributor_array()[iContrib];
- if (contrib->getAuthoring_tool()) {
- authoringTool = contrib->getAuthoring_tool()->getValue();
- break;
- }
- }
- }
- // Check for a match with the known problem-tools
- bool invertTransparency = false;
- const char *toolNames[] = { "FBX COLLADA exporter", "Google SketchUp",
- "Illusoft Collada Exporter", "FCollada" };
- for (S32 iName = 0; iName < (sizeof(toolNames)/sizeof(toolNames[0])); iName++) {
- if (dStrstr(authoringTool, toolNames[iName])) {
- invertTransparency = true;
- break;
- }
- }
- if (!invertTransparency)
- return;
- // Invert transparency as required for each effect
- for (S32 iLib = 0; iLib < root->getLibrary_effects_array().getCount(); iLib++) {
- domLibrary_effects* lib = root->getLibrary_effects_array()[iLib];
- for (S32 iEffect = 0; iEffect < lib->getEffect_array().getCount(); iEffect++) {
- domEffect* effect = lib->getEffect_array()[iEffect];
- // Find the common profile
- const domProfile_COMMON* commonProfile = findEffectCommonProfile(effect);
- if (!commonProfile)
- continue;
- domCommon_transparent_type* transparent = 0;
- if (commonProfile->getTechnique()->getConstant())
- transparent = commonProfile->getTechnique()->getConstant()->getTransparent();
- else if (commonProfile->getTechnique()->getLambert())
- transparent = commonProfile->getTechnique()->getLambert()->getTransparent();
- else if (commonProfile->getTechnique()->getPhong())
- transparent = commonProfile->getTechnique()->getPhong()->getTransparent();
- else if (commonProfile->getTechnique()->getBlinn())
- transparent = commonProfile->getTechnique()->getBlinn()->getTransparent();
- if (!transparent)
- continue;
- // If the shader "opaque" attribute is not specified, set it to
- // RGB_ZERO (the opposite of the Collada default), as this is what
- // the bad exporter tools seem to assume.
- if (!transparent->isAttributeSet("opaque")) {
- daeErrorHandler::get()->handleWarning(avar("Setting <transparent> "
- "\"opaque\" attribute to RGB_ZERO for %s <effect>", effect->getID()));
- transparent->setOpaque(FX_OPAQUE_ENUM_RGB_ZERO);
- }
- }
- }
- }
- static void conditioner_checkBindShapeMatrix(domCOLLADA* root)
- {
- for (S32 iLib = 0; iLib < root->getLibrary_controllers_array().getCount(); iLib++) {
- domLibrary_controllers* lib = root->getLibrary_controllers_array().get(iLib);
- for (S32 iCon = 0; iCon < lib->getController_array().getCount(); iCon++) {
- domController* con = lib->getController_array().get(iCon);
- if (con->getSkin() && con->getSkin()->getBind_shape_matrix()) {
- MatrixF mat = vecToMatrixF<domMatrix>(con->getSkin()->getBind_shape_matrix()->getValue());
- if (!mat.fullInverse()) {
- daeErrorHandler::get()->handleWarning(avar("<bind_shape_matrix> "
- "in %s <controller> is not invertible (may cause problems with "
- "skinning)", con->getID()));
- }
- }
- }
- }
- }
- static void conditioner_fixupVertexWeightJoints(domCOLLADA* root)
- {
- for (S32 iLib = 0; iLib < root->getLibrary_controllers_array().getCount(); iLib++) {
- domLibrary_controllers* lib = root->getLibrary_controllers_array().get(iLib);
- for (S32 iCon = 0; iCon < lib->getController_array().getCount(); iCon++) {
- domController* con = lib->getController_array().get(iCon);
- if (con->getSkin() && con->getSkin()->getVertex_weights())
- {
- domInputLocalOffset_Array& vw_inputs = con->getSkin()->getVertex_weights()->getInput_array();
- for (S32 vInput = 0; vInput < vw_inputs.getCount(); vInput++) {
- domInputLocalOffset *vw_input = vw_inputs.get(vInput);
- if (dStrEqual(vw_input->getSemantic(), "JOINT")) {
- // Check if this input points at a float array (bad)
- domSource* vw_source = daeSafeCast<domSource>(vw_input->getSource().getElement());
- if (vw_source->getFloat_array()) {
- // Copy the value from the <joints> JOINTS input instead
- domInputLocal_Array& joint_inputs = con->getSkin()->getJoints()->getInput_array();
- for (S32 jInput = 0; jInput < joint_inputs.getCount(); jInput++) {
- domInputLocal *joint_input = joint_inputs.get(jInput);
- if (dStrEqual(joint_input->getSemantic(), "JOINT")) {
- vw_input->setSource(joint_input->getSource());
- break;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- static void conditioner_createDefaultClip(domCOLLADA* root)
- {
- // Check if the document has any <animation_clip>s
- for (S32 iLib = 0; iLib < root->getLibrary_animation_clips_array().getCount(); iLib++) {
- if (root->getLibrary_animation_clips_array()[iLib]->getAnimation_clip_array().getCount())
- return;
- }
- // Get all top-level <animation>s into an array
- domAnimation_Array animations;
- for (S32 iAnimLib = 0; iAnimLib < root->getLibrary_animations_array().getCount(); iAnimLib++) {
- const domLibrary_animations* libraryAnims = root->getLibrary_animations_array()[iAnimLib];
- for (S32 iAnim = 0; iAnim < libraryAnims->getAnimation_array().getCount(); iAnim++)
- animations.append(libraryAnims->getAnimation_array()[iAnim]);
- }
- if (!animations.getCount())
- return;
- daeErrorHandler::get()->handleWarning("Creating cyclic animation clip to "
- "hold all animations");
- // Get animation_clip library (create one if necessary)
- if (!root->getLibrary_animation_clips_array().getCount()) {
- root->createAndPlace("library_animation_clips");
- }
- domLibrary_animation_clips* libraryClips = root->getLibrary_animation_clips_array()[0];
- // Create new animation_clip for the default sequence
- CREATE_ELEMENT(libraryClips, animation_clip, domAnimation_clip)
- animation_clip->setName("ambient");
- animation_clip->setId("dummy_ambient_clip");
- animation_clip->setStart(0);
- animation_clip->setEnd(0);
- // Add all top_level animations to the clip (sub-animations will be included
- // when the clip is procesed)
- for (S32 iAnim = 0; iAnim < animations.getCount(); iAnim++) {
- if (!animations[iAnim]->getId())
- animations[iAnim]->setId(avar("dummy-animation-id%d", iAnim));
- CREATE_ELEMENT(animation_clip, instance_animation, domInstanceWithExtra)
- std::string url(std::string("#") + animations[iAnim]->getId());
- instance_animation->setUrl(url.c_str());
- }
- // Add the 'Torque' profile to specify the 'Cyclic' flag
- CREATE_ELEMENT(animation_clip, extra, domExtra)
- CREATE_ELEMENT(extra, technique, domTechnique)
- CREATE_ELEMENT(technique, any, domAny)
- technique->setProfile("Torque");
- any->setElementName("cyclic");
- any->setValue("1");
- }
- static void conditioner_fixupAnimation(domAnimation* anim)
- {
- S32 visibilityLen = dStrlen("/visibility");
- for (S32 iChannel = 0; iChannel < anim->getChannel_array().getCount(); iChannel++) {
- // Get the animation elements: <channel>, <sampler>
- domChannel* channel = anim->getChannel_array()[iChannel];
- domSampler* sampler = daeSafeCast<domSampler>(channel->getSource().getElement());
- if (!sampler)
- continue;
- /*
- // If using a spline interpolation type but no tangents are specified,
- // fall back to LINEAR interpolation.
- bool isSpline = false;
- bool foundInTangent = false;
- bool foundOutTangent = false;
- for (int iInput = 0; iInput < sampler->getInput_array().getCount(); iInput++) {
- const char *semantic = sampler->getInput_array()[iInput]->getSemantic();
- if (dStrEqual(semantic, "INTERPOLATION")) {
- if (
- }
- if (dStrEqual(semantic, "IN_TANGENT"))
- foundInTangent = true;
- if (dStrEqual(semantic, "OUT_TANGENT"))
- foundOutTangent = true;
- }
- if (isSpline && (!foundInTangent || !foundOutTangent)) {
- daeErrorHandler::get()->handleWarning(avar("%s type interpolation "
- "specified for %s, but IN/OUT TANGENTS are not provided. Using "
- "LINEAR interpolation instead.");
- }
- */
- // Find the animation channel target
- daeSIDResolver resolver(channel, channel->getTarget());
- daeElement* target = resolver.getElement();
- if (!target) {
- // Some exporters generate visibility animations but don't add the
- // FCOLLADA extension, so the target doesn't actually exist! Detect
- // this situation and add the extension manually so the animation
- // still works.
- if (dStrEndsWith(channel->getTarget(), "/visibility")) {
- // Get parent SID string
- char *parentSID = dStrdup(channel->getTarget());
- parentSID[dStrlen(parentSID) - visibilityLen] = '\0';
- // Find the parent element (should be a <node>)
- daeSIDResolver parentResolver(channel, parentSID);
- daeElement* parent = parentResolver.getElement();
- delete [] parentSID;
- if (parent && (parent->getElementType() == COLLADA_TYPE::NODE)) {
- // Create the FCOLLADA extension
- daeErrorHandler::get()->handleWarning(avar("Creating missing "
- "visibility animation target: %s", channel->getTarget()));
- // Check if the <visibility> element exists but is missing the SID
- daeElement* vis = parent->getDescendant("visibility");
- if (vis)
- {
- vis->setAttribute("sid", "visibility");
- }
- else
- {
- CREATE_ELEMENT(parent, extra, domExtra)
- CREATE_ELEMENT(extra, technique, domTechnique)
- CREATE_ELEMENT(technique, any, domAny)
- technique->setProfile("FCOLLADA");
- any->setElementName("visibility");
- any->setAttribute("sid", "visibility");
- any->setValue(""); // real initial value will be set when animation is processed in ColladaShapeLoader::processAnimation
- }
- }
- }
- }
- }
- // Process child animations
- for (S32 iAnim = 0; iAnim < anim->getAnimation_array().getCount(); iAnim++)
- conditioner_fixupAnimation(anim->getAnimation_array()[iAnim]);
- }
- /// Apply the set of model conditioners
- void ColladaUtils::applyConditioners(domCOLLADA* root)
- {
- //--------------------------------------------------------------------------
- // The built-in MAX FBX exporter specifies an <image> SID in the <texture>
- // "texture" attribute instead of a <newparam> SID. Detect and fix this.
- conditioner_fixupTextureSIDs(root);
- //--------------------------------------------------------------------------
- // The built-in MAX FBX exporter also generates invalid URI paths in the
- // <image>.<init_from> tag, so fix that up too.
- conditioner_fixupImageURIs(root);
- //--------------------------------------------------------------------------
- // Many exporters get transparency backwards. Check if the model was exported
- // by one with a known issue and correct it.
- conditioner_fixupTransparency(root);
- //--------------------------------------------------------------------------
- // Some exporters (AutoDesk) generate invalid bind_shape matrices. Warn if
- // the bind_shape_matrix is not invertible.
- conditioner_checkBindShapeMatrix(root);
- //--------------------------------------------------------------------------
- // The PoserPro exporter points the <vertex_weights> JOINT input to the
- // inverse bind matrices instead of the joint names array. Detect and fix it.
- conditioner_fixupVertexWeightJoints(root);
- //--------------------------------------------------------------------------
- // If the model contains <animation>s but no <animation_clip>s, just put all
- // top level animations into a single clip.
- conditioner_createDefaultClip(root);
- //--------------------------------------------------------------------------
- // Apply some animation fixups:
- // 1) Some exporters (eg. Blender) generate "BEZIER" type animation curves,
- // but do not specify the IN and OUT tangent data arrays. Detect this and
- // fall back to LINEAR interpolation.
- // 2) Some exporters generate visibility animations but don't add the FCOLLADA
- // extension, so the target doesn't actually exist! Detect this situation
- // and add the extension manually so the animation still works.
- for (S32 iLib = 0; iLib < root->getLibrary_animations_array().getCount(); iLib++) {
- const domLibrary_animations* lib = root->getLibrary_animations_array()[iLib];
- for (S32 iAnim = 0; iAnim < lib->getAnimation_array().getCount(); iAnim++)
- conditioner_fixupAnimation(lib->getAnimation_array()[iAnim]);
- }
- }
- Torque::Path ColladaUtils::findTexture(const Torque::Path& diffuseMap)
- {
- Vector<Torque::Path> foundPaths;
- GBitmap::sFindFiles(diffuseMap, &foundPaths);
- if (foundPaths.size() > 0)
- return Torque::Path(foundPaths[0]);
- // If unable to load texture in current directory
- // look in the parent directory. But never look in the root.
- Torque::Path newPath(diffuseMap);
- String filePath = newPath.getPath();
- String::SizeType slash = filePath.find('/', filePath.length(), String::Right);
- if (slash != String::NPos)
- {
- slash = filePath.find('/', filePath.length(), String::Right);
- if (slash != String::NPos)
- {
- String truncPath = filePath.substr(0, slash);
- newPath.setPath(truncPath);
- return findTexture(newPath);
- }
- }
- return String::EmptyString;
- }
- void ColladaUtils::exportColladaHeader(tinyxml2::XMLElement* rootNode)
- {
- tinyxml2::XMLDocument* doc = rootNode->GetDocument();
- tinyxml2::XMLElement* assetNode = doc->NewElement("asset");
- rootNode->LinkEndChild(assetNode);
- tinyxml2::XMLElement* contributorNode = doc->NewElement("contributor");
- assetNode->LinkEndChild(contributorNode);
- tinyxml2::XMLElement* authorNode = doc->NewElement("author");
- contributorNode->LinkEndChild(authorNode);
- tinyxml2::XMLText* authorNodeText = doc->NewText("Torque3D MIT User");
- authorNode->LinkEndChild(authorNodeText);
- tinyxml2::XMLElement* authoringToolNode = doc->NewElement("authoring_tool");
- contributorNode->LinkEndChild(authoringToolNode);
- tinyxml2::XMLText* authorText = doc->NewText(avar("%s %s Object Exporter", getEngineProductString(), getVersionString()));
- authoringToolNode->LinkEndChild(authorText);
- //tinyxml2::XMLElement* commentsNode = doc->NewElement("comments");
- //contributorNode->LinkEndChild(commentsNode);
- // Get the current time
- Platform::LocalTime lt;
- Platform::getLocalTime(lt);
- String localTime = Platform::localTimeToString(lt);
- localTime.replace('\t', ' ');
- tinyxml2::XMLElement* createdNode = doc->NewElement("created");
- assetNode->LinkEndChild(createdNode);
- tinyxml2::XMLText* createdText = doc->NewText(avar("%s", localTime.c_str()));
- createdNode->LinkEndChild(createdText);
- tinyxml2::XMLElement* modifiedNode = doc->NewElement("modified");
- assetNode->LinkEndChild(modifiedNode);
- tinyxml2::XMLText* modifiedText = doc->NewText(avar("%s", localTime.c_str()));
- modifiedNode->LinkEndChild(modifiedText);
- //tinyxml2::XMLElement* revisionNode = doc->NewElement("revision");
- //assetNode->LinkEndChild(revisionNode);
- //tinyxml2::XMLElement* titleNode = doc->NewElement("title");
- //assetNode->LinkEndChild(titleNode);
- //tinyxml2::XMLElement* subjectNode = doc->NewElement("subject");
- //assetNode->LinkEndChild(subjectNode);
- //tinyxml2::XMLElement* keywordsNode = doc->NewElement("keywords");
- //assetNode->LinkEndChild(keywordsNode);
- // Torque uses Z_UP with 1 unit equal to 1 meter by default
- tinyxml2::XMLElement* unitNode = doc->NewElement("unit");
- assetNode->LinkEndChild(unitNode);
- unitNode->SetAttribute("name", "meter");
- unitNode->SetAttribute("meter", "1");
- tinyxml2::XMLElement* axisNode = doc->NewElement("up_axis");
- assetNode->LinkEndChild(axisNode);
- tinyxml2::XMLText* axisText = doc->NewText("Z_UP");
- axisNode->LinkEndChild(axisText);
- }
- void ColladaUtils::exportColladaMaterials(tinyxml2::XMLElement* rootNode, const OptimizedPolyList& mesh, Vector<String>& matNames, const Torque::Path& colladaFile)
- {
- tinyxml2::XMLDocument* doc = rootNode->GetDocument();
- // First the image library
- tinyxml2::XMLElement* imgLibNode = doc->NewElement("library_images");
- rootNode->LinkEndChild(imgLibNode);
- for (U32 i = 0; i < mesh.mMaterialList.size(); i++)
- {
- BaseMatInstance* baseInst = mesh.mMaterialList[i];
- matNames.push_back(String::ToString("Material%d", i));
- Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
- if (!mat)
- continue;
- String diffuseMap;
- if (mat->getName() && mat->getName()[0])
- matNames.last() = mat->mMapTo;
- // Handle an auto-generated "Default Material" specially
- if (mat->isAutoGenerated())
- {
- Torque::Path diffusePath;
- if (mat->mDiffuseMapName[0] != StringTable->EmptyString())
- diffusePath = Torque::Path(mat->mDiffuseMapName[0]);
- else
- diffusePath = String("warningMat");
- matNames.last() = diffusePath.getFileName();
- diffuseMap += diffusePath.getFullFileName();
- }
- else
- {
- if (mat->mDiffuseMapName[0] != StringTable->EmptyString())
- diffuseMap += Torque::Path(mat->mDiffuseMapName[0]);
- else
- diffuseMap += "warningMat";
- }
- Torque::Path diffusePath = findTexture(colladaFile.getPath() + "/" + diffuseMap);
- // If we didn't get a path
- if (diffusePath.getFullPath().isNotEmpty())
- diffuseMap = Torque::Path::MakeRelativePath(diffusePath, colladaFile);
- tinyxml2::XMLElement* imageNode = doc->NewElement("image");
- imgLibNode->LinkEndChild(imageNode);
- imageNode->SetAttribute("id", avar("%s", matNames.last().c_str()));
- imageNode->SetAttribute("name", avar("%s", matNames.last().c_str()));
- tinyxml2::XMLElement* initNode = doc->NewElement("init_from");
- imageNode->LinkEndChild(initNode);
- tinyxml2::XMLText* initText = doc->NewText(avar("file://%s", diffuseMap.c_str())); // "the file://" is needed to load the texture in some old apps (ex: 3ds Max 2009)
- initNode->LinkEndChild(initText);
- }
- // Next the effects library
- tinyxml2::XMLElement* effectLibNode = doc->NewElement("library_effects");
- rootNode->LinkEndChild(effectLibNode);
- for (U32 i = 0; i < mesh.mMaterialList.size(); i++)
- {
- BaseMatInstance* baseInst = mesh.mMaterialList[i];
- Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
- if (!mat)
- continue;
- tinyxml2::XMLElement* effectNode = doc->NewElement("effect");
- effectLibNode->LinkEndChild(effectNode);
- effectNode->SetAttribute("id", avar("%s-effect", matNames[i].c_str()));
- effectNode->SetAttribute("name", avar("%s-effect", matNames[i].c_str()));
- tinyxml2::XMLElement* profileNode = doc->NewElement("profile_COMMON");
- effectNode->LinkEndChild(profileNode);
-
- // ---------------------------
- tinyxml2::XMLElement* newParamNode = doc->NewElement("newparam");
- profileNode->LinkEndChild(newParamNode);
- newParamNode->SetAttribute("sid", avar("%s-surface", matNames[i].c_str()));
- tinyxml2::XMLElement* surfaceNode = doc->NewElement("surface");
- newParamNode->LinkEndChild(surfaceNode);
- surfaceNode->SetAttribute("type", "2D");
- tinyxml2::XMLElement* initNode2 = doc->NewElement("init_from");
- surfaceNode->LinkEndChild(initNode2);
- tinyxml2::XMLText* init2Text = doc->NewText(avar("%s", matNames[i].c_str()));
- initNode2->LinkEndChild(init2Text);
- tinyxml2::XMLElement* formatNode = doc->NewElement("format");
- surfaceNode->LinkEndChild(formatNode);
- tinyxml2::XMLText* formatText = doc->NewText("A8R8G8B8");
- formatNode->LinkEndChild(formatText);
- // ---------------------------
- tinyxml2::XMLElement* newParam2Node = doc->NewElement("newparam");
- profileNode->LinkEndChild(newParam2Node);
- newParam2Node->SetAttribute("sid", avar("%s-sampler", matNames[i].c_str()));
- tinyxml2::XMLElement* sampler2DNode = doc->NewElement("sampler2D");
- newParam2Node->LinkEndChild(sampler2DNode);
-
- tinyxml2::XMLElement* sourceSampler2DNode = doc->NewElement("source");
- sampler2DNode->LinkEndChild(sourceSampler2DNode);
- tinyxml2::XMLText* sourceSampler2DText = doc->NewText(avar("%s-surface", matNames[i].c_str()));
- sourceSampler2DNode->LinkEndChild(sourceSampler2DText);
- // ---------------------------
- tinyxml2::XMLElement* techniqueNode = doc->NewElement("technique");
- profileNode->LinkEndChild(techniqueNode);
- techniqueNode->SetAttribute("sid", "common");
- tinyxml2::XMLElement* blinnNode = doc->NewElement("blinn");
- techniqueNode->LinkEndChild(blinnNode);
-
- // ---------------------------
- tinyxml2::XMLElement* emissionNode = doc->NewElement("emission");
- blinnNode->LinkEndChild(emissionNode);
- tinyxml2::XMLElement* colorEmissionNode = doc->NewElement("color");
- emissionNode->LinkEndChild(colorEmissionNode);
- colorEmissionNode->SetAttribute("sid", "emission");
- tinyxml2::XMLText* colorEmissionNodeText = doc->NewText("0.0 0.0 0.0 1.0");
- colorEmissionNode->LinkEndChild(colorEmissionNodeText);
-
- // ---------------------------
- tinyxml2::XMLElement* ambientNode = doc->NewElement("ambient");
- blinnNode->LinkEndChild(ambientNode);
- tinyxml2::XMLElement* colorAmbientNode = doc->NewElement("color");
- ambientNode->LinkEndChild(colorAmbientNode);
- colorAmbientNode->SetAttribute("sid", "ambient");
- tinyxml2::XMLText* colorAmbientNodeText = doc->NewText("0.0 0.0 0.0 1.0");
- colorAmbientNode->LinkEndChild(colorAmbientNodeText);
-
- // ---------------------------
- tinyxml2::XMLElement* diffuseNode = doc->NewElement("diffuse");
- blinnNode->LinkEndChild(diffuseNode);
- tinyxml2::XMLElement* textureDiffuseNode = doc->NewElement("texture");
- diffuseNode->LinkEndChild(textureDiffuseNode);
- textureDiffuseNode->SetAttribute("texture", avar("%s-sampler", matNames[i].c_str()));
- textureDiffuseNode->SetAttribute("texcoord", "UVMap");
-
- // Extra info useful for getting the texture to show up correctly in MAYA and 3DS Max
- tinyxml2::XMLElement* extraNode = doc->NewElement("extra");
- textureDiffuseNode->LinkEndChild(extraNode);
- tinyxml2::XMLElement* extraTechNode = doc->NewElement("technique");
- extraNode->LinkEndChild(extraTechNode);
- extraTechNode->SetAttribute("profile", "MAYA");
- tinyxml2::XMLElement* extraWrapUNode = doc->NewElement("wrapU");
- extraTechNode->LinkEndChild(extraWrapUNode);
- extraWrapUNode->SetAttribute("sid", "wrapU0");
- tinyxml2::XMLText* extraWrapUText = doc->NewText("TRUE");
- extraWrapUNode->LinkEndChild(extraWrapUText);
- tinyxml2::XMLElement* extraWrapVNode = doc->NewElement("wrapV");
- extraTechNode->LinkEndChild(extraWrapVNode);
- extraWrapVNode->SetAttribute("sid", "wrapV0");
- tinyxml2::XMLText* extraWrapVText = doc->NewText("TRUE");
- extraWrapVNode->LinkEndChild(extraWrapVText);
- tinyxml2::XMLElement* extraBlendNode = doc->NewElement("blend_mode");
- extraTechNode->LinkEndChild(extraBlendNode);
- tinyxml2::XMLText* extraBlendText = doc->NewText("ADD");
- extraBlendNode->LinkEndChild(extraBlendText);
-
- // ---------------------------
- tinyxml2::XMLElement* specularNode = doc->NewElement("specular");
- blinnNode->LinkEndChild(specularNode);
- tinyxml2::XMLElement* colorSpecularNode = doc->NewElement("color");
- specularNode->LinkEndChild(colorSpecularNode);
- colorSpecularNode->SetAttribute("sid", "specular");
-
- tinyxml2::XMLText* colorSpecularNodeText = doc->NewText("0.5 0.5 0.5 1.0");
- colorSpecularNode->LinkEndChild(colorSpecularNodeText);
- // ---------------------------
- tinyxml2::XMLElement* shininessNode = doc->NewElement("shininess");
- blinnNode->LinkEndChild(shininessNode);
- tinyxml2::XMLElement* colorShininessNode = doc->NewElement("float");
- shininessNode->LinkEndChild(colorShininessNode);
- colorShininessNode->SetAttribute("sid", "shininess");
-
- tinyxml2::XMLText* colorShininessNodeText = doc->NewText("1.0");
- colorShininessNode->LinkEndChild(colorShininessNodeText);
- // ---------------------------
- tinyxml2::XMLElement* reflectiveNode = doc->NewElement("reflective");
- blinnNode->LinkEndChild(reflectiveNode);
- tinyxml2::XMLElement* colorReflectiveNode = doc->NewElement("color");
- reflectiveNode->LinkEndChild(colorReflectiveNode);
- colorReflectiveNode->SetAttribute("sid", "reflective");
-
- tinyxml2::XMLText* colorReflectiveNodeText = doc->NewText("0.0 0.0 0.0 1.0");
- colorReflectiveNode->LinkEndChild(colorReflectiveNodeText);
- // ---------------------------
- tinyxml2::XMLElement* reflectivityNode = doc->NewElement("reflectivity");
- blinnNode->LinkEndChild(reflectivityNode);
- tinyxml2::XMLElement* floatReflectivityNode = doc->NewElement("float");
- reflectivityNode->LinkEndChild(floatReflectivityNode);
- floatReflectivityNode->SetAttribute("sid", "reflectivity");
-
- tinyxml2::XMLText* floatReflectivityText = doc->NewText("0.5");
- floatReflectivityNode->LinkEndChild(floatReflectivityText);
-
- // ---------------------------
- tinyxml2::XMLElement* transparentNode = doc->NewElement("transparent");
- blinnNode->LinkEndChild(transparentNode);
- transparentNode->SetAttribute("opaque", "RGB_ZERO");
- tinyxml2::XMLElement* colorTransparentNode = doc->NewElement("color");
- transparentNode->LinkEndChild(colorTransparentNode);
- colorTransparentNode->SetAttribute("sid", "transparent");
-
- tinyxml2::XMLText* colorTransparentNodeText = doc->NewText("0.0 0.0 0.0 1.0");
- colorTransparentNode->LinkEndChild(colorTransparentNodeText);
- // ---------------------------
- tinyxml2::XMLElement* transparencyNode = doc->NewElement("transparency");
- blinnNode->LinkEndChild(transparencyNode);
- tinyxml2::XMLElement* floatTransparencyNode = doc->NewElement("float");
- transparencyNode->LinkEndChild(floatTransparencyNode);
- floatTransparencyNode->SetAttribute("sid", "transparency");
-
- tinyxml2::XMLText* floatTransparencyText = doc->NewText("0.0");
- floatTransparencyNode->LinkEndChild(floatTransparencyText);
-
- // ---------------------------
- tinyxml2::XMLElement* refractionNode = doc->NewElement("index_of_refraction");
- blinnNode->LinkEndChild(refractionNode);
- tinyxml2::XMLElement* colorRefractionNode = doc->NewElement("float");
- refractionNode->LinkEndChild(colorRefractionNode);
- colorRefractionNode->SetAttribute("sid", "index_of_refraction");
-
- tinyxml2::XMLText* colorRefractionNodeText = doc->NewText("1");
- colorRefractionNode->LinkEndChild(colorRefractionNodeText);
- }
- // Finally the material library
- tinyxml2::XMLElement* matLibNode = doc->NewElement("library_materials");
- rootNode->LinkEndChild(matLibNode);
- for (U32 i = 0; i < mesh.mMaterialList.size(); i++)
- {
- BaseMatInstance* baseInst = mesh.mMaterialList[i];
- Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
- if (!mat)
- continue;
- tinyxml2::XMLElement* materialNode = doc->NewElement("material");
- matLibNode->LinkEndChild(materialNode);
- materialNode->SetAttribute("id", avar("%s-material", matNames[i].c_str()));
- materialNode->SetAttribute("name", matNames[i].c_str());
- tinyxml2::XMLElement* instEffectNode = doc->NewElement("instance_effect");
- materialNode->LinkEndChild(instEffectNode);
- instEffectNode->SetAttribute("url", avar("#%s-effect", matNames[i].c_str()));
- }
-
- }
- void ColladaUtils::exportColladaMaterials(tinyxml2::XMLElement* rootNode, const ExportData& exportData, const Torque::Path& colladaFile)
- {
- tinyxml2::XMLDocument* doc = rootNode->GetDocument();
- // First the image library
- tinyxml2::XMLElement* imgLibNode = doc->NewElement("library_images");
- rootNode->LinkEndChild(imgLibNode);
- Vector<String> matNames;
- for (U32 i = 0; i < exportData.materials.size(); i++)
- {
- BaseMatInstance* baseInst = exportData.materials[i];
- matNames.push_back(String::ToString("Material%d", i));
- Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
- if (!mat)
- continue;
- String diffuseMap;
- if (mat->getName() && mat->getName()[0])
- matNames.last() = mat->mMapTo;
- // Handle an auto-generated "Default Material" specially
- if (mat->isAutoGenerated())
- {
- Torque::Path diffusePath;
- if (mat->mDiffuseMapName[0] != StringTable->EmptyString())
- diffusePath = Torque::Path(mat->mDiffuseMapName[0]);
- else
- diffusePath = String("warningMat");
- matNames.last() = diffusePath.getFileName();
- diffuseMap += diffusePath.getFullFileName();
- }
- else
- {
- if (mat->mDiffuseMapName[0] != StringTable->EmptyString())
- diffuseMap += Torque::Path(mat->mDiffuseMapName[0]);
- else
- diffuseMap += "warningMat";
- }
- Torque::Path diffusePath = findTexture(colladaFile.getPath() + "/" + diffuseMap);
- // If we didn't get a path
- if (diffusePath.getFullPath().isNotEmpty())
- diffuseMap = Torque::Path::MakeRelativePath(diffusePath, colladaFile);
- tinyxml2::XMLElement* imageNode = doc->NewElement("image");
- imgLibNode->LinkEndChild(imageNode);
- imageNode->SetAttribute("id", avar("%s", matNames.last().c_str()));
- imageNode->SetAttribute("name", avar("%s", matNames.last().c_str()));
- tinyxml2::XMLElement* initNode = doc->NewElement("init_from");
- imageNode->LinkEndChild(initNode);
- tinyxml2::XMLText* initText = doc->NewText(avar("file://%s", diffuseMap.c_str())); // "the file://" is needed to load the texture in some old apps (ex: 3ds Max 2009)
- initNode->LinkEndChild(initText);
- }
- // Next the effects library
- tinyxml2::XMLElement* effectLibNode = doc->NewElement("library_effects");
- rootNode->LinkEndChild(effectLibNode);
- for (U32 i = 0; i < exportData.materials.size(); i++)
- {
- BaseMatInstance* baseInst = exportData.materials[i];
- Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
- if (!mat)
- continue;
- tinyxml2::XMLElement* effectNode = doc->NewElement("effect");
- effectLibNode->LinkEndChild(effectNode);
- effectNode->SetAttribute("id", avar("%s-effect", matNames[i].c_str()));
- effectNode->SetAttribute("name", avar("%s-effect", matNames[i].c_str()));
- tinyxml2::XMLElement* profileNode = doc->NewElement("profile_COMMON");
- effectNode->LinkEndChild(profileNode);
- // ---------------------------
- tinyxml2::XMLElement* newParamNode = doc->NewElement("newparam");
- profileNode->LinkEndChild(newParamNode);
- newParamNode->SetAttribute("sid", avar("%s-surface", matNames[i].c_str()));
- tinyxml2::XMLElement* surfaceNode = doc->NewElement("surface");
- newParamNode->LinkEndChild(surfaceNode);
- surfaceNode->SetAttribute("type", "2D");
- tinyxml2::XMLElement* initNode2 = doc->NewElement("init_from");
- surfaceNode->LinkEndChild(initNode2);
- tinyxml2::XMLText* init2Text = doc->NewText(avar("%s", matNames[i].c_str()));
- initNode2->LinkEndChild(init2Text);
- tinyxml2::XMLElement* formatNode = doc->NewElement("format");
- surfaceNode->LinkEndChild(formatNode);
- tinyxml2::XMLText* formatText = doc->NewText("A8R8G8B8");
- formatNode->LinkEndChild(formatText);
- // ---------------------------
- tinyxml2::XMLElement* newParam2Node = doc->NewElement("newparam");
- profileNode->LinkEndChild(newParam2Node);
- newParam2Node->SetAttribute("sid", avar("%s-sampler", matNames[i].c_str()));
- tinyxml2::XMLElement* sampler2DNode = doc->NewElement("sampler2D");
- newParam2Node->LinkEndChild(sampler2DNode);
- tinyxml2::XMLElement* sourceSampler2DNode = doc->NewElement("source");
- sampler2DNode->LinkEndChild(sourceSampler2DNode);
- tinyxml2::XMLText* sourceSampler2DText = doc->NewText(avar("%s-surface", matNames[i].c_str()));
- sourceSampler2DNode->LinkEndChild(sourceSampler2DText);
- // ---------------------------
- tinyxml2::XMLElement* techniqueNode = doc->NewElement("technique");
- profileNode->LinkEndChild(techniqueNode);
- techniqueNode->SetAttribute("sid", "common");
- tinyxml2::XMLElement* blinnNode = doc->NewElement("blinn");
- techniqueNode->LinkEndChild(blinnNode);
- // ---------------------------
- tinyxml2::XMLElement* emissionNode = doc->NewElement("emission");
- blinnNode->LinkEndChild(emissionNode);
- tinyxml2::XMLElement* colorEmissionNode = doc->NewElement("color");
- emissionNode->LinkEndChild(colorEmissionNode);
- colorEmissionNode->SetAttribute("sid", "emission");
- tinyxml2::XMLText* colorEmissionNodeText = doc->NewText("0.0 0.0 0.0 1.0");
- colorEmissionNode->LinkEndChild(colorEmissionNodeText);
- // ---------------------------
- tinyxml2::XMLElement* ambientNode = doc->NewElement("ambient");
- blinnNode->LinkEndChild(ambientNode);
- tinyxml2::XMLElement* colorAmbientNode = doc->NewElement("color");
- ambientNode->LinkEndChild(colorAmbientNode);
- colorAmbientNode->SetAttribute("sid", "ambient");
- tinyxml2::XMLText* colorAmbientNodeText = doc->NewText("0.0 0.0 0.0 1.0");
- colorAmbientNode->LinkEndChild(colorAmbientNodeText);
- // ---------------------------
- tinyxml2::XMLElement* diffuseNode = doc->NewElement("diffuse");
- blinnNode->LinkEndChild(diffuseNode);
- tinyxml2::XMLElement* textureDiffuseNode = doc->NewElement("texture");
- diffuseNode->LinkEndChild(textureDiffuseNode);
- textureDiffuseNode->SetAttribute("texture", avar("%s-sampler", matNames[i].c_str()));
- textureDiffuseNode->SetAttribute("texcoord", "UVMap");
- // Extra info useful for getting the texture to show up correctly in MAYA and 3DS Max
- tinyxml2::XMLElement* extraNode = doc->NewElement("extra");
- textureDiffuseNode->LinkEndChild(extraNode);
- tinyxml2::XMLElement* extraTechNode = doc->NewElement("technique");
- extraNode->LinkEndChild(extraTechNode);
- extraTechNode->SetAttribute("profile", "MAYA");
- tinyxml2::XMLElement* extraWrapUNode = doc->NewElement("wrapU");
- extraTechNode->LinkEndChild(extraWrapUNode);
- extraWrapUNode->SetAttribute("sid", "wrapU0");
- tinyxml2::XMLText* extraWrapUText = doc->NewText("TRUE");
- extraWrapUNode->LinkEndChild(extraWrapUText);
- tinyxml2::XMLElement* extraWrapVNode = doc->NewElement("wrapV");
- extraTechNode->LinkEndChild(extraWrapVNode);
- extraWrapVNode->SetAttribute("sid", "wrapV0");
- tinyxml2::XMLText* extraWrapVText = doc->NewText("TRUE");
- extraWrapVNode->LinkEndChild(extraWrapVText);
- tinyxml2::XMLElement* extraBlendNode = doc->NewElement("blend_mode");
- extraTechNode->LinkEndChild(extraBlendNode);
- tinyxml2::XMLText* extraBlendText = doc->NewText("ADD");
- extraBlendNode->LinkEndChild(extraBlendText);
- // ---------------------------
- tinyxml2::XMLElement* specularNode = doc->NewElement("specular");
- blinnNode->LinkEndChild(specularNode);
- tinyxml2::XMLElement* colorSpecularNode = doc->NewElement("color");
- specularNode->LinkEndChild(colorSpecularNode);
- colorSpecularNode->SetAttribute("sid", "specular");
- tinyxml2::XMLText* colorSpecularNodeText = doc->NewText("0.5 0.5 0.5 1.0");
- colorSpecularNode->LinkEndChild(colorSpecularNodeText);
- // ---------------------------
- tinyxml2::XMLElement* shininessNode = doc->NewElement("shininess");
- blinnNode->LinkEndChild(shininessNode);
- tinyxml2::XMLElement* colorShininessNode = doc->NewElement("float");
- shininessNode->LinkEndChild(colorShininessNode);
- colorShininessNode->SetAttribute("sid", "shininess");
- tinyxml2::XMLText* colorShininessNodeText = doc->NewText("1.0");
- colorShininessNode->LinkEndChild(colorShininessNodeText);
- // ---------------------------
- tinyxml2::XMLElement* reflectiveNode = doc->NewElement("reflective");
- blinnNode->LinkEndChild(reflectiveNode);
- tinyxml2::XMLElement* colorReflectiveNode = doc->NewElement("color");
- reflectiveNode->LinkEndChild(colorReflectiveNode);
- colorReflectiveNode->SetAttribute("sid", "reflective");
- tinyxml2::XMLText* colorReflectiveNodeText = doc->NewText("0.0 0.0 0.0 1.0");
- colorReflectiveNode->LinkEndChild(colorReflectiveNodeText);
- // ---------------------------
- tinyxml2::XMLElement* reflectivityNode = doc->NewElement("reflectivity");
- blinnNode->LinkEndChild(reflectivityNode);
- tinyxml2::XMLElement* floatReflectivityNode = doc->NewElement("float");
- reflectivityNode->LinkEndChild(floatReflectivityNode);
- floatReflectivityNode->SetAttribute("sid", "reflectivity");
- tinyxml2::XMLText* floatReflectivityText = doc->NewText("0.5");
- floatReflectivityNode->LinkEndChild(floatReflectivityText);
- // ---------------------------
- tinyxml2::XMLElement* transparentNode = doc->NewElement("transparent");
- blinnNode->LinkEndChild(transparentNode);
- transparentNode->SetAttribute("opaque", "RGB_ZERO");
- tinyxml2::XMLElement* colorTransparentNode = doc->NewElement("color");
- transparentNode->LinkEndChild(colorTransparentNode);
- colorTransparentNode->SetAttribute("sid", "transparent");
- tinyxml2::XMLText* colorTransparentNodeText = doc->NewText("0.0 0.0 0.0 1.0");
- colorTransparentNode->LinkEndChild(colorTransparentNodeText);
- // ---------------------------
- tinyxml2::XMLElement* transparencyNode = doc->NewElement("transparency");
- blinnNode->LinkEndChild(transparencyNode);
- tinyxml2::XMLElement* floatTransparencyNode = doc->NewElement("float");
- transparencyNode->LinkEndChild(floatTransparencyNode);
- floatTransparencyNode->SetAttribute("sid", "transparency");
- tinyxml2::XMLText* floatTransparencyText = doc->NewText("0.0");
- floatTransparencyNode->LinkEndChild(floatTransparencyText);
- // ---------------------------
- tinyxml2::XMLElement* refractionNode = doc->NewElement("index_of_refraction");
- blinnNode->LinkEndChild(refractionNode);
- tinyxml2::XMLElement* colorRefractionNode = doc->NewElement("float");
- refractionNode->LinkEndChild(colorRefractionNode);
- colorRefractionNode->SetAttribute("sid", "index_of_refraction");
- tinyxml2::XMLText* colorRefractionNodeText = doc->NewText("1");
- colorRefractionNode->LinkEndChild(colorRefractionNodeText);
- }
- // Finally the material library
- tinyxml2::XMLElement* matLibNode = doc->NewElement("library_materials");
- rootNode->LinkEndChild(matLibNode);
- for (U32 i = 0; i < exportData.materials.size(); i++)
- {
- BaseMatInstance* baseInst = exportData.materials[i];
- Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
- if (!mat)
- continue;
- tinyxml2::XMLElement* materialNode = doc->NewElement("material");
- matLibNode->LinkEndChild(materialNode);
- materialNode->SetAttribute("id", avar("%s-material", matNames[i].c_str()));
- materialNode->SetAttribute("name", matNames[i].c_str());
- tinyxml2::XMLElement* instEffectNode = doc->NewElement("instance_effect");
- materialNode->LinkEndChild(instEffectNode);
- instEffectNode->SetAttribute("url", avar("#%s-effect", matNames[i].c_str()));
- }
- }
- void ColladaUtils::exportColladaTriangles(tinyxml2::XMLElement* meshNode, const OptimizedPolyList& mesh, const String& meshName, const Vector<String>& matNames)
- {
- tinyxml2::XMLDocument* doc = meshNode->GetDocument();
- // Start at -1 so we will export polygons that do not have a material.
- for (S32 i = -1; i < matNames.size(); i++)
- {
- // Calculate the number of triangles that uses this Material
- U32 triangleCount = 0;
- for (U32 j = 0; j < mesh.mPolyList.size(); j++)
- {
- const OptimizedPolyList::Poly& poly = mesh.mPolyList[j];
- if (poly.material != i)
- continue;
- if (poly.vertexCount < 3)
- continue;
- if (poly.type == OptimizedPolyList::TriangleList ||
- poly.type == OptimizedPolyList::TriangleFan ||
- poly.type == OptimizedPolyList::TriangleStrip)
- {
- triangleCount += poly.vertexCount - 2;
- }
- else
- AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
- }
- // Make sure that we are actually using this Material
- if (triangleCount == 0)
- continue;
- tinyxml2::XMLElement* trianglesNode = doc->NewElement("triangles");
- meshNode->LinkEndChild(trianglesNode);
- trianglesNode->SetAttribute("material", ( i > -1 ) ? avar("%s-material", matNames[i].c_str()) : "" );
- trianglesNode->SetAttribute("count", avar("%d", triangleCount));
- tinyxml2::XMLElement* trianglesVertInputNode = doc->NewElement("input");
- trianglesNode->LinkEndChild(trianglesVertInputNode);
- trianglesVertInputNode->SetAttribute("semantic", "VERTEX");
- trianglesVertInputNode->SetAttribute("source", avar("#%s-mesh-vertices", meshName.c_str()));
- trianglesVertInputNode->SetAttribute("offset", "0");
- tinyxml2::XMLElement* trianglesNormalInputNode = doc->NewElement("input");
- trianglesNode->LinkEndChild(trianglesNormalInputNode);
- trianglesNormalInputNode->SetAttribute("semantic", "NORMAL");
- trianglesNormalInputNode->SetAttribute("source", avar("#%s-mesh-normals", meshName.c_str()));
- trianglesNormalInputNode->SetAttribute("offset", "1");
- tinyxml2::XMLElement* trianglesUV0InputNode = doc->NewElement("input");
- trianglesNode->LinkEndChild(trianglesUV0InputNode);
- trianglesUV0InputNode->SetAttribute("semantic", "TEXCOORD");
- trianglesUV0InputNode->SetAttribute("source", avar("#%s-mesh-map-0", meshName.c_str()));
- trianglesUV0InputNode->SetAttribute("offset", "2");
- trianglesUV0InputNode->SetAttribute("set", "0");
- tinyxml2::XMLElement* polyNode = doc->NewElement("p");
- trianglesNode->LinkEndChild(polyNode);
- Vector<U32> tempIndices;
- tempIndices.reserve(4);
- for (U32 j = 0; j < mesh.mPolyList.size(); j++)
- {
- const OptimizedPolyList::Poly& poly = mesh.mPolyList[j];
- if (poly.vertexCount < 3)
- continue;
- if (poly.material != i)
- continue;
- tempIndices.setSize(poly.vertexCount);
- dMemset(tempIndices.address(), 0, poly.vertexCount);
- if (poly.type == OptimizedPolyList::TriangleStrip)
- {
- tempIndices[0] = 0;
- U32 idx = 1;
-
- for (U32 k = 1; k < poly.vertexCount; k += 2)
- tempIndices[idx++] = k;
- for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2)
- tempIndices[idx++] = k;
- }
- else if (poly.type == OptimizedPolyList::TriangleList ||
- poly.type == OptimizedPolyList::TriangleFan)
- {
- for (U32 k = 0; k < poly.vertexCount; k++)
- tempIndices[k] = k;
- }
- else
- AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
- const U32& firstIdx = mesh.mIndexList[poly.vertexStart];
- const OptimizedPolyList::VertIndex& firstVertIdx = mesh.mVertexList[firstIdx];
- for (U32 k = 1; k < poly.vertexCount - 1; k++)
- {
- const U32& secondIdx = mesh.mIndexList[poly.vertexStart + tempIndices[k]];
- const U32& thirdIdx = mesh.mIndexList[poly.vertexStart + tempIndices[k + 1]];
- const OptimizedPolyList::VertIndex& secondVertIdx = mesh.mVertexList[secondIdx];
- const OptimizedPolyList::VertIndex& thirdVertIdx = mesh.mVertexList[thirdIdx];
- // Note the reversed winding on the triangles
- const char* tri = avar("%d %d %d %d %d %d %d %d %d ",
- thirdVertIdx.vertIdx, thirdVertIdx.normalIdx, thirdVertIdx.uv0Idx,
- secondVertIdx.vertIdx, secondVertIdx.normalIdx, secondVertIdx.uv0Idx,
- firstVertIdx.vertIdx, firstVertIdx.normalIdx, firstVertIdx.uv0Idx);
- tinyxml2::XMLText* triangleText = doc->NewText(tri);
- polyNode->LinkEndChild(triangleText);
- }
- }
- }
- }
- void ColladaUtils::exportColladaTriangles(tinyxml2::XMLElement* meshNode, const ExportData& exportData, const U32 detailLevel, const String& meshName)
- {
- tinyxml2::XMLDocument* doc = meshNode->GetDocument();
- // Calculate the number of triangles that uses this Material
- U32 triangleCount = 0;
- const ExportData::detailLevel* dl = &exportData.detailLevels[detailLevel];
- for (S32 i = 0; i < dl->materialRefList.size(); i++)
- {
- int matIdx;
- dl->materialRefList.tryGetValue(i, matIdx);
- BaseMatInstance* baseInst = exportData.materials[matIdx];
- Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
- if (!mat)
- continue;
- String matName;
- if (mat->getName() && mat->getName()[0])
- matName = mat->mMapTo;
- for (U32 j = 0; j < dl->mesh.mPolyList.size(); j++)
- {
- const OptimizedPolyList::Poly& poly = dl->mesh.mPolyList[j];
- if (poly.material != i)
- continue;
- if (poly.vertexCount < 3)
- continue;
- if (poly.type == OptimizedPolyList::TriangleList ||
- poly.type == OptimizedPolyList::TriangleFan ||
- poly.type == OptimizedPolyList::TriangleStrip)
- {
- triangleCount += poly.vertexCount - 2;
- }
- else
- AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
- }
- // Make sure that we are actually using this Material
- if (triangleCount == 0)
- continue;
- tinyxml2::XMLElement* trianglesNode = doc->NewElement("triangles");
- meshNode->LinkEndChild(trianglesNode);
- trianglesNode->SetAttribute("material", (i > -1) ? avar("%s-material", matName.c_str()) : "");
- trianglesNode->SetAttribute("count", avar("%d", triangleCount));
- tinyxml2::XMLElement* trianglesVertInputNode = doc->NewElement("input");
- trianglesNode->LinkEndChild(trianglesVertInputNode);
- trianglesVertInputNode->SetAttribute("semantic", "VERTEX");
- trianglesVertInputNode->SetAttribute("source", avar("#%s-mesh-vertices", meshName.c_str()));
- trianglesVertInputNode->SetAttribute("offset", "0");
- tinyxml2::XMLElement* trianglesNormalInputNode = doc->NewElement("input");
- trianglesNode->LinkEndChild(trianglesNormalInputNode);
- trianglesNormalInputNode->SetAttribute("semantic", "NORMAL");
- trianglesNormalInputNode->SetAttribute("source", avar("#%s-mesh-normals", meshName.c_str()));
- trianglesNormalInputNode->SetAttribute("offset", "1");
- tinyxml2::XMLElement* trianglesUV0InputNode = doc->NewElement("input");
- trianglesNode->LinkEndChild(trianglesUV0InputNode);
- trianglesUV0InputNode->SetAttribute("semantic", "TEXCOORD");
- trianglesUV0InputNode->SetAttribute("source", avar("#%s-mesh-map-0", meshName.c_str()));
- trianglesUV0InputNode->SetAttribute("offset", "2");
- trianglesUV0InputNode->SetAttribute("set", "0");
- tinyxml2::XMLElement* polyNode = doc->NewElement("p");
- trianglesNode->LinkEndChild(polyNode);
- Vector<U32> tempIndices;
- tempIndices.reserve(4);
- for (U32 j = 0; j < dl->mesh.mPolyList.size(); j++)
- {
- const OptimizedPolyList::Poly& poly = dl->mesh.mPolyList[j];
- if (poly.vertexCount < 3)
- continue;
- if (poly.material != i)
- continue;
- tempIndices.setSize(poly.vertexCount);
- dMemset(tempIndices.address(), 0, poly.vertexCount);
- if (poly.type == OptimizedPolyList::TriangleStrip)
- {
- tempIndices[0] = 0;
- U32 idx = 1;
- for (U32 k = 1; k < poly.vertexCount; k += 2)
- tempIndices[idx++] = k;
- for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2)
- tempIndices[idx++] = k;
- }
- else if (poly.type == OptimizedPolyList::TriangleList ||
- poly.type == OptimizedPolyList::TriangleFan)
- {
- for (U32 k = 0; k < poly.vertexCount; k++)
- tempIndices[k] = k;
- }
- else
- AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
- const U32& firstIdx = dl->mesh.mIndexList[poly.vertexStart];
- const OptimizedPolyList::VertIndex& firstVertIdx = dl->mesh.mVertexList[firstIdx];
- for (U32 k = 1; k < poly.vertexCount - 1; k++)
- {
- const U32& secondIdx = dl->mesh.mIndexList[poly.vertexStart + tempIndices[k]];
- const U32& thirdIdx = dl->mesh.mIndexList[poly.vertexStart + tempIndices[k + 1]];
- const OptimizedPolyList::VertIndex& secondVertIdx = dl->mesh.mVertexList[secondIdx];
- const OptimizedPolyList::VertIndex& thirdVertIdx = dl->mesh.mVertexList[thirdIdx];
- // Note the reversed winding on the triangles
- const char* tri = avar("%d %d %d %d %d %d %d %d %d ",
- thirdVertIdx.vertIdx, thirdVertIdx.normalIdx, thirdVertIdx.uv0Idx,
- secondVertIdx.vertIdx, secondVertIdx.normalIdx, secondVertIdx.uv0Idx,
- firstVertIdx.vertIdx, firstVertIdx.normalIdx, firstVertIdx.uv0Idx);
- tinyxml2::XMLText* triangleText = doc->NewText(tri);
- polyNode->LinkEndChild(triangleText);
- }
- }
- }
- }
- void ColladaUtils::exportColladaCollisionTriangles(tinyxml2::XMLElement* meshNode, const ExportData& exportData, const U32 collisionIdx)
- {
- tinyxml2::XMLDocument* doc = meshNode->GetDocument();
- // Calculate the number of triangles that uses this Material
- U32 triangleCount = 0;
- const ExportData::colMesh* col = &exportData.colMeshes[collisionIdx];
- String meshName = col->colMeshName;
- for (U32 j = 0; j < col->mesh.mPolyList.size(); j++)
- {
- const OptimizedPolyList::Poly& poly = col->mesh.mPolyList[j];
- if (poly.vertexCount < 3)
- continue;
- if (poly.type == OptimizedPolyList::TriangleList ||
- poly.type == OptimizedPolyList::TriangleFan ||
- poly.type == OptimizedPolyList::TriangleStrip)
- {
- triangleCount += poly.vertexCount - 2;
- }
- else
- AssertISV(false, "ColladaUtils::exportColladaCollisionTriangles(): Unknown Poly type!");
- }
- // Make sure that we are actually using this Material
- if (triangleCount == 0)
- return;
- tinyxml2::XMLElement* trianglesNode = doc->NewElement("triangles");
- meshNode->LinkEndChild(trianglesNode);
- trianglesNode->SetAttribute("material", "");
- trianglesNode->SetAttribute("count", avar("%d", triangleCount));
- tinyxml2::XMLElement* trianglesVertInputNode = doc->NewElement("input");
- trianglesNode->LinkEndChild(trianglesVertInputNode);
- trianglesVertInputNode->SetAttribute("semantic", "VERTEX");
- trianglesVertInputNode->SetAttribute("source", avar("#%s-mesh-vertices", meshName.c_str()));
- trianglesVertInputNode->SetAttribute("offset", "0");
- tinyxml2::XMLElement* trianglesNormalInputNode = doc->NewElement("input");
- trianglesNode->LinkEndChild(trianglesNormalInputNode);
- trianglesNormalInputNode->SetAttribute("semantic", "NORMAL");
- trianglesNormalInputNode->SetAttribute("source", avar("#%s-mesh-normals", meshName.c_str()));
- trianglesNormalInputNode->SetAttribute("offset", "1");
- tinyxml2::XMLElement* trianglesUV0InputNode = doc->NewElement("input");
- trianglesNode->LinkEndChild(trianglesUV0InputNode);
- trianglesUV0InputNode->SetAttribute("semantic", "TEXCOORD");
- trianglesUV0InputNode->SetAttribute("source", avar("#%s-mesh-map-0", meshName.c_str()));
- trianglesUV0InputNode->SetAttribute("offset", "2");
- trianglesUV0InputNode->SetAttribute("set", "0");
- tinyxml2::XMLElement* polyNode = doc->NewElement("p");
- trianglesNode->LinkEndChild(polyNode);
- Vector<U32> tempIndices;
- tempIndices.reserve(4);
- for (U32 j = 0; j < col->mesh.mPolyList.size(); j++)
- {
- const OptimizedPolyList::Poly& poly = col->mesh.mPolyList[j];
- if (poly.vertexCount < 3)
- continue;
- tempIndices.setSize(poly.vertexCount);
- dMemset(tempIndices.address(), 0, poly.vertexCount);
- if (poly.type == OptimizedPolyList::TriangleStrip)
- {
- tempIndices[0] = 0;
- U32 idx = 1;
- for (U32 k = 1; k < poly.vertexCount; k += 2)
- tempIndices[idx++] = k;
- for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2)
- tempIndices[idx++] = k;
- }
- else if (poly.type == OptimizedPolyList::TriangleList ||
- poly.type == OptimizedPolyList::TriangleFan)
- {
- for (U32 k = 0; k < poly.vertexCount; k++)
- tempIndices[k] = k;
- }
- else
- AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
- const U32& firstIdx = col->mesh.mIndexList[poly.vertexStart];
- const OptimizedPolyList::VertIndex& firstVertIdx = col->mesh.mVertexList[firstIdx];
- for (U32 k = 1; k < poly.vertexCount - 1; k++)
- {
- const U32& secondIdx = col->mesh.mIndexList[poly.vertexStart + tempIndices[k]];
- const U32& thirdIdx = col->mesh.mIndexList[poly.vertexStart + tempIndices[k + 1]];
- const OptimizedPolyList::VertIndex& secondVertIdx = col->mesh.mVertexList[secondIdx];
- const OptimizedPolyList::VertIndex& thirdVertIdx = col->mesh.mVertexList[thirdIdx];
- // Note the reversed winding on the triangles
- const char* tri = avar("%d %d %d %d %d %d %d %d %d ",
- thirdVertIdx.vertIdx, thirdVertIdx.normalIdx, thirdVertIdx.uv0Idx,
- secondVertIdx.vertIdx, secondVertIdx.normalIdx, secondVertIdx.uv0Idx,
- firstVertIdx.vertIdx, firstVertIdx.normalIdx, firstVertIdx.uv0Idx);
- tinyxml2::XMLText* triangleText = doc->NewText(tri);
- polyNode->LinkEndChild(triangleText);
- }
- }
- }
- void ColladaUtils::exportColladaMesh(tinyxml2::XMLElement* rootNode, const OptimizedPolyList& mesh, const String& meshName, const Vector<String>& matNames)
- {
- tinyxml2::XMLDocument* doc = rootNode->GetDocument();
- tinyxml2::XMLElement* libGeomsNode = doc->NewElement("library_geometries");
- rootNode->LinkEndChild(libGeomsNode);
- tinyxml2::XMLElement* geometryNode = doc->NewElement("geometry");
- libGeomsNode->LinkEndChild(geometryNode);
- geometryNode->SetAttribute("id", avar("%s-mesh", meshName.c_str()));
- geometryNode->SetAttribute("name", avar("%s", meshName.c_str()));
- tinyxml2::XMLElement* meshNode = doc->NewElement("mesh");
- geometryNode->LinkEndChild(meshNode);
- // Save out the vertices
- tinyxml2::XMLElement* vertsSourceNode = doc->NewElement("source");
- meshNode->LinkEndChild(vertsSourceNode);
- vertsSourceNode->SetAttribute("id", avar("%s-mesh-positions", meshName.c_str()));
- tinyxml2::XMLElement* vertsNode = doc->NewElement("float_array");
- vertsSourceNode->LinkEndChild(vertsNode);
- vertsNode->SetAttribute("id", avar("%s-mesh-positions-array", meshName.c_str()));
- vertsNode->SetAttribute("count", avar("%d", mesh.mPoints.size() * 3));
- for (U32 i = 0; i < mesh.mPoints.size(); i++)
- {
- const Point3F& vert = mesh.mPoints[i];
- tinyxml2::XMLText* vertText = doc->NewText(avar("%.4f %.4f %.4f ", vert.x, vert.y, vert.z));
- vertsNode->LinkEndChild(vertText);
- }
- // Save the vertex accessor
- tinyxml2::XMLElement* vertsTechNode = doc->NewElement("technique_common");
- vertsSourceNode->LinkEndChild(vertsTechNode);
- tinyxml2::XMLElement* vertsAccNode = doc->NewElement("accessor");
- vertsTechNode->LinkEndChild(vertsAccNode);
- vertsAccNode->SetAttribute("source", avar("#%s-mesh-positions-array", meshName.c_str()));
- vertsAccNode->SetAttribute("count", avar("%d", mesh.mPoints.size()));
- vertsAccNode->SetAttribute("stride", "3");
- tinyxml2::XMLElement* vertsAccXNode = doc->NewElement("param");
- vertsAccNode->LinkEndChild(vertsAccXNode);
- vertsAccXNode->SetAttribute("name", "X");
- vertsAccXNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* vertsAccYNode = doc->NewElement("param");
- vertsAccNode->LinkEndChild(vertsAccYNode);
- vertsAccYNode->SetAttribute("name", "Y");
- vertsAccYNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* vertsAccZNode = doc->NewElement("param");
- vertsAccNode->LinkEndChild(vertsAccZNode);
- vertsAccZNode->SetAttribute("name", "Z");
- vertsAccZNode->SetAttribute("type", "float");
- // Save out the normals
- tinyxml2::XMLElement* normalsSourceNode = doc->NewElement("source");
- meshNode->LinkEndChild(normalsSourceNode);
- normalsSourceNode->SetAttribute("id", avar("%s-mesh-normals", meshName.c_str()));
- tinyxml2::XMLElement* normalsNode = doc->NewElement("float_array");
- normalsSourceNode->LinkEndChild(normalsNode);
- normalsNode->SetAttribute("id", avar("%s-mesh-normals-array", meshName.c_str()));
- normalsNode->SetAttribute("count", avar("%d", mesh.mNormals.size() * 3));
- for (U32 i = 0; i < mesh.mNormals.size(); i++)
- {
- const Point3F& normal = mesh.mNormals[i];
- tinyxml2::XMLText* normalText = doc->NewText(avar("%.4f %.4f %.4f ", normal.x, normal.y, normal.z));
- normalsNode->LinkEndChild(normalText);
- }
- // Save the normals accessor
- tinyxml2::XMLElement* normalsTechNode = doc->NewElement("technique_common");
- normalsSourceNode->LinkEndChild(normalsTechNode);
- tinyxml2::XMLElement* normalsAccNode = doc->NewElement("accessor");
- normalsTechNode->LinkEndChild(normalsAccNode);
- normalsAccNode->SetAttribute("source", avar("#%s-mesh-normals-array", meshName.c_str()));
- normalsAccNode->SetAttribute("count", avar("%d", mesh.mNormals.size()));
- normalsAccNode->SetAttribute("stride", "3");
- tinyxml2::XMLElement* normalsAccXNode = doc->NewElement("param");
- normalsAccNode->LinkEndChild(normalsAccXNode);
- normalsAccXNode->SetAttribute("name", "X");
- normalsAccXNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* normalsAccYNode = doc->NewElement("param");
- normalsAccNode->LinkEndChild(normalsAccYNode);
- normalsAccYNode->SetAttribute("name", "Y");
- normalsAccYNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* normalsAccZNode = doc->NewElement("param");
- normalsAccNode->LinkEndChild(normalsAccZNode);
- normalsAccZNode->SetAttribute("name", "Z");
- normalsAccZNode->SetAttribute("type", "float");
- // Save out the uvs
- tinyxml2::XMLElement* uv0SourceNode = doc->NewElement("source");
- meshNode->LinkEndChild(uv0SourceNode);
- uv0SourceNode->SetAttribute("id", avar("%s-mesh-map-0", meshName.c_str()));
- tinyxml2::XMLElement* uv0Node = doc->NewElement("float_array");
- uv0SourceNode->LinkEndChild(uv0Node);
- uv0Node->SetAttribute("id", avar("%s-mesh-map-0-array", meshName.c_str()));
- uv0Node->SetAttribute("count", avar("%d", mesh.mUV0s.size() * 2));
- for (U32 i = 0; i < mesh.mUV0s.size(); i++)
- {
- const Point2F& uv0 = mesh.mUV0s[i];
- tinyxml2::XMLText* uv0Text = doc->NewText(avar("%.4f %.4f ", uv0.x, 1.0f - uv0.y)); // COLLADA uvs are upside down compared to Torque
- uv0Node->LinkEndChild(uv0Text);
- }
- // Save the uv0 accessor
- tinyxml2::XMLElement* uv0TechNode = doc->NewElement("technique_common");
- uv0SourceNode->LinkEndChild(uv0TechNode);
- tinyxml2::XMLElement* uv0AccNode = doc->NewElement("accessor");
- uv0TechNode->LinkEndChild(uv0AccNode);
- uv0AccNode->SetAttribute("source", avar("#%s-mesh-map-0-array", meshName.c_str()));
- uv0AccNode->SetAttribute("count", avar("%d", mesh.mUV0s.size()));
- uv0AccNode->SetAttribute("stride", "2");
- tinyxml2::XMLElement* uv0AccSNode = doc->NewElement("param");
- uv0AccNode->LinkEndChild(uv0AccSNode);
- uv0AccSNode->SetAttribute("name", "S");
- uv0AccSNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* uv0AccTNode = doc->NewElement("param");
- uv0AccNode->LinkEndChild(uv0AccTNode);
- uv0AccTNode->SetAttribute("name", "T");
- uv0AccTNode->SetAttribute("type", "float");
- // Define the vertices position array
- tinyxml2::XMLElement* verticesNode = doc->NewElement("vertices");
- meshNode->LinkEndChild(verticesNode);
- verticesNode->SetAttribute("id", avar("%s-mesh-vertices", meshName.c_str()));
- tinyxml2::XMLElement* verticesInputNode = doc->NewElement("input");
- verticesNode->LinkEndChild(verticesInputNode);
- verticesInputNode->SetAttribute("semantic", "POSITION");
- verticesInputNode->SetAttribute("source", avar("#%s-mesh-positions", meshName.c_str()));
- exportColladaTriangles(meshNode, mesh, meshName, matNames);
-
- // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
- tinyxml2::XMLElement* extraGeoNode = doc->NewElement("extra");
- libGeomsNode->LinkEndChild(extraGeoNode);
- tinyxml2::XMLElement* extraGeoNodeTech = doc->NewElement("technique");
- extraGeoNode->LinkEndChild(extraGeoNodeTech);
- extraGeoNodeTech->SetAttribute("profile", "OpenCOLLADAMaya");
- tinyxml2::XMLElement* mayaNode2Id = doc->NewElement("originalMayaNodeId");
- extraGeoNodeTech->LinkEndChild(mayaNode2Id);
- mayaNode2Id->SetAttribute("sid", "originalMayaNodeId");
- tinyxml2::XMLText* mayaIdMesh = doc->NewText(avar("%s", meshName.c_str()));
- mayaNode2Id->LinkEndChild(mayaIdMesh);
- tinyxml2::XMLElement* doubleSidedId = doc->NewElement("double_sided");
- extraGeoNodeTech->LinkEndChild(doubleSidedId);
- doubleSidedId->SetAttribute("sid", "double_sided");
- tinyxml2::XMLText* doubleSideIdText = doc->NewText("1");
- doubleSidedId->LinkEndChild(doubleSideIdText);
-
- tinyxml2::XMLElement* paramExtraNode = doc->NewElement("param");
- extraGeoNodeTech->LinkEndChild(paramExtraNode);
- paramExtraNode->SetAttribute("sid", "colladaId");
- paramExtraNode->SetAttribute("type", "string");
- tinyxml2::XMLText* mayaParamMesh = doc->NewText(avar("%s-mesh", meshName.c_str()));
- paramExtraNode->LinkEndChild(mayaParamMesh);
-
- }
- void ColladaUtils::exportColladaMesh(tinyxml2::XMLElement* rootNode, const ExportData& exportData, const String& meshName)
- {
- tinyxml2::XMLDocument* doc = rootNode->GetDocument();
- tinyxml2::XMLElement* libGeomsNode = doc->NewElement("library_geometries");
- rootNode->LinkEndChild(libGeomsNode);
- for (U32 d = 0; d < exportData.detailLevels.size(); d++)
- {
- char lodMeshName[256];
- dSprintf(lodMeshName, 256, "%s%d", meshName.c_str(), exportData.detailLevels[d].size);
- char lodMeshID[256];
- dSprintf(lodMeshID, 256, "%s-mesh", lodMeshName);
- tinyxml2::XMLElement* geometryNode = doc->NewElement("geometry");
- libGeomsNode->LinkEndChild(geometryNode);
- geometryNode->SetAttribute("id", lodMeshID);
- geometryNode->SetAttribute("name", lodMeshName);
- tinyxml2::XMLElement* meshNode = doc->NewElement("mesh");
- geometryNode->LinkEndChild(meshNode);
- // Save out the vertices
- tinyxml2::XMLElement* vertsSourceNode = doc->NewElement("source");
- meshNode->LinkEndChild(vertsSourceNode);
- vertsSourceNode->SetAttribute("id", avar("%s-mesh-positions", lodMeshName));
- tinyxml2::XMLElement* vertsNode = doc->NewElement("float_array");
- vertsSourceNode->LinkEndChild(vertsNode);
- vertsNode->SetAttribute("id", avar("%s-mesh-positions-array", lodMeshName));
- vertsNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mPoints.size() * 3));
- for (U32 i = 0; i < exportData.detailLevels[d].mesh.mPoints.size(); i++)
- {
- const Point3F& vert = exportData.detailLevels[d].mesh.mPoints[i];
- tinyxml2::XMLText* vertText = doc->NewText(avar("%.4f %.4f %.4f ", vert.x, vert.y, vert.z));
- vertsNode->LinkEndChild(vertText);
- }
- // Save the vertex accessor
- tinyxml2::XMLElement* vertsTechNode = doc->NewElement("technique_common");
- vertsSourceNode->LinkEndChild(vertsTechNode);
- tinyxml2::XMLElement* vertsAccNode = doc->NewElement("accessor");
- vertsTechNode->LinkEndChild(vertsAccNode);
- vertsAccNode->SetAttribute("source", avar("#%s-mesh-positions-array", lodMeshName));
- vertsAccNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mPoints.size()));
- vertsAccNode->SetAttribute("stride", "3");
- tinyxml2::XMLElement* vertsAccXNode = doc->NewElement("param");
- vertsAccNode->LinkEndChild(vertsAccXNode);
- vertsAccXNode->SetAttribute("name", "X");
- vertsAccXNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* vertsAccYNode = doc->NewElement("param");
- vertsAccNode->LinkEndChild(vertsAccYNode);
- vertsAccYNode->SetAttribute("name", "Y");
- vertsAccYNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* vertsAccZNode = doc->NewElement("param");
- vertsAccNode->LinkEndChild(vertsAccZNode);
- vertsAccZNode->SetAttribute("name", "Z");
- vertsAccZNode->SetAttribute("type", "float");
- // Save out the normals
- tinyxml2::XMLElement* normalsSourceNode = doc->NewElement("source");
- meshNode->LinkEndChild(normalsSourceNode);
- normalsSourceNode->SetAttribute("id", avar("%s-mesh-normals", lodMeshName));
- tinyxml2::XMLElement* normalsNode = doc->NewElement("float_array");
- normalsSourceNode->LinkEndChild(normalsNode);
- normalsNode->SetAttribute("id", avar("%s-mesh-normals-array", lodMeshName));
- normalsNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mNormals.size() * 3));
- for (U32 i = 0; i < exportData.detailLevels[d].mesh.mNormals.size(); i++)
- {
- const Point3F& normal = exportData.detailLevels[d].mesh.mNormals[i];
- tinyxml2::XMLText* normalText = doc->NewText(avar("%.4f %.4f %.4f ", normal.x, normal.y, normal.z));
- normalsNode->LinkEndChild(normalText);
- }
- // Save the normals accessor
- tinyxml2::XMLElement* normalsTechNode = doc->NewElement("technique_common");
- normalsSourceNode->LinkEndChild(normalsTechNode);
- tinyxml2::XMLElement* normalsAccNode = doc->NewElement("accessor");
- normalsTechNode->LinkEndChild(normalsAccNode);
- normalsAccNode->SetAttribute("source", avar("#%s-mesh-normals-array", lodMeshName));
- normalsAccNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mNormals.size()));
- normalsAccNode->SetAttribute("stride", "3");
- tinyxml2::XMLElement* normalsAccXNode = doc->NewElement("param");
- normalsAccNode->LinkEndChild(normalsAccXNode);
- normalsAccXNode->SetAttribute("name", "X");
- normalsAccXNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* normalsAccYNode = doc->NewElement("param");
- normalsAccNode->LinkEndChild(normalsAccYNode);
- normalsAccYNode->SetAttribute("name", "Y");
- normalsAccYNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* normalsAccZNode = doc->NewElement("param");
- normalsAccNode->LinkEndChild(normalsAccZNode);
- normalsAccZNode->SetAttribute("name", "Z");
- normalsAccZNode->SetAttribute("type", "float");
- // Save out the uvs
- tinyxml2::XMLElement* uv0SourceNode = doc->NewElement("source");
- meshNode->LinkEndChild(uv0SourceNode);
- uv0SourceNode->SetAttribute("id", avar("%s-mesh-map-0", lodMeshName));
- tinyxml2::XMLElement* uv0Node = doc->NewElement("float_array");
- uv0SourceNode->LinkEndChild(uv0Node);
- uv0Node->SetAttribute("id", avar("%s-mesh-map-0-array", lodMeshName));
- uv0Node->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mUV0s.size() * 2));
- for (U32 i = 0; i < exportData.detailLevels[d].mesh.mUV0s.size(); i++)
- {
- const Point2F& uv0 = exportData.detailLevels[d].mesh.mUV0s[i];
- tinyxml2::XMLText* uv0Text = doc->NewText(avar("%.4f %.4f ", uv0.x, 1.0f - uv0.y)); // COLLADA uvs are upside down compared to Torque
- uv0Node->LinkEndChild(uv0Text);
- }
- // Save the uv0 accessor
- tinyxml2::XMLElement* uv0TechNode = doc->NewElement("technique_common");
- uv0SourceNode->LinkEndChild(uv0TechNode);
- tinyxml2::XMLElement* uv0AccNode = doc->NewElement("accessor");
- uv0TechNode->LinkEndChild(uv0AccNode);
- uv0AccNode->SetAttribute("source", avar("#%s-mesh-map-0-array", lodMeshName));
- uv0AccNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mUV0s.size()));
- uv0AccNode->SetAttribute("stride", "2");
- tinyxml2::XMLElement* uv0AccSNode = doc->NewElement("param");
- uv0AccNode->LinkEndChild(uv0AccSNode);
- uv0AccSNode->SetAttribute("name", "S");
- uv0AccSNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* uv0AccTNode = doc->NewElement("param");
- uv0AccNode->LinkEndChild(uv0AccTNode);
- uv0AccTNode->SetAttribute("name", "T");
- uv0AccTNode->SetAttribute("type", "float");
- // Define the vertices position array
- tinyxml2::XMLElement* verticesNode = doc->NewElement("vertices");
- meshNode->LinkEndChild(verticesNode);
- verticesNode->SetAttribute("id", avar("%s-mesh-vertices", lodMeshName));
- tinyxml2::XMLElement* verticesInputNode = doc->NewElement("input");
- verticesNode->LinkEndChild(verticesInputNode);
- verticesInputNode->SetAttribute("semantic", "POSITION");
- verticesInputNode->SetAttribute("source", avar("#%s-mesh-positions", lodMeshName));
- Vector<String> mapNames;
- //exportColladaTriangles(meshNode, exportData.detailLevels[d].mesh, lodMeshName, mapNames);
- exportColladaTriangles(meshNode, exportData, d, lodMeshName);
- // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
- tinyxml2::XMLElement* extraGeoNode = doc->NewElement("extra");
- libGeomsNode->LinkEndChild(extraGeoNode);
- tinyxml2::XMLElement* extraGeoNodeTech = doc->NewElement("technique");
- extraGeoNode->LinkEndChild(extraGeoNodeTech);
- extraGeoNodeTech->SetAttribute("profile", "OpenCOLLADAMaya");
- tinyxml2::XMLElement* mayaNode2Id = doc->NewElement("originalMayaNodeId");
- extraGeoNodeTech->LinkEndChild(mayaNode2Id);
- mayaNode2Id->SetAttribute("sid", "originalMayaNodeId");
- tinyxml2::XMLText* mayaIdMesh = doc->NewText(avar("%s", lodMeshName));
- mayaNode2Id->LinkEndChild(mayaIdMesh);
- tinyxml2::XMLElement* doubleSidedId = doc->NewElement("double_sided");
- extraGeoNodeTech->LinkEndChild(doubleSidedId);
- doubleSidedId->SetAttribute("sid", "double_sided");
- tinyxml2::XMLText* doubleSideIdText = doc->NewText("1");
- doubleSidedId->LinkEndChild(doubleSideIdText);
- tinyxml2::XMLElement* paramExtraNode = doc->NewElement("param");
- extraGeoNodeTech->LinkEndChild(paramExtraNode);
- paramExtraNode->SetAttribute("sid", "colladaId");
- paramExtraNode->SetAttribute("type", "string");
- tinyxml2::XMLText* mayaParamMesh = doc->NewText(avar("%s-mesh", lodMeshName));
- paramExtraNode->LinkEndChild(mayaParamMesh);
- }
- //And now collisions
- for (U32 d = 0; d < exportData.colMeshes.size(); d++)
- {
- const char* colMeshName = exportData.colMeshes[d].colMeshName;
- char colMeshId[256];
- dSprintf(colMeshId, 256, "%s-mesh", colMeshName);
- tinyxml2::XMLElement* geometryNode = doc->NewElement("geometry");
- libGeomsNode->LinkEndChild(geometryNode);
- geometryNode->SetAttribute("id", colMeshId);
- geometryNode->SetAttribute("name", colMeshName);
- tinyxml2::XMLElement* meshNode = doc->NewElement("mesh");
- geometryNode->LinkEndChild(meshNode);
- // Save out the vertices
- tinyxml2::XMLElement* vertsSourceNode = doc->NewElement("source");
- meshNode->LinkEndChild(vertsSourceNode);
- vertsSourceNode->SetAttribute("id", avar("%s-mesh-positions", colMeshName));
- tinyxml2::XMLElement* vertsNode = doc->NewElement("float_array");
- vertsSourceNode->LinkEndChild(vertsNode);
- vertsNode->SetAttribute("id", avar("%s-mesh-positions-array", colMeshName));
- vertsNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mPoints.size() * 3));
- for (U32 i = 0; i < exportData.colMeshes[d].mesh.mPoints.size(); i++)
- {
- const Point3F& vert = exportData.colMeshes[d].mesh.mPoints[i];
- tinyxml2::XMLText* vertText = doc->NewText(avar("%.4f %.4f %.4f ", vert.x, vert.y, vert.z));
- vertsNode->LinkEndChild(vertText);
- }
- // Save the vertex accessor
- tinyxml2::XMLElement* vertsTechNode = doc->NewElement("technique_common");
- vertsSourceNode->LinkEndChild(vertsTechNode);
- tinyxml2::XMLElement* vertsAccNode = doc->NewElement("accessor");
- vertsTechNode->LinkEndChild(vertsAccNode);
- vertsAccNode->SetAttribute("source", avar("#%s-mesh-positions-array", colMeshName));
- vertsAccNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mPoints.size()));
- vertsAccNode->SetAttribute("stride", "3");
- tinyxml2::XMLElement* vertsAccXNode = doc->NewElement("param");
- vertsAccNode->LinkEndChild(vertsAccXNode);
- vertsAccXNode->SetAttribute("name", "X");
- vertsAccXNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* vertsAccYNode = doc->NewElement("param");
- vertsAccNode->LinkEndChild(vertsAccYNode);
- vertsAccYNode->SetAttribute("name", "Y");
- vertsAccYNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* vertsAccZNode = doc->NewElement("param");
- vertsAccNode->LinkEndChild(vertsAccZNode);
- vertsAccZNode->SetAttribute("name", "Z");
- vertsAccZNode->SetAttribute("type", "float");
- // Save out the normals
- tinyxml2::XMLElement* normalsSourceNode = doc->NewElement("source");
- meshNode->LinkEndChild(normalsSourceNode);
- normalsSourceNode->SetAttribute("id", avar("%s-mesh-normals", colMeshName));
- tinyxml2::XMLElement* normalsNode = doc->NewElement("float_array");
- normalsSourceNode->LinkEndChild(normalsNode);
- normalsNode->SetAttribute("id", avar("%s-mesh-normals-array", colMeshName));
- normalsNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mNormals.size() * 3));
- for (U32 i = 0; i < exportData.colMeshes[d].mesh.mNormals.size(); i++)
- {
- const Point3F& normal = exportData.colMeshes[d].mesh.mNormals[i];
- tinyxml2::XMLText* normalText = doc->NewText(avar("%.4f %.4f %.4f ", normal.x, normal.y, normal.z));
- normalsNode->LinkEndChild(normalText);
- }
- // Save the normals accessor
- tinyxml2::XMLElement* normalsTechNode = doc->NewElement("technique_common");
- normalsSourceNode->LinkEndChild(normalsTechNode);
- tinyxml2::XMLElement* normalsAccNode = doc->NewElement("accessor");
- normalsTechNode->LinkEndChild(normalsAccNode);
- normalsAccNode->SetAttribute("source", avar("#%s-mesh-normals-array", colMeshName));
- normalsAccNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mNormals.size()));
- normalsAccNode->SetAttribute("stride", "3");
- tinyxml2::XMLElement* normalsAccXNode = doc->NewElement("param");
- normalsAccNode->LinkEndChild(normalsAccXNode);
- normalsAccXNode->SetAttribute("name", "X");
- normalsAccXNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* normalsAccYNode = doc->NewElement("param");
- normalsAccNode->LinkEndChild(normalsAccYNode);
- normalsAccYNode->SetAttribute("name", "Y");
- normalsAccYNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* normalsAccZNode = doc->NewElement("param");
- normalsAccNode->LinkEndChild(normalsAccZNode);
- normalsAccZNode->SetAttribute("name", "Z");
- normalsAccZNode->SetAttribute("type", "float");
- // Save out the uvs
- tinyxml2::XMLElement* uv0SourceNode = doc->NewElement("source");
- meshNode->LinkEndChild(uv0SourceNode);
- uv0SourceNode->SetAttribute("id", avar("%s-mesh-map-0", colMeshName));
- tinyxml2::XMLElement* uv0Node = doc->NewElement("float_array");
- uv0SourceNode->LinkEndChild(uv0Node);
- uv0Node->SetAttribute("id", avar("%s-mesh-map-0-array", colMeshName));
- uv0Node->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mUV0s.size() * 2));
- for (U32 i = 0; i < exportData.colMeshes[d].mesh.mUV0s.size(); i++)
- {
- const Point2F& uv0 = exportData.colMeshes[d].mesh.mUV0s[i];
- tinyxml2::XMLText* uv0Text = doc->NewText(avar("%.4f %.4f ", uv0.x, 1.0f - uv0.y)); // COLLADA uvs are upside down compared to Torque
- uv0Node->LinkEndChild(uv0Text);
- }
- // Save the uv0 accessor
- tinyxml2::XMLElement* uv0TechNode = doc->NewElement("technique_common");
- uv0SourceNode->LinkEndChild(uv0TechNode);
- tinyxml2::XMLElement* uv0AccNode = doc->NewElement("accessor");
- uv0TechNode->LinkEndChild(uv0AccNode);
- uv0AccNode->SetAttribute("source", avar("#%s-mesh-map-0-array", colMeshName));
- uv0AccNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mUV0s.size()));
- uv0AccNode->SetAttribute("stride", "2");
- tinyxml2::XMLElement* uv0AccSNode = doc->NewElement("param");
- uv0AccNode->LinkEndChild(uv0AccSNode);
- uv0AccSNode->SetAttribute("name", "S");
- uv0AccSNode->SetAttribute("type", "float");
- tinyxml2::XMLElement* uv0AccTNode = doc->NewElement("param");
- uv0AccNode->LinkEndChild(uv0AccTNode);
- uv0AccTNode->SetAttribute("name", "T");
- uv0AccTNode->SetAttribute("type", "float");
- // Define the vertices position array
- tinyxml2::XMLElement* verticesNode = doc->NewElement("vertices");
- meshNode->LinkEndChild(verticesNode);
- verticesNode->SetAttribute("id", avar("%s-mesh-vertices", colMeshName));
- tinyxml2::XMLElement* verticesInputNode = doc->NewElement("input");
- verticesNode->LinkEndChild(verticesInputNode);
- verticesInputNode->SetAttribute("semantic", "POSITION");
- verticesInputNode->SetAttribute("source", avar("#%s-mesh-positions", colMeshName));
- Vector<String> mapNames;
- //exportColladaTriangles(meshNode, exportData.detailLevels[d].mesh, lodMeshName, mapNames);
- exportColladaCollisionTriangles(meshNode, exportData, d);
- // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
- tinyxml2::XMLElement* extraGeoNode = doc->NewElement("extra");
- libGeomsNode->LinkEndChild(extraGeoNode);
- tinyxml2::XMLElement* extraGeoNodeTech = doc->NewElement("technique");
- extraGeoNode->LinkEndChild(extraGeoNodeTech);
- extraGeoNodeTech->SetAttribute("profile", "OpenCOLLADAMaya");
- tinyxml2::XMLElement* mayaNode2Id = doc->NewElement("originalMayaNodeId");
- extraGeoNodeTech->LinkEndChild(mayaNode2Id);
- mayaNode2Id->SetAttribute("sid", "originalMayaNodeId");
- tinyxml2::XMLText* mayaIdMesh = doc->NewText(avar("%s", colMeshName));
- mayaNode2Id->LinkEndChild(mayaIdMesh);
- tinyxml2::XMLElement* doubleSidedId = doc->NewElement("double_sided");
- extraGeoNodeTech->LinkEndChild(doubleSidedId);
- doubleSidedId->SetAttribute("sid", "double_sided");
- tinyxml2::XMLText* doubleSideIdText = doc->NewText("1");
- doubleSidedId->LinkEndChild(doubleSideIdText);
- tinyxml2::XMLElement* paramExtraNode = doc->NewElement("param");
- extraGeoNodeTech->LinkEndChild(paramExtraNode);
- paramExtraNode->SetAttribute("sid", "colladaId");
- paramExtraNode->SetAttribute("type", "string");
- tinyxml2::XMLText* mayaParamMesh = doc->NewText(avar("%s-mesh", colMeshName));
- paramExtraNode->LinkEndChild(mayaParamMesh);
- }
- }
- void ColladaUtils::exportColladaScene(tinyxml2::XMLElement* rootNode, const String& meshName, const Vector<String>& matNames)
- {
- tinyxml2::XMLDocument* doc = rootNode->GetDocument();
- tinyxml2::XMLElement* libSceneNode = doc->NewElement("library_visual_scenes");
- rootNode->LinkEndChild(libSceneNode);
- tinyxml2::XMLElement* visSceneNode = doc->NewElement("visual_scene");
- libSceneNode->LinkEndChild(visSceneNode);
- visSceneNode->SetAttribute("id", "RootNode");
- visSceneNode->SetAttribute("name", "RootNode");
- tinyxml2::XMLElement* nodeNode = doc->NewElement("node");
- visSceneNode->LinkEndChild(nodeNode);
- nodeNode->SetAttribute("id", avar("%s", meshName.c_str()));
- nodeNode->SetAttribute("name", avar("%s", meshName.c_str()));
- nodeNode->SetAttribute("type", "NODE");
-
- tinyxml2::XMLElement* instanceGeomNode = doc->NewElement("instance_geometry");
- nodeNode->LinkEndChild(instanceGeomNode);
- instanceGeomNode->SetAttribute("url", avar("#%s-mesh", meshName.c_str()));
- instanceGeomNode->SetAttribute("name", avar("%s", meshName.c_str()));
-
- tinyxml2::XMLElement* bindMatNode = doc->NewElement("bind_material");
- instanceGeomNode->LinkEndChild(bindMatNode);
- tinyxml2::XMLElement* techniqueNode = doc->NewElement("technique_common");
- bindMatNode->LinkEndChild(techniqueNode);
- // Bind the materials
- for (U32 i = 0; i < matNames.size(); i++)
- {
- tinyxml2::XMLElement* instMatNode = doc->NewElement("instance_material");
- techniqueNode->LinkEndChild(instMatNode);
- instMatNode->SetAttribute("symbol", avar("%s-material", matNames[i].c_str()));
- instMatNode->SetAttribute("target", avar("#%s-material", matNames[i].c_str()));
- tinyxml2::XMLElement* bindVertexNode = doc->NewElement("bind_vertex_input");
- instMatNode->LinkEndChild(bindVertexNode);
- //bindVertexNode->SetAttribute("semantic", avar("%s-mesh-map-0", meshName.c_str()));
- bindVertexNode->SetAttribute("semantic", "UVMap");
- bindVertexNode->SetAttribute("input_semantic", "TEXCOORD");
- bindVertexNode->SetAttribute("input_set", "0");
- }
-
- // Extra info useful for COLLADAMax importer (OpenCOLLADA)
- tinyxml2::XMLElement* extraInsGeoNode = doc->NewElement("extra");
- nodeNode->LinkEndChild(extraInsGeoNode);
- tinyxml2::XMLElement* extraInsGeoTechNode = doc->NewElement("technique");
- extraInsGeoNode->LinkEndChild(extraInsGeoTechNode);
- extraInsGeoTechNode->SetAttribute("profile", "OpenCOLLADA");
- tinyxml2::XMLElement* castShadowsNode = doc->NewElement("cast_shadows");
- extraInsGeoTechNode->LinkEndChild(castShadowsNode);
- castShadowsNode->SetAttribute("sid", "cast_shadows");
- castShadowsNode->SetAttribute("type", "bool");
-
- tinyxml2::XMLText* castShadowsText = doc->NewText("1");
- castShadowsNode->LinkEndChild(castShadowsText);
-
- //-----------------------------
- tinyxml2::XMLElement* receiveShadowsNode = doc->NewElement("receive_shadows");
- extraInsGeoTechNode->LinkEndChild(receiveShadowsNode);
- receiveShadowsNode->SetAttribute("sid", "receive_shadows");
- receiveShadowsNode->SetAttribute("type", "bool");
-
- tinyxml2::XMLText* receiveShadowsText = doc->NewText("1");
- receiveShadowsNode->LinkEndChild(receiveShadowsText);
-
- //-----------------------------
- tinyxml2::XMLElement* primaryVisibiltyNode = doc->NewElement("primary_visibility");
- extraInsGeoTechNode->LinkEndChild(primaryVisibiltyNode);
- primaryVisibiltyNode->SetAttribute("sid", "primary_visibility");
- primaryVisibiltyNode->SetAttribute("type", "int");
-
- tinyxml2::XMLText* primaryVisibiltyText = doc->NewText("1");
- primaryVisibiltyNode->LinkEndChild(primaryVisibiltyText);
- //-----------------------------
- tinyxml2::XMLElement* secondaryVisibilityNode = doc->NewElement("secondary_visibility");
- extraInsGeoTechNode->LinkEndChild(secondaryVisibilityNode);
- secondaryVisibilityNode->SetAttribute("sid", "secondary_visibility");
- secondaryVisibilityNode->SetAttribute("type", "int");
-
- tinyxml2::XMLText* secondaryVisibilityText = doc->NewText("1");
- secondaryVisibilityNode->LinkEndChild(secondaryVisibilityText);
- // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
- tinyxml2::XMLElement* extra2InsGeoNode = doc->NewElement("extra");
- nodeNode->LinkEndChild(extra2InsGeoNode);
- tinyxml2::XMLElement* extra2InsGeoTechNode = doc->NewElement("technique");
- extra2InsGeoNode->LinkEndChild(extra2InsGeoTechNode);
- extra2InsGeoTechNode->SetAttribute("profile", "OpenCOLLADAMaya");
- tinyxml2::XMLElement* mayaNodeId = doc->NewElement("originalMayaNodeId");
- extra2InsGeoTechNode->LinkEndChild(mayaNodeId);
- mayaNodeId->SetAttribute("sid", "originalMayaNodeId");
- mayaNodeId->SetAttribute("type", "string");
- tinyxml2::XMLText* mayaNodeIdMesh = doc->NewText(avar("%s", meshName.c_str()));
- mayaNodeId->LinkEndChild(mayaNodeIdMesh);
- tinyxml2::XMLElement* paramExtraNode = doc->NewElement("param");
- extra2InsGeoTechNode->LinkEndChild(paramExtraNode);
- paramExtraNode->SetAttribute("sid", "colladaId");
- paramExtraNode->SetAttribute("type", "string");
- tinyxml2::XMLText* mayaParamMesh = doc->NewText(avar("%s", meshName.c_str()));
- paramExtraNode->LinkEndChild(mayaParamMesh);
-
- //-----------------------------
-
- tinyxml2::XMLElement* sceneNode = doc->NewElement("scene");
- rootNode->LinkEndChild(sceneNode);
- tinyxml2::XMLElement* instVisSceneNode = doc->NewElement("instance_visual_scene");
- sceneNode->LinkEndChild(instVisSceneNode);
- instVisSceneNode->SetAttribute("url", "#RootNode");
- }
- void ColladaUtils::exportColladaScene(tinyxml2::XMLElement* rootNode, const ExportData& exportData, const String& meshName)
- {
- tinyxml2::XMLDocument* doc = rootNode->GetDocument();
- tinyxml2::XMLElement* libSceneNode = doc->NewElement("library_visual_scenes");
- rootNode->LinkEndChild(libSceneNode);
- tinyxml2::XMLElement* visSceneNode = doc->NewElement("visual_scene");
- libSceneNode->LinkEndChild(visSceneNode);
- visSceneNode->SetAttribute("id", "RootNode");
- visSceneNode->SetAttribute("name", "RootNode");
- for (U32 d = 0; d < exportData.detailLevels.size(); d++)
- {
- char lodMeshName[256];
- dSprintf(lodMeshName, 256, "%s%d", meshName.c_str(), exportData.detailLevels[d].size);
- tinyxml2::XMLElement* nodeNode = doc->NewElement("node");
- visSceneNode->LinkEndChild(nodeNode);
- nodeNode->SetAttribute("id", lodMeshName);
- nodeNode->SetAttribute("name", lodMeshName);
- nodeNode->SetAttribute("type", "NODE");
- tinyxml2::XMLElement* instanceGeomNode = doc->NewElement("instance_geometry");
- nodeNode->LinkEndChild(instanceGeomNode);
- instanceGeomNode->SetAttribute("url", avar("#%s%d-mesh", meshName.c_str(), exportData.detailLevels[d].size));
- instanceGeomNode->SetAttribute("name", lodMeshName);
- tinyxml2::XMLElement* bindMatNode = doc->NewElement("bind_material");
- instanceGeomNode->LinkEndChild(bindMatNode);
- tinyxml2::XMLElement* techniqueNode = doc->NewElement("technique_common");
- bindMatNode->LinkEndChild(techniqueNode);
- // Bind the materials
- for (U32 i = 0; i < exportData.detailLevels[d].materialRefList.size(); i++)
- {
- int matIdx;
- exportData.detailLevels[d].materialRefList.tryGetValue(i, matIdx);
- BaseMatInstance* baseInst = exportData.materials[matIdx];
- Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
- if (!mat)
- continue;
- String matName;
- if (mat->getName() && mat->getName()[0])
- matName = mat->mMapTo;
- tinyxml2::XMLElement* instMatNode = doc->NewElement("instance_material");
- techniqueNode->LinkEndChild(instMatNode);
- instMatNode->SetAttribute("symbol", avar("%s-material", matName.c_str()));
- instMatNode->SetAttribute("target", avar("#%s-material", matName.c_str()));
- tinyxml2::XMLElement* bindVertexNode = doc->NewElement("bind_vertex_input");
- instMatNode->LinkEndChild(bindVertexNode);
- //bindVertexNode->SetAttribute("semantic", avar("%s-mesh-map-0", meshName.c_str()));
- bindVertexNode->SetAttribute("semantic", "UVMap");
- bindVertexNode->SetAttribute("input_semantic", "TEXCOORD");
- bindVertexNode->SetAttribute("input_set", "0");
- }
- // Extra info useful for COLLADAMax importer (OpenCOLLADA)
- tinyxml2::XMLElement* extraInsGeoNode = doc->NewElement("extra");
- nodeNode->LinkEndChild(extraInsGeoNode);
- tinyxml2::XMLElement* extraInsGeoTechNode = doc->NewElement("technique");
- extraInsGeoNode->LinkEndChild(extraInsGeoTechNode);
- extraInsGeoTechNode->SetAttribute("profile", "OpenCOLLADA");
- tinyxml2::XMLElement* castShadowsNode = doc->NewElement("cast_shadows");
- extraInsGeoTechNode->LinkEndChild(castShadowsNode);
- castShadowsNode->SetAttribute("sid", "cast_shadows");
- castShadowsNode->SetAttribute("type", "bool");
- tinyxml2::XMLText* castShadowsText = doc->NewText("1");
- castShadowsNode->LinkEndChild(castShadowsText);
- //-----------------------------
- tinyxml2::XMLElement* receiveShadowsNode = doc->NewElement("receive_shadows");
- extraInsGeoTechNode->LinkEndChild(receiveShadowsNode);
- receiveShadowsNode->SetAttribute("sid", "receive_shadows");
- receiveShadowsNode->SetAttribute("type", "bool");
- tinyxml2::XMLText* receiveShadowsText = doc->NewText("1");
- receiveShadowsNode->LinkEndChild(receiveShadowsText);
- //-----------------------------
- tinyxml2::XMLElement* primaryVisibiltyNode = doc->NewElement("primary_visibility");
- extraInsGeoTechNode->LinkEndChild(primaryVisibiltyNode);
- primaryVisibiltyNode->SetAttribute("sid", "primary_visibility");
- primaryVisibiltyNode->SetAttribute("type", "int");
- tinyxml2::XMLText* primaryVisibiltyText = doc->NewText("1");
- primaryVisibiltyNode->LinkEndChild(primaryVisibiltyText);
- //-----------------------------
- tinyxml2::XMLElement* secondaryVisibilityNode = doc->NewElement("secondary_visibility");
- extraInsGeoTechNode->LinkEndChild(secondaryVisibilityNode);
- secondaryVisibilityNode->SetAttribute("sid", "secondary_visibility");
- secondaryVisibilityNode->SetAttribute("type", "int");
- tinyxml2::XMLText* secondaryVisibilityText = doc->NewText("1");
- secondaryVisibilityNode->LinkEndChild(secondaryVisibilityText);
- // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
- tinyxml2::XMLElement* extra2InsGeoNode = doc->NewElement("extra");
- nodeNode->LinkEndChild(extra2InsGeoNode);
- tinyxml2::XMLElement* extra2InsGeoTechNode = doc->NewElement("technique");
- extra2InsGeoNode->LinkEndChild(extra2InsGeoTechNode);
- extra2InsGeoTechNode->SetAttribute("profile", "OpenCOLLADAMaya");
- tinyxml2::XMLElement* mayaNodeId = doc->NewElement("originalMayaNodeId");
- extra2InsGeoTechNode->LinkEndChild(mayaNodeId);
- mayaNodeId->SetAttribute("sid", "originalMayaNodeId");
- mayaNodeId->SetAttribute("type", "string");
- tinyxml2::XMLText* mayaNodeIdMesh = doc->NewText(lodMeshName);
- mayaNodeId->LinkEndChild(mayaNodeIdMesh);
- tinyxml2::XMLElement* paramExtraNode = doc->NewElement("param");
- extra2InsGeoTechNode->LinkEndChild(paramExtraNode);
- paramExtraNode->SetAttribute("sid", "colladaId");
- paramExtraNode->SetAttribute("type", "string");
- tinyxml2::XMLText* mayaParamMesh = doc->NewText(lodMeshName);
- paramExtraNode->LinkEndChild(mayaParamMesh);
- }
- //Collisions
- for (U32 d = 0; d < exportData.colMeshes.size(); d++)
- {
- const char* colMeshName = exportData.colMeshes[d].colMeshName;
- tinyxml2::XMLElement* nodeNode = doc->NewElement("node");
- visSceneNode->LinkEndChild(nodeNode);
- nodeNode->SetAttribute("id", colMeshName);
- nodeNode->SetAttribute("name", colMeshName);
- nodeNode->SetAttribute("type", "NODE");
- tinyxml2::XMLElement* instanceGeomNode = doc->NewElement("instance_geometry");
- nodeNode->LinkEndChild(instanceGeomNode);
- instanceGeomNode->SetAttribute("url", avar("#%s-mesh", colMeshName));
- instanceGeomNode->SetAttribute("name", colMeshName);
- tinyxml2::XMLElement* bindMatNode = doc->NewElement("bind_material");
- instanceGeomNode->LinkEndChild(bindMatNode);
- tinyxml2::XMLElement* techniqueNode = doc->NewElement("technique_common");
- bindMatNode->LinkEndChild(techniqueNode);
- tinyxml2::XMLElement* instMatNode = doc->NewElement("instance_material");
- techniqueNode->LinkEndChild(instMatNode);
- instMatNode->SetAttribute("symbol", avar("%s-material", colMeshName));
- instMatNode->SetAttribute("target", avar("#%s-material", colMeshName));
- tinyxml2::XMLElement* bindVertexNode = doc->NewElement("bind_vertex_input");
- instMatNode->LinkEndChild(bindVertexNode);
- //bindVertexNode->SetAttribute("semantic", avar("%s-mesh-map-0", meshName.c_str()));
- bindVertexNode->SetAttribute("semantic", "UVMap");
- bindVertexNode->SetAttribute("input_semantic", "TEXCOORD");
- bindVertexNode->SetAttribute("input_set", "0");
- // Extra info useful for COLLADAMax importer (OpenCOLLADA)
- tinyxml2::XMLElement* extraInsGeoNode = doc->NewElement("extra");
- nodeNode->LinkEndChild(extraInsGeoNode);
- tinyxml2::XMLElement* extraInsGeoTechNode = doc->NewElement("technique");
- extraInsGeoNode->LinkEndChild(extraInsGeoTechNode);
- extraInsGeoTechNode->SetAttribute("profile", "OpenCOLLADA");
- tinyxml2::XMLElement* castShadowsNode = doc->NewElement("cast_shadows");
- extraInsGeoTechNode->LinkEndChild(castShadowsNode);
- castShadowsNode->SetAttribute("sid", "cast_shadows");
- castShadowsNode->SetAttribute("type", "bool");
- tinyxml2::XMLText* castShadowsText = doc->NewText("1");
- castShadowsNode->LinkEndChild(castShadowsText);
- //-----------------------------
- tinyxml2::XMLElement* receiveShadowsNode = doc->NewElement("receive_shadows");
- extraInsGeoTechNode->LinkEndChild(receiveShadowsNode);
- receiveShadowsNode->SetAttribute("sid", "receive_shadows");
- receiveShadowsNode->SetAttribute("type", "bool");
- tinyxml2::XMLText* receiveShadowsText = doc->NewText("1");
- receiveShadowsNode->LinkEndChild(receiveShadowsText);
- //-----------------------------
- tinyxml2::XMLElement* primaryVisibiltyNode = doc->NewElement("primary_visibility");
- extraInsGeoTechNode->LinkEndChild(primaryVisibiltyNode);
- primaryVisibiltyNode->SetAttribute("sid", "primary_visibility");
- primaryVisibiltyNode->SetAttribute("type", "int");
- tinyxml2::XMLText* primaryVisibiltyText = doc->NewText("1");
- primaryVisibiltyNode->LinkEndChild(primaryVisibiltyText);
- //-----------------------------
- tinyxml2::XMLElement* secondaryVisibilityNode = doc->NewElement("secondary_visibility");
- extraInsGeoTechNode->LinkEndChild(secondaryVisibilityNode);
- secondaryVisibilityNode->SetAttribute("sid", "secondary_visibility");
- secondaryVisibilityNode->SetAttribute("type", "int");
- tinyxml2::XMLText* secondaryVisibilityText = doc->NewText("1");
- secondaryVisibilityNode->LinkEndChild(secondaryVisibilityText);
- // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
- tinyxml2::XMLElement* extra2InsGeoNode = doc->NewElement("extra");
- nodeNode->LinkEndChild(extra2InsGeoNode);
- tinyxml2::XMLElement* extra2InsGeoTechNode = doc->NewElement("technique");
- extra2InsGeoNode->LinkEndChild(extra2InsGeoTechNode);
- extra2InsGeoTechNode->SetAttribute("profile", "OpenCOLLADAMaya");
- tinyxml2::XMLElement* mayaNodeId = doc->NewElement("originalMayaNodeId");
- extra2InsGeoTechNode->LinkEndChild(mayaNodeId);
- mayaNodeId->SetAttribute("sid", "originalMayaNodeId");
- mayaNodeId->SetAttribute("type", "string");
- tinyxml2::XMLText* mayaNodeIdMesh = doc->NewText(colMeshName);
- mayaNodeId->LinkEndChild(mayaNodeIdMesh);
- tinyxml2::XMLElement* paramExtraNode = doc->NewElement("param");
- extra2InsGeoTechNode->LinkEndChild(paramExtraNode);
- paramExtraNode->SetAttribute("sid", "colladaId");
- paramExtraNode->SetAttribute("type", "string");
- tinyxml2::XMLText* mayaParamMesh = doc->NewText(colMeshName);
- paramExtraNode->LinkEndChild(mayaParamMesh);
- }
- //-----------------------------
- tinyxml2::XMLElement* sceneNode = doc->NewElement("scene");
- rootNode->LinkEndChild(sceneNode);
- tinyxml2::XMLElement* instVisSceneNode = doc->NewElement("instance_visual_scene");
- sceneNode->LinkEndChild(instVisSceneNode);
- instVisSceneNode->SetAttribute("url", "#RootNode");
- }
- void ColladaUtils::exportToCollada(const Torque::Path& colladaFile, const OptimizedPolyList& mesh, const String& meshName)
- {
- // Get the mesh name
- String outMeshName = meshName;
- if (outMeshName.isEmpty())
- outMeshName = colladaFile.getFileName();
- // The XML document that will hold all of our data
- VfsXMLDocument doc;
- // Add a standard XML declaration to the top
- tinyxml2::XMLDeclaration* xmlDecl = doc.NewDeclaration();
- doc.LinkEndChild(xmlDecl);
- // Create our Collada root node and populate a couple standard attributes
- tinyxml2::XMLElement* rootNode = doc.NewElement("COLLADA");
- rootNode->SetAttribute("xmlns", "http://www.collada.org/2005/11/COLLADASchema");
- rootNode->SetAttribute("version", "1.4.1");
- //rootNode->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); //T3D Collada loader complaint about this.
-
- // Add the root node to the document
- doc.LinkEndChild(rootNode);
- // Save out our header info
- exportColladaHeader(rootNode);
- // Save out the materials
- Vector<String> mapNames;
- exportColladaMaterials(rootNode, mesh, mapNames, colladaFile);
- S32 suffix;
- String baseMeshName = String::GetTrailingNumber(outMeshName, suffix);
- // Save out our geometry
- exportColladaMesh(rootNode, mesh, baseMeshName, mapNames);
- // Save out our scene nodes
- exportColladaScene(rootNode, baseMeshName, mapNames);
- // Write out the actual Collada file
- char fullPath[MAX_PATH_LENGTH];
- Platform::makeFullPathName(colladaFile.getFullPath(), fullPath, MAX_PATH_LENGTH);
- if (!doc.SaveFile(fullPath))
- Con::errorf("ColladaUtils::exportToCollada(): Unable to export to %s", fullPath);
- }
- void ColladaUtils::exportToCollada(const Torque::Path& colladaFile, const ExportData& exportData)
- {
- // Get the mesh name
- String outMeshName = colladaFile.getFileName();
- // The XML document that will hold all of our data
- VfsXMLDocument doc;
- // Add a standard XML declaration to the top
- tinyxml2::XMLDeclaration* xmlDecl = doc.NewDeclaration();
- doc.LinkEndChild(xmlDecl);
- // Create our Collada root node and populate a couple standard attributes
- tinyxml2::XMLElement* rootNode = doc.NewElement("COLLADA");
- rootNode->SetAttribute("xmlns", "http://www.collada.org/2005/11/COLLADASchema");
- rootNode->SetAttribute("version", "1.4.1");
- //rootNode->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); //T3D Collada loader complaint about this.
- // Add the root node to the document
- doc.LinkEndChild(rootNode);
- // Save out our header info
- exportColladaHeader(rootNode);
- // Save out the materials
- Vector<String> mapNames;
- exportColladaMaterials(rootNode, exportData, colladaFile);
- S32 suffix;
- String baseMeshName = String::GetTrailingNumber(outMeshName, suffix);
- // Save out our geometry
- exportColladaMesh(rootNode, exportData, baseMeshName);
- // Save out our scene nodes
- exportColladaScene(rootNode, exportData, baseMeshName);
- // Write out the actual Collada file
- char fullPath[MAX_PATH_LENGTH];
- Platform::makeFullPathName(colladaFile.getFullPath(), fullPath, MAX_PATH_LENGTH);
- if (!doc.SaveFile(fullPath))
- Con::errorf("ColladaUtils::exportToCollada(): Unable to export to %s", fullPath);
- }
- void ColladaUtils::ExportData::processData()
- {
- //This pref dictates if we 'backfill' lower LODs with higher ones if any given mesh being exported lacks that level.
- //For example, if there are 2 meshes, and one has 500, 200, 100 and the other has 500 and 200 - if this setting is on, the second mesh
- //will backfill the 200 to the 100 so it has all levels filled. If it's off, the second mesh will not render at the 100 level
- bool fillLowDetailLevels = dAtob(Con::getVariable("$exportMesh::fillLowDetailLevels", "1"));
- S32 numDetailLevels = numberOfDetailLevels();
- detailLevels.clear();
- detailLevels.setSize(numDetailLevels);
- for (U32 meshNum = 0; meshNum < meshData.size(); ++meshNum)
- {
- for (U32 i = 0; i < numDetailLevels; ++i)
- {
- //Get our target size
- S32 targetDetailLevelSize = getDetailLevelSize(i);
- //alright, step through each meshdata and propagate the polyList info 'up' to fill
- detailLevel* curDetail = &detailLevels[i];
- curDetail->size = targetDetailLevelSize;
-
- //Do we have a detail level for this?
- S32 detailLevelIdx = -1;
- for (S32 mdl = i; mdl >= 0; mdl--)
- {
- //walk backwards as needed to find our first valid detail level for this mesh. if we find none, just move on
- S32 testDetailLevelSize = getDetailLevelSize(mdl);
- detailLevelIdx = meshData[meshNum].hasDetailLevel(testDetailLevelSize);
- if (detailLevelIdx != -1)
- break;
- }
- if (detailLevelIdx == -1)
- {
- //found nothing backwards, so lets check if we're configured to back-fill the first detail levels
- if (fillLowDetailLevels)
- {
- //if so, search forward, find the first valid detail and fill it in
- for (S32 mdl = 0; mdl < numDetailLevels; mdl++)
- {
- //walk backwards as needed to find our first valid detail level for this mesh. if we find none, just move on
- S32 testDetailLevelSize = getDetailLevelSize(mdl);
- detailLevelIdx = meshData[meshNum].hasDetailLevel(testDetailLevelSize);
- if (detailLevelIdx != -1)
- break;
- }
- }
- }
- //If we found the detail level index, go ahead and build out the data for it
- if (detailLevelIdx != -1)
- {
- curDetail->mesh.setTransform(&meshData[meshNum].meshTransform, meshData[meshNum].scale);
- curDetail->mesh.setObject(meshData[meshNum].originatingObject);
- if (meshData[meshNum].shapeInst != nullptr)
- {
- if (!meshData[meshNum].shapeInst->buildPolyList(&curDetail->mesh, detailLevelIdx))
- {
- Con::errorf("TSStatic::buildExportPolyList - failed to build polylist for LOD %i", i);
- continue;
- }
- }
- else
- {
- //special handling classes
- ConvexShape* convexShp = dynamic_cast<ConvexShape*>(meshData[meshNum].originatingObject);
- if (convexShp != nullptr)
- {
- if (!convexShp->buildPolyList(PLC_Export, &curDetail->mesh, meshData[meshNum].originatingObject->getWorldBox(), meshData[meshNum].originatingObject->getWorldSphere()))
- {
- Con::errorf("TSStatic::buildExportPolyList - failed to build ConvexShape polylist for LOD %i", i);
- continue;
- }
- }
- }
- //lastly, get material
- for (U32 matNum = 0; matNum < curDetail->mesh.mMaterialList.size(); matNum++)
- {
- S32 matIdx = hasMaterialInstance(curDetail->mesh.mMaterialList[matNum]);
- if (matIdx == -1)
- {
- //cool, haven't already got this material, so lets store it out
- materials.push_back(curDetail->mesh.mMaterialList[matNum]);
- curDetail->materialRefList.insert(matNum, materials.size() - 1);
- }
- else
- {
- curDetail->materialRefList.insert(matNum, matIdx);
- }
- }
- }
- }
- }
- }
|