colladaLights.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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 "platform/platform.h"
  23. #include "ts/collada/colladaUtils.h"
  24. #include "ts/collada/colladaAppNode.h"
  25. #include "ts/collada/colladaShapeLoader.h"
  26. #include "T3D/pointLight.h"
  27. #include "T3D/spotLight.h"
  28. //-----------------------------------------------------------------------------
  29. // Collada <light> elements are very similar, but are arranged as separate, unrelated
  30. // classes. These template functions are used to provide a simple way to access the
  31. // common elements.
  32. template<class T> static void resolveLightColor(T* light, ColorF& color)
  33. {
  34. if (light->getColor())
  35. {
  36. color.red = light->getColor()->getValue()[0];
  37. color.green = light->getColor()->getValue()[1];
  38. color.blue = light->getColor()->getValue()[2];
  39. }
  40. }
  41. template<class T> static void resolveLightAttenuation(T* light, Point3F& attenuationRatio)
  42. {
  43. if (light->getConstant_attenuation())
  44. attenuationRatio.x = light->getConstant_attenuation()->getValue();
  45. if (light->getLinear_attenuation())
  46. attenuationRatio.y = light->getLinear_attenuation()->getValue();
  47. if (light->getQuadratic_attenuation())
  48. attenuationRatio.z = light->getQuadratic_attenuation()->getValue();
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Recurse through the collada scene to add <light>s to the Torque scene
  52. static void processNodeLights(AppNode* appNode, const MatrixF& offset, SimGroup* group)
  53. {
  54. const domNode* node = dynamic_cast<ColladaAppNode*>(appNode)->getDomNode();
  55. for (S32 iLight = 0; iLight < node->getInstance_light_array().getCount(); iLight++) {
  56. domInstance_light* instLight = node->getInstance_light_array()[iLight];
  57. domLight* p_domLight = daeSafeCast<domLight>(instLight->getUrl().getElement());
  58. if (!p_domLight) {
  59. Con::warnf("Failed to find light for URL \"%s\"", instLight->getUrl().getOriginalURI());
  60. continue;
  61. }
  62. String lightName = Sim::getUniqueName(_GetNameOrId(node));
  63. const char* lightType = "";
  64. domLight::domTechnique_common* technique = p_domLight->getTechnique_common();
  65. if (!technique) {
  66. Con::warnf("No <technique_common> for light \"%s\"", lightName.c_str());
  67. continue;
  68. }
  69. LightBase* pLight = 0;
  70. ColorF color(ColorF::WHITE);
  71. Point3F attenuation(0, 1, 1);
  72. if (technique->getAmbient()) {
  73. domLight::domTechnique_common::domAmbient* ambient = technique->getAmbient();
  74. // No explicit support for ambient lights, so use a PointLight instead
  75. lightType = "ambient";
  76. pLight = new PointLight;
  77. resolveLightColor(ambient, color);
  78. }
  79. else if (technique->getDirectional()) {
  80. domLight::domTechnique_common::domDirectional* directional = technique->getDirectional();
  81. // No explicit support for directional lights, so use a SpotLight instead
  82. lightType = "directional";
  83. pLight = new SpotLight;
  84. resolveLightColor(directional, color);
  85. }
  86. else if (technique->getPoint()) {
  87. domLight::domTechnique_common::domPoint* point = technique->getPoint();
  88. lightType = "point";
  89. pLight = new PointLight;
  90. resolveLightColor(point, color);
  91. resolveLightAttenuation(point, attenuation);
  92. }
  93. else if (technique->getSpot()) {
  94. domLight::domTechnique_common::domSpot* spot = technique->getSpot();
  95. lightType = "spot";
  96. pLight = new SpotLight;
  97. resolveLightColor(spot, color);
  98. resolveLightAttenuation(spot, attenuation);
  99. }
  100. else
  101. continue;
  102. Con::printf("Adding <%s> light \"%s\" as a %s", lightType, lightName.c_str(), pLight->getClassName());
  103. MatrixF mat(offset);
  104. mat.mul(appNode->getNodeTransform(TSShapeLoader::DefaultTime));
  105. pLight->setDataField(StringTable->insert("color"), 0,
  106. avar("%f %f %f %f", color.red, color.green, color.blue, color.alpha));
  107. pLight->setDataField(StringTable->insert("attenuationRatio"), 0,
  108. avar("%f %f %f", attenuation.x, attenuation.y, attenuation.z));
  109. pLight->setTransform(mat);
  110. if (!pLight->registerObject(lightName)) {
  111. Con::errorf(ConsoleLogEntry::General, "Failed to register light for \"%s\"", lightName.c_str());
  112. delete pLight;
  113. }
  114. if (group)
  115. group->addObject(pLight);
  116. }
  117. // Recurse child nodes
  118. for (S32 iChild = 0; iChild < appNode->getNumChildNodes(); iChild++)
  119. processNodeLights(appNode->getChildNode(iChild), offset, group);
  120. }
  121. // Load lights from a collada file and add to the scene.
  122. ConsoleFunction( loadColladaLights, bool, 2, 4,
  123. "(string filename, SimGroup parentGroup=MissionGroup, SimObject baseObject=-1)"
  124. "Load all light instances from a COLLADA (.dae) file and add to the scene.\n"
  125. "@param filename COLLADA filename to load lights from\n"
  126. "@param parentGroup (optional) name of an existing simgroup to add the new "
  127. "lights to (defaults to MissionGroup)\n"
  128. "@param baseObject (optional) name of an object to use as the origin (useful "
  129. "if you are loading the lights for a collada scene and have moved or rotated "
  130. "the geometry)\n"
  131. "@return true if successful, false otherwise\n\n"
  132. "@tsexample\n"
  133. "// load the lights in room.dae\n"
  134. "loadColladaLights( \"art/shapes/collada/room.dae\" );\n\n"
  135. "// load the lights in room.dae and add them to the RoomLights group\n"
  136. "loadColladaLights( \"art/shapes/collada/room.dae\", \"RoomLights\" );\n\n"
  137. "// load the lights in room.dae and use the transform of the \"Room\"\n"
  138. "object as the origin\n"
  139. "loadColladaLights( \"art/shapes/collada/room.dae\", \"\", \"Room\" );\n"
  140. "@endtsexample\n\n"
  141. "@note Currently for editor use only\n"
  142. "@ingroup Editors\n"
  143. "@internal")
  144. {
  145. Torque::Path path((const char*)argv[1]);
  146. // Optional group to add the lights to. Create if it does not exist, and use
  147. // the MissionGroup if not specified.
  148. SimGroup* missionGroup = dynamic_cast<SimGroup*>(Sim::findObject("MissionGroup"));
  149. SimGroup* group = 0;
  150. if ((argc > 2) && (argv[2][0])) {
  151. if (!Sim::findObject(argv[2], group)) {
  152. // Create the group if it could not be found
  153. group = new SimGroup;
  154. if (group->registerObject(argv[2])) {
  155. if (missionGroup)
  156. missionGroup->addObject(group);
  157. }
  158. else {
  159. delete group;
  160. group = 0;
  161. }
  162. }
  163. }
  164. if (!group)
  165. group = missionGroup;
  166. // Optional object to provide the base transform
  167. MatrixF offset(true);
  168. if (argc > 3) {
  169. SceneObject *obj;
  170. if (Sim::findObject(argv[3], obj))
  171. offset = obj->getTransform();
  172. }
  173. // Load the Collada file into memory
  174. domCOLLADA* root = ColladaShapeLoader::getDomCOLLADA(path);
  175. if (!root) {
  176. TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete");
  177. return false;
  178. }
  179. // Extract the global scale and up_axis from the top level <asset> element,
  180. F32 unit = 1.0f;
  181. domUpAxisType upAxis = UPAXISTYPE_Z_UP;
  182. if (root->getAsset()) {
  183. if (root->getAsset()->getUnit())
  184. unit = root->getAsset()->getUnit()->getMeter();
  185. if (root->getAsset()->getUp_axis())
  186. upAxis = root->getAsset()->getUp_axis()->getValue();
  187. }
  188. ColladaUtils::getOptions().unit = unit;
  189. ColladaUtils::getOptions().upAxis = upAxis;
  190. // First grab all of the top-level nodes
  191. Vector<ColladaAppNode*> sceneNodes;
  192. for (int iSceneLib = 0; iSceneLib < root->getLibrary_visual_scenes_array().getCount(); iSceneLib++) {
  193. const domLibrary_visual_scenes* libScenes = root->getLibrary_visual_scenes_array()[iSceneLib];
  194. for (int iScene = 0; iScene < libScenes->getVisual_scene_array().getCount(); iScene++) {
  195. const domVisual_scene* visualScene = libScenes->getVisual_scene_array()[iScene];
  196. for (int iNode = 0; iNode < visualScene->getNode_array().getCount(); iNode++)
  197. sceneNodes.push_back(new ColladaAppNode(visualScene->getNode_array()[iNode]));
  198. }
  199. }
  200. // Recurse the scene tree looking for <instance_light>s
  201. for (S32 iNode = 0; iNode < sceneNodes.size(); iNode++) {
  202. processNodeLights(sceneNodes[iNode], offset, group);
  203. delete sceneNodes[iNode];
  204. }
  205. TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete");
  206. return true;
  207. }