CImage.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. #include <sstream>
  2. #include "CImage.h"
  3. using namespace WallpaperEngine;
  4. using namespace WallpaperEngine::Render::Objects;
  5. CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
  6. Render::CObject (scene, Type, image),
  7. m_image (image),
  8. m_animationTime (0.0),
  9. m_material (nullptr),
  10. m_colorBlendMaterial (nullptr),
  11. m_texture (nullptr),
  12. m_initialized (false),
  13. m_sceneSpacePosition (GL_NONE),
  14. m_copySpacePosition (GL_NONE),
  15. m_texcoordCopy (GL_NONE),
  16. m_texcoordPass (GL_NONE),
  17. m_passSpacePosition (GL_NONE),
  18. m_modelViewProjectionScreen (),
  19. m_modelViewProjectionCopy (),
  20. m_modelViewProjectionPass (glm::mat4 (1.0)),
  21. m_pos ()
  22. {
  23. auto projection = this->getScene ()->getScene ()->getOrthogonalProjection ();
  24. // get scene width and height to calculate positions
  25. auto scene_width = static_cast <float> (projection->getWidth ());
  26. auto scene_height = static_cast <float> (projection->getHeight ());
  27. glm::vec3 origin = this->getImage ()->getOrigin ();
  28. glm::vec2 size = this->getSize ();
  29. glm::vec3 scale = this->getImage ()->getScale ();
  30. glm::vec2 scaledSize = size * glm::vec2 (scale);
  31. // calculate the center and shift from there
  32. this->m_pos.x = origin.x - (scaledSize.x / 2);
  33. this->m_pos.w = origin.y + (scaledSize.y / 2);
  34. this->m_pos.z = origin.x + (scaledSize.x / 2);
  35. this->m_pos.y = origin.y - (scaledSize.y / 2);
  36. if (this->getImage ()->getAlignment ().find ("top") != std::string::npos)
  37. {
  38. this->m_pos.y -= scaledSize.y / 2;
  39. this->m_pos.w -= scaledSize.y / 2;
  40. }
  41. else if (this->getImage ()->getAlignment ().find ("bottom") != std::string::npos)
  42. {
  43. this->m_pos.y += scaledSize.y / 2;
  44. this->m_pos.w += scaledSize.y / 2;
  45. }
  46. if (this->getImage ()->getAlignment ().find ("left") != std::string::npos)
  47. {
  48. this->m_pos.x += scaledSize.x / 2;
  49. this->m_pos.z += scaledSize.x / 2;
  50. }
  51. else if (this->getImage ()->getAlignment ().find ("right") != std::string::npos)
  52. {
  53. this->m_pos.x -= scaledSize.x / 2;
  54. this->m_pos.z -= scaledSize.x / 2;
  55. }
  56. // wallpaper engine
  57. this->m_pos.x -= scene_width / 2;
  58. this->m_pos.y = scene_height / 2 - this->m_pos.y;
  59. this->m_pos.z -= scene_width / 2;
  60. this->m_pos.w = scene_height / 2 - this->m_pos.w;
  61. // detect texture (if any)
  62. auto textures = (*this->m_image->getMaterial ()->getPasses ().begin ())->getTextures ();
  63. if (!textures.empty())
  64. {
  65. std::string textureName = *textures.begin ();
  66. if (textureName.find ("_rt_") == 0)
  67. {
  68. this->m_texture = this->getScene ()->findFBO (textureName);
  69. }
  70. else
  71. {
  72. // get the first texture on the first pass (this one represents the image assigned to this object)
  73. this->m_texture = this->getContext ().resolveTexture (textureName);
  74. }
  75. }
  76. else
  77. {
  78. glm::vec2 realSize = size * glm::vec2 (scale);
  79. // TODO: create a dummy texture of correct size, fbo constructors should be enough, but this should be properly handled
  80. this->m_texture = new CFBO (
  81. "",
  82. ITexture::TextureFormat::ARGB8888,
  83. ITexture::TextureFlags::NoFlags,
  84. 1,
  85. realSize.x, realSize.y,
  86. realSize.x, realSize.y
  87. );
  88. }
  89. // register both FBOs into the scene
  90. std::ostringstream nameA, nameB;
  91. // TODO: determine when _rt_imageLayerComposite and _rt_imageLayerAlbedo is used
  92. nameA << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_a";
  93. nameB << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_b";
  94. this->m_currentMainFBO = this->m_mainFBO = scene->createFBO (
  95. nameA.str (),
  96. ITexture::TextureFormat::ARGB8888,
  97. this->m_texture->getFlags (),
  98. 1,
  99. this->m_texture->getRealWidth (), this->m_texture->getRealHeight (),
  100. this->m_texture->getRealWidth (), this->m_texture->getRealHeight ()
  101. );
  102. this->m_currentSubFBO = this->m_subFBO = scene->createFBO (
  103. nameB.str (),
  104. ITexture::TextureFormat::ARGB8888,
  105. this->m_texture->getFlags (),
  106. 1,
  107. this->m_texture->getRealWidth (), this->m_texture->getRealHeight (),
  108. this->m_texture->getRealWidth (), this->m_texture->getRealHeight ()
  109. );
  110. GLfloat realWidth = this->m_texture->getRealWidth ();
  111. GLfloat realHeight = this->m_texture->getRealHeight ();
  112. // build a list of vertices, these might need some change later (or maybe invert the camera)
  113. GLfloat sceneSpacePosition [] = {
  114. this->m_pos.x, this->m_pos.y, 0.0f,
  115. this->m_pos.x, this->m_pos.w, 0.0f,
  116. this->m_pos.z, this->m_pos.y, 0.0f,
  117. this->m_pos.z, this->m_pos.y, 0.0f,
  118. this->m_pos.x, this->m_pos.w, 0.0f,
  119. this->m_pos.z, this->m_pos.w, 0.0f
  120. };
  121. GLfloat copySpacePosition [] = {
  122. 0.0, realHeight, 0.0f,
  123. 0.0, 0.0, 0.0f,
  124. realWidth, realHeight, 0.0f,
  125. realWidth, realHeight, 0.0f,
  126. 0.0, 0.0, 0.0f,
  127. realWidth, 0.0, 0.0f
  128. };
  129. GLfloat passSpacePosition [] = {
  130. -1.0, 1.0, 0.0f,
  131. -1.0, -1.0, 0.0f,
  132. 1.0, 1.0, 0.0f,
  133. 1.0, 1.0, 0.0f,
  134. -1.0, -1.0, 0.0f,
  135. 1.0, -1.0, 0.0f
  136. };
  137. float width = 1.0f;
  138. float height = 1.0f;
  139. if (this->getTexture ()->isAnimated ())
  140. {
  141. // animated images use different coordinates as they're essentially a texture atlas
  142. width = static_cast<float> (this->getTexture ()->getRealWidth ()) / static_cast<float> (this->getTexture ()->getTextureWidth ());
  143. height = static_cast<float> (this->getTexture ()->getRealHeight ()) / static_cast<float> (this->getTexture ()->getTextureHeight ());
  144. }
  145. // calculate the correct texCoord limits for the texture based on the texture screen size and real size
  146. else if (this->getTexture () != nullptr &&
  147. (this->getTexture ()->getTextureWidth () != this->getTexture ()->getRealWidth () ||
  148. this->getTexture ()->getTextureHeight () != this->getTexture ()->getRealHeight ())
  149. )
  150. {
  151. uint32_t x = 1;
  152. uint32_t y = 1;
  153. while (x < size.x) x <<= 1;
  154. while (y < size.y) y <<= 1;
  155. width = scaledSize.x / x;
  156. height = scaledSize.y / y;
  157. }
  158. float x = 0.0f;
  159. float y = 0.0f;
  160. if (this->getTexture ()->isAnimated ())
  161. {
  162. // animations should be copied completely
  163. x = 0.0f;
  164. y = 0.0f;
  165. width = 1.0f;
  166. height = 1.0f;
  167. }
  168. GLfloat texcoordCopy [] = {
  169. x, height,
  170. x, y,
  171. width, height,
  172. width, height,
  173. x, y,
  174. width, y
  175. };
  176. GLfloat texcoordPass [] = {
  177. 0.0f, 1.0f,
  178. 0.0f, 0.0f,
  179. 1.0f, 1.0f,
  180. 1.0f, 1.0f,
  181. 0.0f, 0.0f,
  182. 1.0f, 0.0f
  183. };
  184. // bind vertex list to the openGL buffers
  185. glGenBuffers (1, &this->m_sceneSpacePosition);
  186. glBindBuffer (GL_ARRAY_BUFFER, this->m_sceneSpacePosition);
  187. glBufferData (GL_ARRAY_BUFFER, sizeof (sceneSpacePosition), sceneSpacePosition, GL_STATIC_DRAW);
  188. glGenBuffers (1, &this->m_copySpacePosition);
  189. glBindBuffer (GL_ARRAY_BUFFER, this->m_copySpacePosition);
  190. glBufferData (GL_ARRAY_BUFFER, sizeof (copySpacePosition), copySpacePosition, GL_STATIC_DRAW);
  191. // bind pass' vertex list to the openGL buffers
  192. glGenBuffers (1, &this->m_passSpacePosition);
  193. glBindBuffer (GL_ARRAY_BUFFER, this->m_passSpacePosition);
  194. glBufferData (GL_ARRAY_BUFFER, sizeof (passSpacePosition), passSpacePosition, GL_STATIC_DRAW);
  195. glGenBuffers (1, &this->m_texcoordCopy);
  196. glBindBuffer (GL_ARRAY_BUFFER, this->m_texcoordCopy);
  197. glBufferData (GL_ARRAY_BUFFER, sizeof (texcoordCopy), texcoordCopy, GL_STATIC_DRAW);
  198. glGenBuffers (1, &this->m_texcoordPass);
  199. glBindBuffer (GL_ARRAY_BUFFER, this->m_texcoordPass);
  200. glBufferData (GL_ARRAY_BUFFER, sizeof (texcoordPass), texcoordPass, GL_STATIC_DRAW);
  201. this->m_modelViewProjectionScreen =
  202. this->getScene ()->getCamera ()->getProjection () *
  203. this->getScene ()->getCamera ()->getLookAt ();
  204. this->m_modelViewProjectionCopy = glm::ortho <float> (0.0, size.x, 0.0, size.y);
  205. }
  206. void CImage::setup ()
  207. {
  208. // do not double-init stuff, that's bad!
  209. if (this->m_initialized)
  210. return;
  211. // TODO: SUPPORT PASSTHROUGH (IT'S A SHADER)
  212. {
  213. // generate the main material used to render the image
  214. this->m_material = new Effects::CMaterial (
  215. new CEffect (this, new Core::Objects::CEffect ("", "", "", "", this->m_image, Core::UserSettings::CUserSettingBoolean::fromScalar (true))),
  216. this->m_image->getMaterial ()
  217. );
  218. // add blendmode to the combos
  219. for (const auto& cur : this->m_material->getPasses ())
  220. this->m_passes.push_back (cur);
  221. }
  222. // prepare the passes list
  223. if (!this->getImage ()->getEffects ().empty ())
  224. {
  225. // generate the effects used by this material
  226. for (const auto& cur : this->getImage ()->getEffects ())
  227. {
  228. auto effect = new CEffect (this, cur);
  229. for (const auto& material : effect->getMaterials ())
  230. for (const auto& pass : material->getPasses ())
  231. this->m_passes.push_back (pass);
  232. this->m_effects.push_back (effect);
  233. }
  234. }
  235. if (this->m_image->getColorBlendMode () > 0)
  236. {
  237. auto material = Core::Objects::Images::CMaterial::fromFile ("materials/util/effectpassthrough.json", this->getContainer ());
  238. // effectpasshthrough only has one pass
  239. (*material->getPasses ().begin ())->insertCombo ("BLENDMODE", this->m_image->getColorBlendMode ());
  240. // generate the main material used to render the image
  241. this->m_colorBlendMaterial = new Effects::CMaterial(
  242. new CEffect (this, new Core::Objects::CEffect ("", "", "", "", this->m_image, Core::UserSettings::CUserSettingBoolean::fromScalar (true))),
  243. material
  244. );
  245. // add blendmode to the combos
  246. for (const auto& cur : this->m_colorBlendMaterial->getPasses ())
  247. this->m_passes.push_back (cur);
  248. }
  249. // if there's more than one pass the blendmode has to be moved from the beginning to the end
  250. if (this->m_passes.size () > 1)
  251. {
  252. auto first = this->m_passes.begin ();
  253. auto last = this->m_passes.rbegin ();
  254. (*last)->getPass ()->setBlendingMode ((*first)->getPass ()->getBlendingMode ());
  255. (*first)->getPass ()->setBlendingMode ("normal");
  256. }
  257. // calculate full animation time (if any)
  258. this->m_animationTime = 0.0f;
  259. for (const auto& cur : this->getTexture ()->getFrames ())
  260. this->m_animationTime += cur->frametime;
  261. this->setupPasses ();
  262. this->m_initialized = true;
  263. }
  264. void CImage::setupPasses ()
  265. {
  266. // do a pass on everything and setup proper inputs and values
  267. const CFBO* drawTo = this->m_currentMainFBO;
  268. const ITexture* asInput = this->getTexture ();
  269. GLuint texcoord = this->getTexCoordCopy ();
  270. auto cur = this->m_passes.begin ();
  271. auto end = this->m_passes.end ();
  272. bool first = true;
  273. for (; cur != end; cur ++)
  274. {
  275. // TODO: PROPERLY CHECK EFFECT'S VISIBILITY AND TAKE IT INTO ACCOUNT
  276. Effects::CPass* pass = *cur;
  277. const CFBO* prevDrawTo = drawTo;
  278. GLuint spacePosition = (first) ? this->getCopySpacePosition () : this->getPassSpacePosition ();
  279. glm::mat4* projection = (first) ? &this->m_modelViewProjectionCopy : &this->m_modelViewProjectionPass;
  280. first = false;
  281. // set viewport and target texture if needed
  282. if (pass->getMaterial ()->getMaterial ()->hasTarget ())
  283. {
  284. // setup target texture
  285. std::string target = pass->getMaterial ()->getMaterial ()->getTarget ();
  286. drawTo = pass->getMaterial ()->getEffect ()->findFBO (target);
  287. // spacePosition = this->getPassSpacePosition ();
  288. // not a local fbo, try to find a scene fbo with the same name
  289. if (drawTo == nullptr)
  290. // this one throws if no fbo was found
  291. drawTo = this->getScene ()->findFBO (target);
  292. }
  293. // determine if it's the last element in the list as this is a screen-copy-like process
  294. else if (std::next (cur) == end && this->getImage ()->isVisible ())
  295. {
  296. // TODO: PROPERLY CHECK EFFECT'S VISIBILITY AND TAKE IT INTO ACCOUNT
  297. spacePosition = this->getSceneSpacePosition ();
  298. drawTo = this->getScene ()->getFBO ();
  299. projection = &this->m_modelViewProjectionScreen;
  300. }
  301. pass->setDestination (drawTo);
  302. pass->setInput (asInput);
  303. pass->setPosition (spacePosition);
  304. pass->setTexCoord (texcoord);
  305. pass->setModelViewProjectionMatrix (projection);
  306. texcoord = this->getTexCoordPass ();
  307. drawTo = prevDrawTo;
  308. if (!pass->getMaterial ()->getMaterial ()->hasTarget ())
  309. this->pinpongFramebuffer (&drawTo, &asInput);
  310. }
  311. }
  312. void CImage::pinpongFramebuffer (const CFBO** drawTo, const ITexture** asInput)
  313. {
  314. // temporarily store FBOs used
  315. CFBO* currentMainFBO = this->m_currentMainFBO;
  316. CFBO* currentSubFBO = this->m_currentSubFBO;
  317. if (drawTo != nullptr)
  318. *drawTo = currentSubFBO;
  319. if (asInput != nullptr)
  320. *asInput = currentMainFBO;
  321. // swap the FBOs
  322. this->m_currentMainFBO = currentSubFBO;
  323. this->m_currentSubFBO = currentMainFBO;
  324. }
  325. void CImage::render ()
  326. {
  327. // do not try to render something that did not initialize successfully
  328. if (!this->m_initialized)
  329. return;
  330. glColorMask (true, true, true, true);
  331. // update the position if required
  332. if (this->getScene ()->getScene ()->isCameraParallax ())
  333. this->updateScreenSpacePosition ();
  334. #if !NDEBUG
  335. std::string str = "Rendering ";
  336. if (this->getScene ()->getScene ()->isBloom () && this->getId () == 0xFFFFFFFF)
  337. str += "bloom";
  338. else
  339. {
  340. str += this->getImage ()->getName () +
  341. " (" + std::to_string (this->getId ()) + ", " + this->getImage ()->getMaterial ()->getName () + ")";
  342. }
  343. glPushDebugGroup (GL_DEBUG_SOURCE_APPLICATION, 0, -1, str.c_str ());
  344. #endif /* DEBUG */
  345. auto cur = this->m_passes.begin ();
  346. auto end = this->m_passes.end ();
  347. for (; cur != end; cur ++)
  348. {
  349. // TODO: PROPERLY CHECK EFFECT'S VISIBILITY AND TAKE IT INTO ACCOUNT
  350. if (std::next (cur) == end)
  351. glColorMask (true, true, true, false);
  352. (*cur)->render ();
  353. }
  354. #if !NDEBUG
  355. glPopDebugGroup ();
  356. #endif /* DEBUG */
  357. }
  358. void CImage::updateScreenSpacePosition ()
  359. {
  360. double parallaxAmount = this->getScene ()->getScene ()->getCameraParallaxAmount ();
  361. glm::vec2 depth = this->getImage ()->getParallaxDepth ();
  362. glm::vec2* displacement = this->getScene ()->getParallaxDisplacement ();
  363. // no need to update if the depth is 0
  364. if (depth.x == 0.0 && depth.y == 0.0)
  365. return;
  366. float x = (depth.x + parallaxAmount) * displacement->x * this->getSize ().x;
  367. float y = (depth.y + parallaxAmount) * displacement->y * this->getSize ().x;
  368. this->m_modelViewProjectionScreen =
  369. glm::translate (
  370. this->getScene ()->getCamera ()->getProjection () *
  371. this->getScene ()->getCamera ()->getLookAt (),
  372. {x, y, 0.0f}
  373. );
  374. }
  375. const ITexture* CImage::getTexture () const
  376. {
  377. return this->m_texture;
  378. }
  379. double CImage::getAnimationTime () const
  380. {
  381. return this->m_animationTime;
  382. }
  383. const Core::Objects::CImage* CImage::getImage () const
  384. {
  385. return this->m_image;
  386. }
  387. const std::vector<CEffect*>& CImage::getEffects () const
  388. {
  389. return this->m_effects;
  390. }
  391. glm::vec2 CImage::getSize() const
  392. {
  393. if (this->m_texture == nullptr)
  394. return this->getImage ()->getSize ();
  395. return {this->m_texture->getRealWidth (), this->m_texture->getRealHeight ()};
  396. }
  397. GLuint CImage::getSceneSpacePosition () const
  398. {
  399. return this->m_sceneSpacePosition;
  400. }
  401. GLuint CImage::getCopySpacePosition () const
  402. {
  403. return this->m_copySpacePosition;
  404. }
  405. GLuint CImage::getPassSpacePosition () const
  406. {
  407. return this->m_passSpacePosition;
  408. }
  409. GLuint CImage::getTexCoordCopy () const
  410. {
  411. return this->m_texcoordCopy;
  412. }
  413. GLuint CImage::getTexCoordPass () const
  414. {
  415. return this->m_texcoordPass;
  416. }
  417. const std::string CImage::Type = "image";