blob: c478cd439fb776de4f66b5451d23ec2928b278a9 [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
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/Texture.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
daniel@transgaming.com16973022010-03-11 19:22:19 +000013#include <algorithm>
14
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000015#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/mathutil.h"
19#include "libGLESv2/utilities.h"
20#include "libGLESv2/Blit.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021
22namespace gl
23{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000024
25Texture::Image::Image()
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000026 : width(0), height(0), dirty(false), surface(NULL)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000027{
28}
29
30Texture::Image::~Image()
31{
32 if (surface) surface->Release();
33}
34
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000035Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036{
37 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
38 mMagFilter = GL_LINEAR;
39 mWrapS = GL_REPEAT;
40 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000041
daniel@transgaming.com31273552010-08-04 13:42:44 +000042 mWidth = 0;
43 mHeight = 0;
44
daniel@transgaming.com00c75962010-03-11 20:36:15 +000045 mDirtyMetaData = true;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000046 mDirty = true;
daniel@transgaming.com93a81472010-04-20 18:52:58 +000047 mIsRenderable = false;
daniel@transgaming.com0a311a42010-05-17 09:58:33 +000048 mBaseTexture = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000049}
50
51Texture::~Texture()
52{
53}
54
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000055Blit *Texture::getBlitter()
56{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000057 Context *context = getContext();
58 return context->getBlitter();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000059}
60
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000061// Returns true on successful filter state update (valid enum parameter)
62bool Texture::setMinFilter(GLenum filter)
63{
64 switch (filter)
65 {
66 case GL_NEAREST:
67 case GL_LINEAR:
68 case GL_NEAREST_MIPMAP_NEAREST:
69 case GL_LINEAR_MIPMAP_NEAREST:
70 case GL_NEAREST_MIPMAP_LINEAR:
71 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000072 {
73 if (mMinFilter != filter)
74 {
75 mMinFilter = filter;
76 mDirty = true;
77 }
78 return true;
79 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080 default:
81 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000082 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000083}
84
85// Returns true on successful filter state update (valid enum parameter)
86bool Texture::setMagFilter(GLenum filter)
87{
88 switch (filter)
89 {
90 case GL_NEAREST:
91 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000092 {
93 if (mMagFilter != filter)
94 {
95 mMagFilter = filter;
96 mDirty = true;
97 }
98 return true;
99 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100 default:
101 return false;
102 }
103}
104
105// Returns true on successful wrap state update (valid enum parameter)
106bool Texture::setWrapS(GLenum wrap)
107{
108 switch (wrap)
109 {
110 case GL_REPEAT:
111 case GL_CLAMP_TO_EDGE:
112 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000113 {
114 if (mWrapS != wrap)
115 {
116 mWrapS = wrap;
117 mDirty = true;
118 }
119 return true;
120 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000121 default:
122 return false;
123 }
124}
125
126// Returns true on successful wrap state update (valid enum parameter)
127bool Texture::setWrapT(GLenum wrap)
128{
129 switch (wrap)
130 {
131 case GL_REPEAT:
132 case GL_CLAMP_TO_EDGE:
133 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000134 {
135 if (mWrapT != wrap)
136 {
137 mWrapT = wrap;
138 mDirty = true;
139 }
140 return true;
141 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142 default:
143 return false;
144 }
145}
146
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000147GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148{
149 return mMinFilter;
150}
151
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000152GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000153{
154 return mMagFilter;
155}
156
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000157GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158{
159 return mWrapS;
160}
161
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000162GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163{
164 return mWrapT;
165}
166
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000167GLuint Texture::getWidth() const
168{
169 return mWidth;
170}
171
172GLuint Texture::getHeight() const
173{
174 return mHeight;
175}
176
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000178D3DFORMAT Texture::selectFormat(GLenum format)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000180 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181}
182
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000183int Texture::imagePitch(const Image &img) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000185 return img.width * 4;
186}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000187
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000188// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
189// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
190void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000191 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000192{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000193 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000194
195 for (int y = 0; y < height; y++)
196 {
197 const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
198 const unsigned short *source16 = reinterpret_cast<const unsigned short*>(source);
199 unsigned char *dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
200
201 for (int x = 0; x < width; x++)
202 {
203 unsigned char r;
204 unsigned char g;
205 unsigned char b;
206 unsigned char a;
207
208 switch (format)
209 {
210 case GL_ALPHA:
211 a = source[x];
212 r = 0;
213 g = 0;
214 b = 0;
215 break;
216
217 case GL_LUMINANCE:
218 r = source[x];
219 g = source[x];
220 b = source[x];
221 a = 0xFF;
222 break;
223
224 case GL_LUMINANCE_ALPHA:
225 r = source[2*x+0];
226 g = source[2*x+0];
227 b = source[2*x+0];
228 a = source[2*x+1];
229 break;
230
231 case GL_RGB:
232 switch (type)
233 {
234 case GL_UNSIGNED_BYTE:
235 r = source[x * 3 + 0];
daniel@transgaming.com5ac52152010-04-13 19:53:38 +0000236 g = source[x * 3 + 1];
237 b = source[x * 3 + 2];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000238 a = 0xFF;
239 break;
240
241 case GL_UNSIGNED_SHORT_5_6_5:
242 {
243 unsigned short rgba = source16[x];
244
245 a = 0xFF;
246 b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
247 g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
248 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
249 }
250 break;
251
252 default: UNREACHABLE();
253 }
254 break;
255
256 case GL_RGBA:
257 switch (type)
258 {
259 case GL_UNSIGNED_BYTE:
260 r = source[x * 4 + 0];
261 g = source[x * 4 + 1];
262 b = source[x * 4 + 2];
263 a = source[x * 4 + 3];
264 break;
265
266 case GL_UNSIGNED_SHORT_4_4_4_4:
267 {
268 unsigned short rgba = source16[x];
269
270 a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
271 b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
272 g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
273 r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
274 }
275 break;
276
277 case GL_UNSIGNED_SHORT_5_5_5_1:
278 {
279 unsigned short rgba = source16[x];
280
281 a = (rgba & 0x0001) ? 0xFF : 0;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000282 b = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000283 g = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000284 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000285 }
286 break;
287
288 default: UNREACHABLE();
289 }
290 break;
291 default: UNREACHABLE();
292 }
293
294 dest[4 * x + 0] = b;
295 dest[4 * x + 1] = g;
296 dest[4 * x + 2] = r;
297 dest[4 * x + 3] = a;
298 }
299 }
300}
301
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000302void 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 +0000303{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000304 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000305
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000306 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000307 {
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000308 HRESULT result = getDevice()->CreateOffscreenPlainSurface(width, height, selectFormat(format), D3DPOOL_SYSTEMMEM, &newSurface, NULL);
309
310 if (FAILED(result))
311 {
312 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
313 return error(GL_OUT_OF_MEMORY);
314 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000315 }
316
317 if (img->surface) img->surface->Release();
318 img->surface = newSurface;
319
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000320 img->width = width;
321 img->height = height;
322 img->format = format;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000323
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000324 if (pixels != NULL && newSurface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000326 D3DLOCKED_RECT locked;
327 HRESULT result = newSurface->LockRect(&locked, NULL, 0);
328
329 ASSERT(SUCCEEDED(result));
330
331 if (SUCCEEDED(result))
332 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000333 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000334 newSurface->UnlockRect();
335 }
336
337 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000338 }
339
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000340 mDirtyMetaData = true;
341}
342
daniel@transgaming.com31273552010-08-04 13:42:44 +0000343bool 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 +0000344{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000345 if (width + xoffset > img->width || height + yoffset > img->height)
346 {
347 error(GL_INVALID_VALUE);
348 return false;
349 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000350
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000351 D3DLOCKED_RECT locked;
352 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000353
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000354 ASSERT(SUCCEEDED(result));
355
356 if (SUCCEEDED(result))
357 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000358 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000359 img->surface->UnlockRect();
360 }
361
362 img->dirty = true;
daniel@transgaming.com31273552010-08-04 13:42:44 +0000363 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000364}
365
366IDirect3DBaseTexture9 *Texture::getTexture()
367{
368 if (!isComplete())
369 {
370 return NULL;
371 }
372
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000373 if (mDirtyMetaData)
374 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000375 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000376 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000377 }
378
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000379 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000380 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000381 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000382 }
383
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000384 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000385 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000386
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000387 return mBaseTexture;
388}
389
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000390bool Texture::isDirty() const
391{
392 return (mDirty || mDirtyMetaData || dirtyImageData());
393}
394
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000395// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000396void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000397{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000398 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000399 {
400 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000401 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000402 }
403
404 if (dirtyImageData())
405 {
406 updateTexture();
407 }
408
409 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000410}
411
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000412void Texture::dropTexture()
413{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000414 if (mBaseTexture)
415 {
416 mBaseTexture = NULL;
417 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000418
419 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000420}
421
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000422void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000423{
424 mBaseTexture = newTexture;
425 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000426 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000427 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000428}
429
430
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000431GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
432{
433 if (isPow2(width) && isPow2(height))
434 {
435 return maxlevel;
436 }
437 else
438 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000439 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
440 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000441 }
442}
443
444GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
445{
446 return creationLevels(size, size, maxlevel);
447}
448
449int Texture::levelCount() const
450{
451 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
452}
453
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000454Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000455{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000457 mColorbufferProxy = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458}
459
460Texture2D::~Texture2D()
461{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000462 delete mColorbufferProxy;
463
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000464 if (mTexture)
465 {
466 mTexture->Release();
467 mTexture = NULL;
468 }
469}
470
471GLenum Texture2D::getTarget() const
472{
473 return GL_TEXTURE_2D;
474}
475
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000476// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
477// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
478// Call this when a particular level of the texture must be defined with a specific format, width and height.
479//
480// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
481// a new height and width for the texture by working backwards from the given width and height.
482bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height)
483{
484 bool widthOkay = (mWidth >> level == width);
485 bool heightOkay = (mHeight >> level == height);
486
487 bool sizeOkay = ((widthOkay && heightOkay)
488 || (widthOkay && mHeight >> level == 0 && height == 1)
489 || (heightOkay && mWidth >> level == 0 && width == 1));
490
491 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
492
493 if (!textureOkay)
494 {
495 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
496 mImageArray[0].format, mWidth, mHeight,
497 internalFormat, width, height);
498
499 // Purge all the levels and the texture.
500
501 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
502 {
503 if (mImageArray[i].surface != NULL)
504 {
505 mImageArray[i].dirty = false;
506
507 mImageArray[i].surface->Release();
508 mImageArray[i].surface = NULL;
509 }
510 }
511
512 if (mTexture != NULL)
513 {
514 mTexture->Release();
515 mTexture = NULL;
516 dropTexture();
517 }
518
519 mWidth = width << level;
520 mHeight = height << level;
521 mImageArray[0].format = internalFormat;
522 }
523
524 return !textureOkay;
525}
526
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000527void 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 +0000528{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000529 redefineTexture(level, internalFormat, width, height);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000531 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000532}
533
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000534void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
535{
536 ASSERT(mImageArray[level].surface != NULL);
537
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000538 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000539 {
540 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000541 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000542
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000543 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000544
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000545 if (SUCCEEDED(result))
546 {
547 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000548
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000549 RECT sourceRect;
550 sourceRect.left = xoffset;
551 sourceRect.top = yoffset;
552 sourceRect.right = xoffset + width;
553 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000554
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000555 POINT destPoint;
556 destPoint.x = xoffset;
557 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000558
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000559 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
560 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000561
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000562 destLevel->Release();
563
564 img->dirty = false;
565 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000566 }
567}
568
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000569void 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 +0000570{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000571 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
572 {
573 commitRect(level, xoffset, yoffset, width, height);
574 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000575}
576
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000577void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000578{
579 if (redefineTexture(level, internalFormat, width, height))
580 {
581 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000582 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000583 }
584
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000585 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000586 {
587 RECT sourceRect;
588 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000589 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +0000590 sourceRect.top = y;
591 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000592
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000593 IDirect3DSurface9 *dest;
594 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000595
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000596 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
597 dest->Release();
598 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000599
600 mImageArray[level].width = width;
601 mImageArray[level].height = height;
602 mImageArray[level].format = internalFormat;
603}
604
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000605void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000606{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000607 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
608 {
609 return error(GL_INVALID_VALUE);
610 }
611
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000612 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
613 {
614 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000615 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000616 }
617 else
618 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +0000619 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000620 }
621
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000622 if (level < levelCount())
623 {
624 RECT sourceRect;
625 sourceRect.left = x;
626 sourceRect.right = x + width;
627 sourceRect.top = y;
628 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000629
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000630 IDirect3DSurface9 *dest;
631 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000632
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000633 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
634 dest->Release();
635 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000636}
637
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000638// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
639bool Texture2D::isComplete() const
640{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000641 GLsizei width = mImageArray[0].width;
642 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000643
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000644 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000645 {
646 return false;
647 }
648
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000649 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000650
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000651 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000652 {
653 case GL_NEAREST:
654 case GL_LINEAR:
655 mipmapping = false;
656 break;
657 case GL_NEAREST_MIPMAP_NEAREST:
658 case GL_LINEAR_MIPMAP_NEAREST:
659 case GL_NEAREST_MIPMAP_LINEAR:
660 case GL_LINEAR_MIPMAP_LINEAR:
661 mipmapping = true;
662 break;
663 default: UNREACHABLE();
664 }
665
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000666 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
667 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
668 {
669 return false;
670 }
671
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000672 if (mipmapping)
673 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000674 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000675 {
676 return false;
677 }
678
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000679 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680
681 for (int level = 1; level <= q; level++)
682 {
683 if (mImageArray[level].format != mImageArray[0].format)
684 {
685 return false;
686 }
687
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000688 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000689 {
690 return false;
691 }
692
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000693 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000694 {
695 return false;
696 }
697 }
698 }
699
700 return true;
701}
702
703// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000704IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000705{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000706 IDirect3DTexture9 *texture;
707
708 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000709 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000710
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000711 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000712
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000713 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000714 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000715 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000716 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000717 }
718
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000719 if (mTexture) mTexture->Release();
720 mTexture = texture;
721 return texture;
722}
723
724void Texture2D::updateTexture()
725{
726 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000727
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000728 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000729
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000730 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000731 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000732 if (mImageArray[level].dirty)
733 {
734 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000735 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000736
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000737 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000738
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000739 if (SUCCEEDED(result))
740 {
741 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
742 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000743
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000744 levelSurface->Release();
745
746 mImageArray[level].dirty = false;
747 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000748 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000749 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000750}
751
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000752IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000753{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000754 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000755
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000756 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000757 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000758 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000759 IDirect3DDevice9 *device = getDevice();
760 D3DFORMAT format = selectFormat(mImageArray[0].format);
761
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000762 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000763
764 if (FAILED(result))
765 {
766 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
767 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
768 }
769
770 if (mTexture != NULL)
771 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000772 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000773 for (int i = 0; i < levels; i++)
774 {
775 IDirect3DSurface9 *source;
776 result = mTexture->GetSurfaceLevel(i, &source);
777
778 if (FAILED(result))
779 {
780 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
781
782 texture->Release();
783
784 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
785 }
786
787 IDirect3DSurface9 *dest;
788 result = texture->GetSurfaceLevel(i, &dest);
789
790 if (FAILED(result))
791 {
792 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
793
794 texture->Release();
795 source->Release();
796
797 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
798 }
799
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000800 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000801 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
802
803 if (FAILED(result))
804 {
805 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
806
807 texture->Release();
808 source->Release();
809 dest->Release();
810
811 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
812 }
813
814 source->Release();
815 dest->Release();
816 }
817 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000818 }
819
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000820 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000821 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000822 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000823 }
824
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000825 mTexture = texture;
826 return mTexture;
827}
828
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000829bool Texture2D::dirtyImageData() const
830{
831 int q = log2(std::max(mWidth, mHeight));
832
833 for (int i = 0; i <= q; i++)
834 {
835 if (mImageArray[i].dirty) return true;
836 }
837
838 return false;
839}
840
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000841void Texture2D::generateMipmaps()
842{
843 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
844 {
845 return error(GL_INVALID_OPERATION);
846 }
847
848 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
849 unsigned int q = log2(std::max(mWidth, mHeight));
850 for (unsigned int i = 1; i <= q; i++)
851 {
852 if (mImageArray[i].surface != NULL)
853 {
854 mImageArray[i].surface->Release();
855 mImageArray[i].surface = NULL;
856 }
857
858 mImageArray[i].dirty = false;
859
860 mImageArray[i].format = mImageArray[0].format;
861 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
862 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
863 }
864
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000865 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000866
867 for (unsigned int i = 1; i <= q; i++)
868 {
869 IDirect3DSurface9 *upper = NULL;
870 IDirect3DSurface9 *lower = NULL;
871
872 mTexture->GetSurfaceLevel(i-1, &upper);
873 mTexture->GetSurfaceLevel(i, &lower);
874
875 if (upper != NULL && lower != NULL)
876 {
877 getBlitter()->boxFilter(upper, lower);
878 }
879
880 if (upper != NULL) upper->Release();
881 if (lower != NULL) lower->Release();
882 }
883}
884
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000885Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000886{
887 if (target != GL_TEXTURE_2D)
888 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000889 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000890 }
891
892 if (mColorbufferProxy == NULL)
893 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000894 mColorbufferProxy = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
895 mColorbufferProxy->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000896 }
897
898 return mColorbufferProxy;
899}
900
901IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
902{
903 ASSERT(target == GL_TEXTURE_2D);
904
905 needRenderTarget();
906
907 IDirect3DSurface9 *renderTarget = NULL;
908 mTexture->GetSurfaceLevel(0, &renderTarget);
909
910 return renderTarget;
911}
912
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000913TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000914{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000915 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000916
917 for (int i = 0; i < 6; i++)
918 {
919 mFaceProxies[i] = NULL;
920 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000921}
922
923TextureCubeMap::~TextureCubeMap()
924{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000925 for (int i = 0; i < 6; i++)
926 {
927 delete mFaceProxies[i];
928 }
929
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000930 if (mTexture)
931 {
932 mTexture->Release();
933 mTexture = NULL;
934 }
935}
936
937GLenum TextureCubeMap::getTarget() const
938{
939 return GL_TEXTURE_CUBE_MAP;
940}
941
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000942void 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 +0000943{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000944 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945}
946
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000947void 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 +0000948{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000949 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000950}
951
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000952void 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 +0000953{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000954 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000955}
956
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000957void 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 +0000958{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000959 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000960}
961
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000962void 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 +0000963{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000964 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000965}
966
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000967void 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 +0000968{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000969 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000970}
971
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000972void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
973{
974 int face = faceIndex(faceTarget);
975
976 ASSERT(mImageArray[face][level].surface != NULL);
977
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000978 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000979 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000980 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
981 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000982
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000983 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000984 {
985 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000986
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000987 RECT sourceRect;
988 sourceRect.left = xoffset;
989 sourceRect.top = yoffset;
990 sourceRect.right = xoffset + width;
991 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000992
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000993 POINT destPoint;
994 destPoint.x = xoffset;
995 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000996
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000997 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000998 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000999
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001000 destLevel->Release();
1001
1002 img->dirty = false;
1003 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001004 }
1005}
1006
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001007void 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 +00001008{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001009 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1010 {
1011 commitRect(face, level, xoffset, yoffset, width, height);
1012 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001013}
1014
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001015// 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 +00001016bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001017{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001018 int size = mImageArray[0][0].width;
1019
1020 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001021 {
1022 return false;
1023 }
1024
1025 bool mipmapping;
1026
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001027 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001028 {
1029 case GL_NEAREST:
1030 case GL_LINEAR:
1031 mipmapping = false;
1032 break;
1033 case GL_NEAREST_MIPMAP_NEAREST:
1034 case GL_LINEAR_MIPMAP_NEAREST:
1035 case GL_NEAREST_MIPMAP_LINEAR:
1036 case GL_LINEAR_MIPMAP_LINEAR:
1037 mipmapping = true;
1038 break;
1039 default: UNREACHABLE();
1040 }
1041
1042 for (int face = 0; face < 6; face++)
1043 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001044 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001045 {
1046 return false;
1047 }
1048 }
1049
1050 if (mipmapping)
1051 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001052 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1053 {
1054 return false;
1055 }
1056
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001057 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001058
1059 for (int face = 0; face < 6; face++)
1060 {
1061 for (int level = 1; level <= q; level++)
1062 {
1063 if (mImageArray[face][level].format != mImageArray[0][0].format)
1064 {
1065 return false;
1066 }
1067
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001068 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001069 {
1070 return false;
1071 }
1072
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001073 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001074 }
1075 }
1076 }
1077
1078 return true;
1079}
1080
1081// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001082IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001083{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001084 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001085 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001086
1087 IDirect3DCubeTexture9 *texture;
1088
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001089 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001090
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001091 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001092 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001093 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001094 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001095 }
1096
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001097 if (mTexture) mTexture->Release();
1098
1099 mTexture = texture;
1100 return mTexture;
1101}
1102
1103void TextureCubeMap::updateTexture()
1104{
1105 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001106
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001107 for (int face = 0; face < 6; face++)
1108 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001109 int levels = levelCount();
1110 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001111 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001112 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001113
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001114 if (img->dirty)
1115 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001116 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1117 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001118
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001119 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001120 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001121 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001122 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001123
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001124 levelSurface->Release();
1125
1126 img->dirty = false;
1127 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001128 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001129 }
1130 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001131}
1132
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001133IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1134{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001135 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001136
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001137 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001138 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001139 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001140 IDirect3DDevice9 *device = getDevice();
1141 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
1142
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001143 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001144
1145 if (FAILED(result))
1146 {
1147 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1148 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1149 }
1150
1151 if (mTexture != NULL)
1152 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001153 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001154 for (int f = 0; f < 6; f++)
1155 {
1156 for (int i = 0; i < levels; i++)
1157 {
1158 IDirect3DSurface9 *source;
1159 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1160
1161 if (FAILED(result))
1162 {
1163 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1164
1165 texture->Release();
1166
1167 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1168 }
1169
1170 IDirect3DSurface9 *dest;
1171 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1172
1173 if (FAILED(result))
1174 {
1175 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1176
1177 texture->Release();
1178 source->Release();
1179
1180 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1181 }
1182
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001183 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001184 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1185
1186 if (FAILED(result))
1187 {
1188 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1189
1190 texture->Release();
1191 source->Release();
1192 dest->Release();
1193
1194 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1195 }
1196 }
1197 }
1198 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001199 }
1200
1201 if (mTexture != NULL)
1202 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001203 mTexture->Release();
1204 }
1205
1206 mTexture = texture;
1207 return mTexture;
1208}
1209
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001210void 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 +00001211{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001212 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001213
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001214 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001215}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001216
1217unsigned int TextureCubeMap::faceIndex(GLenum face)
1218{
1219 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1220 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1221 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1222 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1223 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1224
1225 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1226}
1227
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001228bool TextureCubeMap::dirtyImageData() const
1229{
1230 int q = log2(mWidth);
1231
1232 for (int f = 0; f < 6; f++)
1233 {
1234 for (int i = 0; i <= q; i++)
1235 {
1236 if (mImageArray[f][i].dirty) return true;
1237 }
1238 }
1239
1240 return false;
1241}
1242
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001243// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1244// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1245// Call this when a particular level of the texture must be defined with a specific format, width and height.
1246//
1247// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1248// a new size for the texture by working backwards from the given size.
1249bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1250{
1251 // Are these settings compatible with level 0?
1252 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1253
1254 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1255
1256 if (!textureOkay)
1257 {
1258 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1259 mImageArray[0][0].format, mImageArray[0][0].width,
1260 internalFormat, width);
1261
1262 // Purge all the levels and the texture.
1263 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1264 {
1265 for (int f = 0; f < 6; f++)
1266 {
1267 if (mImageArray[f][i].surface != NULL)
1268 {
1269 mImageArray[f][i].dirty = false;
1270
1271 mImageArray[f][i].surface->Release();
1272 mImageArray[f][i].surface = NULL;
1273 }
1274 }
1275 }
1276
1277 if (mTexture != NULL)
1278 {
1279 mTexture->Release();
1280 mTexture = NULL;
1281 dropTexture();
1282 }
1283
1284 mWidth = width << level;
1285 mImageArray[0][0].width = width << level;
1286 mHeight = width << level;
1287 mImageArray[0][0].height = width << level;
1288
1289 mImageArray[0][0].format = internalFormat;
1290 }
1291
1292 return !textureOkay;
1293}
1294
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001295void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001296{
1297 unsigned int faceindex = faceIndex(face);
1298
1299 if (redefineTexture(level, internalFormat, width))
1300 {
1301 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001302 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001303 }
1304
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001305 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001306
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001307 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001308 {
1309 RECT sourceRect;
1310 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001311 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001312 sourceRect.top = y;
1313 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001314
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001315 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1316
1317 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1318 dest->Release();
1319 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001320
1321 mImageArray[faceindex][level].width = width;
1322 mImageArray[faceindex][level].height = height;
1323 mImageArray[faceindex][level].format = internalFormat;
1324}
1325
1326IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1327{
1328 unsigned int faceIndex;
1329
1330 if (faceIdentifier < 6)
1331 {
1332 faceIndex = faceIdentifier;
1333 }
1334 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1335 {
1336 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1337 }
1338 else
1339 {
1340 UNREACHABLE();
1341 faceIndex = 0;
1342 }
1343
1344 if (mTexture == NULL)
1345 {
1346 UNREACHABLE();
1347 return NULL;
1348 }
1349
1350 IDirect3DSurface9 *surface = NULL;
1351
1352 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1353
1354 return (SUCCEEDED(hr)) ? surface : NULL;
1355}
1356
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001357void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001358{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001359 GLsizei size = mImageArray[faceIndex(face)][level].width;
1360
1361 if (xoffset + width > size || yoffset + height > size)
1362 {
1363 return error(GL_INVALID_VALUE);
1364 }
1365
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001366 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1367 {
1368 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001369 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001370 }
1371 else
1372 {
1373 getRenderTarget(face);
1374 }
1375
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001376 if (level < levelCount())
1377 {
1378 RECT sourceRect;
1379 sourceRect.left = x;
1380 sourceRect.right = x + width;
1381 sourceRect.top = y;
1382 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001383
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001384 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001385
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001386 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1387 dest->Release();
1388 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001389}
1390
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001391bool TextureCubeMap::isCubeComplete() const
1392{
1393 if (mImageArray[0][0].width == 0)
1394 {
1395 return false;
1396 }
1397
1398 for (unsigned int f = 1; f < 6; f++)
1399 {
1400 if (mImageArray[f][0].width != mImageArray[0][0].width
1401 || mImageArray[f][0].format != mImageArray[0][0].format)
1402 {
1403 return false;
1404 }
1405 }
1406
1407 return true;
1408}
1409
1410void TextureCubeMap::generateMipmaps()
1411{
1412 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1413 {
1414 return error(GL_INVALID_OPERATION);
1415 }
1416
1417 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1418 unsigned int q = log2(mImageArray[0][0].width);
1419 for (unsigned int f = 0; f < 6; f++)
1420 {
1421 for (unsigned int i = 1; i <= q; i++)
1422 {
1423 if (mImageArray[f][i].surface != NULL)
1424 {
1425 mImageArray[f][i].surface->Release();
1426 mImageArray[f][i].surface = NULL;
1427 }
1428
1429 mImageArray[f][i].dirty = false;
1430
1431 mImageArray[f][i].format = mImageArray[f][0].format;
1432 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1433 mImageArray[f][i].height = mImageArray[f][i].width;
1434 }
1435 }
1436
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001437 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001438
1439 for (unsigned int f = 0; f < 6; f++)
1440 {
1441 for (unsigned int i = 1; i <= q; i++)
1442 {
1443 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1444 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1445
1446 if (upper != NULL && lower != NULL)
1447 {
1448 getBlitter()->boxFilter(upper, lower);
1449 }
1450
1451 if (upper != NULL) upper->Release();
1452 if (lower != NULL) lower->Release();
1453 }
1454 }
1455}
1456
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001457Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001458{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001459 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001460 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001461 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001462 }
1463
1464 unsigned int face = faceIndex(target);
1465
1466 if (mFaceProxies[face] == NULL)
1467 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001468 mFaceProxies[face] = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1469 mFaceProxies[face]->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001470 }
1471
1472 return mFaceProxies[face];
1473}
1474
1475IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1476{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001477 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001478
1479 needRenderTarget();
1480
1481 IDirect3DSurface9 *renderTarget = NULL;
1482 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
1483
1484 return renderTarget;
1485}
1486
1487Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
1488 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
1489{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001490 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001491}
1492
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001493void Texture::TextureColorbufferProxy::addRef() const
1494{
1495 mTexture->addRef();
1496}
1497
1498void Texture::TextureColorbufferProxy::release() const
1499{
1500 mTexture->release();
1501}
1502
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001503IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
1504{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001505 if (mRenderTarget) mRenderTarget->Release();
1506
1507 mRenderTarget = mTexture->getRenderTarget(mTarget);
1508
1509 return mRenderTarget;
1510}
1511
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001512int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001513{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001514 return mTexture->getWidth();
1515}
1516
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001517int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001518{
1519 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001520}
1521
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001522}