CWallpaper.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. #include "CWallpaper.h"
  2. #include "CScene.h"
  3. #include "CVideo.h"
  4. #include <utility>
  5. #include <glm/glm.hpp>
  6. #include <glm/gtc/type_ptr.hpp>
  7. using namespace WallpaperEngine::Render;
  8. CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CContainer* container, CContext* context) :
  9. m_container (container),
  10. m_wallpaperData (wallpaperData),
  11. m_type (std::move(type)),
  12. m_context (context)
  13. {
  14. this->setupShaders ();
  15. GLfloat texCoords [] = {
  16. 0.0f, 0.0f,
  17. 1.0f, 0.0f,
  18. 0.0f, 1.0f,
  19. 0.0f, 1.0f,
  20. 1.0f, 0.0f,
  21. 1.0f, 1.0f
  22. };
  23. // inverted positions so the final texture is rendered properly
  24. GLfloat position [] = {
  25. -1.0f, 1.0f, 0.0f,
  26. 1.0, 1.0f, 0.0f,
  27. -1.0f, -1.0f, 0.0f,
  28. -1.0f, -1.0f, 0.0f,
  29. 1.0f, 1.0f, 0.0f,
  30. 1.0f, -1.0f, 0.0f
  31. };
  32. glGenBuffers (1, &this->m_texCoordBuffer);
  33. glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
  34. glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW);
  35. glGenBuffers (1, &this->m_positionBuffer);
  36. glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
  37. glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
  38. }
  39. CWallpaper::~CWallpaper ()
  40. {
  41. }
  42. CContainer* CWallpaper::getContainer () const
  43. {
  44. return this->m_container;
  45. }
  46. WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData ()
  47. {
  48. return this->m_wallpaperData;
  49. }
  50. GLuint CWallpaper::getWallpaperFramebuffer () const
  51. {
  52. return this->m_sceneFBO->getFramebuffer ();
  53. }
  54. GLuint CWallpaper::getWallpaperTexture () const
  55. {
  56. return this->m_sceneFBO->getTextureID();
  57. }
  58. void CWallpaper::setupShaders ()
  59. {
  60. // reserve shaders in OpenGL
  61. GLuint vertexShaderID = glCreateShader (GL_VERTEX_SHADER);
  62. // give shader's source code to OpenGL to be compiled
  63. const char* sourcePointer = "#version 120\n"
  64. "attribute vec3 a_Position;\n"
  65. "attribute vec2 a_TexCoord;\n"
  66. "varying vec2 v_TexCoord;\n"
  67. "void main () {\n"
  68. "gl_Position = vec4 (a_Position, 1.0);\n"
  69. "v_TexCoord = a_TexCoord;\n"
  70. "}";
  71. glShaderSource (vertexShaderID, 1, &sourcePointer, nullptr);
  72. glCompileShader (vertexShaderID);
  73. GLint result = GL_FALSE;
  74. int infoLogLength = 0;
  75. // ensure the vertex shader was correctly compiled
  76. glGetShaderiv (vertexShaderID, GL_COMPILE_STATUS, &result);
  77. glGetShaderiv (vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
  78. if (infoLogLength > 0)
  79. {
  80. char* logBuffer = new char [infoLogLength + 1];
  81. // ensure logBuffer ends with a \0
  82. memset (logBuffer, 0, infoLogLength + 1);
  83. // get information about the error
  84. glGetShaderInfoLog (vertexShaderID, infoLogLength, nullptr, logBuffer);
  85. // throw an exception about the issue
  86. std::string message = logBuffer;
  87. // free the buffer
  88. delete[] logBuffer;
  89. // throw an exception
  90. throw std::runtime_error (message);
  91. }
  92. // reserve shaders in OpenGL
  93. GLuint fragmentShaderID = glCreateShader (GL_FRAGMENT_SHADER);
  94. // give shader's source code to OpenGL to be compiled
  95. sourcePointer = "#version 120\n"
  96. "uniform sampler2D g_Texture0;\n"
  97. "varying vec2 v_TexCoord;\n"
  98. "void main () {\n"
  99. "gl_FragColor = texture2D (g_Texture0, v_TexCoord);\n"
  100. "}";
  101. glShaderSource (fragmentShaderID, 1, &sourcePointer, nullptr);
  102. glCompileShader (fragmentShaderID);
  103. result = GL_FALSE;
  104. infoLogLength = 0;
  105. // ensure the vertex shader was correctly compiled
  106. glGetShaderiv (fragmentShaderID, GL_COMPILE_STATUS, &result);
  107. glGetShaderiv (fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
  108. if (infoLogLength > 0)
  109. {
  110. char* logBuffer = new char [infoLogLength + 1];
  111. // ensure logBuffer ends with a \0
  112. memset (logBuffer, 0, infoLogLength + 1);
  113. // get information about the error
  114. glGetShaderInfoLog (fragmentShaderID, infoLogLength, nullptr, logBuffer);
  115. // throw an exception about the issue
  116. std::string message = logBuffer;
  117. // free the buffer
  118. delete[] logBuffer;
  119. // throw an exception
  120. throw std::runtime_error (message);
  121. }
  122. // create the final program
  123. this->m_shader = glCreateProgram ();
  124. // link the shaders together
  125. glAttachShader (this->m_shader, vertexShaderID);
  126. glAttachShader (this->m_shader, fragmentShaderID);
  127. glLinkProgram (this->m_shader);
  128. // check that the shader was properly linked
  129. result = GL_FALSE;
  130. infoLogLength = 0;
  131. glGetProgramiv (this->m_shader, GL_LINK_STATUS, &result);
  132. glGetProgramiv (this->m_shader, GL_INFO_LOG_LENGTH, &infoLogLength);
  133. if (infoLogLength > 0)
  134. {
  135. char* logBuffer = new char [infoLogLength + 1];
  136. // ensure logBuffer ends with a \0
  137. memset (logBuffer, 0, infoLogLength + 1);
  138. // get information about the error
  139. glGetProgramInfoLog (this->m_shader, infoLogLength, nullptr, logBuffer);
  140. // throw an exception about the issue
  141. std::string message = logBuffer;
  142. // free the buffer
  143. delete[] logBuffer;
  144. // throw an exception
  145. throw std::runtime_error (message);
  146. }
  147. // after being liked shaders can be dettached and deleted
  148. glDetachShader (this->m_shader, vertexShaderID);
  149. glDetachShader (this->m_shader, fragmentShaderID);
  150. glDeleteShader (vertexShaderID);
  151. glDeleteShader (fragmentShaderID);
  152. // get textures
  153. this->g_Texture0 = glGetUniformLocation (this->m_shader, "g_Texture0");
  154. this->a_Position = glGetAttribLocation (this->m_shader, "a_Position");
  155. this->a_TexCoord = glGetAttribLocation (this->m_shader, "a_TexCoord");
  156. }
  157. void CWallpaper::render (glm::vec4 viewport, bool renderFrame, bool newFrame)
  158. {
  159. if (renderFrame == true)
  160. this->renderFrame (viewport);
  161. int windowWidth = 1920;
  162. int windowHeight = 1080;
  163. if (this->getWallpaperData ()->is <WallpaperEngine::Core::CScene> ())
  164. {
  165. auto projection = this->getWallpaperData ()->as <WallpaperEngine::Core::CScene> ()->getOrthogonalProjection ();
  166. windowWidth = projection->getWidth ();
  167. windowHeight = projection->getHeight ();
  168. }
  169. else if (this->is <WallpaperEngine::Render::CVideo> ())
  170. {
  171. auto video = this->as <WallpaperEngine::Render::CVideo> ();
  172. windowWidth = video->getWidth ();
  173. windowHeight = video->getHeight ();
  174. }
  175. float widthRatio = windowWidth / viewport.z;
  176. float heightRatio = windowHeight / viewport.w;
  177. if (widthRatio > 1.0f)
  178. {
  179. float diff = widthRatio - 1.0f;
  180. widthRatio -= diff;
  181. heightRatio -= diff;
  182. }
  183. if (heightRatio > 1.0f)
  184. {
  185. float diff = heightRatio - 1.0f;
  186. widthRatio -= diff;
  187. heightRatio -= diff;
  188. }
  189. if (widthRatio < 1.0f)
  190. {
  191. float diff = 1.0f - widthRatio;
  192. widthRatio += diff;
  193. heightRatio += diff;
  194. }
  195. if (heightRatio < 1.0f)
  196. {
  197. float diff = 1.0f - heightRatio;
  198. widthRatio += diff;
  199. heightRatio += diff;
  200. }
  201. if (widthRatio < 0.0f) widthRatio = -widthRatio;
  202. if (heightRatio < 0.0f) heightRatio = -heightRatio;
  203. GLfloat position [] = {
  204. -widthRatio, -heightRatio, 0.0f,
  205. widthRatio, -heightRatio, 0.0f,
  206. -widthRatio, heightRatio, 0.0f,
  207. -widthRatio, heightRatio, 0.0f,
  208. widthRatio, -heightRatio, 0.0f,
  209. widthRatio, heightRatio, 0.0f
  210. };
  211. glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
  212. glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
  213. glViewport (viewport.x, viewport.y, viewport.z, viewport.w);
  214. // write to default's framebuffer
  215. glBindFramebuffer (GL_FRAMEBUFFER, GL_NONE);
  216. if (newFrame == true)
  217. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  218. glDisable (GL_BLEND);
  219. glDisable (GL_DEPTH_TEST);
  220. // do not use any shader
  221. glUseProgram (this->m_shader);
  222. // activate scene texture
  223. glActiveTexture (GL_TEXTURE0);
  224. glBindTexture (GL_TEXTURE_2D, this->getWallpaperTexture ());
  225. // set uniforms and attribs
  226. glEnableVertexAttribArray (this->a_TexCoord);
  227. glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
  228. glVertexAttribPointer (this->a_TexCoord, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
  229. glEnableVertexAttribArray (this->a_Position);
  230. glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
  231. glVertexAttribPointer (this->a_Position, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
  232. glUniform1i (this->g_Texture0, 0);
  233. // write the framebuffer as is to the screen
  234. glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
  235. glDrawArrays (GL_TRIANGLES, 0, 6);
  236. }
  237. char* CWallpaper::renderImage ()
  238. {
  239. int windowWidth = 1920;
  240. int windowHeight = 1080;
  241. glm::vec4 viewport = {0, 0, windowWidth, windowHeight};
  242. this->renderFrame (viewport);
  243. if (this->getWallpaperData ()->is <WallpaperEngine::Core::CScene> ())
  244. {
  245. auto projection = this->getWallpaperData ()->as <WallpaperEngine::Core::CScene> ()->getOrthogonalProjection ();
  246. windowWidth = projection->getWidth ();
  247. windowHeight = projection->getHeight ();
  248. }
  249. else if (this->is <WallpaperEngine::Render::CVideo> ())
  250. {
  251. auto video = this->as <WallpaperEngine::Render::CVideo> ();
  252. windowWidth = video->getWidth ();
  253. windowHeight = video->getHeight ();
  254. }
  255. float widthRatio = windowWidth / viewport.z;
  256. float heightRatio = windowHeight / viewport.w;
  257. if (widthRatio > 1.0f)
  258. {
  259. float diff = widthRatio - 1.0f;
  260. widthRatio -= diff;
  261. heightRatio -= diff;
  262. }
  263. if (heightRatio > 1.0f)
  264. {
  265. float diff = heightRatio - 1.0f;
  266. widthRatio -= diff;
  267. heightRatio -= diff;
  268. }
  269. if (widthRatio < 1.0f)
  270. {
  271. float diff = 1.0f - widthRatio;
  272. widthRatio += diff;
  273. heightRatio += diff;
  274. }
  275. if (heightRatio < 1.0f)
  276. {
  277. float diff = 1.0f - heightRatio;
  278. widthRatio += diff;
  279. heightRatio += diff;
  280. }
  281. if (widthRatio < 0.0f) widthRatio = -widthRatio;
  282. if (heightRatio < 0.0f) heightRatio = -heightRatio;
  283. GLfloat position [] = {
  284. -widthRatio, -heightRatio, 0.0f,
  285. widthRatio, -heightRatio, 0.0f,
  286. -widthRatio, heightRatio, 0.0f,
  287. -widthRatio, heightRatio, 0.0f,
  288. widthRatio, -heightRatio, 0.0f,
  289. widthRatio, heightRatio, 0.0f
  290. };
  291. glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
  292. glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
  293. // Need to flip the image (FB stores the image upside down)
  294. GLfloat texCoords [] = {
  295. 0.0f, 1.0f,
  296. 1.0f, 1.0f,
  297. 0.0f, 0.0f,
  298. 0.0f, 0.0f,
  299. 1.0f, 1.0f,
  300. 1.0f, 0.0f
  301. };
  302. glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
  303. glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW);
  304. glViewport (viewport.x, viewport.y, viewport.z, viewport.w);
  305. // A fbo for flipping the image. Without this call the image will be flipped.
  306. static CFBO* screen_fbo = this->createFBO ("_sc_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, 1.0, windowWidth, windowHeight, windowWidth, windowHeight);
  307. glBindFramebuffer (GL_FRAMEBUFFER, screen_fbo->getFramebuffer());
  308. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  309. glDisable (GL_BLEND);
  310. glDisable (GL_DEPTH_TEST);
  311. // do not use any shader
  312. glUseProgram (this->m_shader);
  313. // activate scene texture
  314. glActiveTexture (GL_TEXTURE0);
  315. glBindTexture (GL_TEXTURE_2D, this->getWallpaperTexture ());
  316. // set uniforms and attribs
  317. glEnableVertexAttribArray (this->a_TexCoord);
  318. glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
  319. glVertexAttribPointer (this->a_TexCoord, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
  320. glEnableVertexAttribArray (this->a_Position);
  321. glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
  322. glVertexAttribPointer (this->a_Position, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
  323. glUniform1i (this->g_Texture0, 0);
  324. // write the framebuffer as is to the screen
  325. glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
  326. glDrawArrays (GL_TRIANGLES, 0, 6);
  327. glBindTexture (GL_TEXTURE_2D, screen_fbo->getTextureID ());
  328. // Get FB data from OpenGL, X11 will free this pointer when it is created into an XImage.
  329. char* image;
  330. image = (char*)malloc(windowWidth*windowHeight*4);
  331. glReadPixels(0, 0, 1920, 1080, GL_BGRA, GL_UNSIGNED_BYTE, (void*)(image));
  332. return image;
  333. }
  334. void CWallpaper::setupFramebuffers ()
  335. {
  336. int windowWidth = 1920;
  337. int windowHeight = 1080;
  338. if (this->getWallpaperData ()->is <WallpaperEngine::Core::CScene> ())
  339. {
  340. auto projection = this->getWallpaperData ()->as <WallpaperEngine::Core::CScene> ()->getOrthogonalProjection ();
  341. windowWidth = projection->getWidth ();
  342. windowHeight = projection->getHeight ();
  343. }
  344. else if (this->is <WallpaperEngine::Render::CVideo> ())
  345. {
  346. auto video = this->as <WallpaperEngine::Render::CVideo> ();
  347. windowWidth = video->getWidth ();
  348. windowHeight = video->getHeight ();
  349. }
  350. // create framebuffer for the scene
  351. this->m_sceneFBO = this->createFBO ("_rt_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, 1.0, windowWidth, windowHeight, windowWidth, windowHeight);
  352. }
  353. CContext* CWallpaper::getContext ()
  354. {
  355. return this->m_context;
  356. }
  357. CFBO* CWallpaper::createFBO (const std::string& name, ITexture::TextureFormat format, float scale, uint32_t realWidth, uint32_t realHeight, uint32_t textureWidth, uint32_t textureHeight)
  358. {
  359. CFBO* fbo = new CFBO (name, format, scale, realWidth, realHeight, textureWidth, textureHeight);
  360. this->m_fbos.insert (std::make_pair (name, fbo));
  361. return fbo;
  362. }
  363. const std::map<std::string, CFBO*>& CWallpaper::getFBOs () const
  364. {
  365. return this->m_fbos;
  366. }
  367. CFBO* CWallpaper::findFBO (const std::string& name) const
  368. {
  369. auto it = this->m_fbos.find (name);
  370. if (it == this->m_fbos.end ())
  371. throw std::runtime_error ("Cannot find given FBO");
  372. return it->second;
  373. }
  374. CFBO* CWallpaper::getFBO () const
  375. {
  376. return this->m_sceneFBO;
  377. }