| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- #include <sstream>
- #include "CImage.h"
- using namespace WallpaperEngine;
- using namespace WallpaperEngine::Render::Objects;
- CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
- Render::CObject (scene, Type, image),
- m_image (image),
- m_texture (nullptr)
- {
- auto projection = this->getScene ()->getScene ()->getOrthogonalProjection ();
- // get scene width and height to calculate positions
- auto scene_width = static_cast <float> (projection->getWidth ());
- auto scene_height = static_cast <float> (projection->getHeight ());
- glm::vec3 origin = this->getImage ()->getOrigin ();
- glm::vec2 size = this->getSize ();
- glm::vec3 scale = this->getImage ()->getScale ();
- float xleft = 0.0f;
- float ytop = 0.0f;
- float xright = 0.0f;
- float ybottom = 0.0f;
- // TODO: TAKE INTO ACCOUNT SCALE
- // depending on the alignment these values might change, for now just support center
- if (this->getImage ()->getAlignment () == "center")
- {
- // calculate the real position of the image
- xleft = (-scene_width / 2) + (origin.x - (size.x / 2));
- xright = (-scene_width / 2) + (origin.x + (size.x / 2));
- ytop = (-scene_height / 2) + origin.y + (size.y / 2);
- ybottom = (-scene_height / 2) + (origin.y - (size.y / 2));
- }
- else
- {
- throw std::runtime_error ("Only centered images are supported for now!");
- }
- std::string textureName = (*(*this->m_image->getMaterial ()->getPasses ().begin ())->getTextures ().begin ());
- if (textureName.find ("_rt_") == 0)
- {
- this->m_texture = this->getScene ()->findFBO (textureName);
- }
- else
- {
- // get the first texture on the first pass (this one represents the image assigned to this object)
- this->m_texture = this->getScene ()->getContainer ()->readTexture (textureName);
- }
- // register both FBOs into the scene
- std::ostringstream nameA, nameB;
- nameA << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_a";
- nameB << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_b";
- 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 ());
- 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 ());
- GLfloat realWidth = this->m_texture->getRealWidth () / 2;
- GLfloat realHeight = this->m_texture->getRealHeight () / 2;
- // build a list of vertices, these might need some change later (or maybe invert the camera)
- GLfloat sceneSpacePosition [] = {
- xleft, ytop, 0.0f,
- xright, ytop, 0.0f,
- xleft, ybottom, 0.0f,
- xleft, ybottom, 0.0f,
- xright, ytop, 0.0f,
- xright, ybottom, 0.0f
- };
- GLfloat copySpacePosition [] = {
- -realWidth, -realHeight, 0.0f,
- realWidth, -realHeight, 0.0f,
- -realWidth, realHeight, 0.0f,
- -realWidth, realHeight, 0.0f,
- realWidth, -realHeight, 0.0f,
- realWidth, realHeight, 0.0f
- };
- GLfloat passSpacePosition [] = {
- -1.0f, -1.0f, 0.0f,
- 1.0f, -1.0f, 0.0f,
- -1.0f, 1.0f, 0.0f,
- -1.0f, 1.0f, 0.0f,
- 1.0f, -1.0f, 0.0f,
- 1.0f, 1.0f, 0.0f
- };
- float width = 1.0f;
- float height = 1.0f;
- // calculate the correct texCoord limits for the texture based on the texture screen size and real size
- if (this->getTexture () != nullptr &&
- (this->getTexture ()->getTextureWidth () != this->getTexture ()->getRealWidth () ||
- this->getTexture ()->getTextureHeight () != this->getTexture ()->getRealHeight ())
- )
- {
- uint32_t x = 1;
- uint32_t y = 1;
- while (x < size.x) x <<= 1;
- while (y < size.y) y <<= 1;
- width = size.x * scale.x / x;
- height = size.y * scale.y / y;
- }
- GLfloat texcoordCopy [] = {
- 0.0f, 0.0f,
- width, 0.0f,
- 0.0f, height,
- 0.0f, height,
- width, 0.0f,
- width, height
- };
- GLfloat texcoordPass [] = {
- 0.0f, 0.0f,
- 1.0f, 0.0f,
- 0.0f, 1.0f,
- 0.0f, 1.0f,
- 1.0f, 0.0f,
- 1.0f, 1.0f
- };
- // bind vertex list to the openGL buffers
- glGenBuffers (1, &this->m_sceneSpacePosition);
- glBindBuffer (GL_ARRAY_BUFFER, this->m_sceneSpacePosition);
- glBufferData (GL_ARRAY_BUFFER, sizeof (sceneSpacePosition), sceneSpacePosition, GL_STATIC_DRAW);
- glGenBuffers (1, &this->m_copySpacePosition);
- glBindBuffer (GL_ARRAY_BUFFER, this->m_copySpacePosition);
- glBufferData (GL_ARRAY_BUFFER, sizeof (copySpacePosition), copySpacePosition, GL_STATIC_DRAW);
- // bind pass' vertex list to the openGL buffers
- glGenBuffers (1, &this->m_passSpacePosition);
- glBindBuffer (GL_ARRAY_BUFFER, this->m_passSpacePosition);
- glBufferData (GL_ARRAY_BUFFER, sizeof (passSpacePosition), passSpacePosition, GL_STATIC_DRAW);
- glGenBuffers (1, &this->m_texcoordCopy);
- glBindBuffer (GL_ARRAY_BUFFER, this->m_texcoordCopy);
- glBufferData (GL_ARRAY_BUFFER, sizeof (texcoordCopy), texcoordCopy, GL_STATIC_DRAW);
- glGenBuffers (1, &this->m_texcoordPass);
- glBindBuffer (GL_ARRAY_BUFFER, this->m_texcoordPass);
- glBufferData (GL_ARRAY_BUFFER, sizeof (texcoordPass), texcoordPass, GL_STATIC_DRAW);
- this->m_modelViewProjectionScreen =
- this->getScene ()->getCamera ()->getProjection () *
- this->getScene ()->getCamera ()->getLookAt () *
- glm::scale (glm::mat4 (1.0f), scale);
- this->m_modelViewProjectionPass =
- glm::ortho<float> (-size.x / 2, size.x / 2, -size.y / 2, size.y / 2, 0, 10000);
- }
- void CImage::setup ()
- {
- // generate the main material used to copy the image to the correct texture
- this->m_copyMaterial = new Effects::CMaterial (
- new CEffect (this, new Core::Objects::CEffect ("", "", "", "", this->m_image)),
- this->m_image->getMaterial ()
- );
- // generate the main material used to render the image
- this->m_material = new Effects::CMaterial (
- new CEffect (this, new Core::Objects::CEffect ("", "", "", "", this->m_image)),
- this->m_image->getMaterial ()
- );
- // generate the effects used by this material
- auto cur = this->getImage ()->getEffects ().begin ();
- auto end = this->getImage ()->getEffects ().end ();
- for (; cur != end; cur ++)
- this->m_effects.emplace_back (new CEffect (this, *cur));
- }
- void CImage::pinpongFramebuffer (CFBO** drawTo, ITexture** asInput)
- {
- // temporarily store FBOs used
- CFBO* currentMainFBO = this->m_currentMainFBO;
- CFBO* currentSubFBO = this->m_currentSubFBO;
- if (drawTo != nullptr)
- *drawTo = currentSubFBO;
- if (asInput != nullptr)
- *asInput = currentMainFBO;
- // swap the FBOs
- this->m_currentMainFBO = currentSubFBO;
- this->m_currentSubFBO = currentMainFBO;
- }
- void CImage::simpleRender ()
- {
- // first render to the composite layer
- auto cur = this->m_copyMaterial->getPasses ().begin ();
- auto end = this->m_copyMaterial->getPasses ().end ();
- for (; cur != end; cur ++)
- (*cur)->render (this->m_mainFBO, this->getTexture (), *this->getCopySpacePosition (), *this->getTexCoordCopy (), this->m_modelViewProjectionPass);
- // a simple material renders directly to the screen
- cur = this->m_material->getPasses ().begin ();
- end = this->m_material->getPasses ().end ();
- for (; cur != end; cur ++)
- (*cur)->render (this->getScene ()->getFBO (), this->m_mainFBO, *this->getSceneSpacePosition (), *this->getTexCoordPass (), this->m_modelViewProjectionScreen);
- }
- void CImage::complexRender ()
- {
- // start drawing to the main framebuffer
- CFBO* drawTo = this->m_mainFBO;
- ITexture* asInput = this->getTexture ();
- // do the first pass render into the main framebuffer
- auto cur = this->m_copyMaterial->getPasses ().begin ();
- auto end = this->m_copyMaterial->getPasses ().end ();
- for (; cur != end; cur ++)
- (*cur)->render (drawTo, asInput, *this->getCopySpacePosition (), *this->getTexCoordCopy (), this->m_modelViewProjectionPass);
- // render all the other materials
- auto effectCur = this->getEffects ().begin ();
- auto effectEnd = this->getEffects ().end ();
- for (; effectCur != effectEnd; effectCur ++)
- {
- auto materialCur = (*effectCur)->getMaterials ().begin ();
- auto materialEnd = (*effectCur)->getMaterials ().end ();
- for (; materialCur != materialEnd; materialCur ++)
- {
- // set viewport and target texture if needed
- if ((*materialCur)->getMaterial ()->hasTarget () == true)
- {
- // setup target texture
- std::string target = (*materialCur)->getMaterial ()->getTarget ();
- drawTo = (*effectCur)->findFBO (target);
- // not a local FBO, so try that one now
- if (drawTo == nullptr)
- // this one throws if no fbo was found
- drawTo = this->getScene ()->findFBO (target);
- }
- auto passCur = (*materialCur)->getPasses ().begin ();
- auto passEnd = (*materialCur)->getPasses ().end ();
- for (; passCur != passEnd; passCur ++)
- {
- GLuint spacePosition = *this->getPassSpacePosition ();
- glm::mat4 projection = this->m_modelViewProjectionPass;
- // ping-pong only if there's a target
- if ((*materialCur)->getMaterial ()->hasTarget () == false)
- {
- this->pinpongFramebuffer (&drawTo, &asInput);
- spacePosition = *this->getCopySpacePosition ();
- projection = this->m_modelViewProjectionScreen;
- }
- (*passCur)->render (drawTo, asInput, spacePosition, *this->getTexCoordPass (), this->m_modelViewProjectionPass);
- }
- }
- }
- if (this->getImage ()->isVisible () == false)
- return;
- // pinpong the framebuffer so we know exactly what we're drawing to the scene
- this->pinpongFramebuffer (&drawTo, &asInput);
- // final step, this one might need more changes, should passes render directly to the output instead of an intermediate framebuffer?
- // do the first pass render into the main framebuffer
- cur = this->m_material->getPasses ().begin ();
- end = this->m_material->getPasses ().end ();
- glColorMask (true, true, true, false);
- for (; cur != end; cur ++)
- (*cur)->render (this->getScene ()->getFBO (), asInput, *this->getSceneSpacePosition (), *this->getTexCoordPass (), this->m_modelViewProjectionScreen);
- }
- void CImage::render ()
- {
- // first and foremost reset the framebuffer switching
- this->m_currentMainFBO = this->m_mainFBO;
- this->m_currentSubFBO = this->m_subFBO;
- glColorMask (true, true, true, true);
- // check if there's more than one pass and do different things based on that
- if (this->m_effects.empty () == true)
- this->simpleRender ();
- else
- this->complexRender ();
- }
- ITexture* CImage::getTexture () const
- {
- return this->m_texture;
- }
- const Core::Objects::CImage* CImage::getImage () const
- {
- return this->m_image;
- }
- const std::vector<CEffect*>& CImage::getEffects () const
- {
- return this->m_effects;
- }
- const glm::vec2 CImage::getSize() const
- {
- if (this->m_texture == nullptr)
- return this->getImage ()->getSize ();
- return {this->m_texture->getRealWidth (), this->m_texture->getRealHeight ()};
- }
- const GLuint* CImage::getSceneSpacePosition () const
- {
- return &this->m_sceneSpacePosition;
- }
- const GLuint* CImage::getCopySpacePosition () const
- {
- return &this->m_copySpacePosition;
- }
- const GLuint* CImage::getPassSpacePosition () const
- {
- return &this->m_passSpacePosition;
- }
- const GLuint* CImage::getTexCoordCopy () const
- {
- return &this->m_texcoordCopy;
- }
- const GLuint* CImage::getTexCoordPass () const
- {
- return &this->m_texcoordPass;
- }
- const std::string CImage::Type = "image";
|