CImage.cpp 16 KB

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