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