animated texture

This commit is contained in:
Eduardo Bart 2011-05-12 20:24:57 -03:00
parent c6753747fb
commit 42eae9afd8
32 changed files with 289 additions and 146 deletions

View File

@ -22,7 +22,7 @@ MESSAGE(STATUS "BUILD TYPE: " ${CMAKE_BUILD_TYPE})
# setup compiler options
IF(CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror -Wno-unused-parameter -std=gnu++0x")
SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-but-set-variable -std=gnu++0x")
SET(CMAKE_CXX_FLAGS_DEBUG "-O1 -g -ggdb -fno-inline")
SET(CMAKE_CXX_FLAGS_RELEASE "-O2 -Wl,-s")
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
@ -76,6 +76,7 @@ SET(SOURCES
src/framework/util/util.cpp
src/framework/util/logger.cpp
src/framework/util/rsa.cpp
src/framework/util/apngloader.cpp
# framework graphics
src/framework/graphics/image.cpp
@ -85,6 +86,7 @@ SET(SOURCES
src/framework/graphics/fonts.cpp
src/framework/graphics/textureloader.cpp
src/framework/graphics/texture.cpp
src/framework/graphics/animatedtexture.cpp
src/framework/graphics/textures.cpp
src/framework/graphics/graphics.cpp
src/framework/graphics/textarea.cpp

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,8 @@
glyph height: 14
glyph spacing: [0, 1]
top margin: 0
image: sans-11px-bold.png
image glyph size: [16, 16]
glyph widths:
32: 4

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -3,7 +3,6 @@ glyph spacing: [0, 1]
top margin: 0
image: sans-11px.png
image glyph size: [16, 16]
first glyph: 0
glyph widths:
32: 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,8 @@
glyph height: 14
glyph spacing: [0, 1]
top margin: 0
image: sans-12px-bold.png
image glyph size: [20, 16]
glyph widths:
32: 4

BIN
data/fonts/sans-12px.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

8
data/fonts/sans-12px.yml Normal file
View File

@ -0,0 +1,8 @@
glyph height: 16
glyph spacing: [0, 1]
top margin: 0
image: sans-12px.png
image glyph size: [20, 16]
glyph widths:
32: 4

View File

@ -39,6 +39,7 @@ window#infoWindow:
button#websiteButton:
text: Github Page
size: [80,22]
anchors.right: parent.right
anchors.bottom: parent.bottom
margin.bottom: 9

View File

@ -5,6 +5,13 @@ panel#background:
anchors.top: parent.top
anchors.bottom: parent.bottom
panel#icos4d:
skin: icos4d
anchors.left: parent.left
anchors.top: parent.top
margin.left: 60
margin.top: 70
panel#mainMenu:
skin: roundedGridPanel
size: [117, 171]

View File

@ -1,5 +1,5 @@
default font: sans-11px
default font color: [0, 115, 234, 255]
default font: sans-11px-bold
default font color: [51, 51, 51, 255]
buttons:
default:
@ -53,6 +53,9 @@ panels:
image: lightness/background.png
antialised: true
icos4d:
image: lightness/icos4d.png
roundedGridPanel:
bordered image:
source: lightness/menupanel.png
@ -81,10 +84,11 @@ panels:
labels:
default:
font color: [0, 115, 234, 255]
font: sans-12px
windows:
default:
font: sans-12px-bold
font color: [80, 80, 80, 255]
head:
text align: left

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 KiB

View File

@ -32,6 +32,7 @@
#include <net/connection.h>
#include <script/luascript.h>
#include <ui/uiskins.h>
#include <graphics/textures.h>
Engine g_engine;

View File

@ -0,0 +1,106 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <graphics/animatedtexture.h>
#include <GL/gl.h>
#include <core/engine.h>
#include <core/dispatcher.h>
AnimatedTexture::AnimatedTexture(int width, int height, int components, int numFrames, uchar *framesPixels, int *framesDelay) :
Texture(),
m_numFrames(numFrames)
{
m_size.setSize(width, height);
m_framesTextureId = new uint[numFrames];
m_framesDelay = new int[numFrames];
GLenum format = 0;
switch(components) {
case 4:
format = GL_RGBA;
break;
case 3:
format = GL_RGB;
break;
case 2:
format = GL_LUMINANCE_ALPHA;
break;
case 1:
format = GL_LUMINANCE;
break;
}
glGenTextures(numFrames, m_framesTextureId);
for(int i=0;i<numFrames;++i) {
glBindTexture(GL_TEXTURE_2D, m_framesTextureId[i]);
// load the pixels into opengl memory
uchar *framePixels = framesPixels + (i*height*width*components);
glTexImage2D(GL_TEXTURE_2D, 0, components, width, height, 0, format, GL_UNSIGNED_BYTE, framePixels);
// disable texture border
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// nearest filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
m_framesDelay[i] = framesDelay[i];
}
m_currentFrame = -1;
g_dispatcher.scheduleTask(boost::bind(&AnimatedTexture::processAnimation, this), 0);
}
AnimatedTexture::~AnimatedTexture()
{
glDeleteTextures(m_numFrames, m_framesTextureId);
delete[] m_framesTextureId;
delete[] m_framesDelay;
m_textureId = 0;
}
void AnimatedTexture::enableBilinearFilter()
{
for(int i=0;i<m_numFrames;++i) {
glBindTexture(GL_TEXTURE_2D, m_framesTextureId[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
}
void AnimatedTexture::processAnimation()
{
m_currentFrame++;
if(m_currentFrame >= m_numFrames)
m_currentFrame = 0;
m_textureId = m_framesTextureId[m_currentFrame];
AnimatedTexturePtr me = boost::static_pointer_cast<AnimatedTexture>(shared_from_this());
if(me.use_count() > 1)
g_dispatcher.scheduleTask(boost::bind(&AnimatedTexture::processAnimation, me), m_framesDelay[m_currentFrame]);
}

View File

@ -0,0 +1,51 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef ANIMATEDTEXTURE_H
#define ANIMATEDTEXTURE_H
#include <prerequisites.h>
#include <graphics/texture.h>
class AnimatedTexture : public Texture
{
public:
AnimatedTexture(int width, int height, int components, int numFrames, uchar *framesPixels, int *framesDelay);
virtual ~AnimatedTexture();
void enableBilinearFilter();
void processAnimation();
private:
uint *m_framesTextureId;
int *m_framesDelay;
int m_numFrames;
int m_currentFrame;
int m_lastAnimCheckTicks;
};
typedef boost::shared_ptr<AnimatedTexture> AnimatedTexturePtr;
typedef boost::weak_ptr<AnimatedTexture> AnimatedTextureWeakPtr;
#endif // ANIMATEDTEXTURE_H

View File

@ -40,22 +40,24 @@ void Font::calculateGlyphsWidthsAutomatically(const Size& glyphSize)
glyphSize.width(),
m_glyphHeight);
int width = glyphSize.width();
for(int x = glyphCoords.left() + 2; x <= glyphCoords.right(); ++x) {
bool allAlpha = true;
int lastColumnFilledPixels = 0;
for(int x = glyphCoords.left() + 1; x <= glyphCoords.right(); ++x) {
int columnFilledPixels = 0;
// check if all vertical pixels are alpha
for(int y = glyphCoords.top(); y <= glyphCoords.bottom(); ++y) {
if(texturePixels[(y * m_texture->getSize().width() * 4) + (x*4) + 3] != 0) {
allAlpha = false;
break;
}
if(texturePixels[(y * m_texture->getSize().width() * 4) + (x*4) + 3] != 0)
columnFilledPixels++;
}
// if all pixels were alpha we found the width
if(allAlpha) {
if(columnFilledPixels == 0) {
width = x - glyphCoords.left();
if(m_glyphHeight >= 16 && lastColumnFilledPixels >= m_glyphHeight/3)
width += 1;
break;
}
lastColumnFilledPixels = columnFilledPixels;
}
// store glyph size
m_glyphsSize[glyph].setSize(width, m_glyphHeight);
@ -175,6 +177,20 @@ void Font::renderText(const std::string& text,
// nothing to do
}
// only render glyphs that are after 0, 0
if(glyphScreenCoords.bottom() < 0 || glyphScreenCoords.right() < 0)
continue;
// bound glyph topLeft to 0,0 if needed
if(glyphScreenCoords.top() < 0) {
glyphTextureCoords.setTop(glyphTextureCoords.top() - glyphScreenCoords.top());
glyphScreenCoords.setTop(0);
}
if(glyphScreenCoords.left() < 0) {
glyphTextureCoords.setLeft(glyphTextureCoords.left() - glyphScreenCoords.left());
glyphScreenCoords.setLeft(0);
}
// translate rect to screen coords
glyphScreenCoords.translate(screenCoords.topLeft());
@ -212,7 +228,7 @@ const std::vector<Point>& Font::calculateGlyphsPositions(const std::string& text
// return if there is no text
if(textLength == 0) {
if(textBoxSize)
textBoxSize->setSize(0,0);
textBoxSize->setSize(0,m_glyphHeight);
return glyphsPositions;
}

View File

@ -128,8 +128,10 @@ void Graphics::endRender()
void Graphics::disableDrawing()
{
glEnd();
m_drawMode = DRAW_NONE;
if(m_drawMode != DRAW_NONE) {
glEnd();
m_drawMode = DRAW_NONE;
}
}
void Graphics::drawTexturedRect(const Rect& screenCoords, const TexturePtr& texture, const Rect& textureCoords, const Color& color)

View File

@ -146,10 +146,22 @@ void TextArea::recalculate()
m_startInternalPos = Point(0,0);
}
m_drawArea.setLeft(m_screenCoords.left());
m_drawArea.setTop(m_screenCoords.top()+m_font->getTopMargin());
m_drawArea.setRight(m_screenCoords.right());
m_drawArea.setBottom(m_screenCoords.bottom());
m_drawArea = m_screenCoords;
if(m_align & AlignBottom) {
m_drawArea.translate(0, m_screenCoords.height() - textBoxSize.height());
} else if(m_align & AlignVerticalCenter) {
m_drawArea.translate(0, (m_screenCoords.height() - textBoxSize.height()) / 2);
} else { // AlignTop
}
if(m_align & AlignRight) {
m_drawArea.translate(m_screenCoords.width() - textBoxSize.width(), 0);
} else if(m_align & AlignHorizontalCenter) {
m_drawArea.translate((m_screenCoords.width() - textBoxSize.width()) / 2, 0);
} else { // AlignLeft
}
for(int i = 0; i < textLength; ++i) {
glyph = (uchar)m_text[i];

View File

@ -26,7 +26,6 @@
#include <graphics/texture.h>
#include <GL/gl.h>
#include <GL/glext.h>
Texture::Texture(int width, int height, int components, uchar *pixels)
{
@ -85,3 +84,4 @@ uchar *Texture::getPixels()
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
return pixels;
}

View File

@ -27,7 +27,7 @@
#include <prerequisites.h>
class Texture
class Texture : public boost::enable_shared_from_this<Texture>
{
public:
/// Create a texture, width and height must be a multiple of 2
@ -35,17 +35,18 @@ public:
virtual ~Texture();
/// Enable texture bilinear filter (smooth scaled textures)
void enableBilinearFilter();
virtual void enableBilinearFilter();
/// Get OpenGL texture id
uint getTextureId() const { return m_textureId; }
virtual uint getTextureId() const { return m_textureId; }
/// Copy pixels from OpenGL texture
uchar *getPixels();
const Size& getSize() const { return m_size; }
private:
protected:
Texture() { }
uint m_textureId;
Size m_size;
};

View File

@ -25,116 +25,22 @@
#include <prerequisites.h>
#include <graphics/textureloader.h>
#include <graphics/texture.h>
#include <util/apngloader.h>
#include "animatedtexture.h"
#include <png.h>
struct File
TexturePtr TextureLoader::loadPNG(uchar *fileData, uint fileSize)
{
File() {
offset = 0;
TexturePtr texture;
apng_data apng;
if(load_apng(fileData, fileSize, &apng) == 0) {
if(apng.num_frames > 1) { // animated texture
uchar *framesdata = apng.pdata + (apng.first_frame * apng.width * apng.height * apng.bpp);
texture = TexturePtr(new AnimatedTexture(apng.width, apng.height, apng.bpp, apng.num_frames, framesdata, (int*)apng.frames_delay));
} else
texture = TexturePtr(new Texture(apng.width, apng.height, apng.bpp, apng.pdata));
free_apng(&apng);
}
uchar *data;
uint offset;
};
void png_read_from_mem(png_structp png_ptr, png_bytep data, png_size_t size)
{
File *file = (File*)png_get_io_ptr(png_ptr);
/* Copy data from image buffer */
memcpy(data, file->data + file->offset, size);
/* Advance in the file */
file->offset += size;
}
Texture *TextureLoader::loadPNG(uchar *fileData)
{
File file;
file.data = fileData;
if(png_sig_cmp(file.data, 0, 8))
return NULL;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png_ptr)
return NULL;
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
return NULL;
}
if(setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
// Set "png_read" callback function and give source of data
png_set_read_fn(png_ptr, (png_voidp *)&file, png_read_from_mem);
png_read_info(png_ptr, info_ptr);
int bitDepth = png_get_bit_depth(png_ptr, info_ptr);
int colourType = png_get_color_type(png_ptr, info_ptr);
if(colourType == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
if(bitDepth < 8 && (colourType == PNG_COLOR_TYPE_GRAY || colourType == PNG_COLOR_TYPE_GRAY_ALPHA))
png_set_expand_gray_1_2_4_to_8(png_ptr);
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
if(bitDepth < 8)
png_set_packing(png_ptr);
else if(bitDepth == 16)
png_set_strip_16(png_ptr);
png_read_update_info(png_ptr, info_ptr);
png_uint_32 width, height;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colourType, NULL, NULL, NULL);
int components;
switch(colourType)
{
case PNG_COLOR_TYPE_GRAY:
components = 1;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
components = 2;
break;
case PNG_COLOR_TYPE_RGB:
components = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
components = 4;
break;
default:
if(png_ptr)
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
};
uchar *pixels = new uchar[width * height * components];
png_bytep *row_pointers = new png_bytep[height];
for(uint i = 0; i < height; ++i)
row_pointers[i] = (png_bytep)(pixels + (i * width * components));
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, NULL);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
delete[] row_pointers;
Texture *texture = new Texture(width, height, components, pixels);
delete[] pixels;
return texture;
}

View File

@ -26,14 +26,13 @@
#define TEXTURELOADER_H
#include <prerequisites.h>
class Texture;
#include <graphics/texture.h>
class TextureLoader
{
public:
/// Load a png textures using libpng
static Texture *loadPNG(uchar *fileData);
static TexturePtr loadPNG(uchar *fileData, uint fileSize);
};
#endif // TEXTURELOADER_H

View File

@ -26,6 +26,7 @@
#include <core/resources.h>
#include <graphics/textures.h>
#include <graphics/textureloader.h>
#include <core/dispatcher.h>
Textures g_textures;
@ -34,10 +35,10 @@ TexturePtr Textures::get(const std::string& textureFile)
TexturePtr texture;
// check if the texture is already loaded
auto it = m_texturesMap.find(textureFile);
if(it != m_texturesMap.end()) {
auto it = m_textures.find(textureFile);
if(it != m_textures.end()) {
if(it->second.expired())
m_texturesMap.erase(it);
m_textures.erase(it);
else
texture = it->second.lock();
}
@ -60,11 +61,10 @@ TexturePtr Textures::get(const std::string& textureFile)
// load the texture
texture = TexturePtr(TextureLoader::loadPNG(textureFileData));
texture = TexturePtr(TextureLoader::loadPNG(textureFileData, fileSize));
if(!texture)
flogError("ERROR: Unable to load texture %s", textureFile.c_str());
delete[] textureFileData;
}
return texture;
}

View File

@ -27,6 +27,7 @@
#include <prerequisites.h>
#include <graphics/texture.h>
#include <graphics/animatedtexture.h>
class Textures
{
@ -37,8 +38,7 @@ public:
TexturePtr get(const std::string& textureFile);
private:
typedef std::map<std::string, TextureWeakPtr> TexturesMap;
TexturesMap m_texturesMap;
std::map<std::string, TextureWeakPtr> m_textures;
};
extern Textures g_textures;

View File

@ -37,7 +37,7 @@ void UIButton::onInputEvent(const InputEvent& event)
g_dispatcher.addTask(boost::bind(&Scriptable::callLuaTableField, shared_from_this(), "onClick"));
}
} else if(event.type == EV_MOUSE_MOVE && m_state != ButtonDown) {
if(getRect().contains(event.mousePos) && UIContainer::getRoot()->recursiveGetChildByPos(event.mousePos) == asUIElement())
if(isMouseOver())
m_state = ButtonMouseOver;
else
m_state = ButtonUp;

View File

@ -213,6 +213,13 @@ void UIContainer::onInputEvent(const InputEvent& event)
}
} else {
shouldFire = true;
if(event.type == EV_MOUSE_MOVE) {
if(child->getRect().contains(event.mousePos) && UIContainer::getRoot()->recursiveGetChildByPos(event.mousePos) == child)
child->setMouseOver(true);
else
child->setMouseOver(false);
}
}
}
}

View File

@ -35,6 +35,7 @@ UIElement::UIElement(UI::ElementType type) :
m_type(type),
m_visible(true),
m_enabled(true),
m_mouseOver(false),
m_marginLeft(0),
m_marginRight(0),
m_marginTop(0),

View File

@ -83,6 +83,9 @@ public:
void setFocused(bool focused);
bool isFocused() const;
void setMouseOver(bool mouseOver) { m_mouseOver = mouseOver; }
bool isMouseOver() const { return m_mouseOver; }
void setVisible(bool visible) { m_visible = visible; }
bool isVisible() const { return m_visible; }
@ -123,6 +126,7 @@ private:
std::string m_id;
bool m_visible;
bool m_enabled;
bool m_mouseOver;
Rect m_rect;
int m_marginLeft;

View File

@ -92,6 +92,8 @@ ImagePtr UIElementSkin::loadImage(const YAML::Node& node)
texture = g_textures.get("skins/" + yamlRead<std::string>(node, "image"));
if(texture)
image = ImagePtr(new Image(texture));
if(!m_defaultSize.isValid())
m_defaultSize = texture->getSize();
if(!image)
logError(yamlErrorDesc(node["image"], "failed to load image"));

View File

@ -34,8 +34,7 @@ class UILabel : public UIElement
public:
UILabel() :
UIElement(UI::Label),
m_align(AlignTopLeft),
m_color(Color::white) { }
m_align(AlignLeftCenter) { }
void setText(const std::string& text);
std::string getText() const { return m_text; }
@ -48,7 +47,6 @@ public:
private:
std::string m_text;
AlignmentFlag m_align;
Color m_color;
};
typedef boost::shared_ptr<UILabel> UILabelPtr;

View File

@ -232,7 +232,7 @@ void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
else if(element->getElementType() == UI::Label) {
UILabelPtr label = boost::static_pointer_cast<UILabel>(element);
label->setText(yamlRead(node, "text", std::string()));
label->setAlign(parseAlignment(yamlRead(node, "align", std::string())));
label->setAlign(parseAlignment(yamlRead(node, "align", std::string("left"))));
}
}