internal format is then automatically deduced. Only a few 8-bit RGB or RGBA formats are supported for now.legacy
| @@ -42,6 +42,7 @@ class TextureData | |||||
| friend class Texture; | friend class Texture; | ||||
| ivec2 m_size; | ivec2 m_size; | ||||
| PixelFormat m_format; | |||||
| #if defined USE_D3D9 | #if defined USE_D3D9 | ||||
| IDirect3DTexture9 *m_tex; | IDirect3DTexture9 *m_tex; | ||||
| @@ -49,6 +50,8 @@ class TextureData | |||||
| D3DTexture *m_tex; | D3DTexture *m_tex; | ||||
| #else | #else | ||||
| GLuint m_texid; | GLuint m_texid; | ||||
| GLint m_internal_format; | |||||
| GLenum m_gl_format, m_gl_type; | |||||
| #endif | #endif | ||||
| }; | }; | ||||
| @@ -57,37 +60,85 @@ class TextureData | |||||
| // ----------------- | // ----------------- | ||||
| // | // | ||||
| /* 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; | |||||
| #elif !defined USE_D3D9 && !defined _XBOX | |||||
| /* 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 | |||||
| #define GET_CLAMPED(array, index) \ | |||||
| array[std::max(0, std::min((int)(index), \ | |||||
| (int)sizeof(array) / (int)sizeof(*array)))] | |||||
| Texture::Texture(ivec2 size) | |||||
| Texture::Texture(ivec2 size, PixelFormat format) | |||||
| : m_data(new TextureData) | : m_data(new TextureData) | ||||
| { | { | ||||
| m_data->m_size = size; | m_data->m_size = size; | ||||
| m_data->m_format = format; | |||||
| #if defined USE_D3D9 || defined _XBOX | |||||
| static int const d3d_formats[] = | |||||
| { | |||||
| /* Unknown */ | |||||
| D3DFMT_UNKNOWN, | |||||
| /* R8G8B8 */ | |||||
| D3DFMT_R8G8B8, | |||||
| /* A8R8G8B8 */ | |||||
| # if defined USE_D3D9 | |||||
| D3DFMT_A8R8G8B8, | |||||
| # else | |||||
| /* By default the X360 will swizzle the texture. Ask for linear. */ | |||||
| D3DFMT_LIN_A8R8G8B8, | |||||
| # endif | |||||
| }; | |||||
| int d3d_format = GET_CLAMPED(d3d_formats, format); | |||||
| # if defined USE_D3D9 | |||||
| int d3d_usage = D3DUSAGE_DYNAMIC; | |||||
| # else | |||||
| int d3d_usage = D3DUSAGE_WRITEONLY; | |||||
| # endif | |||||
| #if defined USE_D3D9 | |||||
| g_d3ddevice->CreateTexture(m_data->m_size.x, m_data->m_size.y, 1, | |||||
| D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, | |||||
| D3DPOOL_DEFAULT, &m_data->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, | g_d3ddevice->CreateTexture(m_data->m_size.x, m_data->m_size.y, 1, | ||||
| D3DUSAGE_WRITEONLY, D3DFMT_LIN_A8R8G8B8, | |||||
| d3d_usage, d3d_format, | |||||
| D3DPOOL_DEFAULT, &m_data->m_tex, NULL); | D3DPOOL_DEFAULT, &m_data->m_tex, NULL); | ||||
| #else | #else | ||||
| static struct | |||||
| { | |||||
| GLint internal_format; | |||||
| GLenum format, type; | |||||
| } | |||||
| const gl_formats[] = | |||||
| { | |||||
| /* Unknown */ | |||||
| { 0, 0, 0 }, | |||||
| /* R8G8B8 */ | |||||
| { GL_RGB, GL_RGB, GL_UNSIGNED_BYTE }, | |||||
| /* A8R8G8B8 */ | |||||
| #if __CELLOS_LV2__ | |||||
| { GL_ARGB_SCE, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV }, | |||||
| #elif defined __native_client__ || defined HAVE_GLES_2X | |||||
| { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, | |||||
| #else | |||||
| /* Seems efficient for little endian textures */ | |||||
| { GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV }, | |||||
| #endif | |||||
| /* A8B8G8R8 */ | |||||
| #if __CELLOS_LV2__ | |||||
| { GL_ARGB_SCE, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV }, | |||||
| #elif defined __native_client__ || defined HAVE_GLES_2X | |||||
| /* FIXME: if GL_RGBA is not available, we should advertise | |||||
| * this format as "not available" on this platform. */ | |||||
| { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, | |||||
| #else | |||||
| /* Seems efficient for little endian textures */ | |||||
| { GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV }, | |||||
| #endif | |||||
| }; | |||||
| m_data->m_internal_format = GET_CLAMPED(gl_formats, format).internal_format; | |||||
| m_data->m_gl_format = GET_CLAMPED(gl_formats, format).format; | |||||
| m_data->m_gl_type = GET_CLAMPED(gl_formats, format).type; | |||||
| glGenTextures(1, &m_data->m_texid); | glGenTextures(1, &m_data->m_texid); | ||||
| glBindTexture(GL_TEXTURE_2D, m_data->m_texid); | glBindTexture(GL_TEXTURE_2D, m_data->m_texid); | ||||
| @@ -129,9 +180,9 @@ void Texture::SetData(void *data) | |||||
| m_data->m_tex->UnlockRect(0); | m_data->m_tex->UnlockRect(0); | ||||
| #else | #else | ||||
| glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, | |||||
| glTexImage2D(GL_TEXTURE_2D, 0, m_data->m_internal_format, | |||||
| m_data->m_size.x, m_data->m_size.y, 0, | m_data->m_size.x, m_data->m_size.y, 0, | ||||
| TEXTURE_FORMAT, TEXTURE_TYPE, data); | |||||
| m_data->m_gl_format, m_data->m_gl_type, data); | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -153,7 +204,7 @@ void Texture::SetSubData(ivec2 origin, ivec2 size, void *data) | |||||
| #else | #else | ||||
| glTexSubImage2D(GL_TEXTURE_2D, 0, origin.x, origin.y, size.x, size.y, | glTexSubImage2D(GL_TEXTURE_2D, 0, origin.x, origin.y, size.x, size.y, | ||||
| TEXTURE_FORMAT, TEXTURE_TYPE, data); | |||||
| m_data->m_gl_format, m_data->m_gl_type, data); | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -19,10 +19,27 @@ | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| struct PixelFormat | |||||
| { | |||||
| /* XXX: make sure to update texture.cpp when this changes */ | |||||
| enum Value | |||||
| { | |||||
| Unknown = 0, | |||||
| R8G8B8, | |||||
| A8R8G8B8, | |||||
| A8B8G8R8, | |||||
| } | |||||
| m_value; | |||||
| inline PixelFormat() : m_value(Unknown) {} | |||||
| inline PixelFormat(Value v) : m_value(v) {} | |||||
| inline operator Value() { return m_value; } | |||||
| }; | |||||
| class Texture | class Texture | ||||
| { | { | ||||
| public: | public: | ||||
| Texture(ivec2 size); | |||||
| Texture(ivec2 size, PixelFormat format); | |||||
| ~Texture(); | ~Texture(); | ||||
| void Bind(); | void Bind(); | ||||
| @@ -56,13 +56,7 @@ private: | |||||
| float tx, ty; | float tx, ty; | ||||
| Image *img; | Image *img; | ||||
| #if defined USE_D3D9 | |||||
| IDirect3DTexture9 *m_tex; | |||||
| #elif defined _XBOX | |||||
| D3DTexture *m_tex; | |||||
| #else | |||||
| GLuint m_tex; | |||||
| #endif | |||||
| Texture *m_texture; | |||||
| }; | }; | ||||
| /* | /* | ||||
| @@ -77,7 +71,7 @@ TileSet::TileSet(char const *path, ivec2 size, ivec2 count) | |||||
| sprintf(data->name, "<tileset> %s", path); | sprintf(data->name, "<tileset> %s", path); | ||||
| data->tiles = NULL; | data->tiles = NULL; | ||||
| data->m_tex = 0; | |||||
| data->m_texture = 0; | |||||
| data->img = new Image(path); | data->img = new Image(path); | ||||
| data->isize = data->img->GetSize(); | data->isize = data->img->GetSize(); | ||||
| @@ -119,46 +113,24 @@ void TileSet::TickDraw(float seconds) | |||||
| if (data->img) | if (data->img) | ||||
| delete data->img; | delete data->img; | ||||
| else | else | ||||
| #if defined USE_D3D9 || defined _XBOX | |||||
| /* FIXME: is it really the correct call? */ | |||||
| data->m_tex->Release(); | |||||
| #else | |||||
| glDeleteTextures(1, &data->m_tex); | |||||
| #endif | |||||
| delete data->m_texture; | |||||
| } | } | ||||
| else if (data->img) | else if (data->img) | ||||
| { | { | ||||
| #if defined USE_D3D9 || defined _XBOX | |||||
| D3DFORMAT format; | |||||
| #else | |||||
| GLuint format; | |||||
| #endif | |||||
| int planes; | int planes; | ||||
| PixelFormat format = PixelFormat::Unknown; | |||||
| switch (data->img->GetFormat()) | switch (data->img->GetFormat()) | ||||
| { | { | ||||
| case Image::FORMAT_RGB: | case Image::FORMAT_RGB: | ||||
| #if defined USE_D3D9 | |||||
| format = D3DFMT_R8G8B8; | |||||
| #elif defined _XBOX | |||||
| format = D3DFMT_LIN_A8R8G8B8; /* FIXME */ | |||||
| #else | |||||
| format = GL_RGB; | |||||
| #endif | |||||
| planes = 3; | |||||
| break; | |||||
| format = PixelFormat::R8G8B8; | |||||
| planes = 3; | |||||
| break; | |||||
| case Image::FORMAT_RGBA: | case Image::FORMAT_RGBA: | ||||
| default: | default: | ||||
| #if defined USE_D3D9 | |||||
| format = D3DFMT_A8R8G8B8; | |||||
| #elif defined _XBOX | |||||
| /* By default the X360 will swizzle the texture. Ask for linear. */ | |||||
| format = D3DFMT_LIN_A8R8G8B8; | |||||
| #else | |||||
| format = GL_RGBA; | |||||
| #endif | |||||
| planes = 4; | |||||
| break; | |||||
| format = PixelFormat::A8R8G8B8; | |||||
| planes = 4; | |||||
| break; | |||||
| } | } | ||||
| int w = PotUp(data->isize.x); | int w = PotUp(data->isize.x); | ||||
| @@ -175,41 +147,8 @@ void TileSet::TickDraw(float seconds) | |||||
| pixels = tmp; | pixels = tmp; | ||||
| } | } | ||||
| #if defined USE_D3D9 || defined _XBOX | |||||
| D3DLOCKED_RECT rect; | |||||
| HRESULT hr; | |||||
| # if defined USE_D3D9 | |||||
| hr = g_d3ddevice->CreateTexture(w, h, 1, D3DUSAGE_DYNAMIC, format, | |||||
| D3DPOOL_DEFAULT, &data->m_tex, NULL); | |||||
| # elif defined _XBOX | |||||
| hr = g_d3ddevice->CreateTexture(w, h, 1, D3DUSAGE_WRITEONLY, format, | |||||
| D3DPOOL_DEFAULT, &data->m_tex, NULL); | |||||
| # endif | |||||
| if (FAILED(hr)) | |||||
| Abort(); | |||||
| # if defined USE_D3D9 | |||||
| hr = data->m_tex->LockRect(0, &rect, NULL, D3DLOCK_DISCARD); | |||||
| # else | |||||
| hr = data->m_tex->LockRect(0, &rect, NULL, 0); | |||||
| # endif | |||||
| if (FAILED(hr)) | |||||
| Abort(); | |||||
| for (int j = 0; j < h; j++) | |||||
| memcpy((uint8_t *)rect.pBits + j * rect.Pitch, pixels + w * j * 4, w * 4); | |||||
| hr = data->m_tex->UnlockRect(0); | |||||
| if (FAILED(hr)) | |||||
| Abort(); | |||||
| #else | |||||
| glGenTextures(1, &data->m_tex); | |||||
| glEnable(GL_TEXTURE_2D); | |||||
| glBindTexture(GL_TEXTURE_2D, data->m_tex); | |||||
| glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, | |||||
| format, GL_UNSIGNED_BYTE, pixels); | |||||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |||||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |||||
| #endif | |||||
| data->m_texture = new Texture(ivec2(w, h), format); | |||||
| data->m_texture->SetData(pixels); | |||||
| if (pixels != data->img->GetData()) | if (pixels != data->img->GetData()) | ||||
| free(pixels); | free(pixels); | ||||
| @@ -237,32 +176,13 @@ ivec2 TileSet::GetSize(int tileid) const | |||||
| void TileSet::Bind() | void TileSet::Bind() | ||||
| { | { | ||||
| if (!data->img && data->m_tex) | |||||
| { | |||||
| #if defined USE_D3D9 || defined _XBOX | |||||
| HRESULT hr = g_d3ddevice->SetTexture(0, data->m_tex); | |||||
| if (FAILED(hr)) | |||||
| Abort(); | |||||
| #else | |||||
| glActiveTexture(GL_TEXTURE0); | |||||
| glBindTexture(GL_TEXTURE_2D, data->m_tex); | |||||
| #endif | |||||
| } | |||||
| if (!data->img && data->m_texture) | |||||
| data->m_texture->Bind(); | |||||
| } | } | ||||
| void TileSet::Unbind() | void TileSet::Unbind() | ||||
| { | { | ||||
| if (!data->img && data->m_tex) | |||||
| { | |||||
| #if defined USE_D3D9 || defined _XBOX | |||||
| HRESULT hr = g_d3ddevice->SetTexture(0, NULL); | |||||
| if (FAILED(hr)) | |||||
| Abort(); | |||||
| #else | |||||
| glActiveTexture(GL_TEXTURE0); | |||||
| glBindTexture(GL_TEXTURE_2D, 0); | |||||
| #endif | |||||
| } | |||||
| ; | |||||
| } | } | ||||
| void TileSet::BlitTile(uint32_t id, vec3 pos, int o, vec2 scale, | void TileSet::BlitTile(uint32_t id, vec3 pos, int o, vec2 scale, | ||||
| @@ -287,7 +207,7 @@ void TileSet::BlitTile(uint32_t id, vec3 pos, int o, vec2 scale, | |||||
| dtx = -dtx; | dtx = -dtx; | ||||
| } | } | ||||
| if (!data->img && data->m_tex) | |||||
| if (!data->img && data->m_texture) | |||||
| { | { | ||||
| float tmp[10]; | float tmp[10]; | ||||
| @@ -445,7 +445,8 @@ public: | |||||
| { | { | ||||
| /* Create a texture of half the width and twice the height | /* Create a texture of half the width and twice the height | ||||
| * so that we can upload four different subimages each frame. */ | * so that we can upload four different subimages each frame. */ | ||||
| m_texture = new Texture(ivec2(m_size.x / 2, m_size.y * 2)); | |||||
| m_texture = new Texture(ivec2(m_size.x / 2, m_size.y * 2), | |||||
| PixelFormat::A8B8G8R8); | |||||
| /* Ensure the texture data is complete at least once, otherwise | /* Ensure the texture data is complete at least once, otherwise | ||||
| * uploading subimages will not work. */ | * uploading subimages will not work. */ | ||||