+ Support animated images in the background

~ ITextures can now also return sub-textures width and height
+ added proper code to handle animated images to properly play at normal speed

  this should actually fix #79 for good

Signed-off-by: Alexis Maiquez <almamu@almamu.com>
This commit is contained in:
Alexis Maiquez 2022-03-06 01:27:36 +01:00
parent 34635ba6ac
commit cad78c58f9
8 changed files with 173 additions and 68 deletions

View File

@ -191,7 +191,7 @@ CTexture::~CTexture ()
delete this->getHeader ();
}
const GLuint CTexture::getTextureID (int imageIndex) const
const GLuint CTexture::getTextureID (uint32_t imageIndex) const
{
// ensure we do not go out of bounds
if (imageIndex > this->m_header->imageCount)
@ -200,14 +200,20 @@ const GLuint CTexture::getTextureID (int imageIndex) const
return this->m_textureID [imageIndex];
}
const uint32_t CTexture::getTextureWidth () const
const uint32_t CTexture::getTextureWidth (uint32_t imageIndex) const
{
if (imageIndex > this->m_header->imageCount)
return this->getHeader ()->textureWidth;
return (*this->m_header->images [imageIndex].begin ())->width;
}
const uint32_t CTexture::getTextureHeight () const
const uint32_t CTexture::getTextureHeight (uint32_t imageIndex) const
{
if (imageIndex > this->m_header->imageCount)
return this->getHeader ()->textureHeight;
return (*this->m_header->images [imageIndex].begin ())->height;
}
const uint32_t CTexture::getRealWidth () const
@ -235,6 +241,11 @@ const glm::vec4* CTexture::getResolution () const
return &this->m_resolution;
}
const std::vector<ITexture::TextureFrame*>& CTexture::getFrames () const
{
return this->getHeader ()->frames;
}
const bool CTexture::isAnimated () const
{
return this->getHeader ()->isAnimated ();
@ -408,8 +419,8 @@ CTexture::TextureHeader* CTexture::parseHeader (char* fileData)
{
TextureFrame* first = *header->frames.begin ();
header->gifWidth = first->width;
header->gifHeight = first->height;
header->gifWidth = first->width1;
header->gifHeight = first->height1;
}
}
@ -433,10 +444,10 @@ CTexture::TextureFrame* CTexture::parseAnimation (TextureHeader* header, char**
frame->frametime = *fPointer ++;
frame->x = *fPointer ++;
frame->y = *fPointer ++;
frame->width = *fPointer ++;
frame->unk0 = *fPointer ++;
frame->unk1 = *fPointer ++;
frame->height = *fPointer ++;
frame->width1 = *fPointer ++;
frame->width2 = *fPointer ++;
frame->height2 = *fPointer ++;
frame->height1 = *fPointer ++;
// get back the pointer into fileData so it can be reused later
*originalFileData = reinterpret_cast <char*> (fPointer);

View File

@ -21,13 +21,14 @@ namespace WallpaperEngine::Assets
CTexture (void* fileData);
~CTexture ();
const GLuint getTextureID (int imageIndex) const override;
const uint32_t getTextureWidth () const override;
const uint32_t getTextureHeight () const override;
const GLuint getTextureID (uint32_t imageIndex = 0) const override;
const uint32_t getTextureWidth (uint32_t imageIndex = 0) const override;
const uint32_t getTextureHeight (uint32_t imageIndex = 0) const override;
const uint32_t getRealWidth () const override;
const uint32_t getRealHeight () const override;
const TextureFormat getFormat () const override;
const glm::vec4* getResolution () const override;
const std::vector<TextureFrame*>& getFrames () const override;
const bool isAnimated () const override;
private:
@ -74,28 +75,6 @@ namespace WallpaperEngine::Assets
void decompressData ();
};
class TextureFrame
{
public:
TextureFrame();
~TextureFrame();
/** The image index of this frame */
uint32_t frameNumber;
/** The amount of time this frame spends being displayed */
float frametime;
/** The x position of the frame in the texture */
float x;
/** The y position of the frame in the texture */
float y;
/** The width of the frame in the texture */
float width;
float unk0;
float unk1;
/** The height of the frame in the texture */
float height;
};
/**
* Configures how the texture will be handled by the background
*/

View File

