CubemapGenerator.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // Portions Copyright (c) 2008-2015 the Urho3D project.
  2. //
  3. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  4. // LICENSE: Atomic Game Engine Editor and Tools EULA
  5. // Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
  6. // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
  7. //
  8. #include <Atomic/Core/Context.h>
  9. #include <Atomic/Core/CoreEvents.h>
  10. #include <Atomic/IO/Log.h>
  11. #include <Atomic/IO/FileSystem.h>
  12. #include <Atomic/IO/File.h>
  13. #include <Atomic/Graphics/Graphics.h>
  14. #include <Atomic/Graphics/Camera.h>
  15. #include <Atomic/Graphics/Viewport.h>
  16. #include <Atomic/Graphics/Texture2D.h>
  17. #include <Atomic/Resource/XMLFile.h>
  18. #include <Atomic/Scene/Node.h>
  19. #include <ToolCore/ToolSystem.h>
  20. #include <ToolCore/Project/Project.h>
  21. #include "../Editors/SceneEditor3D/SceneEditor3DEvents.h"
  22. #include "../Editors/SceneEditor3D/SceneEditor3D.h"
  23. #include "CubemapGenerator.h"
  24. namespace AtomicEditor
  25. {
  26. CubemapGenerator::CubemapGenerator(Context *context) : EditorComponent(context),
  27. updateCycle_(0),
  28. imageSize_(256),
  29. namePrefix_("Cubemap")
  30. {
  31. }
  32. CubemapGenerator::~CubemapGenerator()
  33. {
  34. }
  35. void CubemapGenerator::Render()
  36. {
  37. if(!InitRender())
  38. {
  39. LOGERRORF("Unable to init render");
  40. return;
  41. }
  42. GetScene()->SendEvent(E_CUBEMAPRENDERBEGIN);
  43. SubscribeToEvent(E_BEGINFRAME, HANDLER(CubemapGenerator, HandleBeginFrame));
  44. SubscribeToEvent(E_ENDFRAME, HANDLER(CubemapGenerator, HandleEndFrame));
  45. }
  46. bool CubemapGenerator::InitPaths()
  47. {
  48. String scenePath = sceneEditor_->GetFullPath();
  49. String pathName;
  50. String fileName;
  51. String ext;
  52. SplitPath(scenePath, pathName, fileName, ext);
  53. outputPathAbsolute_ = pathName + "Cubemaps/" + fileName + "/";
  54. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  55. if (!fileSystem->DirExists(outputPathAbsolute_))
  56. {
  57. if (!fileSystem->CreateDirs(pathName, "Cubemaps/" + fileName + "/"))
  58. {
  59. LOGERRORF("CubemapGenerator::InitRender - Unable to create path: %s", outputPathAbsolute_.CString());
  60. return false;
  61. }
  62. }
  63. // TODO: There should be a better way of getting the resource path
  64. ToolSystem* tsystem = GetSubsystem<ToolSystem>();
  65. Project* project = tsystem->GetProject();
  66. resourcePath_ = outputPathAbsolute_;
  67. resourcePath_.Replace(project->GetResourcePath(), "");
  68. resourcePath_ = AddTrailingSlash(resourcePath_);
  69. return true;
  70. }
  71. bool CubemapGenerator::InitRender()
  72. {
  73. sceneEditor_ = GetSceneEditor();
  74. if (sceneEditor_.Null())
  75. {
  76. LOGERROR("CubemapGenerator::InitRender - unable to get scene editor");
  77. return false;
  78. }
  79. if (!InitPaths())
  80. return false;
  81. cameraNode_ = node_->CreateChild("CubeMapRenderCamera");
  82. cameraNode_->SetTemporary(true);
  83. camera_ = cameraNode_->CreateComponent<Camera>();
  84. camera_->SetTemporary(true);
  85. camera_->SetFov(90.0f);
  86. camera_->SetNearClip(0.0001f);
  87. camera_->SetAspectRatio(1.0f);
  88. RenderPath* renderPath = sceneEditor_->GetSceneView3D()->GetViewport()->GetRenderPath();
  89. viewport_ = new Viewport(context_, GetScene(), camera_, renderPath);
  90. renderImage_ = new Texture2D(context_);
  91. renderImage_->SetSize(imageSize_, imageSize_, Graphics::GetRGBAFormat(), TEXTURE_RENDERTARGET);
  92. renderSurface_ = renderImage_->GetRenderSurface();
  93. renderSurface_->SetViewport(0, viewport_);
  94. renderSurface_->SetUpdateMode(SURFACE_UPDATEALWAYS);
  95. return true;
  96. }
  97. void CubemapGenerator::SaveCubemapXML()
  98. {
  99. SharedPtr<XMLFile> xmlFile(new XMLFile(context_));
  100. XMLElement rootElem = xmlFile->CreateRoot("cubemap");
  101. String prefix = resourcePath_ + namePrefix_ + "_";
  102. String name = prefix + GetFaceName(FACE_POSITIVE_X) + ".png";
  103. rootElem.CreateChild("face").SetAttribute("name", name);
  104. name = prefix + GetFaceName(FACE_NEGATIVE_X) + ".png";
  105. rootElem.CreateChild("face").SetAttribute("name", name);
  106. name = prefix + GetFaceName(FACE_POSITIVE_Y) + ".png";
  107. rootElem.CreateChild("face").SetAttribute("name", name);
  108. name = prefix + GetFaceName(FACE_NEGATIVE_Y) + ".png";
  109. rootElem.CreateChild("face").SetAttribute("name", name);
  110. name = prefix + GetFaceName(FACE_POSITIVE_Z) + ".png";
  111. rootElem.CreateChild("face").SetAttribute("name", name);
  112. name = prefix + GetFaceName(FACE_NEGATIVE_Z) + ".png";
  113. rootElem.CreateChild("face").SetAttribute("name", name);
  114. String xmlPath = outputPathAbsolute_ + namePrefix_ + ".xml";
  115. SharedPtr<File> file(new File(context_, xmlPath, FILE_WRITE));
  116. xmlFile->Save(*file, " ");
  117. file->Close();
  118. }
  119. void CubemapGenerator::EndRender()
  120. {
  121. UnsubscribeFromEvent(E_BEGINFRAME);
  122. UnsubscribeFromEvent(E_ENDFRAME);
  123. SaveCubemapXML();
  124. cameraNode_->Remove();
  125. cameraNode_ = 0;
  126. camera_ = 0;
  127. viewport_ = 0;
  128. renderImage_ = 0;
  129. assert(renderSurface_->Refs() == 1);
  130. renderSurface_ = 0;
  131. updateCycle_ = 0;
  132. GetScene()->SendEvent(E_CUBEMAPRENDEREND);
  133. }
  134. void CubemapGenerator::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
  135. {
  136. updateCycle_++;
  137. if (updateCycle_ < 7)
  138. cameraNode_->SetWorldRotation(RotationOf(GetFaceForCycle(updateCycle_)));
  139. else
  140. {
  141. EndRender();
  142. }
  143. }
  144. void CubemapGenerator::HandleEndFrame(StringHash eventType, VariantMap& eventData)
  145. {
  146. SharedPtr<Image> image(GetImage(renderImage_));
  147. String path = outputPathAbsolute_;
  148. if (namePrefix_.Length())
  149. path += namePrefix_;
  150. path.AppendWithFormat("_%s.png", GetFaceName(GetFaceForCycle(updateCycle_)).CString());
  151. image->SavePNG(path);
  152. }
  153. SharedPtr<Image> CubemapGenerator::GetImage(Texture2D* tex2d)
  154. {
  155. Image* rawImage = new Image(tex2d->GetContext());
  156. const unsigned format = tex2d->GetFormat();
  157. if (format == Graphics::GetRGBAFormat() || format == Graphics::GetRGBA16Format() || format == Graphics::GetRGBAFloat32Format())
  158. rawImage->SetSize(tex2d->GetWidth(), tex2d->GetHeight(), 4);
  159. else if (format == Graphics::GetRGBFormat())
  160. rawImage->SetSize(tex2d->GetWidth(), tex2d->GetHeight(), 3);
  161. else
  162. return SharedPtr<Image>();
  163. tex2d->GetData(0, rawImage->GetData());
  164. return SharedPtr<Image>(rawImage);
  165. }
  166. CubeMapFace CubemapGenerator::GetFaceForCycle(int cycle)
  167. {
  168. switch (cycle)
  169. {
  170. case 1:
  171. return FACE_POSITIVE_X;
  172. case 2:
  173. return FACE_POSITIVE_Y;
  174. case 3:
  175. return FACE_POSITIVE_Z;
  176. case 4:
  177. return FACE_NEGATIVE_X;
  178. case 5:
  179. return FACE_NEGATIVE_Y;
  180. case 6:
  181. return FACE_NEGATIVE_Z;
  182. }
  183. return FACE_POSITIVE_X;
  184. }
  185. String CubemapGenerator::GetFaceName(CubeMapFace face)
  186. {
  187. switch (face)
  188. {
  189. case FACE_POSITIVE_X:
  190. return "PosX";
  191. case FACE_POSITIVE_Y:
  192. return "PosY";
  193. case FACE_POSITIVE_Z:
  194. return "PosZ";
  195. case FACE_NEGATIVE_X:
  196. return "NegX";
  197. case FACE_NEGATIVE_Y:
  198. return "NegY";
  199. case FACE_NEGATIVE_Z:
  200. return "NegZ";
  201. default:
  202. break;
  203. }
  204. return "PosX";
  205. }
  206. Quaternion CubemapGenerator::RotationOf(CubeMapFace face)
  207. {
  208. Quaternion result;
  209. switch (face)
  210. {
  211. // Rotate camera according to probe rotation
  212. case FACE_POSITIVE_X:
  213. result = Quaternion(0, 90, 0);
  214. break;
  215. case FACE_NEGATIVE_X:
  216. result = Quaternion(0, -90, 0);
  217. break;
  218. case FACE_POSITIVE_Y:
  219. result = Quaternion(-90, 0, 0);
  220. break;
  221. case FACE_NEGATIVE_Y:
  222. result = Quaternion(90, 0, 0);
  223. break;
  224. case FACE_POSITIVE_Z:
  225. result = Quaternion(0, 0, 0);
  226. break;
  227. case FACE_NEGATIVE_Z:
  228. result = Quaternion(0, 180, 0);
  229. break;
  230. default:
  231. break;
  232. }
  233. return result;
  234. }
  235. void CubemapGenerator::RegisterObject(Context* context)
  236. {
  237. context->RegisterFactory<CubemapGenerator>();
  238. ATTRIBUTE("Name Prefix", String, namePrefix_, "Cubemap", AM_DEFAULT);
  239. ATTRIBUTE("Image Size", int, imageSize_, 512, AM_DEFAULT);
  240. }
  241. }