blob: b9abb96b09a6cd3dc14f0d5e3e309d8b4a1ceb4e [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
daniel@transgaming.coma9198d92010-08-08 04:49:56 +0000201 // fast path for EXT_texture_format_BGRA8888
202 if (format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE) {
203 memcpy(dest, source, width*4);
204 continue;
205 }
206
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000207 for (int x = 0; x < width; x++)
208 {
209 unsigned char r;
210 unsigned char g;
211 unsigned char b;
212 unsigned char a;
213
214 switch (format)
215 {
216 case GL_ALPHA:
217 a = source[x];
218 r = 0;
219 g = 0;
220 b = 0;
221 break;
222
223 case GL_LUMINANCE:
224 r = source[x];
225 g = source[x];
226 b = source[x];
227 a = 0xFF;
228 break;
229
230 case GL_LUMINANCE_ALPHA:
231 r = source[2*x+0];
232 g = source[2*x+0];
233 b = source[2*x+0];
234 a = source[2*x+1];
235 break;
236
237 case GL_RGB:
238 switch (type)
239 {
240 case GL_UNSIGNED_BYTE:
241 r = source[x * 3 + 0];
daniel@transgaming.com5ac52152010-04-13 19:53:38 +0000242 g = source[x * 3 + 1];
243 b = source[x * 3 + 2];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000244 a = 0xFF;
245 break;
246
247 case GL_UNSIGNED_SHORT_5_6_5:
248 {
249 unsigned short rgba = source16[x];
250
251 a = 0xFF;
252 b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
253 g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
254 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
255 }
256 break;
257
258 default: UNREACHABLE();
259 }
260 break;
261
262 case GL_RGBA:
263 switch (type)
264 {
265 case GL_UNSIGNED_BYTE:
266 r = source[x * 4 + 0];
267 g = source[x * 4 + 1];
268 b = source[x * 4 + 2];
269 a = source[x * 4 + 3];
270 break;
271
272 case GL_UNSIGNED_SHORT_4_4_4_4:
273 {
274 unsigned short rgba = source16[x];
275
276 a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
277 b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
278 g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
279 r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
280 }
281 break;
282
283 case GL_UNSIGNED_SHORT_5_5_5_1:
284 {
285 unsigned short rgba = source16[x];
286
287 a = (rgba & 0x0001) ? 0xFF : 0;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000288 b = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000289 g = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000290 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000291 }
292 break;
293
294 default: UNREACHABLE();
295 }
296 break;
297 default: UNREACHABLE();
298 }
299
300 dest[4 * x + 0] = b;
301 dest[4 * x + 1] = g;
302 dest[4 * x + 2] = r;
303 dest[4 * x + 3] = a;
304 }
305 }
306}
307
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000308void 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 +0000309{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000310 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000311
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000312 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000313 {
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000314 HRESULT result = getDevice()->CreateOffscreenPlainSurface(width, height, selectFormat(format), D3DPOOL_SYSTEMMEM, &newSurface, NULL);
315
316 if (FAILED(result))
317 {
318 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
319 return error(GL_OUT_OF_MEMORY);
320 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000321 }
322
323 if (img->surface) img->surface->Release();
324 img->surface = newSurface;
325
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000326 img->width = width;
327 img->height = height;
328 img->format = format;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000329
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000330 if (pixels != NULL && newSurface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000332 D3DLOCKED_RECT locked;
333 HRESULT result = newSurface->LockRect(&locked, NULL, 0);
334
335 ASSERT(SUCCEEDED(result));
336
337 if (SUCCEEDED(result))
338 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000339 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000340 newSurface->UnlockRect();
341 }
342
343 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344 }
345
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000346 mDirtyMetaData = true;
347}
348
daniel@transgaming.com31273552010-08-04 13:42:44 +0000349bool 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 +0000350{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000351 if (width + xoffset > img->width || height + yoffset > img->height)
352 {
353 error(GL_INVALID_VALUE);
354 return false;
355 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000356
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000357 D3DLOCKED_RECT locked;
358 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000359
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000360 ASSERT(SUCCEEDED(result));
361
362 if (SUCCEEDED(result))
363 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000364 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000365 img->surface->UnlockRect();
366 }
367
368 img->dirty = true;
daniel@transgaming.com31273552010-08-04 13:42:44 +0000369 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000370}
371
372IDirect3DBaseTexture9 *Texture::getTexture()
373{
374 if (!isComplete())
375 {
376 return NULL;
377 }
378
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000379 if (mDirtyMetaData)
380 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000381 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000382 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000383 }
384
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000385 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000386 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000387 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000388 }
389
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000390 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000391 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000392
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000393 return mBaseTexture;
394}
395
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000396bool Texture::isDirty() const
397{
398 return (mDirty || mDirtyMetaData || dirtyImageData());
399}
400
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000401// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000402void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000403{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000404 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000405 {
406 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000407 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000408 }
409
410 if (dirtyImageData())
411 {
412 updateTexture();
413 }
414
415 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000416}
417
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000418void Texture::dropTexture()
419{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000420 if (mBaseTexture)
421 {
422 mBaseTexture = NULL;
423 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000424
425 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000426}
427
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000428void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000429{
430 mBaseTexture = newTexture;
431 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000432 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000433 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000434}
435
436
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000437GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
438{
439 if (isPow2(width) && isPow2(height))
440 {
441 return maxlevel;
442 }
443 else
444 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000445 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
446 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000447 }
448}
449
450GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
451{
452 return creationLevels(size, size, maxlevel);
453}
454
455int Texture::levelCount() const
456{
457 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
458}
459
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000460Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000461{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000462 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000463 mColorbufferProxy = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000464}
465
466Texture2D::~Texture2D()
467{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000468 delete mColorbufferProxy;
469
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470 if (mTexture)
471 {
472 mTexture->Release();
473 mTexture = NULL;
474 }
475}
476
477GLenum Texture2D::getTarget() const
478{
479 return GL_TEXTURE_2D;
480}
481
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000482// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
483// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
484// Call this when a particular level of the texture must be defined with a specific format, width and height.
485//
486// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
487// a new height and width for the texture by working backwards from the given width and height.
488bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height)
489{
490 bool widthOkay = (mWidth >> level == width);
491 bool heightOkay = (mHeight >> level == height);
492
493 bool sizeOkay = ((widthOkay && heightOkay)
494 || (widthOkay && mHeight >> level == 0 && height == 1)
495 || (heightOkay && mWidth >> level == 0 && width == 1));
496
497 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
498
499 if (!textureOkay)
500 {
501 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
502 mImageArray[0].format, mWidth, mHeight,
503 internalFormat, width, height);
504
505 // Purge all the levels and the texture.
506
507 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
508 {
509 if (mImageArray[i].surface != NULL)
510 {
511 mImageArray[i].dirty = false;
512
513 mImageArray[i].surface->Release();
514 mImageArray[i].surface = NULL;
515 }
516 }
517
518 if (mTexture != NULL)
519 {
520 mTexture->Release();
521 mTexture = NULL;
522 dropTexture();
523 }
524
525 mWidth = width << level;
526 mHeight = height << level;
527 mImageArray[0].format = internalFormat;
528 }
529
530 return !textureOkay;
531}
532
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000533void 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 +0000534{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000535 redefineTexture(level, internalFormat, width, height);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000536
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000537 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000538}
539
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000540void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
541{
542 ASSERT(mImageArray[level].surface != NULL);
543
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000544 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000545 {
546 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000547 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000548
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000549 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000550
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000551 if (SUCCEEDED(result))
552 {
553 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000554
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000555 RECT sourceRect;
556 sourceRect.left = xoffset;
557 sourceRect.top = yoffset;
558 sourceRect.right = xoffset + width;
559 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000560
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000561 POINT destPoint;
562 destPoint.x = xoffset;
563 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000564
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000565 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
566 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000567
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000568 destLevel->Release();
569
570 img->dirty = false;
571 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000572 }
573}
574
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000575void 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 +0000576{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000577 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
578 {
579 commitRect(level, xoffset, yoffset, width, height);
580 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000581}
582
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000583void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000584{
585 if (redefineTexture(level, internalFormat, width, height))
586 {
587 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000588 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000589 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +0000590 else
591 {
592 needRenderTarget();
593 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000594
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000595 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000596 {
597 RECT sourceRect;
598 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000599 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +0000600 sourceRect.top = y;
601 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000602
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000603 IDirect3DSurface9 *dest;
604 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000605
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000606 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
607 dest->Release();
608 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000609
610 mImageArray[level].width = width;
611 mImageArray[level].height = height;
612 mImageArray[level].format = internalFormat;
613}
614
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000615void 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 +0000616{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000617 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
618 {
619 return error(GL_INVALID_VALUE);
620 }
621
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000622 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
623 {
624 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000625 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000626 }
627 else
628 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +0000629 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000630 }
631
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000632 if (level < levelCount())
633 {
634 RECT sourceRect;
635 sourceRect.left = x;
636 sourceRect.right = x + width;
637 sourceRect.top = y;
638 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000639
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000640 IDirect3DSurface9 *dest;
641 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000642
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000643 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
644 dest->Release();
645 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000646}
647
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000648// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
649bool Texture2D::isComplete() const
650{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000651 GLsizei width = mImageArray[0].width;
652 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000653
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000654 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000655 {
656 return false;
657 }
658
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000659 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000660
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000661 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000662 {
663 case GL_NEAREST:
664 case GL_LINEAR:
665 mipmapping = false;
666 break;
667 case GL_NEAREST_MIPMAP_NEAREST:
668 case GL_LINEAR_MIPMAP_NEAREST:
669 case GL_NEAREST_MIPMAP_LINEAR:
670 case GL_LINEAR_MIPMAP_LINEAR:
671 mipmapping = true;
672 break;
673 default: UNREACHABLE();
674 }
675
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000676 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
677 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
678 {
679 return false;
680 }
681
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000682 if (mipmapping)
683 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000684 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000685 {
686 return false;
687 }
688
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000689 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000690
691 for (int level = 1; level <= q; level++)
692 {
693 if (mImageArray[level].format != mImageArray[0].format)
694 {
695 return false;
696 }
697
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000698 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000699 {
700 return false;
701 }
702
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000703 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000704 {
705 return false;
706 }
707 }
708 }
709
710 return true;
711}
712
713// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000714IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000715{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000716 IDirect3DTexture9 *texture;
717
718 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000719 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000720
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000721 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000722
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000723 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000724 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000725 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000726 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000727 }
728
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000729 if (mTexture) mTexture->Release();
730 mTexture = texture;
731 return texture;
732}
733
734void Texture2D::updateTexture()
735{
736 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000737
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000738 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000739
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000740 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000741 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000742 if (mImageArray[level].dirty)
743 {
744 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000745 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000746
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000747 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000748
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000749 if (SUCCEEDED(result))
750 {
751 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
752 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000753
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000754 levelSurface->Release();
755
756 mImageArray[level].dirty = false;
757 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000758 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000759 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000760}
761
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000762IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000763{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000764 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000765
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000766 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000767 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000768 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000769 IDirect3DDevice9 *device = getDevice();
770 D3DFORMAT format = selectFormat(mImageArray[0].format);
771
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000772 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 +0000773
774 if (FAILED(result))
775 {
776 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
777 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
778 }
779
780 if (mTexture != NULL)
781 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000782 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000783 for (int i = 0; i < levels; i++)
784 {
785 IDirect3DSurface9 *source;
786 result = mTexture->GetSurfaceLevel(i, &source);
787
788 if (FAILED(result))
789 {
790 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
791
792 texture->Release();
793
794 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
795 }
796
797 IDirect3DSurface9 *dest;
798 result = texture->GetSurfaceLevel(i, &dest);
799
800 if (FAILED(result))
801 {
802 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
803
804 texture->Release();
805 source->Release();
806
807 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
808 }
809
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000810 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000811 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
812
813 if (FAILED(result))
814 {
815 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
816
817 texture->Release();
818 source->Release();
819 dest->Release();
820
821 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
822 }
823
824 source->Release();
825 dest->Release();
826 }
827 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000828 }
829
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000830 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000831 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000832 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000833 }
834
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000835 mTexture = texture;
836 return mTexture;
837}
838
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000839bool Texture2D::dirtyImageData() const
840{
841 int q = log2(std::max(mWidth, mHeight));
842
843 for (int i = 0; i <= q; i++)
844 {
845 if (mImageArray[i].dirty) return true;
846 }
847
848 return false;
849}
850
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000851void Texture2D::generateMipmaps()
852{
853 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
854 {
855 return error(GL_INVALID_OPERATION);
856 }
857
858 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
859 unsigned int q = log2(std::max(mWidth, mHeight));
860 for (unsigned int i = 1; i <= q; i++)
861 {
862 if (mImageArray[i].surface != NULL)
863 {
864 mImageArray[i].surface->Release();
865 mImageArray[i].surface = NULL;
866 }
867
868 mImageArray[i].dirty = false;
869
870 mImageArray[i].format = mImageArray[0].format;
871 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
872 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
873 }
874
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000875 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000876
877 for (unsigned int i = 1; i <= q; i++)
878 {
879 IDirect3DSurface9 *upper = NULL;
880 IDirect3DSurface9 *lower = NULL;
881
882 mTexture->GetSurfaceLevel(i-1, &upper);
883 mTexture->GetSurfaceLevel(i, &lower);
884
885 if (upper != NULL && lower != NULL)
886 {
887 getBlitter()->boxFilter(upper, lower);
888 }
889
890 if (upper != NULL) upper->Release();
891 if (lower != NULL) lower->Release();
892 }
893}
894
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000895Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000896{
897 if (target != GL_TEXTURE_2D)
898 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000899 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000900 }
901
902 if (mColorbufferProxy == NULL)
903 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000904 mColorbufferProxy = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
905 mColorbufferProxy->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000906 }
907
908 return mColorbufferProxy;
909}
910
911IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
912{
913 ASSERT(target == GL_TEXTURE_2D);
914
915 needRenderTarget();
916
917 IDirect3DSurface9 *renderTarget = NULL;
918 mTexture->GetSurfaceLevel(0, &renderTarget);
919
920 return renderTarget;
921}
922
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000923TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000924{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000925 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000926
927 for (int i = 0; i < 6; i++)
928 {
929 mFaceProxies[i] = NULL;
930 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000931}
932
933TextureCubeMap::~TextureCubeMap()
934{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000935 for (int i = 0; i < 6; i++)
936 {
937 delete mFaceProxies[i];
938 }
939
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000940 if (mTexture)
941 {
942 mTexture->Release();
943 mTexture = NULL;
944 }
945}
946
947GLenum TextureCubeMap::getTarget() const
948{
949 return GL_TEXTURE_CUBE_MAP;
950}
951
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000952void 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 +0000953{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000954 setImage(0, 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::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 +0000958{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000959 setImage(1, 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::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 +0000963{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000964 setImage(2, 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::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 +0000968{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000969 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000970}
971
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000972void 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 +0000973{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000974 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000975}
976
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000977void 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 +0000978{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000979 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000980}
981
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000982void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
983{
984 int face = faceIndex(faceTarget);
985
986 ASSERT(mImageArray[face][level].surface != NULL);
987
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000988 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000989 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000990 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
991 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000992
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000993 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000994 {
995 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000996
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000997 RECT sourceRect;
998 sourceRect.left = xoffset;
999 sourceRect.top = yoffset;
1000 sourceRect.right = xoffset + width;
1001 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001002
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001003 POINT destPoint;
1004 destPoint.x = xoffset;
1005 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001006
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001007 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001008 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001009
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001010 destLevel->Release();
1011
1012 img->dirty = false;
1013 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001014 }
1015}
1016
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001017void 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 +00001018{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001019 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1020 {
1021 commitRect(face, level, xoffset, yoffset, width, height);
1022 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001023}
1024
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001025// 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 +00001026bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001027{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001028 int size = mImageArray[0][0].width;
1029
1030 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001031 {
1032 return false;
1033 }
1034
1035 bool mipmapping;
1036
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001037 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001038 {
1039 case GL_NEAREST:
1040 case GL_LINEAR:
1041 mipmapping = false;
1042 break;
1043 case GL_NEAREST_MIPMAP_NEAREST:
1044 case GL_LINEAR_MIPMAP_NEAREST:
1045 case GL_NEAREST_MIPMAP_LINEAR:
1046 case GL_LINEAR_MIPMAP_LINEAR:
1047 mipmapping = true;
1048 break;
1049 default: UNREACHABLE();
1050 }
1051
1052 for (int face = 0; face < 6; face++)
1053 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001054 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001055 {
1056 return false;
1057 }
1058 }
1059
1060 if (mipmapping)
1061 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001062 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1063 {
1064 return false;
1065 }
1066
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001067 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001068
1069 for (int face = 0; face < 6; face++)
1070 {
1071 for (int level = 1; level <= q; level++)
1072 {
1073 if (mImageArray[face][level].format != mImageArray[0][0].format)
1074 {
1075 return false;
1076 }
1077
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001078 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001079 {
1080 return false;
1081 }
1082
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001083 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001084 }
1085 }
1086 }
1087
1088 return true;
1089}
1090
1091// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001092IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001093{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001094 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001095 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001096
1097 IDirect3DCubeTexture9 *texture;
1098
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001099 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001100
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001101 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001102 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001103 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001104 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001105 }
1106
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001107 if (mTexture) mTexture->Release();
1108
1109 mTexture = texture;
1110 return mTexture;
1111}
1112
1113void TextureCubeMap::updateTexture()
1114{
1115 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001116
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001117 for (int face = 0; face < 6; face++)
1118 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001119 int levels = levelCount();
1120 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001121 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001122 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001123
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001124 if (img->dirty)
1125 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001126 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1127 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001128
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001129 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001130 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001131 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001132 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001133
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001134 levelSurface->Release();
1135
1136 img->dirty = false;
1137 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001138 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001139 }
1140 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001141}
1142
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001143IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1144{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001145 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001146
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001147 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001148 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001149 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001150 IDirect3DDevice9 *device = getDevice();
1151 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
1152
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001153 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001154
1155 if (FAILED(result))
1156 {
1157 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1158 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1159 }
1160
1161 if (mTexture != NULL)
1162 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001163 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001164 for (int f = 0; f < 6; f++)
1165 {
1166 for (int i = 0; i < levels; i++)
1167 {
1168 IDirect3DSurface9 *source;
1169 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1170
1171 if (FAILED(result))
1172 {
1173 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1174
1175 texture->Release();
1176
1177 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1178 }
1179
1180 IDirect3DSurface9 *dest;
1181 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1182
1183 if (FAILED(result))
1184 {
1185 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1186
1187 texture->Release();
1188 source->Release();
1189
1190 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1191 }
1192
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001193 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001194 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1195
1196 if (FAILED(result))
1197 {
1198 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1199
1200 texture->Release();
1201 source->Release();
1202 dest->Release();
1203
1204 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1205 }
1206 }
1207 }
1208 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001209 }
1210
1211 if (mTexture != NULL)
1212 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001213 mTexture->Release();
1214 }
1215
1216 mTexture = texture;
1217 return mTexture;
1218}
1219
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001220void 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 +00001221{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001222 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001223
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001224 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001225}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001226
1227unsigned int TextureCubeMap::faceIndex(GLenum face)
1228{
1229 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1230 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1231 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1232 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1233 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1234
1235 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1236}
1237
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001238bool TextureCubeMap::dirtyImageData() const
1239{
1240 int q = log2(mWidth);
1241
1242 for (int f = 0; f < 6; f++)
1243 {
1244 for (int i = 0; i <= q; i++)
1245 {
1246 if (mImageArray[f][i].dirty) return true;
1247 }
1248 }
1249
1250 return false;
1251}
1252
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001253// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1254// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1255// Call this when a particular level of the texture must be defined with a specific format, width and height.
1256//
1257// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1258// a new size for the texture by working backwards from the given size.
1259bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1260{
1261 // Are these settings compatible with level 0?
1262 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1263
1264 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1265
1266 if (!textureOkay)
1267 {
1268 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1269 mImageArray[0][0].format, mImageArray[0][0].width,
1270 internalFormat, width);
1271
1272 // Purge all the levels and the texture.
1273 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1274 {
1275 for (int f = 0; f < 6; f++)
1276 {
1277 if (mImageArray[f][i].surface != NULL)
1278 {
1279 mImageArray[f][i].dirty = false;
1280
1281 mImageArray[f][i].surface->Release();
1282 mImageArray[f][i].surface = NULL;
1283 }
1284 }
1285 }
1286
1287 if (mTexture != NULL)
1288 {
1289 mTexture->Release();
1290 mTexture = NULL;
1291 dropTexture();
1292 }
1293
1294 mWidth = width << level;
1295 mImageArray[0][0].width = width << level;
1296 mHeight = width << level;
1297 mImageArray[0][0].height = width << level;
1298
1299 mImageArray[0][0].format = internalFormat;
1300 }
1301
1302 return !textureOkay;
1303}
1304
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001305void 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 +00001306{
1307 unsigned int faceindex = faceIndex(face);
1308
1309 if (redefineTexture(level, internalFormat, width))
1310 {
1311 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001312 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001313 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001314 else
1315 {
1316 needRenderTarget();
1317 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001318
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001319 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001320
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001321 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001322 {
1323 RECT sourceRect;
1324 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001325 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001326 sourceRect.top = y;
1327 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001328
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001329 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1330
1331 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1332 dest->Release();
1333 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001334
1335 mImageArray[faceindex][level].width = width;
1336 mImageArray[faceindex][level].height = height;
1337 mImageArray[faceindex][level].format = internalFormat;
1338}
1339
1340IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1341{
1342 unsigned int faceIndex;
1343
1344 if (faceIdentifier < 6)
1345 {
1346 faceIndex = faceIdentifier;
1347 }
1348 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1349 {
1350 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1351 }
1352 else
1353 {
1354 UNREACHABLE();
1355 faceIndex = 0;
1356 }
1357
1358 if (mTexture == NULL)
1359 {
1360 UNREACHABLE();
1361 return NULL;
1362 }
1363
1364 IDirect3DSurface9 *surface = NULL;
1365
1366 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1367
1368 return (SUCCEEDED(hr)) ? surface : NULL;
1369}
1370
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001371void 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 +00001372{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001373 GLsizei size = mImageArray[faceIndex(face)][level].width;
1374
1375 if (xoffset + width > size || yoffset + height > size)
1376 {
1377 return error(GL_INVALID_VALUE);
1378 }
1379
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001380 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1381 {
1382 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001383 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001384 }
1385 else
1386 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001387 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001388 }
1389
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001390 if (level < levelCount())
1391 {
1392 RECT sourceRect;
1393 sourceRect.left = x;
1394 sourceRect.right = x + width;
1395 sourceRect.top = y;
1396 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001397
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001398 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001399
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001400 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1401 dest->Release();
1402 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001403}
1404
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001405bool TextureCubeMap::isCubeComplete() const
1406{
1407 if (mImageArray[0][0].width == 0)
1408 {
1409 return false;
1410 }
1411
1412 for (unsigned int f = 1; f < 6; f++)
1413 {
1414 if (mImageArray[f][0].width != mImageArray[0][0].width
1415 || mImageArray[f][0].format != mImageArray[0][0].format)
1416 {
1417 return false;
1418 }
1419 }
1420
1421 return true;
1422}
1423
1424void TextureCubeMap::generateMipmaps()
1425{
1426 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1427 {
1428 return error(GL_INVALID_OPERATION);
1429 }
1430
1431 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1432 unsigned int q = log2(mImageArray[0][0].width);
1433 for (unsigned int f = 0; f < 6; f++)
1434 {
1435 for (unsigned int i = 1; i <= q; i++)
1436 {
1437 if (mImageArray[f][i].surface != NULL)
1438 {
1439 mImageArray[f][i].surface->Release();
1440 mImageArray[f][i].surface = NULL;
1441 }
1442
1443 mImageArray[f][i].dirty = false;
1444
1445 mImageArray[f][i].format = mImageArray[f][0].format;
1446 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1447 mImageArray[f][i].height = mImageArray[f][i].width;
1448 }
1449 }
1450
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001451 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001452
1453 for (unsigned int f = 0; f < 6; f++)
1454 {
1455 for (unsigned int i = 1; i <= q; i++)
1456 {
1457 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1458 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1459
1460 if (upper != NULL && lower != NULL)
1461 {
1462 getBlitter()->boxFilter(upper, lower);
1463 }
1464
1465 if (upper != NULL) upper->Release();
1466 if (lower != NULL) lower->Release();
1467 }
1468 }
1469}
1470
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001471Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001472{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001473 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001474 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001475 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001476 }
1477
1478 unsigned int face = faceIndex(target);
1479
1480 if (mFaceProxies[face] == NULL)
1481 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001482 mFaceProxies[face] = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1483 mFaceProxies[face]->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001484 }
1485
1486 return mFaceProxies[face];
1487}
1488
1489IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1490{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001491 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001492
1493 needRenderTarget();
1494
1495 IDirect3DSurface9 *renderTarget = NULL;
1496 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
1497
1498 return renderTarget;
1499}
1500
1501Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
1502 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
1503{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001504 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001505}
1506
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001507void Texture::TextureColorbufferProxy::addRef() const
1508{
1509 mTexture->addRef();
1510}
1511
1512void Texture::TextureColorbufferProxy::release() const
1513{
1514 mTexture->release();
1515}
1516
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001517IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
1518{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001519 if (mRenderTarget) mRenderTarget->Release();
1520
1521 mRenderTarget = mTexture->getRenderTarget(mTarget);
1522
1523 return mRenderTarget;
1524}
1525
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001526int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001527{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001528 return mTexture->getWidth();
1529}
1530
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001531int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001532{
1533 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001534}
1535
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001536}