CubemapGenerator.cpp 7.9 KB

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