colladaLights.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/engineAPI.h"
  23. #include "platform/platform.h"
  24. #include "ts/collada/colladaUtils.h"
  25. #include "ts/collada/colladaAppNode.h"
  26. #include "ts/collada/colladaShapeLoader.h"
  27. #include "T3D/pointLight.h"
  28. #include "T3D/spotLight.h"
  29. #include "T3D/Scene.h"
  30. //-----------------------------------------------------------------------------
  31. // Collada <light> elements are very similar, but are arranged as separate, unrelated
  32. // classes. These template functions are used to provide a simple way to access the
  33. // common elements.
  34. template<class T> static void resolveLightColor(T* light, LinearColorF& color)
  35. {
  36. if (light->getColor())
  37. {
  38. color.red = light->getColor()->getValue()[0];
  39. color.green = light->getColor()->getValue()[1];
  40. color.blue = light->getColor()->getValue()[2];
  41. }
  42. }
  43. template<class T> static void resolveLightAttenuation(T* light, Point3F& attenuationRatio)
  44. {
  45. if (light->getConstant_attenuation())
  46. attenuationRatio.x = light->getConstant_attenuation()->getValue();
  47. if (light->getLinear_attenuation())
  48. attenuationRatio.y = light->getLinear_attenuation()->getValue();
  49. if (light->getQuadratic_attenuation())
  50. attenuationRatio.z = light->getQuadratic_attenuation()->getValue();
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Recurse through the collada scene to add <light>s to the Torque scene
  54. static void processNodeLights(AppNode* appNode, const MatrixF& offset, SimGroup* group)
  55. {
  56. const domNode* node = dynamic_cast<ColladaAppNode*>(appNode)->getDomNode();
  57. for (S32 iLight = 0; iLight < node->getInstance_light_array().getCount(); iLight++) {
  58. domInstance_light* instLight = node->getInstance_light_array()[iLight];
  59. domLight* p_domLight = daeSafeCast<domLight>(instLight->getUrl().getElement());
  60. if (!p_domLight) {
  61. Con::warnf("Failed to find light for URL \"%s\"", instLight->getUrl().getOriginalURI());
  62. continue;
  63. }
  64. String lightName = Sim::getUniqueName(_GetNameOrId(node));
  65. const char* lightType = "";
  66. domLight::domTechnique_common* technique = p_domLight->getTechnique_common();
  67. if (!technique) {
  68. Con::warnf("No <technique_common> for light \"%s\"", lightName.c_str());
  69. continue;
  70. }
  71. LightBase* pLight = 0;
  72. LinearColorF color(LinearColorF::WHITE);
  73. Point3F attenuation(0, 1, 1);
  74. if (technique->getAmbient()) {
  75. domLight::domTechnique_common::domAmbient* ambient = technique->getAmbient();
  76. // No explicit support for ambient lights, so use a PointLight instead
  77. lightType = "ambient";
  78. pLight = new PointLight;
  79. resolveLightColor(ambient, color);
  80. }
  81. else if (technique->getDirectional()) {
  82. domLight::domTechnique_common::domDirectional* directional = technique->getDirectional();
  83. // No explicit support for directional lights, so use a SpotLight instead
  84. lightType = "directional";
  85. pLight = new SpotLight;
  86. resolveLightColor(directional, color);
  87. }
  88. else if (technique->getPoint()) {
  89. domLight::domTechnique_common::domPoint* point = technique->getPoint();
  90. lightType = "point";
  91. pLight = new PointLight;
  92. resolveLightColor(point, color);
  93. resolveLightAttenuation(point, attenuation);
  94. }
  95. else if (technique->getSpot()) {
  96. domLight::domTechnique_common::domSpot* spot = technique->getSpot();
  97. lightType = "spot";
  98. pLight = new SpotLight;
  99. resolveLightColor(spot, color);
  100. resolveLightAttenuation(spot, attenuation);
  101. }
  102. else
  103. continue;
  104. Con::printf("Adding <%s> light \"%s\" as a %s", lightType, lightName.c_str(), pLight->getClassName());
  105. MatrixF mat(offset);
  106. mat.mul(appNode->getNodeTransform(TSShapeLoader::DefaultTime));
  107. pLight->setDataField(StringTable->insert("color"), 0,
  108. avar("%f %f %f %f", color.red, color.green, color.blue, color.alpha));
  109. pLight->setDataField(StringTable->insert("attenuationRatio"), 0,
  110. avar("%f %f %f", attenuation.x, attenuation.y, attenuation.z));
  111. pLight->setTransform(mat);
  112. if (!pLight->registerObject(lightName)) {
  113. Con::errorf(ConsoleLogEntry::General, "Failed to register light for \"%s\"", lightName.c_str());
  114. delete pLight;
  115. }
  116. else if (group)
  117. group->addObject(pLight);
  118. }
  119. // Recurse child nodes
  120. for (S32 iChild = 0; iChild < appNode->getNumChildNodes(); iChild++)
  121. processNodeLights(appNode->getChildNode(iChild), offset, group);
  122. }
  123. // Load lights from a collada file and add to the scene.
  124. DefineEngineFunction( loadColladaLights, bool, (const char * filename, const char * parentGroup, const char * baseObject), ("", ""),
  125. "(string filename, SimGroup parentGroup=Scene, SimObject baseObject=-1)"
  126. "Load all light instances from a COLLADA (.dae) file and add to the scene.\n"
  127. "@param filename COLLADA filename to load lights from\n"
  128. "@param parentGroup (optional) name of an existing simgroup to add the new "
  129. "lights to (defaults to root Scene)\n"
  130. "@param baseObject (optional) name of an object to use as the origin (useful "
  131. "if you are loading the lights for a collada scene and have moved or rotated "
  132. "the geometry)\n"
  133. "@return true if successful, false otherwise\n\n"
  134. "@tsexample\n"
  135. "// load the lights in room.dae\n"
  136. "loadColladaLights( \"art/shapes/collada/room.dae\" );\n\n"
  137. "// load the lights in room.dae and add them to the RoomLights group\n"
  138. "loadColladaLights( \"art/shapes/collada/room.dae\", \"RoomLights\" );\n\n"
  139. "// load the lights in room.dae and use the transform of the \"Room\"\n"
  140. "object as the origin\n"
  141. "loadColladaLights( \"art/shapes/collada/room.dae\", \"\", \"Room\" );\n"
  142. "@endtsexample\n\n"
  143. "@note Currently for editor use only\n"
  144. "@ingroup Editors\n"
  145. "@internal")
  146. {
  147. Torque::Path path(filename);
  148. // Optional group to add the lights to. Create if it does not exist, and use
  149. // the root Scene if not specified.
  150. Scene* scene = Scene::getRootScene();
  151. SimGroup* group = 0;
  152. if (!String::isEmpty(parentGroup)){
  153. if (!Sim::findObject(parentGroup, group)) {
  154. // Create the group if it could not be found
  155. group = new SimGroup;
  156. if (group->registerObject(parentGroup)) {
  157. if (scene)
  158. scene->addObject(group);
  159. }
  160. else {
  161. delete group;
  162. group = 0;
  163. }
  164. }
  165. }
  166. if (!group)
  167. group = scene;
  168. // Optional object to provide the base transform
  169. MatrixF offset(true);
  170. if (!String::isEmpty(baseObject)){
  171. SceneObject *obj;
  172. if (Sim::findObject(baseObject, obj))
  173. offset = obj->getTransform();
  174. }
  175. // Load the Collada file into memory
  176. domCOLLADA* root = ColladaShapeLoader::getDomCOLLADA(path);
  177. if (!root) {
  178. TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete");
  179. return false;
  180. }
  181. // Extract the global scale and up_axis from the top level <asset> element,
  182. F32 unit = 1.0f;
  183. domUpAxisType upAxis = UPAXISTYPE_Z_UP;
  184. if (root->getAsset()) {
  185. if (root->getAsset()->getUnit())
  186. unit = root->getAsset()->getUnit()->getMeter();
  187. if (root->getAsset()->getUp_axis())
  188. upAxis = root->getAsset()->getUp_axis()->getValue();
  189. }
  190. ColladaUtils::getOptions().unit = unit;
  191. ColladaUtils::getOptions().upAxis = upAxis;
  192. // First grab all of the top-level nodes
  193. Vector<ColladaAppNode*> sceneNodes;
  194. for (S32 iSceneLib = 0; iSceneLib < root->getLibrary_visual_scenes_array().getCount(); iSceneLib++) {
  195. const domLibrary_visual_scenes* libScenes = root->getLibrary_visual_scenes_array()[iSceneLib];
  196. for (S32 iScene = 0; iScene < libScenes->getVisual_scene_array().getCount(); iScene++) {
  197. const domVisual_scene* visualScene = libScenes->getVisual_scene_array()[iScene];
  198. for (S32 iNode = 0; iNode < visualScene->getNode_array().getCount(); iNode++)
  199. sceneNodes.push_back(new ColladaAppNode(visualScene->getNode_array()[iNode]));
  200. }
  201. }
  202. // Recurse the scene tree looking for <instance_light>s
  203. for (S32 iNode = 0; iNode < sceneNodes.size(); iNode++) {
  204. processNodeLights(sceneNodes[iNode], offset, group);
  205. delete sceneNodes[iNode];
  206. }
  207. TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete");
  208. return true;
  209. }