blob: 9e203e8bc1cbae2a5b366dc2c830bedda9aaf69d [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"
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000017#include "common/debug.h"
daniel@transgaming.com7051b972010-03-21 04:31:07 +000018#include "utilities.h"
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000019#include "Blit.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000020
21namespace gl
22{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000023
24Texture::Image::Image()
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000025 : width(0), height(0), dirty(false), surface(NULL)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000026{
27}
28
29Texture::Image::~Image()
30{
31 if (surface) surface->Release();
32}
33
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000034Texture::Texture(Context *context) : Colorbuffer(0), mContext(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000035{
36 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
37 mMagFilter = GL_LINEAR;
38 mWrapS = GL_REPEAT;
39 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000040
daniel@transgaming.com00c75962010-03-11 20:36:15 +000041 mDirtyMetaData = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000042}
43
44Texture::~Texture()
45{
46}
47
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000048Blit *Texture::getBlitter()
49{
50 return mContext->getBlitter();
51}
52
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053// Returns true on successful filter state update (valid enum parameter)
54bool Texture::setMinFilter(GLenum filter)
55{
56 switch (filter)
57 {
58 case GL_NEAREST:
59 case GL_LINEAR:
60 case GL_NEAREST_MIPMAP_NEAREST:
61 case GL_LINEAR_MIPMAP_NEAREST:
62 case GL_NEAREST_MIPMAP_LINEAR:
63 case GL_LINEAR_MIPMAP_LINEAR:
64 mMinFilter = filter;
65 return true;
66 default:
67 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000068 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000069}
70
71// Returns true on successful filter state update (valid enum parameter)
72bool Texture::setMagFilter(GLenum filter)
73{
74 switch (filter)
75 {
76 case GL_NEAREST:
77 case GL_LINEAR:
78 mMagFilter = filter;
79 return true;
80 default:
81 return false;
82 }
83}
84
85// Returns true on successful wrap state update (valid enum parameter)
86bool Texture::setWrapS(GLenum wrap)
87{
88 switch (wrap)
89 {
90 case GL_REPEAT:
91 case GL_CLAMP_TO_EDGE:
92 case GL_MIRRORED_REPEAT:
93 mWrapS = wrap;
94 return true;
95 default:
96 return false;
97 }
98}
99
100// Returns true on successful wrap state update (valid enum parameter)
101bool Texture::setWrapT(GLenum wrap)
102{
103 switch (wrap)
104 {
105 case GL_REPEAT:
106 case GL_CLAMP_TO_EDGE:
107 case GL_MIRRORED_REPEAT:
108 mWrapT = wrap;
109 return true;
110 default:
111 return false;
112 }
113}
114
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000115GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000116{
117 return mMinFilter;
118}
119
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000120GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000121{
122 return mMagFilter;
123}
124
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000125GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000126{
127 return mWrapS;
128}
129
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000130GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131{
132 return mWrapT;
133}
134
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000136D3DFORMAT Texture::selectFormat(GLenum format)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000138 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000139}
140
141// Returns the size, in bytes, of a single texel in an Image
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000142int Texture::pixelSize(GLenum format, GLenum type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000144 switch (type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145 {
146 case GL_UNSIGNED_BYTE:
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000147 switch (format)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148 {
149 case GL_ALPHA: return sizeof(unsigned char);
150 case GL_LUMINANCE: return sizeof(unsigned char);
151 case GL_LUMINANCE_ALPHA: return sizeof(unsigned char) * 2;
152 case GL_RGB: return sizeof(unsigned char) * 3;
153 case GL_RGBA: return sizeof(unsigned char) * 4;
154 default: UNREACHABLE();
155 }
156 break;
157 case GL_UNSIGNED_SHORT_4_4_4_4:
158 case GL_UNSIGNED_SHORT_5_5_5_1:
159 case GL_UNSIGNED_SHORT_5_6_5:
160 return sizeof(unsigned short);
161 default: UNREACHABLE();
162 }
163
164 return 0;
165}
166
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000167int Texture::imagePitch(const Image &img) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000168{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000169 return img.width * 4;
170}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000171
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000172GLsizei Texture::computePitch(GLsizei width, GLenum format, GLenum type, GLint alignment) const
173{
174 ASSERT(alignment > 0 && isPow2(alignment));
175
176 GLsizei rawPitch = pixelSize(format, type) * width;
177 return (rawPitch + alignment - 1) & ~(alignment - 1);
178}
179
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000180// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
181// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
182void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000183 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000184{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000185 GLsizei inputPitch = computePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000186
187 for (int y = 0; y < height; y++)
188 {
189 const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
190 const unsigned short *source16 = reinterpret_cast<const unsigned short*>(source);
191 unsigned char *dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
192
193 for (int x = 0; x < width; x++)
194 {
195 unsigned char r;
196 unsigned char g;
197 unsigned char b;
198 unsigned char a;
199
200 switch (format)
201 {
202 case GL_ALPHA:
203 a = source[x];
204 r = 0;
205 g = 0;
206 b = 0;
207 break;
208
209 case GL_LUMINANCE:
210 r = source[x];
211 g = source[x];
212 b = source[x];
213 a = 0xFF;
214 break;
215
216 case GL_LUMINANCE_ALPHA:
217 r = source[2*x+0];
218 g = source[2*x+0];
219 b = source[2*x+0];
220 a = source[2*x+1];
221 break;
222
223 case GL_RGB:
224 switch (type)
225 {
226 case GL_UNSIGNED_BYTE:
227 r = source[x * 3 + 0];
228 b = source[x * 3 + 1];
229 g = source[x * 3 + 2];
230 a = 0xFF;
231 break;
232
233 case GL_UNSIGNED_SHORT_5_6_5:
234 {
235 unsigned short rgba = source16[x];
236
237 a = 0xFF;
238 b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
239 g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
240 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
241 }
242 break;
243
244 default: UNREACHABLE();
245 }
246 break;
247
248 case GL_RGBA:
249 switch (type)
250 {
251 case GL_UNSIGNED_BYTE:
252 r = source[x * 4 + 0];
253 g = source[x * 4 + 1];
254 b = source[x * 4 + 2];
255 a = source[x * 4 + 3];
256 break;
257
258 case GL_UNSIGNED_SHORT_4_4_4_4:
259 {
260 unsigned short rgba = source16[x];
261
262 a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
263 b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
264 g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
265 r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
266 }
267 break;
268
269 case GL_UNSIGNED_SHORT_5_5_5_1:
270 {
271 unsigned short rgba = source16[x];
272
273 a = (rgba & 0x0001) ? 0xFF : 0;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000274 b = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000275 g = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000276 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000277 }
278 break;
279
280 default: UNREACHABLE();
281 }
282 break;
283 default: UNREACHABLE();
284 }
285
286 dest[4 * x + 0] = b;
287 dest[4 * x + 1] = g;
288 dest[4 * x + 2] = r;
289 dest[4 * x + 3] = a;
290 }
291 }
292}
293
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000294void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000295{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000296 IDirect3DSurface9 *newSurface = NULL;
297 HRESULT result = getDevice()->CreateOffscreenPlainSurface(width, height, selectFormat(format), D3DPOOL_SYSTEMMEM, &newSurface, NULL);
298
299 if (FAILED(result))
300 {
301 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
302 return error(GL_OUT_OF_MEMORY);
303 }
304
305 if (img->surface) img->surface->Release();
306 img->surface = newSurface;
307
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000308 img->width = width;
309 img->height = height;
310 img->format = format;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000311
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000312 if (pixels != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000314 D3DLOCKED_RECT locked;
315 HRESULT result = newSurface->LockRect(&locked, NULL, 0);
316
317 ASSERT(SUCCEEDED(result));
318
319 if (SUCCEEDED(result))
320 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000321 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000322 newSurface->UnlockRect();
323 }
324
325 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326 }
327
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000328 mDirtyMetaData = true;
329}
330
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000331void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000332{
333 if (width + xoffset > img->width || height + yoffset > img->height) return error(GL_INVALID_VALUE);
334
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000335 D3DLOCKED_RECT locked;
336 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000337
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000338 ASSERT(SUCCEEDED(result));
339
340 if (SUCCEEDED(result))
341 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000342 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000343 img->surface->UnlockRect();
344 }
345
346 img->dirty = true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000347}
348
349IDirect3DBaseTexture9 *Texture::getTexture()
350{
351 if (!isComplete())
352 {
353 return NULL;
354 }
355
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000356 if (mDirtyMetaData)
357 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000358 mBaseTexture = createTexture();
359 }
360
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000361 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000362 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000363 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000364 }
365
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000366 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000367 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000368
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000369 return mBaseTexture;
370}
371
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000372// Returns the top-level texture surface as a render target
373IDirect3DSurface9 *Texture::getRenderTarget(GLenum target)
374{
375 if (mDirtyMetaData && mRenderTarget)
376 {
377 mRenderTarget->Release();
378 mRenderTarget = NULL;
379 }
380
381 if (!mRenderTarget)
382 {
383 mBaseTexture = convertToRenderTarget();
384 mRenderTarget = getSurface(target);
385 }
386
387 if (dirtyImageData())
388 {
389 updateTexture();
390 }
391
392 mDirtyMetaData = false;
393
394 return mRenderTarget;
395}
396
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000397void Texture::dropTexture()
398{
399 if (mRenderTarget)
400 {
401 mRenderTarget->Release();
402 mRenderTarget = NULL;
403 }
404
405 if (mBaseTexture)
406 {
407 mBaseTexture = NULL;
408 }
409}
410
411void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture)
412{
413 mBaseTexture = newTexture;
414 mDirtyMetaData = false;
415}
416
417
418Texture2D::Texture2D(Context *context) : Texture(context)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000419{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420 mTexture = NULL;
421}
422
423Texture2D::~Texture2D()
424{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425 if (mTexture)
426 {
427 mTexture->Release();
428 mTexture = NULL;
429 }
430}
431
432GLenum Texture2D::getTarget() const
433{
434 return GL_TEXTURE_2D;
435}
436
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000437// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
438// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
439// Call this when a particular level of the texture must be defined with a specific format, width and height.
440//
441// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
442// a new height and width for the texture by working backwards from the given width and height.
443bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height)
444{
445 bool widthOkay = (mWidth >> level == width);
446 bool heightOkay = (mHeight >> level == height);
447
448 bool sizeOkay = ((widthOkay && heightOkay)
449 || (widthOkay && mHeight >> level == 0 && height == 1)
450 || (heightOkay && mWidth >> level == 0 && width == 1));
451
452 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
453
454 if (!textureOkay)
455 {
456 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
457 mImageArray[0].format, mWidth, mHeight,
458 internalFormat, width, height);
459
460 // Purge all the levels and the texture.
461
462 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
463 {
464 if (mImageArray[i].surface != NULL)
465 {
466 mImageArray[i].dirty = false;
467
468 mImageArray[i].surface->Release();
469 mImageArray[i].surface = NULL;
470 }
471 }
472
473 if (mTexture != NULL)
474 {
475 mTexture->Release();
476 mTexture = NULL;
477 dropTexture();
478 }
479
480 mWidth = width << level;
481 mHeight = height << level;
482 mImageArray[0].format = internalFormat;
483 }
484
485 return !textureOkay;
486}
487
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000488void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000490 redefineTexture(level, internalFormat, width, height);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000491
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000492 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000493}
494
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000495void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
496{
497 ASSERT(mImageArray[level].surface != NULL);
498
499 if (mTexture != NULL)
500 {
501 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000502 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000503
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000504 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000505
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000506 if (SUCCEEDED(result))
507 {
508 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000509
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000510 RECT sourceRect;
511 sourceRect.left = xoffset;
512 sourceRect.top = yoffset;
513 sourceRect.right = xoffset + width;
514 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000515
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000516 POINT destPoint;
517 destPoint.x = xoffset;
518 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000519
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000520 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
521 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000522
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000523 destLevel->Release();
524
525 img->dirty = false;
526 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000527 }
528}
529
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000530void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000531{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000532 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000533 commitRect(level, xoffset, yoffset, width, height);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000534}
535
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000536void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
537{
538 if (redefineTexture(level, internalFormat, width, height))
539 {
540 convertToRenderTarget();
541 pushTexture(mTexture);
542 }
543
544 RECT sourceRect;
545 sourceRect.left = x;
546 sourceRect.top = y + height;
547 sourceRect.right = x + width;
548 sourceRect.bottom = y;
549
550 IDirect3DSurface9 *dest;
551 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
552
553 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
554 dest->Release();
555
556 mImageArray[level].width = width;
557 mImageArray[level].height = height;
558 mImageArray[level].format = internalFormat;
559}
560
561void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
562{
563 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
564 {
565 convertToRenderTarget();
566 pushTexture(mTexture);
567 }
568 else
569 {
570 getRenderTarget(GL_TEXTURE_2D);
571 }
572
573 RECT sourceRect;
574 sourceRect.left = x;
575 sourceRect.top = y + height;
576 sourceRect.right = x + width;
577 sourceRect.bottom = y;
578
579 IDirect3DSurface9 *dest;
580 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
581
582 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
583 dest->Release();
584}
585
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000586// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
587bool Texture2D::isComplete() const
588{
589 ASSERT(mWidth == mImageArray[0].width && mHeight == mImageArray[0].height);
590
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000591 if (mWidth <= 0 || mHeight <= 0)
592 {
593 return false;
594 }
595
596 bool mipmapping;
597
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000598 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000599 {
600 case GL_NEAREST:
601 case GL_LINEAR:
602 mipmapping = false;
603 break;
604 case GL_NEAREST_MIPMAP_NEAREST:
605 case GL_LINEAR_MIPMAP_NEAREST:
606 case GL_NEAREST_MIPMAP_LINEAR:
607 case GL_LINEAR_MIPMAP_LINEAR:
608 mipmapping = true;
609 break;
610 default: UNREACHABLE();
611 }
612
613 if (mipmapping)
614 {
daniel@transgaming.com16973022010-03-11 19:22:19 +0000615 int q = log2(std::max(mWidth, mHeight));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000616
617 for (int level = 1; level <= q; level++)
618 {
619 if (mImageArray[level].format != mImageArray[0].format)
620 {
621 return false;
622 }
623
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000624 if (mImageArray[level].width != (mImageArray[level - 1].width + 1) / 2)
625 {
626 return false;
627 }
628
629 if (mImageArray[level].height != (mImageArray[level - 1].height + 1) / 2)
630 {
631 return false;
632 }
633 }
634 }
635
636 return true;
637}
638
639// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000640IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000641{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000642 IDirect3DTexture9 *texture;
643
644 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000645 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000646
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000647 HRESULT result = device->CreateTexture(mWidth, mHeight, 0, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000648
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000649 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000650 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000651 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000652 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000653 }
654
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000655 if (mTexture) mTexture->Release();
656 mTexture = texture;
657 return texture;
658}
659
660void Texture2D::updateTexture()
661{
662 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000663
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000664 int levelCount = mTexture->GetLevelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000665
666 for (int level = 0; level < levelCount; level++)
667 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000668 if (mImageArray[level].dirty)
669 {
670 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000671 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000672
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000673 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000674
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000675 if (SUCCEEDED(result))
676 {
677 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
678 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000679
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000680 levelSurface->Release();
681
682 mImageArray[level].dirty = false;
683 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000684 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000685 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000686}
687
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000688IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000689{
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000690 IDirect3DTexture9 *texture;
691
692 IDirect3DDevice9 *device = getDevice();
693 D3DFORMAT format = selectFormat(mImageArray[0].format);
694
695 HRESULT result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
696
697 if (FAILED(result))
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000698 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000699 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
700 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000701 }
702
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000703 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000704 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000705 int levels = texture->GetLevelCount();
706 for (int i = 0; i < levels; i++)
707 {
708 IDirect3DSurface9 *source;
709 result = mTexture->GetSurfaceLevel(i, &source);
710
711 if (FAILED(result))
712 {
713 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
714
715 texture->Release();
716
717 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
718 }
719
720 IDirect3DSurface9 *dest;
721 result = texture->GetSurfaceLevel(i, &dest);
722
723 if (FAILED(result))
724 {
725 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
726
727 texture->Release();
728 source->Release();
729
730 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
731 }
732
733 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
734
735 if (FAILED(result))
736 {
737 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
738
739 texture->Release();
740 source->Release();
741 dest->Release();
742
743 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
744 }
745
746 source->Release();
747 dest->Release();
748 }
749
750 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000751 }
752
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000753 mTexture = texture;
754 return mTexture;
755}
756
757IDirect3DSurface9 *Texture2D::getSurface(GLenum target)
758{
759 ASSERT(target == GL_TEXTURE_2D);
760
761 IDirect3DSurface9 *surface = NULL;
762 HRESULT result = mTexture->GetSurfaceLevel(0, &surface);
763
764 ASSERT(SUCCEEDED(result));
765
766 return surface;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000767}
768
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000769bool Texture2D::dirtyImageData() const
770{
771 int q = log2(std::max(mWidth, mHeight));
772
773 for (int i = 0; i <= q; i++)
774 {
775 if (mImageArray[i].dirty) return true;
776 }
777
778 return false;
779}
780
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000781TextureCubeMap::TextureCubeMap(Context *context) : Texture(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000782{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000783 mTexture = NULL;
784}
785
786TextureCubeMap::~TextureCubeMap()
787{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000788 if (mTexture)
789 {
790 mTexture->Release();
791 mTexture = NULL;
792 }
793}
794
795GLenum TextureCubeMap::getTarget() const
796{
797 return GL_TEXTURE_CUBE_MAP;
798}
799
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000800void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000801{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000802 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000803}
804
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000805void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000806{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000807 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000808}
809
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000810void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000811{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000812 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000813}
814
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000815void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000816{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000817 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000818}
819
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000820void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000821{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000822 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000823}
824
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000825void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000826{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000827 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000828}
829
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000830void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
831{
832 int face = faceIndex(faceTarget);
833
834 ASSERT(mImageArray[face][level].surface != NULL);
835
836 if (mTexture != NULL)
837 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000838 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
839 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000840
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000841 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000842 {
843 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000844
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000845 RECT sourceRect;
846 sourceRect.left = xoffset;
847 sourceRect.top = yoffset;
848 sourceRect.right = xoffset + width;
849 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000850
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000851 POINT destPoint;
852 destPoint.x = xoffset;
853 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000854
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000855 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000856 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000857
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000858 destLevel->Release();
859
860 img->dirty = false;
861 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000862 }
863}
864
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000865void TextureCubeMap::subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000866{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000867 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000868 commitRect(face, level, xoffset, yoffset, width, height);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000869}
870
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000871// 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 +0000872bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000873{
874 if (mWidth <= 0 || mHeight <= 0 || mWidth != mHeight)
875 {
876 return false;
877 }
878
879 bool mipmapping;
880
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000881 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000882 {
883 case GL_NEAREST:
884 case GL_LINEAR:
885 mipmapping = false;
886 break;
887 case GL_NEAREST_MIPMAP_NEAREST:
888 case GL_LINEAR_MIPMAP_NEAREST:
889 case GL_NEAREST_MIPMAP_LINEAR:
890 case GL_LINEAR_MIPMAP_LINEAR:
891 mipmapping = true;
892 break;
893 default: UNREACHABLE();
894 }
895
896 for (int face = 0; face < 6; face++)
897 {
898 if (mImageArray[face][0].width != mWidth || mImageArray[face][0].height != mHeight)
899 {
900 return false;
901 }
902 }
903
904 if (mipmapping)
905 {
906 int q = log2(mWidth);
907
908 for (int face = 0; face < 6; face++)
909 {
910 for (int level = 1; level <= q; level++)
911 {
912 if (mImageArray[face][level].format != mImageArray[0][0].format)
913 {
914 return false;
915 }
916
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000917 if (mImageArray[face][level].width != (mImageArray[0][level - 1].width + 1) / 2)
918 {
919 return false;
920 }
921
922 if (mImageArray[face][level].height != (mImageArray[0][level - 1].height + 1) / 2)
923 {
924 return false;
925 }
926 }
927 }
928 }
929
930 return true;
931}
932
933// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000934IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000935{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000936 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000937 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000938
939 IDirect3DCubeTexture9 *texture;
940
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000941 HRESULT result = device->CreateCubeTexture(mWidth, 0, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000942
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000943 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000944 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000945 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000946 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000947 }
948
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000949 if (mTexture) mTexture->Release();
950
951 mTexture = texture;
952 return mTexture;
953}
954
955void TextureCubeMap::updateTexture()
956{
957 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000958
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000959 for (int face = 0; face < 6; face++)
960 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000961 for (int level = 0; level <= log2(mWidth); level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000962 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000963 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000964
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000965 if (img->dirty)
966 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000967 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
968 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000969
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000970 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000971 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000972 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000973 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000974
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000975 levelSurface->Release();
976
977 img->dirty = false;
978 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000979 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000980 }
981 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000982}
983
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000984IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
985{
986 IDirect3DCubeTexture9 *texture;
987
988 IDirect3DDevice9 *device = getDevice();
989 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
990
991 HRESULT result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
992
993 if (FAILED(result))
994 {
995 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
996 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
997 }
998
999 if (mTexture != NULL)
1000 {
1001 int levels = texture->GetLevelCount();
1002 for (int f = 0; f < 6; f++)
1003 {
1004 for (int i = 0; i < levels; i++)
1005 {
1006 IDirect3DSurface9 *source;
1007 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1008
1009 if (FAILED(result))
1010 {
1011 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1012
1013 texture->Release();
1014
1015 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1016 }
1017
1018 IDirect3DSurface9 *dest;
1019 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1020
1021 if (FAILED(result))
1022 {
1023 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1024
1025 texture->Release();
1026 source->Release();
1027
1028 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1029 }
1030
1031 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1032
1033 if (FAILED(result))
1034 {
1035 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1036
1037 texture->Release();
1038 source->Release();
1039 dest->Release();
1040
1041 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1042 }
1043 }
1044 }
1045
1046 mTexture->Release();
1047 }
1048
1049 mTexture = texture;
1050 return mTexture;
1051}
1052
1053IDirect3DSurface9 *TextureCubeMap::getSurface(GLenum target)
1054{
1055 ASSERT(es2dx::IsCubemapTextureTarget(target));
1056
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001057 IDirect3DSurface9 *surface = getCubeMapSurface(target, 0);
1058 ASSERT(surface != NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001059 return surface;
1060}
1061
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001062void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001063{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001064 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001065
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001066 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001067}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001068
1069unsigned int TextureCubeMap::faceIndex(GLenum face)
1070{
1071 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1072 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1073 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1074 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1075 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1076
1077 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1078}
1079
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001080bool TextureCubeMap::dirtyImageData() const
1081{
1082 int q = log2(mWidth);
1083
1084 for (int f = 0; f < 6; f++)
1085 {
1086 for (int i = 0; i <= q; i++)
1087 {
1088 if (mImageArray[f][i].dirty) return true;
1089 }
1090 }
1091
1092 return false;
1093}
1094
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001095// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1096// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1097// Call this when a particular level of the texture must be defined with a specific format, width and height.
1098//
1099// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1100// a new size for the texture by working backwards from the given size.
1101bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1102{
1103 // Are these settings compatible with level 0?
1104 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1105
1106 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1107
1108 if (!textureOkay)
1109 {
1110 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1111 mImageArray[0][0].format, mImageArray[0][0].width,
1112 internalFormat, width);
1113
1114 // Purge all the levels and the texture.
1115 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1116 {
1117 for (int f = 0; f < 6; f++)
1118 {
1119 if (mImageArray[f][i].surface != NULL)
1120 {
1121 mImageArray[f][i].dirty = false;
1122
1123 mImageArray[f][i].surface->Release();
1124 mImageArray[f][i].surface = NULL;
1125 }
1126 }
1127 }
1128
1129 if (mTexture != NULL)
1130 {
1131 mTexture->Release();
1132 mTexture = NULL;
1133 dropTexture();
1134 }
1135
1136 mWidth = width << level;
1137 mImageArray[0][0].width = width << level;
1138 mHeight = width << level;
1139 mImageArray[0][0].height = width << level;
1140
1141 mImageArray[0][0].format = internalFormat;
1142 }
1143
1144 return !textureOkay;
1145}
1146
1147void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
1148{
1149 unsigned int faceindex = faceIndex(face);
1150
1151 if (redefineTexture(level, internalFormat, width))
1152 {
1153 convertToRenderTarget();
1154 pushTexture(mTexture);
1155 }
1156
1157 RECT sourceRect;
1158 sourceRect.left = x;
1159 sourceRect.top = y + height;
1160 sourceRect.right = x + width;
1161 sourceRect.bottom = y;
1162
1163 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1164
1165 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1166 dest->Release();
1167
1168 mImageArray[faceindex][level].width = width;
1169 mImageArray[faceindex][level].height = height;
1170 mImageArray[faceindex][level].format = internalFormat;
1171}
1172
1173IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1174{
1175 unsigned int faceIndex;
1176
1177 if (faceIdentifier < 6)
1178 {
1179 faceIndex = faceIdentifier;
1180 }
1181 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1182 {
1183 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1184 }
1185 else
1186 {
1187 UNREACHABLE();
1188 faceIndex = 0;
1189 }
1190
1191 if (mTexture == NULL)
1192 {
1193 UNREACHABLE();
1194 return NULL;
1195 }
1196
1197 IDirect3DSurface9 *surface = NULL;
1198
1199 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1200
1201 return (SUCCEEDED(hr)) ? surface : NULL;
1202}
1203
1204void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
1205{
1206 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1207 {
1208 convertToRenderTarget();
1209 pushTexture(mTexture);
1210 }
1211 else
1212 {
1213 getRenderTarget(face);
1214 }
1215
1216 RECT sourceRect;
1217 sourceRect.left = x;
1218 sourceRect.top = y + height;
1219 sourceRect.right = x + width;
1220 sourceRect.bottom = y;
1221
1222 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1223
1224 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1225 dest->Release();
1226}
1227
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001228}