source: trunk/src/gpu/texture.cpp @ 2787

Last change on this file since 2787 was 2787, checked in by sam, 9 years ago

build: fix the X360 port.

  • Property svn:keywords set to Id
File size: 9.8 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://www.wtfpl.net/ for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include "core.h"
16#include "lolgl.h"
17
18#if defined _WIN32 && defined USE_D3D9
19#   define FAR
20#   define NEAR
21#   include <d3d9.h>
22#endif
23
24using namespace std;
25
26namespace lol
27{
28
29//
30// The TextureData class
31// ---------------------
32//
33
34class TextureData
35{
36    friend class Texture;
37
38    ivec2 m_size;
39    PixelFormat m_format;
40
41#if defined USE_D3D9
42    IDirect3DDevice9 *m_dev;
43    IDirect3DTexture9 *m_texture;
44    D3DTEXTUREFILTERTYPE m_mag_filter;
45    D3DTEXTUREFILTERTYPE m_min_filter;
46    D3DTEXTUREFILTERTYPE m_mip_filter;
47#elif defined _XBOX
48    D3DDevice *m_dev;
49    D3DTexture *m_texture;
50    D3DTEXTUREFILTERTYPE m_mag_filter;
51    D3DTEXTUREFILTERTYPE m_min_filter;
52    D3DTEXTUREFILTERTYPE m_mip_filter;
53#else
54    GLuint m_texture;
55    GLint m_internal_format;
56    GLenum m_gl_format, m_gl_type;
57#endif
58    int m_bytes_per_elem;
59};
60
61//
62// The Texture class
63// -----------------
64//
65
66#define GET_CLAMPED(array, index) \
67    array[std::max(0, std::min((int)(index), \
68                   (int)sizeof(array) / (int)sizeof(*array)))]
69
70Texture::Texture(ivec2 size, PixelFormat format)
71  : m_data(new TextureData)
72{
73    m_data->m_size = size;
74    m_data->m_format = format;
75
76#if defined USE_D3D9 || defined _XBOX
77#   if defined USE_D3D9
78    m_data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
79#   elif defined _XBOX
80    m_data->m_dev = (D3DDevice *)g_renderer->GetDevice();
81#   endif
82
83    static struct
84    {
85        D3DFORMAT format;
86        int bytes;
87    }
88    const d3d_formats[] =
89    {
90        /* Unknown */
91        { D3DFMT_UNKNOWN, 0 },
92
93        /* FIXME: this is all mixed up for the RGBA/ARGB combinations */
94#   if defined USE_D3D9
95        { D3DFMT_R8G8B8, 3 },   /* RGB_8 */
96        { D3DFMT_A8R8G8B8, 4 }, /* RGBA_8 */
97        { D3DFMT_A8R8G8B8, 4 }, /* ARGB_8 */
98        { D3DFMT_UNKNOWN, 0 },  /* ABGR_8 */
99        { D3DFMT_L8, 1 },       /* Y8 */
100#   else
101        { D3DFMT_UNKNOWN, 0 },
102        { D3DFMT_UNKNOWN, 0 },
103        /* By default the X360 will swizzle the texture. Ask for linear. */
104        { D3DFMT_LIN_A8R8G8B8, 4 },
105        { D3DFMT_UNKNOWN, 0 },
106        { D3DFMT_LIN_L8, 1 },
107#   endif
108    };
109
110    D3DFORMAT d3d_format = GET_CLAMPED(d3d_formats, format).format;
111    ASSERT(d3d_format != D3DFMT_UNKNOWN,
112           "unsupported texture format %d\n", format);
113#   if defined USE_D3D9
114    int d3d_usage = D3DUSAGE_DYNAMIC;
115#   else
116    int d3d_usage = D3DUSAGE_WRITEONLY;
117#   endif
118
119    m_data->m_dev->CreateTexture(m_data->m_size.x, m_data->m_size.y, 1,
120                                 d3d_usage, d3d_format,
121                                 D3DPOOL_DEFAULT, &m_data->m_texture, nullptr);
122    m_data->m_bytes_per_elem = GET_CLAMPED(d3d_formats, format).bytes;
123#else
124    static struct
125    {
126        GLint internal_format;
127        GLenum format, type;
128        int bytes;
129    }
130    const gl_formats[] =
131    {
132        { 0, 0, 0, 0 }, /* Unknown */
133
134        /* FIXME: this is all mixed up for the RGBA/ARGB combinations */
135#if __CELLOS_LV2__
136        { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, 3 },
137        { GL_ARGB_SCE, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 4 },
138        { GL_ARGB_SCE, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 4 },
139        { GL_ARGB_SCE, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, 4 },
140        { GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1 },
141#elif defined __native_client__ || defined HAVE_GLES_2X
142        { GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, 3 },
143        { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 4 },
144        { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 4 },
145        /* FIXME: if GL_RGBA is not available, we should advertise
146         * this format as "not available" on this platform. */
147        { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 4 },
148        { GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1 },
149#else
150        { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, 3 }, /* RGB_8 */
151        /* Seems efficient for little endian textures */
152        { GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 4 }, /* ARGB_8 */
153        { GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 4 }, /* ARGB_8 */
154        { GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 4 }, /* ABGR_8 */
155        { GL_R8, GL_RED, GL_UNSIGNED_BYTE, 1 }, /* A8 */
156#endif
157    };
158
159    m_data->m_internal_format = GET_CLAMPED(gl_formats, format).internal_format;
160    m_data->m_gl_format = GET_CLAMPED(gl_formats, format).format;
161    m_data->m_gl_type = GET_CLAMPED(gl_formats, format).type;
162    m_data->m_bytes_per_elem = GET_CLAMPED(gl_formats, format).bytes;
163
164    glGenTextures(1, &m_data->m_texture);
165    glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
166
167#   if defined __CELLOS_LV2__
168    /* We need this hint because by default the storage type is
169     * GL_TEXTURE_SWIZZLED_GPU_SCE. */
170    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ALLOCATION_HINT_SCE,
171                    GL_TEXTURE_TILED_GPU_SCE);
172#   endif
173    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
174    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
175#endif
176}
177
178ShaderTexture Texture::GetTexture() const
179{
180    ShaderTexture ret;
181#if defined USE_D3D9 || defined _XBOX
182    ret.m_flags = (uint64_t)(uintptr_t)m_data->m_texture;
183    ret.m_attrib = m_data->m_mag_filter;
184    ret.m_attrib |= m_data->m_min_filter << 8;
185    ret.m_attrib |= m_data->m_mip_filter << 16;
186#else
187    ret.m_flags = m_data->m_texture;
188#endif
189    return ret;
190}
191
192void Texture::Bind()
193{
194#if defined _XBOX || defined USE_D3D9
195    m_data->m_dev->SetTexture(0, m_data->m_texture);
196#else
197#   if !defined HAVE_GLES_2X
198    glEnable(GL_TEXTURE_2D);
199#   endif
200    glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
201#endif
202}
203
204void Texture::SetData(void *data)
205{
206#if defined _XBOX || defined USE_D3D9
207    D3DLOCKED_RECT rect;
208#   if defined USE_D3D9
209    m_data->m_texture->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD);
210#   else
211    m_data->m_texture->LockRect(0, &rect, nullptr, 0);
212#   endif
213
214    memcpy(rect.pBits, data, rect.Pitch * m_data->m_size.y);
215
216    m_data->m_texture->UnlockRect(0);
217
218#else
219    glTexImage2D(GL_TEXTURE_2D, 0, m_data->m_internal_format,
220                 m_data->m_size.x, m_data->m_size.y, 0,
221                 m_data->m_gl_format, m_data->m_gl_type, data);
222#endif
223}
224
225void Texture::SetSubData(ivec2 origin, ivec2 size, void *data)
226{
227#if defined _XBOX || defined USE_D3D9
228    D3DLOCKED_RECT rect;
229    m_data->m_texture->LockRect(0, &rect, nullptr, 0);
230
231    int stride = size.x * m_data->m_bytes_per_elem;
232    for (int j = 0; j < size.y; j++)
233    {
234        uint8_t *dst = (uint8_t *)rect.pBits + (origin.y + j) * rect.Pitch;
235        uint8_t *src = (uint8_t *)data + j * stride;
236        memcpy(dst, src, stride);
237    }
238
239    m_data->m_texture->UnlockRect(0);
240
241#else
242    glTexSubImage2D(GL_TEXTURE_2D, 0, origin.x, origin.y, size.x, size.y,
243                    m_data->m_gl_format, m_data->m_gl_type, data);
244#endif
245}
246
247void Texture::SetMagFiltering(TextureMagFilter filter)
248{
249#if defined _XBOX || defined USE_D3D9
250    // In DirectX, texture filtering is a per-texture-unit state
251    switch (filter)
252    {
253    case TextureMagFilter::NEAREST_TEXEL: m_data->m_mag_filter = D3DTEXF_POINT; break;
254    case TextureMagFilter::LINEAR_TEXEL: m_data->m_mag_filter = D3DTEXF_LINEAR; break;
255    }
256#else
257    glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
258    GLenum gl_filter;
259    switch (filter)
260    {
261    case TextureMagFilter::NEAREST_TEXEL: gl_filter = GL_NEAREST; break;
262    case TextureMagFilter::LINEAR_TEXEL: gl_filter = GL_LINEAR; break;
263    }
264    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter);
265#endif
266}
267
268void Texture::SetMinFiltering(TextureMinFilter filter)
269{
270#if defined _XBOX || defined USE_D3D9
271    // In DirectX, texture filtering is a per-texture-unit state
272#define F(x, y) \
273    m_data->m_min_filter = x; m_data->m_mip_filter = y;
274    switch (filter)
275    {
276    case TextureMinFilter::NEAREST_TEXEL_NO_MIPMAP: F(D3DTEXF_POINT, D3DTEXF_NONE); break;
277    case TextureMinFilter::LINEAR_TEXEL_NO_MIPMAP: F(D3DTEXF_POINT, D3DTEXF_NONE); break;
278    case TextureMinFilter::NEAREST_TEXEL_NEAREST_MIPMAP: F(D3DTEXF_POINT, D3DTEXF_POINT); break;
279    case TextureMinFilter::LINEAR_TEXEL_NEAREST_MIPMAP: F(D3DTEXF_LINEAR, D3DTEXF_POINT); break;
280    case TextureMinFilter::NEAREST_TEXEL_LINEAR_MIPMAP: F(D3DTEXF_POINT, D3DTEXF_LINEAR); break;
281    case TextureMinFilter::LINEAR_TEXEL_LINEAR_MIPMAP: F(D3DTEXF_LINEAR, D3DTEXF_LINEAR); break;
282    }
283#undef F
284
285#else
286    glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
287    GLenum gl_filter;
288    switch (filter)
289    {
290    case TextureMinFilter::NEAREST_TEXEL_NO_MIPMAP: gl_filter = GL_NEAREST; break;
291    case TextureMinFilter::LINEAR_TEXEL_NO_MIPMAP: gl_filter = GL_LINEAR; break;
292    case TextureMinFilter::NEAREST_TEXEL_NEAREST_MIPMAP: gl_filter = GL_NEAREST_MIPMAP_NEAREST; break;
293    case TextureMinFilter::NEAREST_TEXEL_LINEAR_MIPMAP: gl_filter = GL_NEAREST_MIPMAP_LINEAR; break;
294    case TextureMinFilter::LINEAR_TEXEL_NEAREST_MIPMAP: gl_filter = GL_LINEAR_MIPMAP_NEAREST; break;
295    case TextureMinFilter::LINEAR_TEXEL_LINEAR_MIPMAP: gl_filter = GL_LINEAR_MIPMAP_LINEAR; break;
296    }
297    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter);
298#endif
299}
300
301void Texture::GenerateMipmaps()
302{
303#if defined USE_D3D9
304    m_data->m_texture->->GenerateMipSubLevels();
305#elif defined _XBOX
306    /* FIXME: No direct mipmap generation support on X360 */
307#elif defined __CELLOS_LV2__
308    glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
309    glGenerateMipmapOES(GL_TEXTURE_2D);
310#else
311    glBindTexture(GL_TEXTURE_2D, m_data->m_texture);
312    glGenerateMipmap(GL_TEXTURE_2D);
313#endif
314}
315
316Texture::~Texture()
317{
318#if defined USE_D3D9 || defined _XBOX
319    m_data->m_texture->Release();
320#else
321    glDeleteTextures(1, &m_data->m_texture);
322#endif
323
324    delete m_data;
325}
326
327} /* namespace lol */
328
Note: See TracBrowser for help on using the repository browser.