diff --git a/src/Makefile.am b/src/Makefile.am index c0d3dece..34cd258a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -50,6 +50,7 @@ liblol_a_SOURCES = \ gpu/indexbuffer.cpp gpu/indexbuffer.h \ gpu/vertexbuffer.cpp gpu/vertexbuffer.h \ gpu/framebuffer.cpp gpu/framebuffer.h \ + gpu/texture.cpp gpu/texture.h \ \ gpu/defaultmaterial.lolfx \ gpu/tile.lolfx \ diff --git a/src/core.h b/src/core.h index eb08aae6..87a3e64d 100644 --- a/src/core.h +++ b/src/core.h @@ -115,6 +115,7 @@ static inline int isnan(float f) #include "layer.h" #include "gpu/lolfx.h" #include "gpu/shader.h" +#include "gpu/texture.h" #include "gpu/indexbuffer.h" #include "gpu/vertexbuffer.h" #include "gpu/framebuffer.h" diff --git a/src/gpu/texture.cpp b/src/gpu/texture.cpp new file mode 100644 index 00000000..81d0d91a --- /dev/null +++ b/src/gpu/texture.cpp @@ -0,0 +1,176 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2012 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://sam.zoy.org/projects/COPYING.WTFPL for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" +#include "lolgl.h" + +#if defined _WIN32 && defined USE_D3D9 +# define FAR +# define NEAR +# include +#endif + +using namespace std; + +#if defined USE_D3D9 +extern IDirect3DDevice9 *g_d3ddevice; +#elif defined _XBOX +extern D3DDevice *g_d3ddevice; +#endif + +namespace lol +{ + +// +// The TextureData class +// --------------------- +// + +class TextureData +{ + friend class Texture; + + ivec2 m_size; + +#if defined USE_D3D9 + IDirect3DTexture9 *m_tex; +#elif defined _XBOX + D3DTexture *m_tex; +#else + GLuint m_texid; +#endif +}; + +// +// The Texture class +// ----------------- +// + +/* FIXME: this is all hardcoded over the place */ +#if __CELLOS_LV2__ +static GLint const INTERNAL_FORMAT = GL_ARGB_SCE; +static GLenum const TEXTURE_FORMAT = GL_BGRA; +static GLenum const TEXTURE_TYPE = GL_UNSIGNED_INT_8_8_8_8_REV; +#elif defined __native_client__ || defined HAVE_GLES_2X +static GLint const INTERNAL_FORMAT = GL_RGBA; +static GLenum const TEXTURE_FORMAT = GL_RGBA; +static GLenum const TEXTURE_TYPE = GL_UNSIGNED_BYTE; +#else +/* Seems efficient for little endian textures */ +static GLint const INTERNAL_FORMAT = GL_RGBA; +static GLenum const TEXTURE_FORMAT = GL_BGRA; +static GLenum const TEXTURE_TYPE = GL_UNSIGNED_INT_8_8_8_8_REV; +#endif + +Texture::Texture(ivec2 size) + : m_data(new TextureData) +{ + m_data->m_size = size; + +#if defined USE_D3D9 + g_d3ddevice->CreateTexture(m_data->m_size.x, m_data->m_size.y, 1, + D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, + D3DPOOL_SYSTEMMEM, &m_tex, NULL); +#elif defined _XBOX + /* By default the X360 will swizzle the texture. Ask for linear. */ + g_d3ddevice->CreateTexture(m_data->m_size.x, m_data->m_size.y, 1, + D3DUSAGE_WRITEONLY, D3DFMT_LIN_A8R8G8B8, + D3DPOOL_DEFAULT, &m_tex, NULL); +#else + glGenTextures(1, &m_data->m_texid); + glBindTexture(GL_TEXTURE_2D, m_data->m_texid); + +# if defined __CELLOS_LV2__ + /* We need this hint because by default the storage type is + * GL_TEXTURE_SWIZZLED_GPU_SCE. */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ALLOCATION_HINT_SCE, + GL_TEXTURE_TILED_GPU_SCE); +# endif + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +#endif +} + +void Texture::Bind() +{ +#if defined _XBOX || defined USE_D3D9 + g_d3ddevice->SetTexture(0, m_data->m_tex); +#else +# if !defined HAVE_GLES_2X + glEnable(GL_TEXTURE_2D); +# endif + glBindTexture(GL_TEXTURE_2D, m_data->m_texid); +#endif +} + +void Texture::SetData(void *data) +{ +#if defined _XBOX || defined USE_D3D9 + D3DLOCKED_RECT rect; +# if defined _XBOX + m_data->m_tex->LockRect(0, &rect, NULL, D3DLOCK_NOOVERWRITE); +# else + m_data->m_tex->LockRect(0, &rect, NULL, + D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE); +# endif + memcpy(rect.pBits, data, rect.Pitch * rect.Height); + + m_data->m_tex->UnlockRect(0); + +#else + glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, + m_data->m_size.x, m_data->m_size.y, 0, + TEXTURE_FORMAT, TEXTURE_TYPE, data); +#endif +} + +void Texture::SetSubData(ivec2 origin, ivec2 size, void *data) +{ +#if defined _XBOX || defined USE_D3D9 + D3DLOCKED_RECT rect; +# if defined _XBOX + m_data->m_tex->LockRect(0, &rect, NULL, D3DLOCK_NOOVERWRITE); +# else + m_data->m_tex->LockRect(0, &rect, NULL, + D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE); +# endif + for (int j = 0; j < size.y; j++) + { + uint8_t *dst = (uint8_t *)rect.pBits + (origin.y + j) * rect.Pitch; + /* FIXME: the source or destination pitch isn't necessarily 4! */ + uint8_t *src = (uint8_t *)data + j * size.y * 4; + memcpy(dst, src, size.y * 4); + } + + m_data->m_tex->UnlockRect(0); + +#else + glTexSubImage2D(GL_TEXTURE_2D, 0, origin.x, origin.y, size.x, size.y, + TEXTURE_FORMAT, TEXTURE_TYPE, data); +#endif +} + +Texture::~Texture() +{ +#if defined USE_D3D9 || defined _XBOX + m_data->m_tex->Release(); +#else + glDeleteTextures(1, &m_data->m_texid); +#endif + + delete m_data; +} + +} /* namespace lol */ + diff --git a/src/gpu/texture.h b/src/gpu/texture.h new file mode 100644 index 00000000..b9bb3332 --- /dev/null +++ b/src/gpu/texture.h @@ -0,0 +1,39 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2012 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://sam.zoy.org/projects/COPYING.WTFPL for more details. +// + +// +// The Texture class +// ----------------- +// + +#if !defined __LOL_TEXTURE_H__ +#define __LOL_TEXTURE_H__ + +namespace lol +{ + +class Texture +{ +public: + Texture(ivec2 size); + ~Texture(); + + void Bind(); + void SetData(void *data); + void SetSubData(ivec2 origin, ivec2 size, void *data); + +private: + class TextureData *m_data; +}; + +} /* namespace lol */ + +#endif // __LOL_TEXTURE_H__ + diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index 03321df5..00dcff14 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -254,6 +254,7 @@ + @@ -567,6 +568,7 @@ + diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters index e5160ce7..27db2b4f 100644 --- a/src/lolcore.vcxproj.filters +++ b/src/lolcore.vcxproj.filters @@ -97,6 +97,9 @@ src\gpu + + src\gpu + src\gpu @@ -669,6 +672,9 @@ src\gpu + + src\gpu + src\gpu diff --git a/tutorial/11_fractal.cpp b/tutorial/11_fractal.cpp index b9afa71c..1316fc8f 100644 --- a/tutorial/11_fractal.cpp +++ b/tutorial/11_fractal.cpp @@ -15,41 +15,12 @@ #include #include "core.h" -#include "lolgl.h" #include "loldebug.h" using namespace lol; -#if defined _WIN32 -# include -# if defined USE_D3D9 -# define FAR -# define NEAR -# include -# endif -#endif - extern char const *lolfx_11_fractal; -#if defined USE_D3D9 -extern IDirect3DDevice9 *g_d3ddevice; -#elif defined _XBOX -extern D3DDevice *g_d3ddevice; -#elif __CELLOS_LV2__ -static GLint const INTERNAL_FORMAT = GL_ARGB_SCE; -static GLenum const TEXTURE_FORMAT = GL_BGRA; -static GLenum const TEXTURE_TYPE = GL_UNSIGNED_INT_8_8_8_8_REV; -#elif defined __native_client__ || defined HAVE_GLES_2X -static GLint const INTERNAL_FORMAT = GL_RGBA; -static GLenum const TEXTURE_FORMAT = GL_RGBA; -static GLenum const TEXTURE_TYPE = GL_UNSIGNED_BYTE; -#else -/* Seems efficient for little endian textures */ -static GLint const INTERNAL_FORMAT = GL_RGBA; -static GLenum const TEXTURE_FORMAT = GL_BGRA; -static GLenum const TEXTURE_TYPE = GL_UNSIGNED_INT_8_8_8_8_REV; -#endif - class Fractal : public WorldEntity { public: @@ -467,32 +438,13 @@ public: if (!m_ready) { -#if !defined _XBOX && !defined USE_D3D9 /* Create a texture of half the width and twice the height * so that we can upload four different subimages each frame. */ - glGenTextures(1, &m_texid); - glBindTexture(GL_TEXTURE_2D, m_texid); - glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, - m_size.x / 2, m_size.y * 2, 0, - TEXTURE_FORMAT, TEXTURE_TYPE, &m_pixels[0]); -# if defined __CELLOS_LV2__ - /* We need this hint because by default the storage type is - * GL_TEXTURE_SWIZZLED_GPU_SCE. */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ALLOCATION_HINT_SCE, - GL_TEXTURE_TILED_GPU_SCE); -# endif - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -#elif defined _XBOX - /* By default the X360 will swizzle the texture. Ask for linear. */ - g_d3ddevice->CreateTexture(m_size.x / 2, m_size.y * 2, 1, - D3DUSAGE_WRITEONLY, D3DFMT_LIN_A8R8G8B8, - D3DPOOL_DEFAULT, &m_tex, NULL); -#else - g_d3ddevice->CreateTexture(m_size.x / 2, m_size.y * 2, 1, - D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, - D3DPOOL_SYSTEMMEM, &m_tex, NULL); -#endif + m_texture = new Texture(ivec2(m_size.x / 2, m_size.y * 2)); + + /* Ensure the texture data is complete at least once, otherwise + * uploading subimages will not work. */ + m_texture->SetData(&m_pixels[0]); m_shader = Shader::Create(lolfx_11_fractal); @@ -520,14 +472,7 @@ public: m_ready = true; } -#if defined _XBOX || defined USE_D3D9 - -#else -# if !defined HAVE_GLES_2X - glEnable(GL_TEXTURE_2D); -# endif - glBindTexture(GL_TEXTURE_2D, m_texid); -#endif + m_texture->Bind(); if (m_dirty[m_frame]) { @@ -536,32 +481,14 @@ public: m_dirty[m_frame]--; -#if defined _XBOX || defined USE_D3D9 - D3DLOCKED_RECT rect; -# if defined _XBOX - m_tex->LockRect(0, &rect, NULL, D3DLOCK_NOOVERWRITE); -# else - m_tex->LockRect(0, &rect, NULL, - D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE); -# endif - for (int j = 0; j < m_size.y * 2; j++) - { - u8vec4 *line = (u8vec4 *)rect.pBits + j * rect.Pitch / 4; - for (int i = 0; i < m_size.x / 2; i++) - line[i] = m_pixels[m_size.x / 2 * j + i]; - } - m_tex->UnlockRect(0); -#elif defined __CELLOS_LV2__ +#if defined __CELLOS_LV2__ /* glTexSubImage2D is extremely slow on the PS3, to the point * that uploading the whole texture is 40 times faster. */ - glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, - m_size.x / 2, m_size.y * 2, 0, - TEXTURE_FORMAT, TEXTURE_TYPE, &m_pixels[0]); + m_texture->SetData(&m_pixels[0]); #else - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_frame * m_size.y / 2, - m_size.x / 2, m_size.y / 2, - TEXTURE_FORMAT, TEXTURE_TYPE, - &m_pixels[m_size.x * m_size.y / 4 * m_frame]); + m_texture->SetSubData(ivec2(0, m_frame * m_size.y / 2), + m_size / 2, + &m_pixels[m_size.x * m_size.y / 4 * m_frame]); #endif } @@ -572,12 +499,7 @@ public: m_vdecl->Bind(); m_vdecl->SetStream(m_vbo, m_vertexattrib); m_vdecl->SetStream(m_tbo, m_texattrib); -#if defined _XBOX || defined USE_D3D9 - g_d3ddevice->SetTexture(0, m_tex); - g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); -#elif !defined __CELLOS_LV2__ && !defined __ANDROID__ -#else -#endif + m_texture->Bind(); m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6); m_vdecl->Unbind(); } @@ -599,13 +521,8 @@ private: VertexDeclaration *m_vdecl; VertexBuffer *m_vbo, *m_tbo; -#if defined USE_D3D9 - IDirect3DTexture9 *m_tex; -#elif defined _XBOX - D3DTexture *m_tex; -#else - GLuint m_texid; -#endif + Texture *m_texture; + int m_frame, m_slices, m_dirty[4]; bool m_ready, m_drag;