blob: d671592626bf0a6d5b497d0fa393842181f2cd91 [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 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +0000584 else
585 {
586 needRenderTarget();
587 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000588
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000589 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000590 {
591 RECT sourceRect;
592 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000593 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +0000594 sourceRect.top = y;
595 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000596
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000597 IDirect3DSurface9 *dest;
598 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000599
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000600 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
601 dest->Release();
602 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000603
604 mImageArray[level].width = width;
605 mImageArray[level].height = height;
606 mImageArray[level].format = internalFormat;
607}
608
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000609void 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 +0000610{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000611 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
612 {
613 return error(GL_INVALID_VALUE);
614 }
615
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000616 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
617 {
618 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000619 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000620 }
621 else
622 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +0000623 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000624 }
625
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000626 if (level < levelCount())
627 {
628 RECT sourceRect;
629 sourceRect.left = x;
630 sourceRect.right = x + width;
631 sourceRect.top = y;
632 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000633
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000634 IDirect3DSurface9 *dest;
635 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000636
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000637 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
638 dest->Release();
639 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000640}
641
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000642// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
643bool Texture2D::isComplete() const
644{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000645 GLsizei width = mImageArray[0].width;
646 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000647
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000648 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000649 {
650 return false;
651 }
652
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000653 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000654
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000655 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000656 {
657 case GL_NEAREST:
658 case GL_LINEAR:
659 mipmapping = false;
660 break;
661 case GL_NEAREST_MIPMAP_NEAREST:
662 case GL_LINEAR_MIPMAP_NEAREST:
663 case GL_NEAREST_MIPMAP_LINEAR:
664 case GL_LINEAR_MIPMAP_LINEAR:
665 mipmapping = true;
666 break;
667 default: UNREACHABLE();
668 }
669
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000670 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
671 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
672 {
673 return false;
674 }
675
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000676 if (mipmapping)
677 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000678 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000679 {
680 return false;
681 }
682
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000683 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000684
685 for (int level = 1; level <= q; level++)
686 {
687 if (mImageArray[level].format != mImageArray[0].format)
688 {
689 return false;
690 }
691
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000692 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000693 {
694 return false;
695 }
696
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000697 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000698 {
699 return false;
700 }
701 }
702 }
703
704 return true;
705}
706
707// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000708IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000709{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000710 IDirect3DTexture9 *texture;
711
712 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000713 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000714
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000715 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000716
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000717 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000718 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000719 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000720 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000721 }
722
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000723 if (mTexture) mTexture->Release();
724 mTexture = texture;
725 return texture;
726}
727
728void Texture2D::updateTexture()
729{
730 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000731
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000732 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000733
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000734 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000735 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000736 if (mImageArray[level].dirty)
737 {
738 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000739 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000740
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000741 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000742
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000743 if (SUCCEEDED(result))
744 {
745 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
746 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000747
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000748 levelSurface->Release();
749
750 mImageArray[level].dirty = false;
751 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000752 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000753 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000754}
755
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000756IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000757{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000758 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000759
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000760 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000761 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000762 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000763 IDirect3DDevice9 *device = getDevice();
764 D3DFORMAT format = selectFormat(mImageArray[0].format);
765
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000766 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 +0000767
768 if (FAILED(result))
769 {
770 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
771 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
772 }
773
774 if (mTexture != NULL)
775 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000776 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000777 for (int i = 0; i < levels; i++)
778 {
779 IDirect3DSurface9 *source;
780 result = mTexture->GetSurfaceLevel(i, &source);
781
782 if (FAILED(result))
783 {
784 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
785
786 texture->Release();
787
788 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
789 }
790
791 IDirect3DSurface9 *dest;
792 result = texture->GetSurfaceLevel(i, &dest);
793
794 if (FAILED(result))
795 {
796 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
797
798 texture->Release();
799 source->Release();
800
801 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
802 }
803
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000804 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000805 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
806
807 if (FAILED(result))
808 {
809 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
810
811 texture->Release();
812 source->Release();
813 dest->Release();
814
815 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
816 }
817
818 source->Release();
819 dest->Release();
820 }
821 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000822 }
823
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000824 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000825 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000826 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000827 }
828
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000829 mTexture = texture;
830 return mTexture;
831}
832
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000833bool Texture2D::dirtyImageData() const
834{
835 int q = log2(std::max(mWidth, mHeight));
836
837 for (int i = 0; i <= q; i++)
838 {
839 if (mImageArray[i].dirty) return true;
840 }
841
842 return false;
843}
844
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000845void Texture2D::generateMipmaps()
846{
847 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
848 {
849 return error(GL_INVALID_OPERATION);
850 }
851
852 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
853 unsigned int q = log2(std::max(mWidth, mHeight));
854 for (unsigned int i = 1; i <= q; i++)
855 {
856 if (mImageArray[i].surface != NULL)
857 {
858 mImageArray[i].surface->Release();
859 mImageArray[i].surface = NULL;
860 }
861
862 mImageArray[i].dirty = false;
863
864 mImageArray[i].format = mImageArray[0].format;
865 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
866 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
867 }
868
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000869 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000870
871 for (unsigned int i = 1; i <= q; i++)
872 {
873 IDirect3DSurface9 *upper = NULL;
874 IDirect3DSurface9 *lower = NULL;
875
876 mTexture->GetSurfaceLevel(i-1, &upper);
877 mTexture->GetSurfaceLevel(i, &lower);
878
879 if (upper != NULL && lower != NULL)
880 {
881 getBlitter()->boxFilter(upper, lower);
882 }
883
884 if (upper != NULL) upper->Release();
885 if (lower != NULL) lower->Release();
886 }
887}
888
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000889Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000890{
891 if (target != GL_TEXTURE_2D)
892 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000893 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000894 }
895
896 if (mColorbufferProxy == NULL)
897 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000898 mColorbufferProxy = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
899 mColorbufferProxy->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000900 }
901
902 return mColorbufferProxy;
903}
904
905IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
906{
907 ASSERT(target == GL_TEXTURE_2D);
908
909 needRenderTarget();
910
911 IDirect3DSurface9 *renderTarget = NULL;
912 mTexture->GetSurfaceLevel(0, &renderTarget);
913
914 return renderTarget;
915}
916
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000917TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000918{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000919 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000920
921 for (int i = 0; i < 6; i++)
922 {
923 mFaceProxies[i] = NULL;
924 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000925}
926
927TextureCubeMap::~TextureCubeMap()
928{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000929 for (int i = 0; i < 6; i++)
930 {
931 delete mFaceProxies[i];
932 }
933
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000934 if (mTexture)
935 {
936 mTexture->Release();
937 mTexture = NULL;
938 }
939}
940
941GLenum TextureCubeMap::getTarget() const
942{
943 return GL_TEXTURE_CUBE_MAP;
944}
945
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000946void 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 +0000947{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000948 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000949}
950
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000951void 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 +0000952{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000953 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000954}
955
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000956void 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 +0000957{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000958 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000959}
960
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000961void 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 +0000962{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000963 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000964}
965
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000966void 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 +0000967{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000968 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000969}
970
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000971void 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 +0000972{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000973 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000974}
975
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000976void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
977{
978 int face = faceIndex(faceTarget);
979
980 ASSERT(mImageArray[face][level].surface != NULL);
981
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000982 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000983 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000984 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
985 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000986
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000987 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000988 {
989 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000990
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000991 RECT sourceRect;
992 sourceRect.left = xoffset;
993 sourceRect.top = yoffset;
994 sourceRect.right = xoffset + width;
995 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000996
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000997 POINT destPoint;
998 destPoint.x = xoffset;
999 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001000
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001001 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001002 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001003
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001004 destLevel->Release();
1005
1006 img->dirty = false;
1007 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001008 }
1009}
1010
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001011void 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 +00001012{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001013 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1014 {
1015 commitRect(face, level, xoffset, yoffset, width, height);
1016 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001017}
1018
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001019// 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 +00001020bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001021{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001022 int size = mImageArray[0][0].width;
1023
1024 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001025 {
1026 return false;
1027 }
1028
1029 bool mipmapping;
1030
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001031 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001032 {
1033 case GL_NEAREST:
1034 case GL_LINEAR:
1035 mipmapping = false;
1036 break;
1037 case GL_NEAREST_MIPMAP_NEAREST:
1038 case GL_LINEAR_MIPMAP_NEAREST:
1039 case GL_NEAREST_MIPMAP_LINEAR:
1040 case GL_LINEAR_MIPMAP_LINEAR:
1041 mipmapping = true;
1042 break;
1043 default: UNREACHABLE();
1044 }
1045
1046 for (int face = 0; face < 6; face++)
1047 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001048 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001049 {
1050 return false;
1051 }
1052 }
1053
1054 if (mipmapping)
1055 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001056 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1057 {
1058 return false;
1059 }
1060
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001061 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001062
1063 for (int face = 0; face < 6; face++)
1064 {
1065 for (int level = 1; level <= q; level++)
1066 {
1067 if (mImageArray[face][level].format != mImageArray[0][0].format)
1068 {
1069 return false;
1070 }
1071
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001072 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001073 {
1074 return false;
1075 }
1076
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001077 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001078 }
1079 }
1080 }
1081
1082 return true;
1083}
1084
1085// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001086IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001087{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001088 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001089 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001090
1091 IDirect3DCubeTexture9 *texture;
1092
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001093 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001094
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001095 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001096 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001097 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001098 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001099 }
1100
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001101 if (mTexture) mTexture->Release();
1102
1103 mTexture = texture;
1104 return mTexture;
1105}
1106
1107void TextureCubeMap::updateTexture()
1108{
1109 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001110
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001111 for (int face = 0; face < 6; face++)
1112 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001113 int levels = levelCount();
1114 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001115 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001116 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001117
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001118 if (img->dirty)
1119 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001120 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1121 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001122
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001123 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001124 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001125 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001126 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001127
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001128 levelSurface->Release();
1129
1130 img->dirty = false;
1131 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001132 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001133 }
1134 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001135}
1136
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001137IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1138{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001139 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001140
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001141 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001142 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001143 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001144 IDirect3DDevice9 *device = getDevice();
1145 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
1146
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001147 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001148
1149 if (FAILED(result))
1150 {
1151 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1152 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1153 }
1154
1155 if (mTexture != NULL)
1156 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001157 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001158 for (int f = 0; f < 6; f++)
1159 {
1160 for (int i = 0; i < levels; i++)
1161 {
1162 IDirect3DSurface9 *source;
1163 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1164
1165 if (FAILED(result))
1166 {
1167 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1168
1169 texture->Release();
1170
1171 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1172 }
1173
1174 IDirect3DSurface9 *dest;
1175 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1176
1177 if (FAILED(result))
1178 {
1179 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1180
1181 texture->Release();
1182 source->Release();
1183
1184 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1185 }
1186
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001187 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001188 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1189
1190 if (FAILED(result))
1191 {
1192 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1193
1194 texture->Release();
1195 source->Release();
1196 dest->Release();
1197
1198 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1199 }
1200 }
1201 }
1202 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001203 }
1204
1205 if (mTexture != NULL)
1206 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001207 mTexture->Release();
1208 }
1209
1210 mTexture = texture;
1211 return mTexture;
1212}
1213
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001214void 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 +00001215{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001216 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001217
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001218 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001219}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001220
1221unsigned int TextureCubeMap::faceIndex(GLenum face)
1222{
1223 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1224 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1225 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1226 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1227 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1228
1229 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1230}
1231
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001232bool TextureCubeMap::dirtyImageData() const
1233{
1234 int q = log2(mWidth);
1235
1236 for (int f = 0; f < 6; f++)
1237 {
1238 for (int i = 0; i <= q; i++)
1239 {
1240 if (mImageArray[f][i].dirty) return true;
1241 }
1242 }
1243
1244 return false;
1245}
1246
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001247// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1248// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1249// Call this when a particular level of the texture must be defined with a specific format, width and height.
1250//
1251// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1252// a new size for the texture by working backwards from the given size.
1253bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1254{
1255 // Are these settings compatible with level 0?
1256 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1257
1258 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1259
1260 if (!textureOkay)
1261 {
1262 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1263 mImageArray[0][0].format, mImageArray[0][0].width,
1264 internalFormat, width);
1265
1266 // Purge all the levels and the texture.
1267 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1268 {
1269 for (int f = 0; f < 6; f++)
1270 {
1271 if (mImageArray[f][i].surface != NULL)
1272 {
1273 mImageArray[f][i].dirty = false;
1274
1275 mImageArray[f][i].surface->Release();
1276 mImageArray[f][i].surface = NULL;
1277 }
1278 }
1279 }
1280
1281 if (mTexture != NULL)
1282 {
1283 mTexture->Release();
1284 mTexture = NULL;
1285 dropTexture();
1286 }
1287
1288 mWidth = width << level;
1289 mImageArray[0][0].width = width << level;
1290 mHeight = width << level;
1291 mImageArray[0][0].height = width << level;
1292
1293 mImageArray[0][0].format = internalFormat;
1294 }
1295
1296 return !textureOkay;
1297}
1298
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001299void 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 +00001300{
1301 unsigned int faceindex = faceIndex(face);
1302
1303 if (redefineTexture(level, internalFormat, width))
1304 {
1305 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001306 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001307 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001308 else
1309 {
1310 needRenderTarget();
1311 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001312
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001313 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001314
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001315 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001316 {
1317 RECT sourceRect;
1318 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001319 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001320 sourceRect.top = y;
1321 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001322
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001323 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1324
1325 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1326 dest->Release();
1327 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001328
1329 mImageArray[faceindex][level].width = width;
1330 mImageArray[faceindex][level].height = height;
1331 mImageArray[faceindex][level].format = internalFormat;
1332}
1333
1334IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1335{
1336 unsigned int faceIndex;
1337
1338 if (faceIdentifier < 6)
1339 {
1340 faceIndex = faceIdentifier;
1341 }
1342 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1343 {
1344 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1345 }
1346 else
1347 {
1348 UNREACHABLE();
1349 faceIndex = 0;
1350 }
1351
1352 if (mTexture == NULL)
1353 {
1354 UNREACHABLE();
1355 return NULL;
1356 }
1357
1358 IDirect3DSurface9 *surface = NULL;
1359
1360 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1361
1362 return (SUCCEEDED(hr)) ? surface : NULL;
1363}
1364
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001365void 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 +00001366{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001367 GLsizei size = mImageArray[faceIndex(face)][level].width;
1368
1369 if (xoffset + width > size || yoffset + height > size)
1370 {
1371 return error(GL_INVALID_VALUE);
1372 }
1373
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001374 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1375 {
1376 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001377 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001378 }
1379 else
1380 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001381 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001382 }
1383
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001384 if (level < levelCount())
1385 {
1386 RECT sourceRect;
1387 sourceRect.left = x;
1388 sourceRect.right = x + width;
1389 sourceRect.top = y;
1390 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001391
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001392 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001393
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001394 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1395 dest->Release();
1396 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001397}
1398
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001399bool TextureCubeMap::isCubeComplete() const
1400{
1401 if (mImageArray[0][0].width == 0)
1402 {
1403 return false;
1404 }
1405
1406 for (unsigned int f = 1; f < 6; f++)
1407 {
1408 if (mImageArray[f][0].width != mImageArray[0][0].width
1409 || mImageArray[f][0].format != mImageArray[0][0].format)
1410 {
1411 return false;
1412 }
1413 }
1414
1415 return true;
1416}
1417
1418void TextureCubeMap::generateMipmaps()
1419{
1420 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1421 {
1422 return error(GL_INVALID_OPERATION);
1423 }
1424
1425 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1426 unsigned int q = log2(mImageArray[0][0].width);
1427 for (unsigned int f = 0; f < 6; f++)
1428 {
1429 for (unsigned int i = 1; i <= q; i++)
1430 {
1431 if (mImageArray[f][i].surface != NULL)
1432 {
1433 mImageArray[f][i].surface->Release();
1434 mImageArray[f][i].surface = NULL;
1435 }
1436
1437 mImageArray[f][i].dirty = false;
1438
1439 mImageArray[f][i].format = mImageArray[f][0].format;
1440 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1441 mImageArray[f][i].height = mImageArray[f][i].width;
1442 }
1443 }
1444
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001445 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001446
1447 for (unsigned int f = 0; f < 6; f++)
1448 {
1449 for (unsigned int i = 1; i <= q; i++)
1450 {
1451 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1452 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1453
1454 if (upper != NULL && lower != NULL)
1455 {
1456 getBlitter()->boxFilter(upper, lower);
1457 }
1458
1459 if (upper != NULL) upper->Release();
1460 if (lower != NULL) lower->Release();
1461 }
1462 }
1463}
1464
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001465Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001466{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001467 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001468 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001469 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001470 }
1471
1472 unsigned int face = faceIndex(target);
1473
1474 if (mFaceProxies[face] == NULL)
1475 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001476 mFaceProxies[face] = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1477 mFaceProxies[face]->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001478 }
1479
1480 return mFaceProxies[face];
1481}
1482
1483IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1484{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001485 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001486
1487 needRenderTarget();
1488
1489 IDirect3DSurface9 *renderTarget = NULL;
1490 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
1491
1492 return renderTarget;
1493}
1494
1495Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
1496 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
1497{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001498 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001499}
1500
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001501void Texture::TextureColorbufferProxy::addRef() const
1502{
1503 mTexture->addRef();
1504}
1505
1506void Texture::TextureColorbufferProxy::release() const
1507{
1508 mTexture->release();
1509}
1510
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001511IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
1512{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001513 if (mRenderTarget) mRenderTarget->Release();
1514
1515 mRenderTarget = mTexture->getRenderTarget(mTarget);
1516
1517 return mRenderTarget;
1518}
1519
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001520int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001521{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001522 return mTexture->getWidth();
1523}
1524
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001525int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001526{
1527 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001528}
1529
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001530}