CImage.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. {
  10. auto projection = this->getScene ()->getScene ()->getOrthogonalProjection ();
  11. // get scene width and height to calculate positions
  12. auto scene_width = static_cast <float> (projection->getWidth ());
  13. auto scene_height = static_cast <float> (projection->getHeight ());
  14. glm::vec3 origin = this->getImage ()->getOrigin ();
  15. glm::vec2 size = this->getSize ();
  16. glm::vec3 scale = this->getImage ()->getScale ();
  17. float xleft = 0.0f;
  18. float ytop = 0.0f;
  19. float xright = 0.0f;
  20. float ybottom = 0.0f;
  21. // TODO: TAKE INTO ACCOUNT SCALE
  22. // depending on the alignment these values might change, for now just support center
  23. if (this->getImage ()->getAlignment () == "center")
  24. {
  25. // calculate the real position of the image
  26. xleft = (-scene_width / 2) + (origin.x - (size.x / 2));
  27. xright = (-scene_width / 2) + (origin.x + (size.x / 2));
  28. ytop = (-scene_height / 2) + origin.y + (size.y / 2);
  29. ybottom = (-scene_height / 2) + (origin.y - (size.y / 2));
  30. }
  31. else
  32. {
  33. throw std::runtime_error ("Only centered images are supported for now!");
  34. }
  35. std::string textureName = (*(*this->m_image->getMaterial ()->getPasses ().begin ())->getTextures ().begin ());
  36. if (textureName.find ("_rt_") == 0)
  37. {
  38. this->m_texture = this->getScene ()->findFBO (textureName);
  39. }
  40. else
  41. {
  42. // get the first texture on the first pass (this one represents the image assigned to this object)
  43. this->m_texture = this->getScene ()->getContainer ()->readTexture (textureName);
  44. }
  45. // register both FBOs into the scene
  46. std::ostringstream nameA, nameB;
  47. nameA << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_a";
  48. nameB << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_b";
  49. this->m_currentMainFBO = this->m_mainFBO = scene->createFBO (nameB.str (), ITexture::TextureFormat::ARGB8888, 1, this->m_texture->getRealWidth (), this->m_texture->getRealHeight (), this->m_texture->getRealWidth (), this->m_texture->getRealHeight ());
  50. this->m_currentSubFBO = this->m_subFBO = scene->createFBO (nameA.str (), ITexture::TextureFormat::ARGB8888, 1, this->m_texture->getRealWidth (), this->m_texture->getRealHeight (), this->m_texture->getRealWidth (), this->m_texture->getRealHeight ());
  51. GLfloat realWidth = this->m_texture->getRealWidth () / 2;
  52. GLfloat realHeight = this->m_texture->getRealHeight () / 2;
  53. // build a list of vertices, these might need some change later (or maybe invert the camera)
  54. GLfloat sceneSpacePosition [] = {
  55. xleft, ytop, 0.0f,
  56. xright, ytop, 0.0f,
  57. xleft, ybottom, 0.0f,
  58. xleft, ybottom, 0.0f,
  59. xright, ytop, 0.0f,
  60. xright, ybottom, 0.0f
  61. };
  62. GLfloat copySpacePosition [] = {
  63. -realWidth, -realHeight, 0.0f,
  64. realWidth, -realHeight, 0.0f,
  65. -realWidth, realHeight, 0.0f,
  66. -realWidth, realHeight, 0.0f,
  67. realWidth, -realHeight, 0.0f,
  68. realWidth, realHeight, 0.0f
  69. };
  70. GLfloat passSpacePosition [] = {
  71. -1.0f, -1.0f, 0.0f,
  72. 1.0f, -1.0f, 0.0f,
  73. -1.0f, 1.0f, 0.0f,
  74. -1.0f, 1.0f, 0.0f,
  75. 1.0f, -1.0f, 0.0f,
  76. 1.0f, 1.0f, 0.0f
  77. };
  78. float width = 1.0f;
  79. float height = 1.0f;
  80. // calculate the correct texCoord limits for the texture based on the texture screen size and real size
  81. if (this->getTexture () != nullptr &&
  82. (this->getTexture ()->getTextureWidth () != this->getTexture ()->getRealWidth () ||
  83. this->getTexture ()->getTextureHeight () != this->getTexture ()->getRealHeight ())
  84. )
  85. {
  86. uint32_t x = 1;
  87. uint32_t y = 1;
  88. while (x < size.x) x <<= 1;
  89. while (y < size.y) y <<= 1;
  90. width = size.x * scale.x / x;
  91. height = size.y * scale.y / y;
  92. }
  93. GLfloat texcoordCopy [] = {
  94. 0.0f, 0.0f,
  95. width, 0.0f,
  96. 0.0f, height,
  97. 0.0f, height,
  98. width, 0.0f,
  99. width, height
  100. };
  101. GLfloat texcoordPass [] = {
  102. 0.0f, 0.0f,
  103. 1.0f, 0.0f,
  104. 0.0f, 1.0f,
  105. 0.0f, 1.0f,
  106. 1.0f, 0.0f,
  107. 1.0f, 1.0f
  108. };
  109. // bind vertex list to the openGL buffers
  110. glGenBuffers (1, &this->m_sceneSpacePosition);
  111. glBindBuffer (GL_ARRAY_BUFFER, this->m_sceneSpacePosition);
  112. glBufferData (GL_ARRAY_BUFFER, sizeof (sceneSpacePosition), sceneSpacePosition, GL_STATIC_DRAW);
  113. glGenBuffers (1, &this->m_copySpacePosition);
  114. glBindBuffer (GL_ARRAY_BUFFER, this->m_copySpacePosition);
  115. glBufferData (GL_ARRAY_BUFFER, sizeof (copySpacePosition), copySpacePosition, GL_STATIC_DRAW);
  116. // bind pass' vertex list to the openGL buffers
  117. glGenBuffers (1, &this->m_passSpacePosition);
  118. glBindBuffer (GL_ARRAY_BUFFER, this->m_passSpacePosition);
  119. glBufferData (GL_ARRAY_BUFFER, sizeof (passSpacePosition), passSpacePosition, GL_STATIC_DRAW);
  120. glGenBuffers (1, &this->m_texcoordCopy);
  121. glBindBuffer (GL_ARRAY_BUFFER, this->m_texcoordCopy);
  122. glBufferData (GL_ARRAY_BUFFER, sizeof (texcoordCopy), texcoordCopy, GL_STATIC_DRAW);
  123. glGenBuffers (1, &this->m_texcoordPass);
  124. glBindBuffer (GL_ARRAY_BUFFER, this->m_texcoordPass);
  125. glBufferData (GL_ARRAY_BUFFER, sizeof (texcoordPass), texcoordPass, GL_STATIC_DRAW);
  126. this->m_modelViewProjectionScreen =
  127. this->getScene ()->getCamera ()->getProjection () *
  128. this->getScene ()->getCamera ()->getLookAt () *
  129. glm::scale (glm::mat4 (1.0f), scale);
  130. this->m_modelViewProjectionPass =
  131. glm::ortho<float> (-size.x / 2, size.x / 2, -size.y / 2, size.y / 2, 0, 10000);
  132. }
  133. void CImage::setup ()
  134. {
  135. // generate the main material used to copy the image to the correct texture
  136. this->m_copyMaterial = new Effects::CMaterial (
  137. new CEffect (this, new Core::Objects::CEffect ("", "", "", "", this->m_image)),
  138. this->m_image->getMaterial ()
  139. );
  140. // generate the main material used to render the image
  141. this->m_material = new Effects::CMaterial (
  142. new CEffect (this, new Core::Objects::CEffect ("", "", "", "", this->m_image)),
  143. this->m_image->getMaterial ()
  144. );
  145. // generate the effects used by this material
  146. auto cur = this->getImage ()->getEffects ().begin ();
  147. auto end = this->getImage ()->getEffects ().end ();
  148. for (; cur != end; cur ++)
  149. this->m_effects.emplace_back (new CEffect (this, *cur));
  150. }
  151. void CImage::pinpongFramebuffer (CFBO** drawTo, ITexture** asInput)
  152. {
  153. // temporarily store FBOs used
  154. CFBO* currentMainFBO = this->m_currentMainFBO;
  155. CFBO* currentSubFBO = this->m_currentSubFBO;
  156. if (drawTo != nullptr)
  157. *drawTo = currentSubFBO;
  158. if (asInput != nullptr)
  159. *asInput = currentMainFBO;
  160. // swap the FBOs
  161. this->m_currentMainFBO = currentSubFBO;
  162. this->m_currentSubFBO = currentMainFBO;
  163. }
  164. void CImage::simpleRender ()
  165. {
  166. // first render to the composite layer
  167. auto cur = this->m_copyMaterial->getPasses ().begin ();
  168. auto end = this->m_copyMaterial->getPasses ().end ();
  169. for (; cur != end; cur ++)
  170. (*cur)->render (this->m_mainFBO, this->getTexture (), *this->getCopySpacePosition (), *this->getTexCoordCopy (), this->m_modelViewProjectionPass);
  171. // a simple material renders directly to the screen
  172. cur = this->m_material->getPasses ().begin ();
  173. end = this->m_material->getPasses ().end ();
  174. for (; cur != end; cur ++)
  175. (*cur)->render (this->getScene ()->getFBO (), this->m_mainFBO, *this->getSceneSpacePosition (), *this->getTexCoordPass (), this->m_modelViewProjectionScreen);
  176. }
  177. void CImage::complexRender ()
  178. {
  179. // start drawing to the main framebuffer
  180. CFBO* drawTo = this->m_mainFBO;
  181. ITexture* asInput = this->getTexture ();
  182. // do the first pass render into the main framebuffer
  183. auto cur = this->m_copyMaterial->getPasses ().begin ();
  184. auto end = this->m_copyMaterial->getPasses ().end ();
  185. for (; cur != end; cur ++)
  186. (*cur)->render (drawTo, asInput, *this->getCopySpacePosition (), *this->getTexCoordCopy (), this->m_modelViewProjectionPass);
  187. // render all the other materials
  188. auto effectCur = this->getEffects ().begin ();
  189. auto effectEnd = this->getEffects ().end ();
  190. for (; effectCur != effectEnd; effectCur ++)
  191. {
  192. auto materialCur = (*effectCur)->getMaterials ().begin ();
  193. auto materialEnd = (*effectCur)->getMaterials ().end ();
  194. for (; materialCur != materialEnd; materialCur ++)
  195. {
  196. // set viewport and target texture if needed
  197. if ((*materialCur)->getMaterial ()->hasTarget () == true)
  198. {
  199. // setup target texture
  200. std::string target = (*materialCur)->getMaterial ()->getTarget ();
  201. drawTo = (*effectCur)->findFBO (target);
  202. // not a local FBO, so try that one now
  203. if (drawTo == nullptr)
  204. // this one throws if no fbo was found
  205. drawTo = this->getScene ()->findFBO (target);
  206. }
  207. auto passCur = (*materialCur)->getPasses ().begin ();
  208. auto passEnd = (*materialCur)->getPasses ().end ();
  209. for (; passCur != passEnd; passCur ++)
  210. {
  211. GLuint spacePosition = *this->getPassSpacePosition ();
  212. glm::mat4 projection = this->m_modelViewProjectionPass;
  213. // ping-pong only if there's a target
  214. if ((*materialCur)->getMaterial ()->hasTarget () == false)
  215. {
  216. this->pinpongFramebuffer (&drawTo, &asInput);
  217. spacePosition = *this->getCopySpacePosition ();
  218. projection = this->m_modelViewProjectionScreen;
  219. }
  220. (*passCur)->render (drawTo, asInput, spacePosition, *this->getTexCoordPass (), this->m_modelViewProjectionPass);
  221. }
  222. }
  223. }
  224. if (this->getImage ()->isVisible () == false)
  225. return;
  226. // pinpong the framebuffer so we know exactly what we're drawing to the scene
  227. this->pinpongFramebuffer (&drawTo, &asInput);
  228. // final step, this one might need more changes, should passes render directly to the output instead of an intermediate framebuffer?
  229. // do the first pass render into the main framebuffer
  230. cur = this->m_material->getPasses ().begin ();
  231. end = this->m_material->getPasses ().end ();
  232. glColorMask (true, true, true, false);
  233. for (; cur != end; cur ++)
  234. (*cur)->render (this->getScene ()->getFBO (), asInput, *this->getSceneSpacePosition (), *this->getTexCoordPass (), this->m_modelViewProjectionScreen);
  235. }
  236. void CImage::render ()
  237. {
  238. // first and foremost reset the framebuffer switching
  239. this->m_currentMainFBO = this->m_mainFBO;
  240. this->m_currentSubFBO = this->m_subFBO;
  241. glColorMask (true, true, true, true);
  242. // check if there's more than one pass and do different things based on that
  243. if (this->m_effects.empty () == true)
  244. this->simpleRender ();
  245. else
  246. this->complexRender ();
  247. }
  248. ITexture* CImage::getTexture () const
  249. {
  250. return this->m_texture;
  251. }
  252. const Core::Objects::CImage* CImage::getImage () const
  253. {
  254. return this->m_image;
  255. }
  256. const std::vector<CEffect*>& CImage::getEffects () const
  257. {
  258. return this->m_effects;
  259. }
  260. const glm::vec2 CImage::getSize() const
  261. {
  262. if (this->m_texture == nullptr)
  263. return this->getImage ()->getSize ();
  264. return {this->m_texture->getRealWidth (), this->m_texture->getRealHeight ()};
  265. }
  266. const GLuint* CImage::getSceneSpacePosition () const
  267. {
  268. return &this->m_sceneSpacePosition;
  269. }
  270. const GLuint* CImage::getCopySpacePosition () const
  271. {
  272. return &this->m_copySpacePosition;
  273. }
  274. const GLuint* CImage::getPassSpacePosition () const
  275. {
  276. return &this->m_passSpacePosition;
  277. }
  278. const GLuint* CImage::getTexCoordCopy () const
  279. {
  280. return &this->m_texcoordCopy;
  281. }
  282. const GLuint* CImage::getTexCoordPass () const
  283. {
  284. return &this->m_texcoordPass;
  285. }
  286. const std::string CImage::Type = "image";