@ -2,12 +2,35 @@
#include <GL/glew.h>
#include <glm/vec4.hpp>
#include <vector>
namespace WallpaperEngine::Assets
{
class ITexture
{
public:
class TextureFrame
{
public:
TextureFrame();
~TextureFrame();
/** The image index of this frame */
uint32_t frameNumber;
/** The amount of time this frame spends being displayed */
float frametime;
/** The x position of the frame in the texture */
float x;
/** The y position of the frame in the texture */
float y;
/** The width of the frame in the texture */
float width1;
float width2;
float height2;
/** The height of the frame in the texture */
float height1;
};
enum TextureFormat : uint32_t
{
ARGB8888 = 0,
@ -18,12 +41,13 @@ namespace WallpaperEngine::Assets
R8 = 9,
};
virtual const GLuint getTextureID (int imageIndex) const = 0;
virtual const uint32_t getTextureWidth () const = 0;
virtual const uint32_t getTextureHeight () const = 0;
virtual const GLuint getTextureID (uint32_t imageIndex = 0) const = 0;
virtual const uint32_t getTextureWidth (uint32_t imageIndex = 0) const = 0;
virtual const uint32_t getTextureHeight (uint32_t imageIndex = 0) const = 0;
virtual const uint32_t getRealWidth () const = 0;
virtual const uint32_t getRealHeight () const = 0;
virtual const TextureFormat getFormat () const = 0;
virtual const std::vector<TextureFrame*>& getFrames () const = 0;
virtual const glm::vec4* getResolution () const = 0;
virtual const bool isAnimated () const = 0;
};

View File

@ -69,16 +69,16 @@ GLuint CFBO::getDepthbuffer () const
return this->m_depthbuffer;
}
const GLuint CFBO::getTextureID (int imageIndex) const
const GLuint CFBO::getTextureID (uint32_t imageIndex) const
{
return this->m_texture;
}
const uint32_t CFBO::getTextureWidth () const
const uint32_t CFBO::getTextureWidth (uint32_t imageIndex) const
{
return this->m_resolution.x;
}
const uint32_t CFBO::getTextureHeight () const
const uint32_t CFBO::getTextureHeight (uint32_t imageIndex) const
{
return this->m_resolution.y;
}
@ -93,6 +93,11 @@ const uint32_t CFBO::getRealHeight () const
return this->m_resolution.w;
}
const std::vector<ITexture::TextureFrame*>& CFBO::getFrames () const
{
return std::vector<TextureFrame*> ();
}
const glm::vec4* CFBO::getResolution () const
{
return &this->m_resolution;

View File

@ -18,11 +18,12 @@ namespace WallpaperEngine::Render
const ITexture::TextureFormat getFormat () const override;
GLuint getFramebuffer () const;
GLuint getDepthbuffer () const;
const GLuint getTextureID (int imageIndex) const override;
const uint32_t getTextureWidth () const override;
const uint32_t getTextureHeight () const override;
const GLuint getTextureID (uint32_t imageIndex = 0) const override;
const uint32_t getTextureWidth (uint32_t imageIndex = 0) const override;
const uint32_t getTextureHeight (uint32_t imageIndex = 0) const override;
const uint32_t getRealWidth () const override;
const uint32_t getRealHeight () const override;
const std::vector<TextureFrame*>& getFrames () const override;
const glm::vec4* getResolution () const override;
const bool isAnimated () const override;

View File

@ -69,8 +69,8 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
nameA << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_a";
nameB << "_rt_imageLayerComposite_" << this->getImage ()->getId () << "_b";
this->m_currentMainFBO = this->m_mainFBO = scene->createFBO (nameA.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 (nameB.str (), ITexture::TextureFormat::ARGB8888, 1, this->m_texture->getRealWidth (), this->m_texture->getRealHeight (), this->m_texture->getRealWidth (), this->m_texture->getRealHeight ());
this->m_currentMainFBO = this->m_mainFBO = scene->createFBO (nameA.str (), ITexture::TextureFormat::ARGB8888, 1, this->m_texture->getTextureWidth (), this->m_texture->getTextureHeight (), this->m_texture->getTextureWidth (), this->m_texture->getTextureHeight ());
this->m_currentSubFBO = this->m_subFBO = scene->createFBO (nameB.str (), ITexture::TextureFormat::ARGB8888, 1, this->m_texture->getTextureWidth (), this->m_texture->getTextureHeight (), this->m_texture->getTextureWidth (), this->m_texture->getTextureHeight ());
GLfloat realWidth = this->m_texture->getRealWidth () / 2;
GLfloat realHeight = this->m_texture->getRealHeight () / 2;
@ -106,8 +106,14 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
float width = 1.0f;
float height = 1.0f;
if (this->getTexture ()->isAnimated () == true)
{
// animated images use different coordinates as they're essentially a texture atlast
width = static_cast<float> (this->getTexture ()->getRealWidth ()) / static_cast<float> (this->getTexture ()->getTextureWidth ());
height = static_cast<float> (this->getTexture ()->getRealHeight ()) / static_cast<float> (this->getTexture ()->getTextureHeight ());
}
// calculate the correct texCoord limits for the texture based on the texture screen size and real size
if (this->getTexture () != nullptr &&
else if (this->getTexture () != nullptr &&
(this->getTexture ()->getTextureWidth () != this->getTexture ()->getRealWidth () ||
this->getTexture ()->getTextureHeight () != this->getTexture ()->getRealHeight ())
)
@ -122,12 +128,24 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
height = size.y * scale.y / y;
}
float x = 0.0f;
float y = 0.0f;
if (this->getTexture ()->isAnimated () == true)
{
// animations should be copied completely
x = 0.0f;
y = 0.0f;
width = 1.0f;
height = 1.0f;
}
GLfloat texcoordCopy [] = {
0.0f, 0.0f,
width, 0.0f,
0.0f, height,
0.0f, height,
width, 0.0f,
x, y,
width, y,
x, height,
x, height,
width, y,
width, height
};
@ -177,12 +195,14 @@ void CImage::setup ()
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 ();
@ -191,6 +211,16 @@ void CImage::setup ()
this->m_effects.emplace_back (new CEffect (this, *cur));
}
// calculate full animation time (if any)
this->m_animationTime = 0.0f;
auto cur = this->getTexture ()->getFrames ().begin ();
auto end = this->getTexture ()->getFrames ().end ();
for (; cur != end; cur ++)
this->m_animationTime += (*cur)->frametime;
}
void CImage::pinpongFramebuffer (CFBO** drawTo, ITexture** asInput)
{
// temporarily store FBOs used
@ -208,6 +238,15 @@ void CImage::pinpongFramebuffer (CFBO** drawTo, ITexture** asInput)
}
void CImage::simpleRender ()
{
ITexture* input = this->m_mainFBO;
// FIXME: THIS IS A QUICK HACK FOR ANIMATED IMAGES, IF ANY OF THOSE HAVE ANY EFFECT ON THEM THIS WILL LIKELY BREAK
if (this->getTexture ()->isAnimated () == true)
{
input = this->getTexture ();
}
else
{
// first render to the composite layer
auto cur = this->m_copyMaterial->getPasses ().begin ();
@ -215,13 +254,14 @@ void CImage::simpleRender ()
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 ();
auto cur = this->m_material->getPasses ().begin ();
auto 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);
(*cur)->render (this->getScene ()->getFBO (), input, *this->getSceneSpacePosition (), *this->getTexCoordPass (), this->m_modelViewProjectionScreen);
}
void CImage::complexRender ()
@ -319,6 +359,11 @@ ITexture* CImage::getTexture () const
return this->m_texture;
}
const double CImage::getAnimationTime () const
{
return this->m_animationTime;
}
const Core::Objects::CImage* CImage::getImage () const
{
return this->m_image;

View File

@ -45,6 +45,7 @@ namespace WallpaperEngine::Render::Objects
const GLuint* getTexCoordCopy () const;
const GLuint* getTexCoordPass () const;
ITexture* getTexture () const;
const double getAnimationTime () const;
/**
* Performs a ping-pong on the available framebuffers to be able to continue rendering things to them
@ -80,5 +81,7 @@ namespace WallpaperEngine::Render::Objects
std::vector<CEffect*> m_effects;
Effects::CMaterial* m_material;
Effects::CMaterial* m_copyMaterial;
double m_animationTime;
};
}

View File

@ -138,8 +138,42 @@ void CPass::render (CFBO* drawTo, ITexture* input, GLuint position, GLuint texco
ITexture* texture = this->resolveTexture (input, 0, input);
uint32_t currentTexture = 0;
glm::vec2 translation = {0.0f, 0.0f};
glm::vec4 rotation = {0.0f, 0.0f, 0.0f, 0.0f};
if (texture->isAnimated () == true)
{
// calculate current texture and frame
double currentRenderTime = fmod (static_cast <double> (g_Time), this->m_material->getImage ()->getAnimationTime ());
// find the right frame now
auto frameCur = texture->getFrames ().begin ();
auto frameEnd = texture->getFrames ().end ();
for (; frameCur != frameEnd; frameCur ++)
{
currentRenderTime -= (*frameCur)->frametime;
if (currentRenderTime <= 0.0f)
{
// frame found, store coordinates and done
currentTexture = (*frameCur)->frameNumber;
translation.x = (*frameCur)->x / texture->getTextureWidth (currentTexture);
translation.y = (*frameCur)->y / texture->getTextureHeight (currentTexture);
rotation.x = (*frameCur)->width1 / static_cast<float> (texture->getTextureWidth (currentTexture));
rotation.y = (*frameCur)->width2 / static_cast<float> (texture->getTextureWidth(currentTexture));
rotation.z = (*frameCur)->height2 / static_cast<float> (texture->getTextureHeight (currentTexture));
rotation.w = (*frameCur)->height1 / static_cast<float> (texture->getTextureHeight (currentTexture));
break;
}
}
}
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, texture->getTextureID (0));
glBindTexture (GL_TEXTURE_2D, texture->getTextureID (currentTexture));
int lastTextureIndex = 0;
// first bind the textures to their sampler place
@ -233,11 +267,14 @@ void CPass::render (CFBO* drawTo, ITexture* input, GLuint position, GLuint texco
if (this->g_Texture0Rotation != -1)
{
glUniform4f (this->g_Texture0Rotation, 1.0f, 0.0f, 1.0f, 0.0f);
// used in animations when one of the frames is vertical instead of horizontal
// rotation with translation = origin and end of the image to display
glUniform4f (this->g_Texture0Rotation, rotation.x, rotation.y, rotation.z, rotation.w);
}
if (this->g_Texture0Translation != -1)
{
glUniform2f (this->g_Texture0Translation, 0.0f, 0.0f);
// this actually picks the origin point of the image from the atlast
glUniform2f (this->g_Texture0Translation, translation.x, translation.y);
}
{
auto cur = this->m_attribs.begin ();