CImage.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. #include "CImage.h"
  2. #include <sstream>
  3. #include "WallpaperEngine/Data/Parsers/MaterialParser.h"
  4. #include "WallpaperEngine/Data/Model/Object.h"
  5. #include "WallpaperEngine/Data/Model/Material.h"
  6. using namespace WallpaperEngine;
  7. using namespace WallpaperEngine::Render::Objects;
  8. using namespace WallpaperEngine::Render::Objects::Effects;
  9. using namespace WallpaperEngine::Data::Parsers;
  10. using namespace WallpaperEngine::Data::Builders;
  11. CImage::CImage (Wallpapers::CScene& scene, const Image& image) :
  12. Render::CObject (scene, image),
  13. Render::FBOProvider (&scene),
  14. m_texture (nullptr),
  15. m_sceneSpacePosition (GL_NONE),
  16. m_copySpacePosition (GL_NONE),
  17. m_passSpacePosition (GL_NONE),
  18. m_texcoordCopy (GL_NONE),
  19. m_texcoordPass (GL_NONE),
  20. m_modelViewProjectionScreen (),
  21. m_modelViewProjectionPass (glm::mat4 (1.0)),
  22. m_modelViewProjectionCopy (),
  23. m_modelViewProjectionScreenInverse (),
  24. m_modelViewProjectionPassInverse (glm::inverse (m_modelViewProjectionPass)),
  25. m_modelViewProjectionCopyInverse (),
  26. m_modelMatrix(),
  27. m_viewProjectionMatrix(),
  28. m_image (image),
  29. m_material (nullptr),
  30. m_colorBlendMaterial (nullptr),
  31. m_pos (),
  32. m_animationTime (0.0),
  33. m_initialized (false) {
  34. // get scene width and height to calculate positions
  35. auto scene_width = static_cast<float> (scene.getWidth ());
  36. auto scene_height = static_cast<float> (scene.getHeight ());
  37. // TODO: MAKE USE OF THE USER PROPERTIES POINTER HERE TOO! SO EVERYTHING IS UPDATED ACCORDINGLY
  38. glm::vec3 origin = this->getImage ().origin->value->getVec3 ();
  39. glm::vec2 size = this->getSize ();
  40. glm::vec3 scale = this->getImage ().scale->value->getVec3 ();
  41. // detect texture (if any)
  42. if (auto textures = (*this->m_image.model->material->passes.begin ())->textures; !textures.empty ()) {
  43. std::string textureName = textures.begin ()->second;
  44. if (textureName.find ("_rt_") == 0 || textureName.find ("_alias_") == 0) {
  45. this->m_texture = this->getScene ().findFBO (textureName);
  46. } else {
  47. // get the first texture on the first pass (this one represents the image assigned to this object)
  48. this->m_texture = this->getContext ().resolveTexture (textureName);
  49. }
  50. } else {
  51. if (this->m_image.model->solidlayer && size.x == 0.0f && size.y == 0.0f) {
  52. size.x = scene_width;
  53. size.y = scene_height;
  54. }
  55. // if (this->m_image->isSolid ()) // layer receives cursor events: https://docs.wallpaperengine.io/en/scene/scenescript/reference/event/cursor.html
  56. // same applies to effects
  57. // TODO: create a dummy texture of correct size, fbo constructors should be enough, but this should be properly
  58. // handled
  59. this->m_texture = std::make_shared<CFBO> (
  60. "", TextureFormat_ARGB8888, TextureFlags_NoFlags, 1, size.x,
  61. size.y, size.x, size.y);
  62. }
  63. // If the wallpaper doesn't specify a size, fall back to the texture or model dimensions
  64. if ((size.x == 0.0f || size.y == 0.0f) && this->m_texture != nullptr) {
  65. size.x = static_cast<float> (this->m_texture->getRealWidth ());
  66. size.y = static_cast<float> (this->m_texture->getRealHeight ());
  67. } else if ((size.x == 0.0f || size.y == 0.0f) &&
  68. this->getImage ().model->width.has_value () &&
  69. this->getImage ().model->height.has_value ()) {
  70. size.x = static_cast<float> (this->getImage ().model->width.value ());
  71. size.y = static_cast<float> (this->getImage ().model->height.value ());
  72. }
  73. // fullscreen layers should use the whole projection's size
  74. // TODO: WHAT SHOULD AUTOSIZE DO?
  75. if (this->getImage ().model->fullscreen) {
  76. size = {scene_width, scene_height};
  77. origin = {scene_width / 2, scene_height / 2, 0};
  78. // TODO: CHANGE ALIGNMENT TOO?
  79. }
  80. glm::vec2 scaledSize = size * glm::vec2 (scale);
  81. // calculate the center and shift from there
  82. this->m_pos.x = origin.x - (scaledSize.x / 2);
  83. this->m_pos.w = origin.y + (scaledSize.y / 2);
  84. this->m_pos.z = origin.x + (scaledSize.x / 2);
  85. this->m_pos.y = origin.y - (scaledSize.y / 2);
  86. if (this->getImage ().alignment.find ("top") != std::string::npos) {
  87. this->m_pos.y -= scaledSize.y / 2;
  88. this->m_pos.w -= scaledSize.y / 2;
  89. } else if (this->getImage ().alignment.find ("bottom") != std::string::npos) {
  90. this->m_pos.y += scaledSize.y / 2;
  91. this->m_pos.w += scaledSize.y / 2;
  92. }
  93. if (this->getImage ().alignment.find ("left") != std::string::npos) {
  94. this->m_pos.x += scaledSize.x / 2;
  95. this->m_pos.z += scaledSize.x / 2;
  96. } else if (this->getImage ().alignment.find ("right") != std::string::npos) {
  97. this->m_pos.x -= scaledSize.x / 2;
  98. this->m_pos.z -= scaledSize.x / 2;
  99. }
  100. // wallpaper engine
  101. this->m_pos.x -= scene_width / 2;
  102. this->m_pos.y = scene_height / 2 - this->m_pos.y;
  103. this->m_pos.z -= scene_width / 2;
  104. this->m_pos.w = scene_height / 2 - this->m_pos.w;
  105. // register both FBOs into the scene
  106. std::ostringstream nameA, nameB;
  107. // TODO: determine when _rt_imageLayerComposite and _rt_imageLayerAlbedo is used
  108. nameA << "_rt_imageLayerComposite_" << this->getImage ().id << "_a";
  109. nameB << "_rt_imageLayerComposite_" << this->getImage ().id << "_b";
  110. this->m_currentMainFBO = this->m_mainFBO =
  111. scene.create (nameA.str (), TextureFormat_ARGB8888, this->m_texture->getFlags (), 1,
  112. {size.x, size.y}, {size.x, size.y});
  113. this->m_currentSubFBO = this->m_subFBO =
  114. scene.create (nameB.str (), TextureFormat_ARGB8888, this->m_texture->getFlags (), 1,
  115. {size.x, size.y}, {size.x, size.y});
  116. // build a list of vertices, these might need some change later (or maybe invert the camera)
  117. GLfloat sceneSpacePosition [] = {this->m_pos.x, this->m_pos.y, 0.0f, this->m_pos.x, this->m_pos.w, 0.0f,
  118. this->m_pos.z, this->m_pos.y, 0.0f, this->m_pos.z, this->m_pos.y, 0.0f,
  119. this->m_pos.x, this->m_pos.w, 0.0f, this->m_pos.z, this->m_pos.w, 0.0f};
  120. float width = 1.0f;
  121. float height = 1.0f;
  122. if (this->getTexture ()->isAnimated ()) {
  123. // animated images use different coordinates as they're essentially a texture atlas
  124. width = static_cast<float> (this->getTexture ()->getRealWidth ()) /
  125. static_cast<float> (this->getTexture ()->getTextureWidth (0));
  126. height = static_cast<float> (this->getTexture ()->getRealHeight ()) /
  127. static_cast<float> (this->getTexture ()->getTextureHeight (0));
  128. }
  129. // calculate the correct texCoord limits for the texture based on the texture screen size and real size
  130. else if (this->getTexture () != nullptr &&
  131. (this->getTexture ()->getTextureWidth (0) != this->getTexture ()->getRealWidth () ||
  132. this->getTexture ()->getTextureHeight (0) != this->getTexture ()->getRealHeight ())) {
  133. // Account for padding in non-power-of-two textures: clamp UVs to the real content
  134. width = static_cast<float> (this->getTexture ()->getRealWidth ()) /
  135. static_cast<float> (this->getTexture ()->getTextureWidth (0));
  136. height = static_cast<float> (this->getTexture ()->getRealHeight ()) /
  137. static_cast<float> (this->getTexture ()->getTextureHeight (0));
  138. }
  139. // TODO: RECALCULATE THESE POSITIONS FOR PASSTHROUGH SO THEY TAKE THE RIGHT PART OF THE TEXTURE
  140. float x = 0.0f;
  141. float y = 0.0f;
  142. if (this->getTexture ()->isAnimated ()) {
  143. // animations should be copied completely
  144. x = 0.0f;
  145. y = 0.0f;
  146. width = 1.0f;
  147. height = 1.0f;
  148. }
  149. GLfloat realWidth = size.x;
  150. GLfloat realHeight = size.y;
  151. GLfloat realX = 0.0;
  152. GLfloat realY = 0.0;
  153. if (this->getImage ().model->passthrough) {
  154. x = -((this->m_pos.x + (scene_width / 2)) / size.x);
  155. y = -((this->m_pos.w + (scene_height / 2)) / size.y);
  156. height = (this->m_pos.y + (scene_height / 2)) / size.y;
  157. width = (this->m_pos.z + (scene_width / 2)) / size.x;
  158. if (this->getImage ().model->fullscreen) {
  159. realX = -1.0;
  160. realY = -1.0;
  161. realWidth = 1.0;
  162. realHeight = 1.0;
  163. }
  164. }
  165. GLfloat texcoordCopy [] = {x, height, x, y, width, height, width, height, x, y, width, y};
  166. GLfloat copySpacePosition [] = {realX, realHeight, 0.0f, realX, realY, 0.0f, realWidth, realHeight, 0.0f,
  167. realWidth, realHeight, 0.0f, realX, realY, 0.0f, realWidth, realY, 0.0f};
  168. GLfloat texcoordPass [] = {0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f};
  169. GLfloat passSpacePosition [] = {-1.0, 1.0, 0.0f, -1.0, -1.0, 0.0f, 1.0, 1.0, 0.0f,
  170. 1.0, 1.0, 0.0f, -1.0, -1.0, 0.0f, 1.0, -1.0, 0.0f};
  171. // bind vertex list to the openGL buffers
  172. glGenBuffers (1, &this->m_sceneSpacePosition);
  173. glBindBuffer (GL_ARRAY_BUFFER, this->m_sceneSpacePosition);
  174. glBufferData (GL_ARRAY_BUFFER, sizeof (sceneSpacePosition), sceneSpacePosition, GL_STATIC_DRAW);
  175. glGenBuffers (1, &this->m_copySpacePosition);
  176. glBindBuffer (GL_ARRAY_BUFFER, this->m_copySpacePosition);
  177. glBufferData (GL_ARRAY_BUFFER, sizeof (copySpacePosition), copySpacePosition, GL_STATIC_DRAW);
  178. // bind pass' vertex list to the openGL buffers
  179. glGenBuffers (1, &this->m_passSpacePosition);
  180. glBindBuffer (GL_ARRAY_BUFFER, this->m_passSpacePosition);
  181. glBufferData (GL_ARRAY_BUFFER, sizeof (passSpacePosition), passSpacePosition, GL_STATIC_DRAW);
  182. glGenBuffers (1, &this->m_texcoordCopy);
  183. glBindBuffer (GL_ARRAY_BUFFER, this->m_texcoordCopy);
  184. glBufferData (GL_ARRAY_BUFFER, sizeof (texcoordCopy), texcoordCopy, GL_STATIC_DRAW);
  185. glGenBuffers (1, &this->m_texcoordPass);
  186. glBindBuffer (GL_ARRAY_BUFFER, this->m_texcoordPass);
  187. glBufferData (GL_ARRAY_BUFFER, sizeof (texcoordPass), texcoordPass, GL_STATIC_DRAW);
  188. this->m_modelViewProjectionScreen =
  189. this->getScene ().getCamera ().getProjection () * this->getScene ().getCamera ().getLookAt ();
  190. this->m_modelViewProjectionScreenInverse = glm::inverse (this->m_modelViewProjectionScreen);
  191. this->m_modelViewProjectionCopy = glm::ortho<float> (0.0, size.x, 0.0, size.y);
  192. this->m_modelViewProjectionCopyInverse = glm::inverse (this->m_modelViewProjectionCopy);
  193. this->m_modelMatrix = glm::ortho<float> (0.0, size.x, 0.0, size.y);
  194. this->m_viewProjectionMatrix = glm::mat4 (1.0);
  195. }
  196. void CImage::setup () {
  197. // do not double-init stuff, that's bad!
  198. if (this->m_initialized) {
  199. return;
  200. }
  201. // TODO: CHECK ORDER OF THINGS, 2419444134'S ID 27 DEPENDS ON 104'S COMPOSITE_A WHEN OUR LAST RENDER IS ON COMPOSITE_B
  202. // TODO: SUPPORT PASSTHROUGH (IT'S A SHADER)
  203. // passthrough images without effects are bad, do not draw them
  204. if (this->m_image.model->passthrough && this->m_image.effects.empty ()) {
  205. return;
  206. }
  207. // copy pass to the composite layer
  208. for (const auto& cur : this->getImage ().model->material->passes) {
  209. this->m_passes.push_back (
  210. new CPass (*this, std::make_shared<FBOProvider> (this), *cur, std::nullopt, std::nullopt, std::nullopt)
  211. );
  212. }
  213. // prepare the passes list
  214. if (!this->getImage ().effects.empty ()) {
  215. // generate the effects used by this material
  216. for (const auto& cur : this->m_image.effects) {
  217. // do not add non-visible effects, this might need some adjustements tho as some effects might not be visible
  218. // but affect the output of the image...
  219. if (!cur->visible->value->getBool ()) {
  220. continue;
  221. }
  222. const auto fboProvider = std::make_shared<FBOProvider> (this);
  223. // create all the fbos for this effect
  224. for (const auto& fbo : cur->effect->fbos) {
  225. fboProvider->create (*fbo, this->m_texture->getFlags (), this->getSize ());
  226. }
  227. // TODO: MAKE USE OF ZIP OPERATOR IN BOOST? WAY OVERKILL JUST FOR THIS...
  228. auto curEffect = cur->effect->passes.begin ();
  229. auto endEffect = cur->effect->passes.end ();
  230. auto curOverride = cur->passOverrides.begin ();
  231. auto endOverride = cur->passOverrides.end ();
  232. for (; curEffect != endEffect; ++curEffect) {
  233. if (!(*curEffect)->material.has_value ()) {
  234. if (!(*curEffect)->command.has_value ()) {
  235. sLog.error ("Pass without material and command not supported");
  236. continue;
  237. }
  238. if (!(*curEffect)->source.has_value ()) {
  239. sLog.error ("Pass without material and source not supported");
  240. continue;
  241. }
  242. if (!(*curEffect)->target.has_value ()) {
  243. sLog.error ("Pass without material and target not supported");
  244. continue;
  245. }
  246. if ((*curEffect)->command != Command_Copy) {
  247. sLog.error ("Only copy command is supported for pass without material");
  248. continue;
  249. }
  250. auto virtualPass = std::make_unique<MaterialPass>(MaterialPass {
  251. .blending = BlendingMode_Normal,
  252. .cullmode = CullingMode_Disable,
  253. .depthtest = DepthtestMode_Disabled,
  254. .depthwrite = DepthwriteMode_Disabled,
  255. .shader = "commands/copy",
  256. .textures = {
  257. {0, *(*curEffect)->source}
  258. },
  259. .combos = {},
  260. .constants = {}
  261. });
  262. const auto& config = *this->m_virtualPassess.emplace_back (std::move(virtualPass));
  263. // build a pass for a copy shader
  264. this->m_passes.push_back (
  265. new CPass (*this, fboProvider, config, std::nullopt, std::nullopt, (*curEffect)->target.value ())
  266. );
  267. } else {
  268. for (auto& pass : (*curEffect)->material.value ()->passes) {
  269. const auto override =
  270. curOverride != endOverride
  271. ? **curOverride
  272. : std::optional<std::reference_wrapper<const ImageEffectPassOverride>> (std::nullopt);
  273. const auto target = (*curEffect)->target.has_value ()
  274. ? *(*curEffect)->target
  275. : std::optional<std::reference_wrapper<std::string>> (std::nullopt);
  276. this->m_passes.push_back (
  277. new CPass (*this, fboProvider, *pass, override, (*curEffect)->binds, target));
  278. }
  279. if (curOverride != endOverride) {
  280. ++curOverride;
  281. }
  282. }
  283. }
  284. }
  285. }
  286. // extra render pass if there's any blending to be done
  287. if (this->m_image.colorBlendMode > 0) {
  288. this->m_materials.colorBlending.material = MaterialParser::load (this->getScene ().getScene ().project, "materials/util/effectpassthrough.json");
  289. this->m_materials.colorBlending.override = std::make_unique<ImageEffectPassOverride> (ImageEffectPassOverride {
  290. .id = -1,
  291. .combos = {
  292. {"BLENDMODE", this->m_image.colorBlendMode},
  293. },
  294. .constants = {},
  295. .textures = {},
  296. });
  297. this->m_passes.push_back (
  298. new CPass (
  299. *this,
  300. std::make_shared <FBOProvider>(this),
  301. **this->m_materials.colorBlending.material->passes.begin (),
  302. *this->m_materials.colorBlending.override,
  303. std::nullopt,
  304. std::nullopt
  305. )
  306. );
  307. }
  308. // if there's more than one pass the blendmode has to be moved from the beginning to the end
  309. if (this->m_passes.size () > 1) {
  310. const auto first = this->m_passes.begin ();
  311. const auto last = this->m_passes.rbegin ();
  312. (*last)->setBlendingMode ((*first)->getBlendingMode ());
  313. (*first)->setBlendingMode (BlendingMode_Normal);
  314. }
  315. // calculate full animation time (if any)
  316. this->m_animationTime = 0.0f;
  317. for (const auto& cur : this->getTexture ()->getFrames ()) {
  318. this->m_animationTime += cur->frametime;
  319. }
  320. this->setupPasses ();
  321. this->m_initialized = true;
  322. }
  323. void CImage::setupPasses () {
  324. // do a pass on everything and setup proper inputs and values
  325. std::shared_ptr<const CFBO> drawTo = this->m_currentMainFBO;
  326. std::shared_ptr<const TextureProvider> asInput = this->getTexture ();
  327. GLuint texcoord = this->getTexCoordCopy ();
  328. auto cur = this->m_passes.begin ();
  329. auto end = this->m_passes.end ();
  330. bool first = true;
  331. for (; cur != end; ++cur) {
  332. // TODO: PROPERLY CHECK EFFECT'S VISIBILITY AND TAKE IT INTO ACCOUNT
  333. // TODO: THIS REQUIRES ON-THE-FLY EVALUATION OF EFFECTS VISIBILITY TO FIGURE OUT
  334. // TODO: WHICH ONE IS THE LAST + A FEW OTHER THINGS
  335. Effects::CPass* pass = *cur;
  336. std::shared_ptr<const CFBO> prevDrawTo = drawTo;
  337. GLuint spacePosition = (first) ? this->getCopySpacePosition () : this->getPassSpacePosition ();
  338. const glm::mat4* projection = (first) ? &this->m_modelViewProjectionCopy : &this->m_modelViewProjectionPass;
  339. const glm::mat4* inverseProjection =
  340. (first) ? &this->m_modelViewProjectionCopyInverse : &this->m_modelViewProjectionPassInverse;
  341. first = false;
  342. pass->setModelMatrix (&this->m_modelMatrix);
  343. pass->setViewProjectionMatrix (&this->m_viewProjectionMatrix);
  344. // set viewport and target texture if needed
  345. if (pass->getTarget ().has_value ()) {
  346. // setup target texture
  347. std::string target = pass->getTarget ().value ();
  348. drawTo = pass->getFBOProvider ()->find (target);
  349. // spacePosition = this->getPassSpacePosition ();
  350. // not a local fbo, try to find a scene fbo with the same name
  351. if (drawTo == nullptr) {
  352. // this one throws if no fbo was found
  353. drawTo = this->getScene ().findFBO (target);
  354. }
  355. }
  356. // determine if it's the last element in the list as this is a screen-copy-like process
  357. // TODO: PROPERLY CHECK IF THIS IS ALL THAT'S NEEDED
  358. else if (std::next (cur) == end && this->getImage ().visible->value->getBool ()) {
  359. // TODO: PROPERLY CHECK EFFECT'S VISIBILITY AND TAKE IT INTO ACCOUNT
  360. spacePosition = this->getSceneSpacePosition ();
  361. drawTo = this->getScene ().getFBO ();
  362. projection = &this->m_modelViewProjectionScreen;
  363. inverseProjection = &this->m_modelViewProjectionScreenInverse;
  364. }
  365. pass->setDestination (drawTo);
  366. pass->setInput (asInput);
  367. pass->setPosition (spacePosition);
  368. pass->setTexCoord (texcoord);
  369. pass->setModelViewProjectionMatrix (projection);
  370. pass->setModelViewProjectionMatrixInverse (inverseProjection);
  371. texcoord = this->getTexCoordPass ();
  372. drawTo = prevDrawTo;
  373. if (!pass->getTarget ().has_value ())
  374. this->pinpongFramebuffer (&drawTo, &asInput);
  375. }
  376. }
  377. void CImage::pinpongFramebuffer (std::shared_ptr<const CFBO>* drawTo, std::shared_ptr<const TextureProvider>* asInput) {
  378. // temporarily store FBOs used
  379. std::shared_ptr<const CFBO> currentMainFBO = this->m_currentMainFBO;
  380. std::shared_ptr<const CFBO> currentSubFBO = this->m_currentSubFBO;
  381. if (drawTo != nullptr)
  382. *drawTo = currentSubFBO;
  383. if (asInput != nullptr)
  384. *asInput = currentMainFBO;
  385. // swap the FBOs
  386. this->m_currentMainFBO = currentSubFBO;
  387. this->m_currentSubFBO = currentMainFBO;
  388. }
  389. void CImage::render () {
  390. // do not try to render something that did not initialize successfully
  391. // non-visible materials do need to be rendered
  392. if (!this->m_initialized) {
  393. return;
  394. }
  395. glColorMask (true, true, true, true);
  396. // update the position if required
  397. // TODO: There's more images that are not affected by parallax, autosize or fullscreen are not affected
  398. if (this->getScene ().getScene ().camera.parallax.enabled && !this->getImage ().model->fullscreen) {
  399. this->updateScreenSpacePosition ();
  400. }
  401. #if !NDEBUG
  402. std::string str = "Rendering ";
  403. if (this->getScene ().getScene ().camera.bloom.enabled->value->getBool () && this->getId () == -1)
  404. str += "bloom";
  405. else {
  406. str += this->getImage ().name + " (" + std::to_string (this->getId ()) + ", " +
  407. this->getImage ().model->material->filename + ")";
  408. }
  409. glPushDebugGroup (GL_DEBUG_SOURCE_APPLICATION, 0, -1, str.c_str ());
  410. #endif /* DEBUG */
  411. auto cur = this->m_passes.begin ();
  412. for (const auto end = this->m_passes.end (); cur != end; ++cur) {
  413. if (std::next (cur) == end) {
  414. glColorMask (true, true, true, false);
  415. }
  416. (*cur)->render ();
  417. }
  418. #if !NDEBUG
  419. glPopDebugGroup ();
  420. #endif /* DEBUG */
  421. }
  422. void CImage::updateScreenSpacePosition () {
  423. // do not perform any changes to the image based on the parallax if it was explicitly disabled
  424. if (this->getScene ().getContext ().getApp ().getContext ().settings.mouse.disableparallax) {
  425. return;
  426. }
  427. const double parallaxAmount = this->getScene ().getScene ().camera.parallax.amount->value->getFloat ();
  428. const glm::vec2 depth = this->getImage ().parallaxDepth;
  429. const glm::vec2* displacement = this->getScene ().getParallaxDisplacement ();
  430. float x = (depth.x + parallaxAmount) * displacement->x * this->getSize ().x;
  431. float y = (depth.y + parallaxAmount) * displacement->y * this->getSize ().x;
  432. this->m_modelViewProjectionScreen = glm::translate (
  433. this->getScene ().getCamera ().getProjection () * this->getScene ().getCamera ().getLookAt (),
  434. {x, y, 0.0f}
  435. );
  436. }
  437. std::shared_ptr<const TextureProvider> CImage::getTexture () const {
  438. return this->m_texture;
  439. }
  440. double CImage::getAnimationTime () const {
  441. return this->m_animationTime;
  442. }
  443. const Image& CImage::getImage () const {
  444. return this->m_image;
  445. }
  446. const std::vector<CEffect*>& CImage::getEffects () const {
  447. return this->m_effects;
  448. }
  449. const Effects::CMaterial* CImage::getMaterial () const {
  450. return this->m_material;
  451. }
  452. glm::vec2 CImage::getSize () const {
  453. if (this->m_texture == nullptr) {
  454. return this->getImage ().size;
  455. }
  456. return {this->m_texture->getRealWidth (), this->m_texture->getRealHeight ()};
  457. }
  458. GLuint CImage::getSceneSpacePosition () const {
  459. return this->m_sceneSpacePosition;
  460. }
  461. GLuint CImage::getCopySpacePosition () const {
  462. return this->m_copySpacePosition;
  463. }
  464. GLuint CImage::getPassSpacePosition () const {
  465. return this->m_passSpacePosition;
  466. }
  467. GLuint CImage::getTexCoordCopy () const {
  468. return this->m_texcoordCopy;
  469. }
  470. GLuint CImage::getTexCoordPass () const {
  471. return this->m_texcoordPass;
  472. }