//----------------------------------------------------------------------------- // 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 "console/engineAPI.h" #include "platform/platform.h" #include "ts/collada/colladaUtils.h" #include "ts/collada/colladaAppNode.h" #include "ts/collada/colladaShapeLoader.h" #include "T3D/pointLight.h" #include "T3D/spotLight.h" #include "T3D/Scene.h" //----------------------------------------------------------------------------- // Collada elements are very similar, but are arranged as separate, unrelated // classes. These template functions are used to provide a simple way to access the // common elements. template static void resolveLightColor(T* light, LinearColorF& color) { if (light->getColor()) { color.red = light->getColor()->getValue()[0]; color.green = light->getColor()->getValue()[1]; color.blue = light->getColor()->getValue()[2]; } } template static void resolveLightAttenuation(T* light, Point3F& attenuationRatio) { if (light->getConstant_attenuation()) attenuationRatio.x = light->getConstant_attenuation()->getValue(); if (light->getLinear_attenuation()) attenuationRatio.y = light->getLinear_attenuation()->getValue(); if (light->getQuadratic_attenuation()) attenuationRatio.z = light->getQuadratic_attenuation()->getValue(); } //----------------------------------------------------------------------------- // Recurse through the collada scene to add s to the Torque scene static void processNodeLights(AppNode* appNode, const MatrixF& offset, SimGroup* group) { const domNode* node = dynamic_cast(appNode)->getDomNode(); for (S32 iLight = 0; iLight < node->getInstance_light_array().getCount(); iLight++) { domInstance_light* instLight = node->getInstance_light_array()[iLight]; domLight* p_domLight = daeSafeCast(instLight->getUrl().getElement()); if (!p_domLight) { Con::warnf("Failed to find light for URL \"%s\"", instLight->getUrl().getOriginalURI()); continue; } String lightName = Sim::getUniqueName(_GetNameOrId(node)); const char* lightType = ""; domLight::domTechnique_common* technique = p_domLight->getTechnique_common(); if (!technique) { Con::warnf("No for light \"%s\"", lightName.c_str()); continue; } LightBase* pLight = 0; LinearColorF color(LinearColorF::WHITE); Point3F attenuation(0, 1, 1); if (technique->getAmbient()) { domLight::domTechnique_common::domAmbient* ambient = technique->getAmbient(); // No explicit support for ambient lights, so use a PointLight instead lightType = "ambient"; pLight = new PointLight; resolveLightColor(ambient, color); } else if (technique->getDirectional()) { domLight::domTechnique_common::domDirectional* directional = technique->getDirectional(); // No explicit support for directional lights, so use a SpotLight instead lightType = "directional"; pLight = new SpotLight; resolveLightColor(directional, color); } else if (technique->getPoint()) { domLight::domTechnique_common::domPoint* point = technique->getPoint(); lightType = "point"; pLight = new PointLight; resolveLightColor(point, color); resolveLightAttenuation(point, attenuation); } else if (technique->getSpot()) { domLight::domTechnique_common::domSpot* spot = technique->getSpot(); lightType = "spot"; pLight = new SpotLight; resolveLightColor(spot, color); resolveLightAttenuation(spot, attenuation); } else continue; Con::printf("Adding <%s> light \"%s\" as a %s", lightType, lightName.c_str(), pLight->getClassName()); MatrixF mat(offset); mat.mul(appNode->getNodeTransform(TSShapeLoader::DefaultTime)); pLight->setDataField(StringTable->insert("color"), 0, avar("%f %f %f %f", color.red, color.green, color.blue, color.alpha)); pLight->setDataField(StringTable->insert("attenuationRatio"), 0, avar("%f %f %f", attenuation.x, attenuation.y, attenuation.z)); pLight->setTransform(mat); if (!pLight->registerObject(lightName)) { Con::errorf(ConsoleLogEntry::General, "Failed to register light for \"%s\"", lightName.c_str()); delete pLight; } else if (group) group->addObject(pLight); } // Recurse child nodes for (S32 iChild = 0; iChild < appNode->getNumChildNodes(); iChild++) processNodeLights(appNode->getChildNode(iChild), offset, group); } // Load lights from a collada file and add to the scene. DefineEngineFunction( loadColladaLights, bool, (const char * filename, const char * parentGroup, const char * baseObject), ("", ""), "(string filename, SimGroup parentGroup=Scene, SimObject baseObject=-1)" "Load all light instances from a COLLADA (.dae) file and add to the scene.\n" "@param filename COLLADA filename to load lights from\n" "@param parentGroup (optional) name of an existing simgroup to add the new " "lights to (defaults to root Scene)\n" "@param baseObject (optional) name of an object to use as the origin (useful " "if you are loading the lights for a collada scene and have moved or rotated " "the geometry)\n" "@return true if successful, false otherwise\n\n" "@tsexample\n" "// load the lights in room.dae\n" "loadColladaLights( \"art/shapes/collada/room.dae\" );\n\n" "// load the lights in room.dae and add them to the RoomLights group\n" "loadColladaLights( \"art/shapes/collada/room.dae\", \"RoomLights\" );\n\n" "// load the lights in room.dae and use the transform of the \"Room\"\n" "object as the origin\n" "loadColladaLights( \"art/shapes/collada/room.dae\", \"\", \"Room\" );\n" "@endtsexample\n\n" "@note Currently for editor use only\n" "@ingroup Editors\n" "@internal") { Torque::Path path(filename); // Optional group to add the lights to. Create if it does not exist, and use // the root Scene if not specified. Scene* scene = Scene::getRootScene(); SimGroup* group = 0; if (!String::isEmpty(parentGroup)){ if (!Sim::findObject(parentGroup, group)) { // Create the group if it could not be found group = new SimGroup; if (group->registerObject(parentGroup)) { if (scene) scene->addObject(group); } else { delete group; group = 0; } } } if (!group) group = scene; // Optional object to provide the base transform MatrixF offset(true); if (!String::isEmpty(baseObject)){ SceneObject *obj; if (Sim::findObject(baseObject, obj)) offset = obj->getTransform(); } // Load the Collada file into memory domCOLLADA* root = ColladaShapeLoader::getDomCOLLADA(path); if (!root) { TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete"); return false; } // Extract the global scale and up_axis from the top level element, F32 unit = 1.0f; domUpAxisType upAxis = UPAXISTYPE_Z_UP; if (root->getAsset()) { if (root->getAsset()->getUnit()) unit = root->getAsset()->getUnit()->getMeter(); if (root->getAsset()->getUp_axis()) upAxis = root->getAsset()->getUp_axis()->getValue(); } ColladaUtils::getOptions().unit = unit; ColladaUtils::getOptions().upAxis = upAxis; // First grab all of the top-level nodes Vector sceneNodes; for (S32 iSceneLib = 0; iSceneLib < root->getLibrary_visual_scenes_array().getCount(); iSceneLib++) { const domLibrary_visual_scenes* libScenes = root->getLibrary_visual_scenes_array()[iSceneLib]; for (S32 iScene = 0; iScene < libScenes->getVisual_scene_array().getCount(); iScene++) { const domVisual_scene* visualScene = libScenes->getVisual_scene_array()[iScene]; for (S32 iNode = 0; iNode < visualScene->getNode_array().getCount(); iNode++) sceneNodes.push_back(new ColladaAppNode(visualScene->getNode_array()[iNode])); } } // Recurse the scene tree looking for s for (S32 iNode = 0; iNode < sceneNodes.size(); iNode++) { processNodeLights(sceneNodes[iNode], offset, group); delete sceneNodes[iNode]; } TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete"); return true; }