123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- //-----------------------------------------------------------------------------
- // 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 <light> 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<class T> 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<class T> 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 <light>s to the Torque scene
- static void processNodeLights(AppNode* appNode, const MatrixF& offset, SimGroup* group)
- {
- const domNode* node = dynamic_cast<ColladaAppNode*>(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<domLight>(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 <technique_common> 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 <asset> 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<ColladaAppNode*> 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 <instance_light>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;
- }
|