CScene.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #include "WallpaperEngine/Core/Objects/CImage.h"
  2. #include "WallpaperEngine/Core/Objects/CSound.h"
  3. #include "WallpaperEngine/Render/Objects/CImage.h"
  4. #include "WallpaperEngine/Render/Objects/CSound.h"
  5. #include "CScene.h"
  6. using namespace WallpaperEngine;
  7. using namespace WallpaperEngine::Render;
  8. CScene::CScene (Core::CScene* scene, CContext* context) :
  9. CWallpaper (scene, Type, context)
  10. {
  11. // setup the scene camera
  12. this->m_camera = new CCamera (this, scene->getCamera ());
  13. // detect size if the orthogonal project is auto
  14. if (scene->getOrthogonalProjection ()->isAuto () == true)
  15. {
  16. // calculate the size of the projection based on the size of everything
  17. auto cur = scene->getObjects ().begin ();
  18. auto end = scene->getObjects ().end ();
  19. for (; cur != end; cur ++)
  20. {
  21. if ((*cur).second->is<Core::Objects::CImage> () == false)
  22. continue;
  23. glm::vec2 size = (*cur).second->as <Core::Objects::CImage> ()->getSize ();
  24. scene->getOrthogonalProjection ()->setWidth (size.x);
  25. scene->getOrthogonalProjection ()->setHeight (size.y);
  26. }
  27. }
  28. this->m_parallaxDisplacement = {0, 0};
  29. this->m_camera->setOrthogonalProjection (
  30. scene->getOrthogonalProjection ()->getWidth (),
  31. scene->getOrthogonalProjection ()->getHeight ()
  32. );
  33. // set clear color
  34. FloatColor clearColor = this->getScene ()->getClearColor ();
  35. glClearColor (clearColor.r, clearColor.g, clearColor.b, 1.0f);
  36. // setup framebuffers
  37. this->setupFramebuffers ();
  38. // create all objects based off their dependencies
  39. {
  40. auto cur = scene->getObjects ().begin ();
  41. auto end = scene->getObjects ().end ();
  42. for (; cur != end; cur++)
  43. this->createObject ((*cur).second);
  44. }
  45. // now setup the render order
  46. auto cur = scene->getObjectsByRenderOrder ().begin ();
  47. auto end = scene->getObjectsByRenderOrder ().end ();
  48. for (; cur != end; cur ++)
  49. {
  50. auto obj = this->m_objects.find ((*cur)->getId ());
  51. // ignores not created objects like particle systems
  52. if (obj == this->m_objects.end ())
  53. continue;
  54. this->m_objectsByRenderOrder.emplace_back ((*obj).second);
  55. }
  56. uint32_t sceneWidth = scene->getOrthogonalProjection ()->getWidth ();
  57. uint32_t sceneHeight = scene->getOrthogonalProjection ()->getHeight ();
  58. // create extra framebuffers for the bloom effect
  59. this->_rt_4FrameBuffer = this->createFBO (
  60. "_rt_4FrameBuffer",
  61. ITexture::TextureFormat::ARGB8888,
  62. ITexture::TextureFlags::NoInterpolation,
  63. 1.0,
  64. sceneWidth / 4, sceneHeight / 4,
  65. sceneWidth / 4, sceneHeight / 4
  66. );
  67. this->_rt_8FrameBuffer = this->createFBO (
  68. "_rt_8FrameBuffer",
  69. ITexture::TextureFormat::ARGB8888,
  70. ITexture::TextureFlags::NoInterpolation,
  71. 1.0,
  72. sceneWidth / 8, sceneHeight / 8,
  73. sceneWidth / 8, sceneHeight / 8
  74. );
  75. this->_rt_Bloom = this->createFBO (
  76. "_rt_Bloom",
  77. ITexture::TextureFormat::ARGB8888,
  78. ITexture::TextureFlags::NoInterpolation,
  79. 1.0,
  80. sceneWidth / 8, sceneHeight / 8,
  81. sceneWidth / 8, sceneHeight / 8
  82. );
  83. this->_rt_FullFrameBuffer_b = this->createFBO (
  84. "_rt_FullFrameBuffer_b",
  85. ITexture::TextureFormat::ARGB8888,
  86. ITexture::TextureFlags::NoInterpolation,
  87. 1.0,
  88. sceneWidth, sceneHeight,
  89. sceneWidth, sceneHeight
  90. );
  91. //
  92. // Had to get a little creative with the effects to achieve the same bloom effect without any custom code
  93. // this custom image loads some effect files from the virtual container to achieve the same bloom effect
  94. // this approach requires of two extra draw calls due to the way the effect works in official WPE
  95. // (it renders directly to the screen, whereas here we never do that from a scene)
  96. //
  97. std::string imagejson =
  98. "{"
  99. "\t\"image\": \"models/wpenginelinux.json\","
  100. "\t\"name\": \"bloomimagewpenginelinux\","
  101. "\t\"visible\": true,"
  102. "\t\"scale\": \"1.0 1.0 1.0\","
  103. "\t\"angles\": \"0.0 0.0 0.0\","
  104. "\t\"origin\": \"" + std::to_string (sceneWidth / 2) + " " + std::to_string (sceneHeight / 2) + " 0.0\","
  105. "\t\"id\": " + std::to_string (0xFFFFFFFF) + ","
  106. "\t\"effects\":"
  107. "\t["
  108. "\t\t{"
  109. "\t\t\t\"file\": \"effects/wpenginelinux/bloomeffect.json\","
  110. "\t\t\t\"id\": 15242000,"
  111. "\t\t\t\"name\": \"\","
  112. "\t\t\t\"passes\":"
  113. "\t\t\t["
  114. "\t\t\t\t{"
  115. "\t\t\t\t\t\"constantshadervalues\":"
  116. "\t\t\t\t\t{"
  117. "\t\t\t\t\t\t\"bloomstrength\": " + std::to_string (this->getScene ()->getBloomStrength ()) + ","
  118. "\t\t\t\t\t\t\"bloomthreshold\": " + std::to_string (this->getScene ()->getBloomThreshold ()) +
  119. "\t\t\t\t\t}"
  120. "\t\t\t\t},"
  121. "\t\t\t\t{"
  122. "\t\t\t\t\t\"constantshadervalues\":"
  123. "\t\t\t\t\t{"
  124. "\t\t\t\t\t\t\"bloomstrength\": " + std::to_string (this->getScene ()->getBloomStrength ()) + ","
  125. "\t\t\t\t\t\t\"bloomthreshold\": " + std::to_string (this->getScene ()->getBloomThreshold ()) +
  126. "\t\t\t\t\t}"
  127. "\t\t\t\t},"
  128. "\t\t\t\t{"
  129. "\t\t\t\t\t\"constantshadervalues\":"
  130. "\t\t\t\t\t{"
  131. "\t\t\t\t\t\t\"bloomstrength\": " + std::to_string (this->getScene ()->getBloomStrength ()) + ","
  132. "\t\t\t\t\t\t\"bloomthreshold\": " + std::to_string (this->getScene ()->getBloomThreshold ()) +
  133. "\t\t\t\t\t}"
  134. "\t\t\t\t}"
  135. "\t\t\t]"
  136. "\t\t}"
  137. "\t],"
  138. "\t\"size\": \"" + std::to_string (sceneWidth) + " " + std::to_string (sceneHeight) + "\""
  139. "}";
  140. auto json = nlohmann::json::parse (imagejson);
  141. // create image for bloom passes
  142. auto bloomPass = this->createObject (
  143. WallpaperEngine::Core::CObject::fromJSON (
  144. json, this->getContainer ()
  145. )
  146. );
  147. if (this->getScene ()->isBloom () == true)
  148. this->m_objectsByRenderOrder.emplace_back (bloomPass);
  149. }
  150. Render::CObject* CScene::createObject (Core::CObject* object)
  151. {
  152. Render::CObject* renderObject = nullptr;
  153. // ensure the item is not loaded already
  154. auto current = this->m_objects.find (object->getId ());
  155. if (current != this->m_objects.end ())
  156. return (*current).second;
  157. // check dependencies too!
  158. auto depCur = object->getDependencies ().begin ();
  159. auto depEnd = object->getDependencies ().end ();
  160. for (; depCur != depEnd; depCur ++)
  161. {
  162. // self-dependency is a possibility...
  163. if ((*depCur) == object->getId ())
  164. continue;
  165. auto dep = this->getScene ()->getObjects ().find (*depCur);
  166. if (dep != this->getScene ()->getObjects ().end ())
  167. this->createObject ((*dep).second);
  168. }
  169. if (object->is<Core::Objects::CImage>() == true)
  170. {
  171. Objects::CImage* image = new Objects::CImage (this, object->as<Core::Objects::CImage>());
  172. try
  173. {
  174. image->setup ();
  175. }
  176. catch (std::runtime_error ex)
  177. {
  178. std::cerr << "Cannot setup image resource: " << std::endl;
  179. std::cerr << ex.what () << std::endl;
  180. }
  181. renderObject = image;
  182. }
  183. else if (object->is<Core::Objects::CSound>() == true)
  184. {
  185. renderObject = new Objects::CSound (this, object->as<Core::Objects::CSound>());
  186. }
  187. if (renderObject != nullptr)
  188. this->m_objects.insert (std::make_pair (renderObject->getId (), renderObject));
  189. return renderObject;
  190. }
  191. CCamera* CScene::getCamera () const
  192. {
  193. return this->m_camera;
  194. }
  195. void CScene::renderFrame (glm::ivec4 viewport)
  196. {
  197. auto projection = this->getScene ()->getOrthogonalProjection ();
  198. auto cur = this->m_objectsByRenderOrder.begin ();
  199. auto end = this->m_objectsByRenderOrder.end ();
  200. // ensure the virtual mouse position is up to date
  201. this->updateMouse (viewport);
  202. // update the parallax position if required
  203. if (this->getScene ()->isCameraParallax () == true)
  204. {
  205. float influence = this->getScene ()->getCameraParallaxMouseInfluence ();
  206. float amount = this->getScene ()->getCameraParallaxAmount ();
  207. float delay = this->getScene ()->getCameraParallaxDelay ();
  208. this->m_parallaxDisplacement.x = glm::mix (this->m_parallaxDisplacement.x, (this->m_mousePosition.x * amount) * influence, delay);
  209. this->m_parallaxDisplacement.y = glm::mix (this->m_parallaxDisplacement.y, (this->m_mousePosition.y * amount) * influence, delay);
  210. }
  211. // use the scene's framebuffer by default
  212. glBindFramebuffer (GL_FRAMEBUFFER, this->getWallpaperFramebuffer());
  213. // ensure we render over the whole screen
  214. glViewport (0, 0, projection->getWidth (), projection->getHeight ());
  215. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  216. for (; cur != end; cur ++)
  217. (*cur)->render ();
  218. }
  219. void CScene::updateMouse (glm::ivec4 viewport)
  220. {
  221. // update virtual mouse position first
  222. CMouseInput* mouse = this->getContext ()->getMouse ();
  223. // TODO: PROPERLY TRANSLATE THESE TO WHAT'S VISIBLE ON SCREEN (FOR BACKGROUNDS THAT DO NOT EXACTLY FIT ON SCREEN)
  224. this->m_mousePosition.x = glm::clamp ((mouse->position.x - viewport.x) / viewport.z, 0.0, 1.0);
  225. this->m_mousePosition.y = glm::clamp ((mouse->position.y - viewport.y) / viewport.w, 0.0, 1.0);
  226. // screen-space positions have to be transposed to what the screen will actually show
  227. }
  228. Core::CScene* CScene::getScene ()
  229. {
  230. return this->getWallpaperData ()->as<Core::CScene> ();
  231. }
  232. glm::vec2* CScene::getMousePosition ()
  233. {
  234. return &this->m_mousePosition;
  235. }
  236. glm::vec2* CScene::getParallaxDisplacement ()
  237. {
  238. return &this->m_parallaxDisplacement;
  239. }
  240. const std::string CScene::Type = "scene";