blob: 08ba11383dd489dfc52fcaffea6cfa63abb01e21 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "Texture.h"
12
daniel@transgaming.com16973022010-03-11 19:22:19 +000013#include <algorithm>
14
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000015#include "main.h"
16#include "mathutil.h"
17#include "debug.h"
18
19namespace gl
20{
21Texture::Texture() : Colorbuffer(0)
22{
23 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
24 mMagFilter = GL_LINEAR;
25 mWrapS = GL_REPEAT;
26 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000027
28 mDirtyImageData = true;
daniel@transgaming.com00c75962010-03-11 20:36:15 +000029 mDirtyMetaData = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030}
31
32Texture::~Texture()
33{
34}
35
36// Returns true on successful filter state update (valid enum parameter)
37bool Texture::setMinFilter(GLenum filter)
38{
39 switch (filter)
40 {
41 case GL_NEAREST:
42 case GL_LINEAR:
43 case GL_NEAREST_MIPMAP_NEAREST:
44 case GL_LINEAR_MIPMAP_NEAREST:
45 case GL_NEAREST_MIPMAP_LINEAR:
46 case GL_LINEAR_MIPMAP_LINEAR:
47 mMinFilter = filter;
48 return true;
49 default:
50 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000051 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000052}
53
54// Returns true on successful filter state update (valid enum parameter)
55bool Texture::setMagFilter(GLenum filter)
56{
57 switch (filter)
58 {
59 case GL_NEAREST:
60 case GL_LINEAR:
61 mMagFilter = filter;
62 return true;
63 default:
64 return false;
65 }
66}
67
68// Returns true on successful wrap state update (valid enum parameter)
69bool Texture::setWrapS(GLenum wrap)
70{
71 switch (wrap)
72 {
73 case GL_REPEAT:
74 case GL_CLAMP_TO_EDGE:
75 case GL_MIRRORED_REPEAT:
76 mWrapS = wrap;
77 return true;
78 default:
79 return false;
80 }
81}
82
83// Returns true on successful wrap state update (valid enum parameter)
84bool Texture::setWrapT(GLenum wrap)
85{
86 switch (wrap)
87 {
88 case GL_REPEAT:
89 case GL_CLAMP_TO_EDGE:
90 case GL_MIRRORED_REPEAT:
91 mWrapT = wrap;
92 return true;
93 default:
94 return false;
95 }
96}
97
daniel@transgaming.com00c75962010-03-11 20:36:15 +000098GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000099{
100 return mMinFilter;
101}
102
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000103GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104{
105 return mMagFilter;
106}
107
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000108GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000109{
110 return mWrapS;
111}
112
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000113GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000114{
115 return mWrapT;
116}
117
118// Copies an Image into an already locked Direct3D 9 surface, performing format conversions as necessary
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000119void Texture::copyImage(const D3DLOCKED_RECT &lock, D3DFORMAT format, const Image &image)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000121 ASSERT(format == D3DFMT_A8R8G8B8);
122
123 std::size_t sourcePitch = imagePitch(image);
124
125 if (lock.pBits && !image.pixels.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000126 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000127 if (lock.Pitch == sourcePitch)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000128 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000129 memcpy(lock.pBits, &image.pixels[0], lock.Pitch * image.height);
130 }
131 else
132 {
133 for (int y = 0; y < image.height; y++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000134 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000135 memcpy(static_cast<unsigned char*>(lock.pBits) + y * lock.Pitch, &image.pixels[0] + y * sourcePitch, sourcePitch);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136 }
137 }
138 }
139}
140
141// Selects an internal Direct3D 9 format for storing an Image
142D3DFORMAT Texture::selectFormat(const Image &image)
143{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000144 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145}
146
147// Returns the size, in bytes, of a single texel in an Image
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000148int Texture::pixelSize(GLenum format, GLenum type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000150 switch (type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151 {
152 case GL_UNSIGNED_BYTE:
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000153 switch (format)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154 {
155 case GL_ALPHA: return sizeof(unsigned char);
156 case GL_LUMINANCE: return sizeof(unsigned char);
157 case GL_LUMINANCE_ALPHA: return sizeof(unsigned char) * 2;
158 case GL_RGB: return sizeof(unsigned char) * 3;
159 case GL_RGBA: return sizeof(unsigned char) * 4;
160 default: UNREACHABLE();
161 }
162 break;
163 case GL_UNSIGNED_SHORT_4_4_4_4:
164 case GL_UNSIGNED_SHORT_5_5_5_1:
165 case GL_UNSIGNED_SHORT_5_6_5:
166 return sizeof(unsigned short);
167 default: UNREACHABLE();
168 }
169
170 return 0;
171}
172
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000173int Texture::imagePitch(const Image &img) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000175 return img.width * 4;
176}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000177
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000178// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
179// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
180void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
181 const void *input, size_t outputPitch, void *output) const
182{
183 size_t inputPitch = width * pixelSize(format, type);
184
185 for (int y = 0; y < height; y++)
186 {
187 const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
188 const unsigned short *source16 = reinterpret_cast<const unsigned short*>(source);
189 unsigned char *dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
190
191 for (int x = 0; x < width; x++)
192 {
193 unsigned char r;
194 unsigned char g;
195 unsigned char b;
196 unsigned char a;
197
198 switch (format)
199 {
200 case GL_ALPHA:
201 a = source[x];
202 r = 0;
203 g = 0;
204 b = 0;
205 break;
206
207 case GL_LUMINANCE:
208 r = source[x];
209 g = source[x];
210 b = source[x];
211 a = 0xFF;
212 break;
213
214 case GL_LUMINANCE_ALPHA:
215 r = source[2*x+0];
216 g = source[2*x+0];
217 b = source[2*x+0];
218 a = source[2*x+1];
219 break;
220
221 case GL_RGB:
222 switch (type)
223 {
224 case GL_UNSIGNED_BYTE:
225 r = source[x * 3 + 0];
226 b = source[x * 3 + 1];
227 g = source[x * 3 + 2];
228 a = 0xFF;
229 break;
230
231 case GL_UNSIGNED_SHORT_5_6_5:
232 {
233 unsigned short rgba = source16[x];
234
235 a = 0xFF;
236 b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
237 g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
238 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
239 }
240 break;
241
242 default: UNREACHABLE();
243 }
244 break;
245
246 case GL_RGBA:
247 switch (type)
248 {
249 case GL_UNSIGNED_BYTE:
250 r = source[x * 4 + 0];
251 g = source[x * 4 + 1];
252 b = source[x * 4 + 2];
253 a = source[x * 4 + 3];
254 break;
255
256 case GL_UNSIGNED_SHORT_4_4_4_4:
257 {
258 unsigned short rgba = source16[x];
259
260 a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
261 b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
262 g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
263 r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
264 }
265 break;
266
267 case GL_UNSIGNED_SHORT_5_5_5_1:
268 {
269 unsigned short rgba = source16[x];
270
271 a = (rgba & 0x0001) ? 0xFF : 0;
272 b = ((rgba & 0x003E) << 2) | ((rgba & 0x903E) >> 3);
273 g = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
274 r = ((rgba & 0xF800) >> 8) | ((rgba & 0x07C0) >> 13);
275 }
276 break;
277
278 default: UNREACHABLE();
279 }
280 break;
281 default: UNREACHABLE();
282 }
283
284 dest[4 * x + 0] = b;
285 dest[4 * x + 1] = g;
286 dest[4 * x + 2] = r;
287 dest[4 * x + 3] = a;
288 }
289 }
290}
291
292void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img)
293{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000294 img->width = width;
295 img->height = height;
296 img->format = format;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000297
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000298 size_t imageSize = imagePitch(*img) * img->height;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000299
300 std::vector<unsigned char> storage(imageSize);
301
302 if (pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000304 loadImageData(0, 0, width, height, format, type, pixels, imagePitch(*img), &storage[0]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000305 }
306
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000307 img->pixels.swap(storage);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000308
309 mDirtyImageData = true;
310 mDirtyMetaData = true;
311}
312
313void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img)
314{
315 if (width + xoffset > img->width || height + yoffset > img->height) return error(GL_INVALID_VALUE);
316
317 loadImageData(xoffset, yoffset, width, height, format, type, pixels, imagePitch(*img), &img->pixels[0]);
318
319 mDirtyImageData = true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000320}
321
322IDirect3DBaseTexture9 *Texture::getTexture()
323{
324 if (!isComplete())
325 {
326 return NULL;
327 }
328
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000329 if (mDirtyMetaData)
330 {
331 ASSERT(mDirtyImageData);
332
333 mBaseTexture = createTexture();
334 }
335
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000336 if (mDirtyImageData)
337 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000338 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000339 }
340
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000341 mDirtyMetaData = false;
342 mDirtyImageData = false;
343
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000344 return mBaseTexture;
345}
346
347Texture2D::Texture2D()
348{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349 mTexture = NULL;
350}
351
352Texture2D::~Texture2D()
353{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354 if (mTexture)
355 {
356 mTexture->Release();
357 mTexture = NULL;
358 }
359}
360
361GLenum Texture2D::getTarget() const
362{
363 return GL_TEXTURE_2D;
364}
365
366void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
367{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000368 Texture::setImage(width, height, format, type, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000369
370 if (level == 0)
371 {
372 mWidth = width;
373 mHeight = height;
374 }
375}
376
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000377void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000378{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000379 Texture::subImage(xoffset, yoffset, width, height, format, type, pixels, &mImageArray[level]);
380}
381
382// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
383bool Texture2D::isComplete() const
384{
385 ASSERT(mWidth == mImageArray[0].width && mHeight == mImageArray[0].height);
386
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000387 if (mWidth <= 0 || mHeight <= 0)
388 {
389 return false;
390 }
391
392 bool mipmapping;
393
394 switch (mMagFilter)
395 {
396 case GL_NEAREST:
397 case GL_LINEAR:
398 mipmapping = false;
399 break;
400 case GL_NEAREST_MIPMAP_NEAREST:
401 case GL_LINEAR_MIPMAP_NEAREST:
402 case GL_NEAREST_MIPMAP_LINEAR:
403 case GL_LINEAR_MIPMAP_LINEAR:
404 mipmapping = true;
405 break;
406 default: UNREACHABLE();
407 }
408
409 if (mipmapping)
410 {
daniel@transgaming.com16973022010-03-11 19:22:19 +0000411 int q = log2(std::max(mWidth, mHeight));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000412
413 for (int level = 1; level <= q; level++)
414 {
415 if (mImageArray[level].format != mImageArray[0].format)
416 {
417 return false;
418 }
419
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420 if (mImageArray[level].width != (mImageArray[level - 1].width + 1) / 2)
421 {
422 return false;
423 }
424
425 if (mImageArray[level].height != (mImageArray[level - 1].height + 1) / 2)
426 {
427 return false;
428 }
429 }
430 }
431
432 return true;
433}
434
435// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000436IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000437{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000438 IDirect3DTexture9 *texture;
439
440 IDirect3DDevice9 *device = getDevice();
441 D3DFORMAT format = selectFormat(mImageArray[0]);
442
443 HRESULT result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
444
445 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000446 {
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000447 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 }
449
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000450 if (mTexture) mTexture->Release();
451 mTexture = texture;
452 return texture;
453}
454
455void Texture2D::updateTexture()
456{
457 IDirect3DDevice9 *device = getDevice();
458 D3DFORMAT format = selectFormat(mImageArray[0]);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000459
460 IDirect3DTexture9 *lockableTexture;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000461 HRESULT result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000462
463 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000464 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000465 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466 }
467
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000468 int levelCount = mTexture->GetLevelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000469
470 for (int level = 0; level < levelCount; level++)
471 {
472 D3DLOCKED_RECT lock = {0};
473 lockableTexture->LockRect(level, &lock, NULL, 0);
474
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000475 copyImage(lock, format, mImageArray[level]);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000476
477 lockableTexture->UnlockRect(level);
478 }
479
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000480 device->UpdateTexture(lockableTexture, mTexture);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000481 lockableTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000482}
483
484// Returns the top-level texture surface as a render target
485IDirect3DSurface9 *Texture2D::getRenderTarget()
486{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000487 if (mDirtyMetaData && mRenderTarget)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000488 {
489 mRenderTarget->Release();
490 mRenderTarget = NULL;
491 }
492
493 if (!mRenderTarget && getTexture()) // FIXME: getTexture fails for incomplete textures. Check spec.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000494 {
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000495 mTexture->GetSurfaceLevel(0, &mRenderTarget);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000496 }
497
498 return mRenderTarget;
499}
500
501TextureCubeMap::TextureCubeMap()
502{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000503 mTexture = NULL;
504}
505
506TextureCubeMap::~TextureCubeMap()
507{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508 if (mTexture)
509 {
510 mTexture->Release();
511 mTexture = NULL;
512 }
513}
514
515GLenum TextureCubeMap::getTarget() const
516{
517 return GL_TEXTURE_CUBE_MAP;
518}
519
520void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
521{
522 setImage(0, level, internalFormat, width, height, format, type, pixels);
523}
524
525void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
526{
527 setImage(1, level, internalFormat, width, height, format, type, pixels);
528}
529
530void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
531{
532 setImage(2, level, internalFormat, width, height, format, type, pixels);
533}
534
535void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
536{
537 setImage(3, level, internalFormat, width, height, format, type, pixels);
538}
539
540void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
541{
542 setImage(4, level, internalFormat, width, height, format, type, pixels);
543}
544
545void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
546{
547 setImage(5, level, internalFormat, width, height, format, type, pixels);
548}
549
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000550void TextureCubeMap::subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
551{
552 Texture::subImage(xoffset, yoffset, width, height, format, type, pixels, &mImageArray[faceIndex(face)][level]);
553}
554
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000555// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000556bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000557{
558 if (mWidth <= 0 || mHeight <= 0 || mWidth != mHeight)
559 {
560 return false;
561 }
562
563 bool mipmapping;
564
565 switch (mMagFilter)
566 {
567 case GL_NEAREST:
568 case GL_LINEAR:
569 mipmapping = false;
570 break;
571 case GL_NEAREST_MIPMAP_NEAREST:
572 case GL_LINEAR_MIPMAP_NEAREST:
573 case GL_NEAREST_MIPMAP_LINEAR:
574 case GL_LINEAR_MIPMAP_LINEAR:
575 mipmapping = true;
576 break;
577 default: UNREACHABLE();
578 }
579
580 for (int face = 0; face < 6; face++)
581 {
582 if (mImageArray[face][0].width != mWidth || mImageArray[face][0].height != mHeight)
583 {
584 return false;
585 }
586 }
587
588 if (mipmapping)
589 {
590 int q = log2(mWidth);
591
592 for (int face = 0; face < 6; face++)
593 {
594 for (int level = 1; level <= q; level++)
595 {
596 if (mImageArray[face][level].format != mImageArray[0][0].format)
597 {
598 return false;
599 }
600
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000601 if (mImageArray[face][level].width != (mImageArray[0][level - 1].width + 1) / 2)
602 {
603 return false;
604 }
605
606 if (mImageArray[face][level].height != (mImageArray[0][level - 1].height + 1) / 2)
607 {
608 return false;
609 }
610 }
611 }
612 }
613
614 return true;
615}
616
617// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000618IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000619{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000620 IDirect3DDevice9 *device = getDevice();
621 D3DFORMAT format = selectFormat(mImageArray[0][0]);
622
623 IDirect3DCubeTexture9 *texture;
624
625 HRESULT result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
626
627 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000628 {
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000629 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000630 }
631
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000632 if (mTexture) mTexture->Release();
633
634 mTexture = texture;
635 return mTexture;
636}
637
638void TextureCubeMap::updateTexture()
639{
640 IDirect3DDevice9 *device = getDevice();
641 D3DFORMAT format = selectFormat(mImageArray[0][0]);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000642
643 IDirect3DCubeTexture9 *lockableTexture;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000644 HRESULT result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000645
646 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000647 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000648 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000649 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000650
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000651 ASSERT(SUCCEEDED(result));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000652
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000653 for (int face = 0; face < 6; face++)
654 {
655 for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000656 {
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000657 D3DLOCKED_RECT lock = {0};
658 lockableTexture->LockRect((D3DCUBEMAP_FACES)face, level, &lock, NULL, 0);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000659
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000660 copyImage(lock, format, mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000661
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000662 lockableTexture->UnlockRect((D3DCUBEMAP_FACES)face, level);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000663 }
664 }
665
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000666 device->UpdateTexture(lockableTexture, mTexture);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000667 lockableTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000668}
669
670void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
671{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000672 Texture::setImage(width, height, format, type, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673
674 if (face == 0 && level == 0)
675 {
676 mWidth = width;
677 mHeight = height;
678 }
679}
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000680
681unsigned int TextureCubeMap::faceIndex(GLenum face)
682{
683 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
684 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
685 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
686 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
687 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
688
689 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
690}
691
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000692}