blob: 4079d43d9ec95de85c9bf6f01a106a64a3ef8b81 [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.com93a81472010-04-20 18:52:58 +000035Texture::Texture(Context *context) : mContext(context)
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.com00c75962010-03-11 20:36:15 +000042 mDirtyMetaData = true;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000043 mDirty = true;
daniel@transgaming.com93a81472010-04-20 18:52:58 +000044 mIsRenderable = false;
daniel@transgaming.com0a311a42010-05-17 09:58:33 +000045 mBaseTexture = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000046}
47
48Texture::~Texture()
49{
50}
51
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000052Blit *Texture::getBlitter()
53{
54 return mContext->getBlitter();
55}
56
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000057// Returns true on successful filter state update (valid enum parameter)
58bool Texture::setMinFilter(GLenum filter)
59{
60 switch (filter)
61 {
62 case GL_NEAREST:
63 case GL_LINEAR:
64 case GL_NEAREST_MIPMAP_NEAREST:
65 case GL_LINEAR_MIPMAP_NEAREST:
66 case GL_NEAREST_MIPMAP_LINEAR:
67 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000068 {
69 if (mMinFilter != filter)
70 {
71 mMinFilter = filter;
72 mDirty = true;
73 }
74 return true;
75 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000076 default:
77 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000078 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000079}
80
81// Returns true on successful filter state update (valid enum parameter)
82bool Texture::setMagFilter(GLenum filter)
83{
84 switch (filter)
85 {
86 case GL_NEAREST:
87 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000088 {
89 if (mMagFilter != filter)
90 {
91 mMagFilter = filter;
92 mDirty = true;
93 }
94 return true;
95 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000096 default:
97 return false;
98 }
99}
100
101// Returns true on successful wrap state update (valid enum parameter)
102bool Texture::setWrapS(GLenum wrap)
103{
104 switch (wrap)
105 {
106 case GL_REPEAT:
107 case GL_CLAMP_TO_EDGE:
108 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000109 {
110 if (mWrapS != wrap)
111 {
112 mWrapS = wrap;
113 mDirty = true;
114 }
115 return true;
116 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000117 default:
118 return false;
119 }
120}
121
122// Returns true on successful wrap state update (valid enum parameter)
123bool Texture::setWrapT(GLenum wrap)
124{
125 switch (wrap)
126 {
127 case GL_REPEAT:
128 case GL_CLAMP_TO_EDGE:
129 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000130 {
131 if (mWrapT != wrap)
132 {
133 mWrapT = wrap;
134 mDirty = true;
135 }
136 return true;
137 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138 default:
139 return false;
140 }
141}
142
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000143GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144{
145 return mMinFilter;
146}
147
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000148GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149{
150 return mMagFilter;
151}
152
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000153GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154{
155 return mWrapS;
156}
157
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000158GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159{
160 return mWrapT;
161}
162
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000163GLuint Texture::getWidth() const
164{
165 return mWidth;
166}
167
168GLuint Texture::getHeight() const
169{
170 return mHeight;
171}
172
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000173// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000174D3DFORMAT Texture::selectFormat(GLenum format)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000176 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177}
178
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000179int Texture::imagePitch(const Image &img) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000181 return img.width * 4;
182}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000183
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000184// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
185// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
186void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000187 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000188{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000189 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000190
191 for (int y = 0; y < height; y++)
192 {
193 const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
194 const unsigned short *source16 = reinterpret_cast<const unsigned short*>(source);
195 unsigned char *dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
196
197 for (int x = 0; x < width; x++)
198 {
199 unsigned char r;
200 unsigned char g;
201 unsigned char b;
202 unsigned char a;
203
204 switch (format)
205 {
206 case GL_ALPHA:
207 a = source[x];
208 r = 0;
209 g = 0;
210 b = 0;
211 break;
212
213 case GL_LUMINANCE:
214 r = source[x];
215 g = source[x];
216 b = source[x];
217 a = 0xFF;
218 break;
219
220 case GL_LUMINANCE_ALPHA:
221 r = source[2*x+0];
222 g = source[2*x+0];
223 b = source[2*x+0];
224 a = source[2*x+1];
225 break;
226
227 case GL_RGB:
228 switch (type)
229 {
230 case GL_UNSIGNED_BYTE:
231 r = source[x * 3 + 0];
daniel@transgaming.com5ac52152010-04-13 19:53:38 +0000232 g = source[x * 3 + 1];
233 b = source[x * 3 + 2];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000234 a = 0xFF;
235 break;
236
237 case GL_UNSIGNED_SHORT_5_6_5:
238 {
239 unsigned short rgba = source16[x];
240
241 a = 0xFF;
242 b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
243 g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
244 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
245 }
246 break;
247
248 default: UNREACHABLE();
249 }
250 break;
251
252 case GL_RGBA:
253 switch (type)
254 {
255 case GL_UNSIGNED_BYTE:
256 r = source[x * 4 + 0];
257 g = source[x * 4 + 1];
258 b = source[x * 4 + 2];
259 a = source[x * 4 + 3];
260 break;
261
262 case GL_UNSIGNED_SHORT_4_4_4_4:
263 {
264 unsigned short rgba = source16[x];
265
266 a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
267 b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
268 g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
269 r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
270 }
271 break;
272
273 case GL_UNSIGNED_SHORT_5_5_5_1:
274 {
275 unsigned short rgba = source16[x];
276
277 a = (rgba & 0x0001) ? 0xFF : 0;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000278 b = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000279 g = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000280 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000281 }
282 break;
283
284 default: UNREACHABLE();
285 }
286 break;
287 default: UNREACHABLE();
288 }
289
290 dest[4 * x + 0] = b;
291 dest[4 * x + 1] = g;
292 dest[4 * x + 2] = r;
293 dest[4 * x + 3] = a;
294 }
295 }
296}
297
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000298void 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 +0000299{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000300 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000301
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000302 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000303 {
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000304 HRESULT result = getDevice()->CreateOffscreenPlainSurface(width, height, selectFormat(format), D3DPOOL_SYSTEMMEM, &newSurface, NULL);
305
306 if (FAILED(result))
307 {
308 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
309 return error(GL_OUT_OF_MEMORY);
310 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000311 }
312
313 if (img->surface) img->surface->Release();
314 img->surface = newSurface;
315
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000316 img->width = width;
317 img->height = height;
318 img->format = format;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000319
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000320 if (pixels != NULL && newSurface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000322 D3DLOCKED_RECT locked;
323 HRESULT result = newSurface->LockRect(&locked, NULL, 0);
324
325 ASSERT(SUCCEEDED(result));
326
327 if (SUCCEEDED(result))
328 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000329 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000330 newSurface->UnlockRect();
331 }
332
333 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000334 }
335
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000336 mDirtyMetaData = true;
337}
338
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000339void 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 +0000340{
341 if (width + xoffset > img->width || height + yoffset > img->height) return error(GL_INVALID_VALUE);
342
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000343 D3DLOCKED_RECT locked;
344 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000345
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000346 ASSERT(SUCCEEDED(result));
347
348 if (SUCCEEDED(result))
349 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000350 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000351 img->surface->UnlockRect();
352 }
353
354 img->dirty = true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000355}
356
357IDirect3DBaseTexture9 *Texture::getTexture()
358{
359 if (!isComplete())
360 {
361 return NULL;
362 }
363
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000364 if (mDirtyMetaData)
365 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000366 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000367 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000368 }
369
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000370 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000371 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000372 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000373 }
374
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000375 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000376 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000377
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000378 return mBaseTexture;
379}
380
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000381bool Texture::isDirty() const
382{
383 return (mDirty || mDirtyMetaData || dirtyImageData());
384}
385
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000386// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000387void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000388{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000389 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000390 {
391 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000392 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000393 }
394
395 if (dirtyImageData())
396 {
397 updateTexture();
398 }
399
400 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000401}
402
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000403void Texture::dropTexture()
404{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000405 if (mBaseTexture)
406 {
407 mBaseTexture = NULL;
408 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000409
410 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000411}
412
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000413void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000414{
415 mBaseTexture = newTexture;
416 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000417 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000418 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000419}
420
421
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000422GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
423{
424 if (isPow2(width) && isPow2(height))
425 {
426 return maxlevel;
427 }
428 else
429 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000430 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
431 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000432 }
433}
434
435GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
436{
437 return creationLevels(size, size, maxlevel);
438}
439
440int Texture::levelCount() const
441{
442 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
443}
444
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000445Texture2D::Texture2D(Context *context) : Texture(context)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000446{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000448 mColorbufferProxy = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449}
450
451Texture2D::~Texture2D()
452{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000453 delete mColorbufferProxy;
454
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000455 if (mTexture)
456 {
457 mTexture->Release();
458 mTexture = NULL;
459 }
460}
461
462GLenum Texture2D::getTarget() const
463{
464 return GL_TEXTURE_2D;
465}
466
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000467// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
468// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
469// Call this when a particular level of the texture must be defined with a specific format, width and height.
470//
471// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
472// a new height and width for the texture by working backwards from the given width and height.
473bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height)
474{
475 bool widthOkay = (mWidth >> level == width);
476 bool heightOkay = (mHeight >> level == height);
477
478 bool sizeOkay = ((widthOkay && heightOkay)
479 || (widthOkay && mHeight >> level == 0 && height == 1)
480 || (heightOkay && mWidth >> level == 0 && width == 1));
481
482 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
483
484 if (!textureOkay)
485 {
486 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
487 mImageArray[0].format, mWidth, mHeight,
488 internalFormat, width, height);
489
490 // Purge all the levels and the texture.
491
492 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
493 {
494 if (mImageArray[i].surface != NULL)
495 {
496 mImageArray[i].dirty = false;
497
498 mImageArray[i].surface->Release();
499 mImageArray[i].surface = NULL;
500 }
501 }
502
503 if (mTexture != NULL)
504 {
505 mTexture->Release();
506 mTexture = NULL;
507 dropTexture();
508 }
509
510 mWidth = width << level;
511 mHeight = height << level;
512 mImageArray[0].format = internalFormat;
513 }
514
515 return !textureOkay;
516}
517
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000518void 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 +0000519{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000520 redefineTexture(level, internalFormat, width, height);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000521
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000522 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000523}
524
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000525void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
526{
527 ASSERT(mImageArray[level].surface != NULL);
528
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000529 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000530 {
531 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000532 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000533
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000534 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000535
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000536 if (SUCCEEDED(result))
537 {
538 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000539
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000540 RECT sourceRect;
541 sourceRect.left = xoffset;
542 sourceRect.top = yoffset;
543 sourceRect.right = xoffset + width;
544 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000545
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000546 POINT destPoint;
547 destPoint.x = xoffset;
548 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000549
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000550 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
551 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000552
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000553 destLevel->Release();
554
555 img->dirty = false;
556 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000557 }
558}
559
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000560void 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 +0000561{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000562 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000563 commitRect(level, xoffset, yoffset, width, height);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000564}
565
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000566void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
567{
568 if (redefineTexture(level, internalFormat, width, height))
569 {
570 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000571 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000572 }
573
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000574 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000575 {
576 RECT sourceRect;
577 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000578 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +0000579 sourceRect.top = y;
580 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000581
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000582 IDirect3DSurface9 *dest;
583 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000584
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000585 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
586 dest->Release();
587 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000588
589 mImageArray[level].width = width;
590 mImageArray[level].height = height;
591 mImageArray[level].format = internalFormat;
592}
593
594void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
595{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000596 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
597 {
598 return error(GL_INVALID_VALUE);
599 }
600
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000601 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
602 {
603 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000604 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000605 }
606 else
607 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +0000608 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000609 }
610
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000611 if (level < levelCount())
612 {
613 RECT sourceRect;
614 sourceRect.left = x;
615 sourceRect.right = x + width;
616 sourceRect.top = y;
617 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000618
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000619 IDirect3DSurface9 *dest;
620 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000621
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000622 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
623 dest->Release();
624 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000625}
626
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000627// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
628bool Texture2D::isComplete() const
629{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000630 GLsizei width = mImageArray[0].width;
631 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000632
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000633 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634 {
635 return false;
636 }
637
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000638 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000639
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000640 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000641 {
642 case GL_NEAREST:
643 case GL_LINEAR:
644 mipmapping = false;
645 break;
646 case GL_NEAREST_MIPMAP_NEAREST:
647 case GL_LINEAR_MIPMAP_NEAREST:
648 case GL_NEAREST_MIPMAP_LINEAR:
649 case GL_LINEAR_MIPMAP_LINEAR:
650 mipmapping = true;
651 break;
652 default: UNREACHABLE();
653 }
654
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000655 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
656 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
657 {
658 return false;
659 }
660
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000661 if (mipmapping)
662 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000663 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000664 {
665 return false;
666 }
667
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000668 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000669
670 for (int level = 1; level <= q; level++)
671 {
672 if (mImageArray[level].format != mImageArray[0].format)
673 {
674 return false;
675 }
676
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000677 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000678 {
679 return false;
680 }
681
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000682 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000683 {
684 return false;
685 }
686 }
687 }
688
689 return true;
690}
691
692// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000693IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000694{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000695 IDirect3DTexture9 *texture;
696
697 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000698 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000699
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000700 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000701
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000702 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000703 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000704 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000705 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000706 }
707
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000708 if (mTexture) mTexture->Release();
709 mTexture = texture;
710 return texture;
711}
712
713void Texture2D::updateTexture()
714{
715 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000716
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000717 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000718
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000719 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000720 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000721 if (mImageArray[level].dirty)
722 {
723 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000724 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000725
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000726 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000727
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000728 if (SUCCEEDED(result))
729 {
730 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
731 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000732
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000733 levelSurface->Release();
734
735 mImageArray[level].dirty = false;
736 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000737 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000738 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000739}
740
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000741IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000742{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000743 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000744
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000745 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000746 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000747 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000748 IDirect3DDevice9 *device = getDevice();
749 D3DFORMAT format = selectFormat(mImageArray[0].format);
750
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000751 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 +0000752
753 if (FAILED(result))
754 {
755 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
756 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
757 }
758
759 if (mTexture != NULL)
760 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000761 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000762 for (int i = 0; i < levels; i++)
763 {
764 IDirect3DSurface9 *source;
765 result = mTexture->GetSurfaceLevel(i, &source);
766
767 if (FAILED(result))
768 {
769 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
770
771 texture->Release();
772
773 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
774 }
775
776 IDirect3DSurface9 *dest;
777 result = texture->GetSurfaceLevel(i, &dest);
778
779 if (FAILED(result))
780 {
781 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
782
783 texture->Release();
784 source->Release();
785
786 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
787 }
788
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000789 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000790 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
791
792 if (FAILED(result))
793 {
794 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
795
796 texture->Release();
797 source->Release();
798 dest->Release();
799
800 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
801 }
802
803 source->Release();
804 dest->Release();
805 }
806 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000807 }
808
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000809 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000810 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000811 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000812 }
813
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000814 mTexture = texture;
815 return mTexture;
816}
817
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000818bool Texture2D::dirtyImageData() const
819{
820 int q = log2(std::max(mWidth, mHeight));
821
822 for (int i = 0; i <= q; i++)
823 {
824 if (mImageArray[i].dirty) return true;
825 }
826
827 return false;
828}
829
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000830void Texture2D::generateMipmaps()
831{
832 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
833 {
834 return error(GL_INVALID_OPERATION);
835 }
836
837 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
838 unsigned int q = log2(std::max(mWidth, mHeight));
839 for (unsigned int i = 1; i <= q; i++)
840 {
841 if (mImageArray[i].surface != NULL)
842 {
843 mImageArray[i].surface->Release();
844 mImageArray[i].surface = NULL;
845 }
846
847 mImageArray[i].dirty = false;
848
849 mImageArray[i].format = mImageArray[0].format;
850 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
851 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
852 }
853
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000854 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000855
856 for (unsigned int i = 1; i <= q; i++)
857 {
858 IDirect3DSurface9 *upper = NULL;
859 IDirect3DSurface9 *lower = NULL;
860
861 mTexture->GetSurfaceLevel(i-1, &upper);
862 mTexture->GetSurfaceLevel(i, &lower);
863
864 if (upper != NULL && lower != NULL)
865 {
866 getBlitter()->boxFilter(upper, lower);
867 }
868
869 if (upper != NULL) upper->Release();
870 if (lower != NULL) lower->Release();
871 }
872}
873
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000874Colorbuffer *Texture2D::getColorbuffer(GLenum target)
875{
876 if (target != GL_TEXTURE_2D)
877 {
878 return error(GL_INVALID_OPERATION, (Colorbuffer *)NULL);
879 }
880
881 if (mColorbufferProxy == NULL)
882 {
883 mColorbufferProxy = new TextureColorbufferProxy(this, target);
884 }
885
886 return mColorbufferProxy;
887}
888
889IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
890{
891 ASSERT(target == GL_TEXTURE_2D);
892
893 needRenderTarget();
894
895 IDirect3DSurface9 *renderTarget = NULL;
896 mTexture->GetSurfaceLevel(0, &renderTarget);
897
898 return renderTarget;
899}
900
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000901TextureCubeMap::TextureCubeMap(Context *context) : Texture(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000902{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000903 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000904
905 for (int i = 0; i < 6; i++)
906 {
907 mFaceProxies[i] = NULL;
908 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000909}
910
911TextureCubeMap::~TextureCubeMap()
912{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000913 for (int i = 0; i < 6; i++)
914 {
915 delete mFaceProxies[i];
916 }
917
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000918 if (mTexture)
919 {
920 mTexture->Release();
921 mTexture = NULL;
922 }
923}
924
925GLenum TextureCubeMap::getTarget() const
926{
927 return GL_TEXTURE_CUBE_MAP;
928}
929
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000930void 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 +0000931{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000932 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000933}
934
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000935void 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 +0000936{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000937 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000938}
939
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000940void 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 +0000941{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000942 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000943}
944
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000945void 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 +0000946{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000947 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000948}
949
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000950void 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 +0000951{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000952 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000953}
954
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000955void 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 +0000956{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000957 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000958}
959
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000960void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
961{
962 int face = faceIndex(faceTarget);
963
964 ASSERT(mImageArray[face][level].surface != NULL);
965
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000966 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000967 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000968 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
969 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000970
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000971 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000972 {
973 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000974
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000975 RECT sourceRect;
976 sourceRect.left = xoffset;
977 sourceRect.top = yoffset;
978 sourceRect.right = xoffset + width;
979 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000980
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000981 POINT destPoint;
982 destPoint.x = xoffset;
983 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000984
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000985 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000986 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000987
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000988 destLevel->Release();
989
990 img->dirty = false;
991 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000992 }
993}
994
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000995void 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 +0000996{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000997 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000998 commitRect(face, level, xoffset, yoffset, width, height);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000999}
1000
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001001// 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 +00001002bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001003{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001004 int size = mImageArray[0][0].width;
1005
1006 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001007 {
1008 return false;
1009 }
1010
1011 bool mipmapping;
1012
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001013 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001014 {
1015 case GL_NEAREST:
1016 case GL_LINEAR:
1017 mipmapping = false;
1018 break;
1019 case GL_NEAREST_MIPMAP_NEAREST:
1020 case GL_LINEAR_MIPMAP_NEAREST:
1021 case GL_NEAREST_MIPMAP_LINEAR:
1022 case GL_LINEAR_MIPMAP_LINEAR:
1023 mipmapping = true;
1024 break;
1025 default: UNREACHABLE();
1026 }
1027
1028 for (int face = 0; face < 6; face++)
1029 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001030 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001031 {
1032 return false;
1033 }
1034 }
1035
1036 if (mipmapping)
1037 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001038 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1039 {
1040 return false;
1041 }
1042
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001043 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001044
1045 for (int face = 0; face < 6; face++)
1046 {
1047 for (int level = 1; level <= q; level++)
1048 {
1049 if (mImageArray[face][level].format != mImageArray[0][0].format)
1050 {
1051 return false;
1052 }
1053
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001054 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001055 {
1056 return false;
1057 }
1058
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001059 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001060 }
1061 }
1062 }
1063
1064 return true;
1065}
1066
1067// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001068IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001069{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001070 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001071 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001072
1073 IDirect3DCubeTexture9 *texture;
1074
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001075 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001076
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001077 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001078 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001079 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001080 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001081 }
1082
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001083 if (mTexture) mTexture->Release();
1084
1085 mTexture = texture;
1086 return mTexture;
1087}
1088
1089void TextureCubeMap::updateTexture()
1090{
1091 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001092
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001093 for (int face = 0; face < 6; face++)
1094 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001095 int levels = levelCount();
1096 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001097 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001098 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001099
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001100 if (img->dirty)
1101 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001102 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1103 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001104
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001105 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001106 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001107 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001108 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001109
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001110 levelSurface->Release();
1111
1112 img->dirty = false;
1113 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001114 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001115 }
1116 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001117}
1118
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001119IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1120{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001121 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001122
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001123 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001124 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001125 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001126 IDirect3DDevice9 *device = getDevice();
1127 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
1128
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001129 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001130
1131 if (FAILED(result))
1132 {
1133 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1134 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1135 }
1136
1137 if (mTexture != NULL)
1138 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001139 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001140 for (int f = 0; f < 6; f++)
1141 {
1142 for (int i = 0; i < levels; i++)
1143 {
1144 IDirect3DSurface9 *source;
1145 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1146
1147 if (FAILED(result))
1148 {
1149 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1150
1151 texture->Release();
1152
1153 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1154 }
1155
1156 IDirect3DSurface9 *dest;
1157 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1158
1159 if (FAILED(result))
1160 {
1161 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1162
1163 texture->Release();
1164 source->Release();
1165
1166 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1167 }
1168
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001169 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001170 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1171
1172 if (FAILED(result))
1173 {
1174 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1175
1176 texture->Release();
1177 source->Release();
1178 dest->Release();
1179
1180 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1181 }
1182 }
1183 }
1184 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001185 }
1186
1187 if (mTexture != NULL)
1188 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001189 mTexture->Release();
1190 }
1191
1192 mTexture = texture;
1193 return mTexture;
1194}
1195
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001196void 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 +00001197{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001198 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001199
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001200 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001201}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001202
1203unsigned int TextureCubeMap::faceIndex(GLenum face)
1204{
1205 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1206 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1207 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1208 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1209 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1210
1211 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1212}
1213
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001214bool TextureCubeMap::dirtyImageData() const
1215{
1216 int q = log2(mWidth);
1217
1218 for (int f = 0; f < 6; f++)
1219 {
1220 for (int i = 0; i <= q; i++)
1221 {
1222 if (mImageArray[f][i].dirty) return true;
1223 }
1224 }
1225
1226 return false;
1227}
1228
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001229// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1230// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1231// Call this when a particular level of the texture must be defined with a specific format, width and height.
1232//
1233// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1234// a new size for the texture by working backwards from the given size.
1235bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1236{
1237 // Are these settings compatible with level 0?
1238 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1239
1240 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1241
1242 if (!textureOkay)
1243 {
1244 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1245 mImageArray[0][0].format, mImageArray[0][0].width,
1246 internalFormat, width);
1247
1248 // Purge all the levels and the texture.
1249 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1250 {
1251 for (int f = 0; f < 6; f++)
1252 {
1253 if (mImageArray[f][i].surface != NULL)
1254 {
1255 mImageArray[f][i].dirty = false;
1256
1257 mImageArray[f][i].surface->Release();
1258 mImageArray[f][i].surface = NULL;
1259 }
1260 }
1261 }
1262
1263 if (mTexture != NULL)
1264 {
1265 mTexture->Release();
1266 mTexture = NULL;
1267 dropTexture();
1268 }
1269
1270 mWidth = width << level;
1271 mImageArray[0][0].width = width << level;
1272 mHeight = width << level;
1273 mImageArray[0][0].height = width << level;
1274
1275 mImageArray[0][0].format = internalFormat;
1276 }
1277
1278 return !textureOkay;
1279}
1280
1281void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
1282{
1283 unsigned int faceindex = faceIndex(face);
1284
1285 if (redefineTexture(level, internalFormat, width))
1286 {
1287 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001288 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001289 }
1290
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001291 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001292
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001293 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001294 {
1295 RECT sourceRect;
1296 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001297 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001298 sourceRect.top = y;
1299 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001300
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001301 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1302
1303 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1304 dest->Release();
1305 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001306
1307 mImageArray[faceindex][level].width = width;
1308 mImageArray[faceindex][level].height = height;
1309 mImageArray[faceindex][level].format = internalFormat;
1310}
1311
1312IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1313{
1314 unsigned int faceIndex;
1315
1316 if (faceIdentifier < 6)
1317 {
1318 faceIndex = faceIdentifier;
1319 }
1320 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1321 {
1322 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1323 }
1324 else
1325 {
1326 UNREACHABLE();
1327 faceIndex = 0;
1328 }
1329
1330 if (mTexture == NULL)
1331 {
1332 UNREACHABLE();
1333 return NULL;
1334 }
1335
1336 IDirect3DSurface9 *surface = NULL;
1337
1338 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1339
1340 return (SUCCEEDED(hr)) ? surface : NULL;
1341}
1342
1343void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
1344{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001345 GLsizei size = mImageArray[faceIndex(face)][level].width;
1346
1347 if (xoffset + width > size || yoffset + height > size)
1348 {
1349 return error(GL_INVALID_VALUE);
1350 }
1351
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001352 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1353 {
1354 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001355 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001356 }
1357 else
1358 {
1359 getRenderTarget(face);
1360 }
1361
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001362 if (level < levelCount())
1363 {
1364 RECT sourceRect;
1365 sourceRect.left = x;
1366 sourceRect.right = x + width;
1367 sourceRect.top = y;
1368 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001369
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001370 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001371
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001372 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1373 dest->Release();
1374 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001375}
1376
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001377bool TextureCubeMap::isCubeComplete() const
1378{
1379 if (mImageArray[0][0].width == 0)
1380 {
1381 return false;
1382 }
1383
1384 for (unsigned int f = 1; f < 6; f++)
1385 {
1386 if (mImageArray[f][0].width != mImageArray[0][0].width
1387 || mImageArray[f][0].format != mImageArray[0][0].format)
1388 {
1389 return false;
1390 }
1391 }
1392
1393 return true;
1394}
1395
1396void TextureCubeMap::generateMipmaps()
1397{
1398 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1399 {
1400 return error(GL_INVALID_OPERATION);
1401 }
1402
1403 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1404 unsigned int q = log2(mImageArray[0][0].width);
1405 for (unsigned int f = 0; f < 6; f++)
1406 {
1407 for (unsigned int i = 1; i <= q; i++)
1408 {
1409 if (mImageArray[f][i].surface != NULL)
1410 {
1411 mImageArray[f][i].surface->Release();
1412 mImageArray[f][i].surface = NULL;
1413 }
1414
1415 mImageArray[f][i].dirty = false;
1416
1417 mImageArray[f][i].format = mImageArray[f][0].format;
1418 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1419 mImageArray[f][i].height = mImageArray[f][i].width;
1420 }
1421 }
1422
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001423 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001424
1425 for (unsigned int f = 0; f < 6; f++)
1426 {
1427 for (unsigned int i = 1; i <= q; i++)
1428 {
1429 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1430 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1431
1432 if (upper != NULL && lower != NULL)
1433 {
1434 getBlitter()->boxFilter(upper, lower);
1435 }
1436
1437 if (upper != NULL) upper->Release();
1438 if (lower != NULL) lower->Release();
1439 }
1440 }
1441}
1442
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001443Colorbuffer *TextureCubeMap::getColorbuffer(GLenum target)
1444{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001445 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001446 {
1447 return error(GL_INVALID_OPERATION, (Colorbuffer *)NULL);
1448 }
1449
1450 unsigned int face = faceIndex(target);
1451
1452 if (mFaceProxies[face] == NULL)
1453 {
1454 mFaceProxies[face] = new TextureColorbufferProxy(this, target);
1455 }
1456
1457 return mFaceProxies[face];
1458}
1459
1460IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1461{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001462 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001463
1464 needRenderTarget();
1465
1466 IDirect3DSurface9 *renderTarget = NULL;
1467 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
1468
1469 return renderTarget;
1470}
1471
1472Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
1473 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
1474{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001475 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001476}
1477
1478IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
1479{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001480 if (mRenderTarget) mRenderTarget->Release();
1481
1482 mRenderTarget = mTexture->getRenderTarget(mTarget);
1483
1484 return mRenderTarget;
1485}
1486
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001487int Texture::TextureColorbufferProxy::getWidth()
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001488{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001489 return mTexture->getWidth();
1490}
1491
1492int Texture::TextureColorbufferProxy::getHeight()
1493{
1494 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001495}
1496
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001497}