blob: 98d47cae9a52fd7e8195dcea5013a14f17deb54e [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.com4f39fd92010-03-08 20:26:45 +000045}
46
47Texture::~Texture()
48{
49}
50
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000051Blit *Texture::getBlitter()
52{
53 return mContext->getBlitter();
54}
55
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000056// Returns true on successful filter state update (valid enum parameter)
57bool Texture::setMinFilter(GLenum filter)
58{
59 switch (filter)
60 {
61 case GL_NEAREST:
62 case GL_LINEAR:
63 case GL_NEAREST_MIPMAP_NEAREST:
64 case GL_LINEAR_MIPMAP_NEAREST:
65 case GL_NEAREST_MIPMAP_LINEAR:
66 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000067 {
68 if (mMinFilter != filter)
69 {
70 mMinFilter = filter;
71 mDirty = true;
72 }
73 return true;
74 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000075 default:
76 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000077 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000078}
79
80// Returns true on successful filter state update (valid enum parameter)
81bool Texture::setMagFilter(GLenum filter)
82{
83 switch (filter)
84 {
85 case GL_NEAREST:
86 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000087 {
88 if (mMagFilter != filter)
89 {
90 mMagFilter = filter;
91 mDirty = true;
92 }
93 return true;
94 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000095 default:
96 return false;
97 }
98}
99
100// Returns true on successful wrap state update (valid enum parameter)
101bool Texture::setWrapS(GLenum wrap)
102{
103 switch (wrap)
104 {
105 case GL_REPEAT:
106 case GL_CLAMP_TO_EDGE:
107 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000108 {
109 if (mWrapS != wrap)
110 {
111 mWrapS = wrap;
112 mDirty = true;
113 }
114 return true;
115 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000116 default:
117 return false;
118 }
119}
120
121// Returns true on successful wrap state update (valid enum parameter)
122bool Texture::setWrapT(GLenum wrap)
123{
124 switch (wrap)
125 {
126 case GL_REPEAT:
127 case GL_CLAMP_TO_EDGE:
128 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000129 {
130 if (mWrapT != wrap)
131 {
132 mWrapT = wrap;
133 mDirty = true;
134 }
135 return true;
136 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137 default:
138 return false;
139 }
140}
141
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000142GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143{
144 return mMinFilter;
145}
146
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000147GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148{
149 return mMagFilter;
150}
151
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000152GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000153{
154 return mWrapS;
155}
156
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000157GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158{
159 return mWrapT;
160}
161
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000162GLuint Texture::getWidth() const
163{
164 return mWidth;
165}
166
167GLuint Texture::getHeight() const
168{
169 return mHeight;
170}
171
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000172// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000173D3DFORMAT Texture::selectFormat(GLenum format)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000175 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176}
177
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000178int Texture::imagePitch(const Image &img) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000180 return img.width * 4;
181}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000182
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000183// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
184// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
185void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000186 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000187{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000188 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000189
190 for (int y = 0; y < height; y++)
191 {
192 const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
193 const unsigned short *source16 = reinterpret_cast<const unsigned short*>(source);
194 unsigned char *dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
195
196 for (int x = 0; x < width; x++)
197 {
198 unsigned char r;
199 unsigned char g;
200 unsigned char b;
201 unsigned char a;
202
203 switch (format)
204 {
205 case GL_ALPHA:
206 a = source[x];
207 r = 0;
208 g = 0;
209 b = 0;
210 break;
211
212 case GL_LUMINANCE:
213 r = source[x];
214 g = source[x];
215 b = source[x];
216 a = 0xFF;
217 break;
218
219 case GL_LUMINANCE_ALPHA:
220 r = source[2*x+0];
221 g = source[2*x+0];
222 b = source[2*x+0];
223 a = source[2*x+1];
224 break;
225
226 case GL_RGB:
227 switch (type)
228 {
229 case GL_UNSIGNED_BYTE:
230 r = source[x * 3 + 0];
daniel@transgaming.com5ac52152010-04-13 19:53:38 +0000231 g = source[x * 3 + 1];
232 b = source[x * 3 + 2];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000233 a = 0xFF;
234 break;
235
236 case GL_UNSIGNED_SHORT_5_6_5:
237 {
238 unsigned short rgba = source16[x];
239
240 a = 0xFF;
241 b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
242 g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
243 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
244 }
245 break;
246
247 default: UNREACHABLE();
248 }
249 break;
250
251 case GL_RGBA:
252 switch (type)
253 {
254 case GL_UNSIGNED_BYTE:
255 r = source[x * 4 + 0];
256 g = source[x * 4 + 1];
257 b = source[x * 4 + 2];
258 a = source[x * 4 + 3];
259 break;
260
261 case GL_UNSIGNED_SHORT_4_4_4_4:
262 {
263 unsigned short rgba = source16[x];
264
265 a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
266 b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
267 g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
268 r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
269 }
270 break;
271
272 case GL_UNSIGNED_SHORT_5_5_5_1:
273 {
274 unsigned short rgba = source16[x];
275
276 a = (rgba & 0x0001) ? 0xFF : 0;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000277 b = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000278 g = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000279 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000280 }
281 break;
282
283 default: UNREACHABLE();
284 }
285 break;
286 default: UNREACHABLE();
287 }
288
289 dest[4 * x + 0] = b;
290 dest[4 * x + 1] = g;
291 dest[4 * x + 2] = r;
292 dest[4 * x + 3] = a;
293 }
294 }
295}
296
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000297void 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 +0000298{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000299 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000300
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000301 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000302 {
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000303 HRESULT result = getDevice()->CreateOffscreenPlainSurface(width, height, selectFormat(format), D3DPOOL_SYSTEMMEM, &newSurface, NULL);
304
305 if (FAILED(result))
306 {
307 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
308 return error(GL_OUT_OF_MEMORY);
309 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000310 }
311
312 if (img->surface) img->surface->Release();
313 img->surface = newSurface;
314
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000315 img->width = width;
316 img->height = height;
317 img->format = format;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000318
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000319 if (pixels != NULL && newSurface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000320 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000321 D3DLOCKED_RECT locked;
322 HRESULT result = newSurface->LockRect(&locked, NULL, 0);
323
324 ASSERT(SUCCEEDED(result));
325
326 if (SUCCEEDED(result))
327 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000328 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000329 newSurface->UnlockRect();
330 }
331
332 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000333 }
334
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000335 mDirtyMetaData = true;
336}
337
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000338void 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 +0000339{
340 if (width + xoffset > img->width || height + yoffset > img->height) return error(GL_INVALID_VALUE);
341
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000342 D3DLOCKED_RECT locked;
343 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000344
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000345 ASSERT(SUCCEEDED(result));
346
347 if (SUCCEEDED(result))
348 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000349 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000350 img->surface->UnlockRect();
351 }
352
353 img->dirty = true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000354}
355
356IDirect3DBaseTexture9 *Texture::getTexture()
357{
358 if (!isComplete())
359 {
360 return NULL;
361 }
362
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000363 if (mDirtyMetaData)
364 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000365 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000366 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000367 }
368
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000369 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000370 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000371 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000372 }
373
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000374 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000375 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000376
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000377 return mBaseTexture;
378}
379
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000380bool Texture::isDirty() const
381{
382 return (mDirty || mDirtyMetaData || dirtyImageData());
383}
384
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000385// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000386void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000387{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000388 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000389 {
390 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000391 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000392 }
393
394 if (dirtyImageData())
395 {
396 updateTexture();
397 }
398
399 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000400}
401
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000402void Texture::dropTexture()
403{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000404 if (mBaseTexture)
405 {
406 mBaseTexture = NULL;
407 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000408
409 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000410}
411
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000412void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000413{
414 mBaseTexture = newTexture;
415 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000416 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000417 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000418}
419
420
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000421GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
422{
423 if (isPow2(width) && isPow2(height))
424 {
425 return maxlevel;
426 }
427 else
428 {
429 // One of the restrictions of NONPOW2CONDITIONAL is that NPOTs may only have a single level.
430 return (getContext()->getDeviceCaps().TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) ? 1 : maxlevel;
431 }
432}
433
434GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
435{
436 return creationLevels(size, size, maxlevel);
437}
438
439int Texture::levelCount() const
440{
441 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
442}
443
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000444Texture2D::Texture2D(Context *context) : Texture(context)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000445{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000446 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000447 mColorbufferProxy = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448}
449
450Texture2D::~Texture2D()
451{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000452 delete mColorbufferProxy;
453
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454 if (mTexture)
455 {
456 mTexture->Release();
457 mTexture = NULL;
458 }
459}
460
461GLenum Texture2D::getTarget() const
462{
463 return GL_TEXTURE_2D;
464}
465
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000466// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
467// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
468// Call this when a particular level of the texture must be defined with a specific format, width and height.
469//
470// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
471// a new height and width for the texture by working backwards from the given width and height.
472bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height)
473{
474 bool widthOkay = (mWidth >> level == width);
475 bool heightOkay = (mHeight >> level == height);
476
477 bool sizeOkay = ((widthOkay && heightOkay)
478 || (widthOkay && mHeight >> level == 0 && height == 1)
479 || (heightOkay && mWidth >> level == 0 && width == 1));
480
481 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
482
483 if (!textureOkay)
484 {
485 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
486 mImageArray[0].format, mWidth, mHeight,
487 internalFormat, width, height);
488
489 // Purge all the levels and the texture.
490
491 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
492 {
493 if (mImageArray[i].surface != NULL)
494 {
495 mImageArray[i].dirty = false;
496
497 mImageArray[i].surface->Release();
498 mImageArray[i].surface = NULL;
499 }
500 }
501
502 if (mTexture != NULL)
503 {
504 mTexture->Release();
505 mTexture = NULL;
506 dropTexture();
507 }
508
509 mWidth = width << level;
510 mHeight = height << level;
511 mImageArray[0].format = internalFormat;
512 }
513
514 return !textureOkay;
515}
516
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000517void 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 +0000518{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000519 redefineTexture(level, internalFormat, width, height);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000520
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000521 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522}
523
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000524void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
525{
526 ASSERT(mImageArray[level].surface != NULL);
527
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000528 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000529 {
530 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000531 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000532
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000533 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000534
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000535 if (SUCCEEDED(result))
536 {
537 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000538
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000539 RECT sourceRect;
540 sourceRect.left = xoffset;
541 sourceRect.top = yoffset;
542 sourceRect.right = xoffset + width;
543 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000544
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000545 POINT destPoint;
546 destPoint.x = xoffset;
547 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000548
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000549 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
550 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000551
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000552 destLevel->Release();
553
554 img->dirty = false;
555 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000556 }
557}
558
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000559void 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 +0000560{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000561 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000562 commitRect(level, xoffset, yoffset, width, height);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000563}
564
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000565void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
566{
567 if (redefineTexture(level, internalFormat, width, height))
568 {
569 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000570 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000571 }
572
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000573 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000574 {
575 RECT sourceRect;
576 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000577 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +0000578 sourceRect.top = y;
579 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000580
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000581 IDirect3DSurface9 *dest;
582 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000583
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000584 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
585 dest->Release();
586 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000587
588 mImageArray[level].width = width;
589 mImageArray[level].height = height;
590 mImageArray[level].format = internalFormat;
591}
592
593void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
594{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000595 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
596 {
597 return error(GL_INVALID_VALUE);
598 }
599
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000600 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
601 {
602 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000603 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000604 }
605 else
606 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +0000607 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000608 }
609
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000610 if (level < levelCount())
611 {
612 RECT sourceRect;
613 sourceRect.left = x;
614 sourceRect.right = x + width;
615 sourceRect.top = y;
616 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000617
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000618 IDirect3DSurface9 *dest;
619 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000620
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000621 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
622 dest->Release();
623 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000624}
625
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000626// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
627bool Texture2D::isComplete() const
628{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000629 GLsizei width = mImageArray[0].width;
630 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000631
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000632 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000633 {
634 return false;
635 }
636
637 bool mipmapping;
638
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000639 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000640 {
641 case GL_NEAREST:
642 case GL_LINEAR:
643 mipmapping = false;
644 break;
645 case GL_NEAREST_MIPMAP_NEAREST:
646 case GL_LINEAR_MIPMAP_NEAREST:
647 case GL_NEAREST_MIPMAP_LINEAR:
648 case GL_LINEAR_MIPMAP_LINEAR:
649 mipmapping = true;
650 break;
651 default: UNREACHABLE();
652 }
653
654 if (mipmapping)
655 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000656 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
657 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
658 {
659 return false;
660 }
661
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000662 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000663
664 for (int level = 1; level <= q; level++)
665 {
666 if (mImageArray[level].format != mImageArray[0].format)
667 {
668 return false;
669 }
670
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000671 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000672 {
673 return false;
674 }
675
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000676 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000677 {
678 return false;
679 }
680 }
681 }
682
683 return true;
684}
685
686// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000687IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000688{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000689 IDirect3DTexture9 *texture;
690
691 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000692 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000693
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000694 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000695
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000696 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000697 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000698 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000699 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000700 }
701
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000702 if (mTexture) mTexture->Release();
703 mTexture = texture;
704 return texture;
705}
706
707void Texture2D::updateTexture()
708{
709 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000710
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000711 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000712
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000713 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000714 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000715 if (mImageArray[level].dirty)
716 {
717 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000718 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000719
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000720 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000721
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000722 if (SUCCEEDED(result))
723 {
724 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
725 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000726
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000727 levelSurface->Release();
728
729 mImageArray[level].dirty = false;
730 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000731 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000732 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000733}
734
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000735IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000736{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000737 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000738
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000739 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000740 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000741 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000742 IDirect3DDevice9 *device = getDevice();
743 D3DFORMAT format = selectFormat(mImageArray[0].format);
744
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000745 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 +0000746
747 if (FAILED(result))
748 {
749 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
750 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
751 }
752
753 if (mTexture != NULL)
754 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000755 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000756 for (int i = 0; i < levels; i++)
757 {
758 IDirect3DSurface9 *source;
759 result = mTexture->GetSurfaceLevel(i, &source);
760
761 if (FAILED(result))
762 {
763 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
764
765 texture->Release();
766
767 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
768 }
769
770 IDirect3DSurface9 *dest;
771 result = texture->GetSurfaceLevel(i, &dest);
772
773 if (FAILED(result))
774 {
775 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
776
777 texture->Release();
778 source->Release();
779
780 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
781 }
782
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000783 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000784 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
785
786 if (FAILED(result))
787 {
788 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
789
790 texture->Release();
791 source->Release();
792 dest->Release();
793
794 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
795 }
796
797 source->Release();
798 dest->Release();
799 }
800 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000801 }
802
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000803 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000804 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000805 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000806 }
807
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000808 mTexture = texture;
809 return mTexture;
810}
811
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000812bool Texture2D::dirtyImageData() const
813{
814 int q = log2(std::max(mWidth, mHeight));
815
816 for (int i = 0; i <= q; i++)
817 {
818 if (mImageArray[i].dirty) return true;
819 }
820
821 return false;
822}
823
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000824void Texture2D::generateMipmaps()
825{
826 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
827 {
828 return error(GL_INVALID_OPERATION);
829 }
830
831 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
832 unsigned int q = log2(std::max(mWidth, mHeight));
833 for (unsigned int i = 1; i <= q; i++)
834 {
835 if (mImageArray[i].surface != NULL)
836 {
837 mImageArray[i].surface->Release();
838 mImageArray[i].surface = NULL;
839 }
840
841 mImageArray[i].dirty = false;
842
843 mImageArray[i].format = mImageArray[0].format;
844 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
845 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
846 }
847
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000848 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000849
850 for (unsigned int i = 1; i <= q; i++)
851 {
852 IDirect3DSurface9 *upper = NULL;
853 IDirect3DSurface9 *lower = NULL;
854
855 mTexture->GetSurfaceLevel(i-1, &upper);
856 mTexture->GetSurfaceLevel(i, &lower);
857
858 if (upper != NULL && lower != NULL)
859 {
860 getBlitter()->boxFilter(upper, lower);
861 }
862
863 if (upper != NULL) upper->Release();
864 if (lower != NULL) lower->Release();
865 }
866}
867
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000868Colorbuffer *Texture2D::getColorbuffer(GLenum target)
869{
870 if (target != GL_TEXTURE_2D)
871 {
872 return error(GL_INVALID_OPERATION, (Colorbuffer *)NULL);
873 }
874
875 if (mColorbufferProxy == NULL)
876 {
877 mColorbufferProxy = new TextureColorbufferProxy(this, target);
878 }
879
880 return mColorbufferProxy;
881}
882
883IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
884{
885 ASSERT(target == GL_TEXTURE_2D);
886
887 needRenderTarget();
888
889 IDirect3DSurface9 *renderTarget = NULL;
890 mTexture->GetSurfaceLevel(0, &renderTarget);
891
892 return renderTarget;
893}
894
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000895TextureCubeMap::TextureCubeMap(Context *context) : Texture(context)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000896{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000897 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000898
899 for (int i = 0; i < 6; i++)
900 {
901 mFaceProxies[i] = NULL;
902 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000903}
904
905TextureCubeMap::~TextureCubeMap()
906{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000907 for (int i = 0; i < 6; i++)
908 {
909 delete mFaceProxies[i];
910 }
911
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000912 if (mTexture)
913 {
914 mTexture->Release();
915 mTexture = NULL;
916 }
917}
918
919GLenum TextureCubeMap::getTarget() const
920{
921 return GL_TEXTURE_CUBE_MAP;
922}
923
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000924void 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 +0000925{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000926 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000927}
928
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000929void 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 +0000930{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000931 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000932}
933
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000934void 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 +0000935{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000936 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000937}
938
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000939void 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 +0000940{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000941 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000942}
943
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000944void 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 +0000945{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000946 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000947}
948
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000949void 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 +0000950{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000951 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000952}
953
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000954void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
955{
956 int face = faceIndex(faceTarget);
957
958 ASSERT(mImageArray[face][level].surface != NULL);
959
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000960 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000961 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000962 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
963 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000964
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000965 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000966 {
967 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000968
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000969 RECT sourceRect;
970 sourceRect.left = xoffset;
971 sourceRect.top = yoffset;
972 sourceRect.right = xoffset + width;
973 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000974
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000975 POINT destPoint;
976 destPoint.x = xoffset;
977 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000978
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000979 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000980 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000981
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000982 destLevel->Release();
983
984 img->dirty = false;
985 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000986 }
987}
988
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000989void 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 +0000990{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000991 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000992 commitRect(face, level, xoffset, yoffset, width, height);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000993}
994
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000995// 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 +0000996bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000997{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000998 int size = mImageArray[0][0].width;
999
1000 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001001 {
1002 return false;
1003 }
1004
1005 bool mipmapping;
1006
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001007 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001008 {
1009 case GL_NEAREST:
1010 case GL_LINEAR:
1011 mipmapping = false;
1012 break;
1013 case GL_NEAREST_MIPMAP_NEAREST:
1014 case GL_LINEAR_MIPMAP_NEAREST:
1015 case GL_NEAREST_MIPMAP_LINEAR:
1016 case GL_LINEAR_MIPMAP_LINEAR:
1017 mipmapping = true;
1018 break;
1019 default: UNREACHABLE();
1020 }
1021
1022 for (int face = 0; face < 6; face++)
1023 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001024 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001025 {
1026 return false;
1027 }
1028 }
1029
1030 if (mipmapping)
1031 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001032 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1033 {
1034 return false;
1035 }
1036
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001037 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001038
1039 for (int face = 0; face < 6; face++)
1040 {
1041 for (int level = 1; level <= q; level++)
1042 {
1043 if (mImageArray[face][level].format != mImageArray[0][0].format)
1044 {
1045 return false;
1046 }
1047
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001048 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001049 {
1050 return false;
1051 }
1052
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001053 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001054 }
1055 }
1056 }
1057
1058 return true;
1059}
1060
1061// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001062IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001063{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001064 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001065 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001066
1067 IDirect3DCubeTexture9 *texture;
1068
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001069 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001070
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001071 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001072 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001073 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001074 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001075 }
1076
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001077 if (mTexture) mTexture->Release();
1078
1079 mTexture = texture;
1080 return mTexture;
1081}
1082
1083void TextureCubeMap::updateTexture()
1084{
1085 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001086
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001087 for (int face = 0; face < 6; face++)
1088 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001089 int levels = levelCount();
1090 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001091 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001092 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001093
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001094 if (img->dirty)
1095 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001096 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1097 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001098
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001099 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001100 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001101 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001102 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001103
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001104 levelSurface->Release();
1105
1106 img->dirty = false;
1107 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001108 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001109 }
1110 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001111}
1112
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001113IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1114{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001115 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001116
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001117 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001118 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001119 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001120 IDirect3DDevice9 *device = getDevice();
1121 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
1122
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001123 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001124
1125 if (FAILED(result))
1126 {
1127 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1128 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1129 }
1130
1131 if (mTexture != NULL)
1132 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001133 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001134 for (int f = 0; f < 6; f++)
1135 {
1136 for (int i = 0; i < levels; i++)
1137 {
1138 IDirect3DSurface9 *source;
1139 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1140
1141 if (FAILED(result))
1142 {
1143 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1144
1145 texture->Release();
1146
1147 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1148 }
1149
1150 IDirect3DSurface9 *dest;
1151 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1152
1153 if (FAILED(result))
1154 {
1155 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1156
1157 texture->Release();
1158 source->Release();
1159
1160 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1161 }
1162
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001163 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001164 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1165
1166 if (FAILED(result))
1167 {
1168 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1169
1170 texture->Release();
1171 source->Release();
1172 dest->Release();
1173
1174 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1175 }
1176 }
1177 }
1178 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001179 }
1180
1181 if (mTexture != NULL)
1182 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001183 mTexture->Release();
1184 }
1185
1186 mTexture = texture;
1187 return mTexture;
1188}
1189
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001190void 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 +00001191{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001192 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001193
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001194 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001195}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001196
1197unsigned int TextureCubeMap::faceIndex(GLenum face)
1198{
1199 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1200 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1201 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1202 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1203 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1204
1205 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1206}
1207
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001208bool TextureCubeMap::dirtyImageData() const
1209{
1210 int q = log2(mWidth);
1211
1212 for (int f = 0; f < 6; f++)
1213 {
1214 for (int i = 0; i <= q; i++)
1215 {
1216 if (mImageArray[f][i].dirty) return true;
1217 }
1218 }
1219
1220 return false;
1221}
1222
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001223// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1224// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1225// Call this when a particular level of the texture must be defined with a specific format, width and height.
1226//
1227// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1228// a new size for the texture by working backwards from the given size.
1229bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1230{
1231 // Are these settings compatible with level 0?
1232 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1233
1234 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1235
1236 if (!textureOkay)
1237 {
1238 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1239 mImageArray[0][0].format, mImageArray[0][0].width,
1240 internalFormat, width);
1241
1242 // Purge all the levels and the texture.
1243 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1244 {
1245 for (int f = 0; f < 6; f++)
1246 {
1247 if (mImageArray[f][i].surface != NULL)
1248 {
1249 mImageArray[f][i].dirty = false;
1250
1251 mImageArray[f][i].surface->Release();
1252 mImageArray[f][i].surface = NULL;
1253 }
1254 }
1255 }
1256
1257 if (mTexture != NULL)
1258 {
1259 mTexture->Release();
1260 mTexture = NULL;
1261 dropTexture();
1262 }
1263
1264 mWidth = width << level;
1265 mImageArray[0][0].width = width << level;
1266 mHeight = width << level;
1267 mImageArray[0][0].height = width << level;
1268
1269 mImageArray[0][0].format = internalFormat;
1270 }
1271
1272 return !textureOkay;
1273}
1274
1275void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
1276{
1277 unsigned int faceindex = faceIndex(face);
1278
1279 if (redefineTexture(level, internalFormat, width))
1280 {
1281 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001282 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001283 }
1284
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001285 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001286
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001287 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001288 {
1289 RECT sourceRect;
1290 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001291 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001292 sourceRect.top = y;
1293 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001294
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001295 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1296
1297 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1298 dest->Release();
1299 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001300
1301 mImageArray[faceindex][level].width = width;
1302 mImageArray[faceindex][level].height = height;
1303 mImageArray[faceindex][level].format = internalFormat;
1304}
1305
1306IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1307{
1308 unsigned int faceIndex;
1309
1310 if (faceIdentifier < 6)
1311 {
1312 faceIndex = faceIdentifier;
1313 }
1314 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1315 {
1316 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1317 }
1318 else
1319 {
1320 UNREACHABLE();
1321 faceIndex = 0;
1322 }
1323
1324 if (mTexture == NULL)
1325 {
1326 UNREACHABLE();
1327 return NULL;
1328 }
1329
1330 IDirect3DSurface9 *surface = NULL;
1331
1332 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1333
1334 return (SUCCEEDED(hr)) ? surface : NULL;
1335}
1336
1337void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source)
1338{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001339 GLsizei size = mImageArray[faceIndex(face)][level].width;
1340
1341 if (xoffset + width > size || yoffset + height > size)
1342 {
1343 return error(GL_INVALID_VALUE);
1344 }
1345
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001346 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1347 {
1348 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001349 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001350 }
1351 else
1352 {
1353 getRenderTarget(face);
1354 }
1355
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001356 if (level < levelCount())
1357 {
1358 RECT sourceRect;
1359 sourceRect.left = x;
1360 sourceRect.right = x + width;
1361 sourceRect.top = y;
1362 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001363
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001364 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001365
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001366 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1367 dest->Release();
1368 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001369}
1370
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001371bool TextureCubeMap::isCubeComplete() const
1372{
1373 if (mImageArray[0][0].width == 0)
1374 {
1375 return false;
1376 }
1377
1378 for (unsigned int f = 1; f < 6; f++)
1379 {
1380 if (mImageArray[f][0].width != mImageArray[0][0].width
1381 || mImageArray[f][0].format != mImageArray[0][0].format)
1382 {
1383 return false;
1384 }
1385 }
1386
1387 return true;
1388}
1389
1390void TextureCubeMap::generateMipmaps()
1391{
1392 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1393 {
1394 return error(GL_INVALID_OPERATION);
1395 }
1396
1397 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1398 unsigned int q = log2(mImageArray[0][0].width);
1399 for (unsigned int f = 0; f < 6; f++)
1400 {
1401 for (unsigned int i = 1; i <= q; i++)
1402 {
1403 if (mImageArray[f][i].surface != NULL)
1404 {
1405 mImageArray[f][i].surface->Release();
1406 mImageArray[f][i].surface = NULL;
1407 }
1408
1409 mImageArray[f][i].dirty = false;
1410
1411 mImageArray[f][i].format = mImageArray[f][0].format;
1412 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1413 mImageArray[f][i].height = mImageArray[f][i].width;
1414 }
1415 }
1416
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001417 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001418
1419 for (unsigned int f = 0; f < 6; f++)
1420 {
1421 for (unsigned int i = 1; i <= q; i++)
1422 {
1423 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1424 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1425
1426 if (upper != NULL && lower != NULL)
1427 {
1428 getBlitter()->boxFilter(upper, lower);
1429 }
1430
1431 if (upper != NULL) upper->Release();
1432 if (lower != NULL) lower->Release();
1433 }
1434 }
1435}
1436
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001437Colorbuffer *TextureCubeMap::getColorbuffer(GLenum target)
1438{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001439 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001440 {
1441 return error(GL_INVALID_OPERATION, (Colorbuffer *)NULL);
1442 }
1443
1444 unsigned int face = faceIndex(target);
1445
1446 if (mFaceProxies[face] == NULL)
1447 {
1448 mFaceProxies[face] = new TextureColorbufferProxy(this, target);
1449 }
1450
1451 return mFaceProxies[face];
1452}
1453
1454IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1455{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001456 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001457
1458 needRenderTarget();
1459
1460 IDirect3DSurface9 *renderTarget = NULL;
1461 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
1462
1463 return renderTarget;
1464}
1465
1466Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
1467 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
1468{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001469 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001470 latchTextureInfo();
1471}
1472
1473IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
1474{
1475 latchTextureInfo();
1476
1477 if (mRenderTarget) mRenderTarget->Release();
1478
1479 mRenderTarget = mTexture->getRenderTarget(mTarget);
1480
1481 return mRenderTarget;
1482}
1483
1484void Texture::TextureColorbufferProxy::latchTextureInfo()
1485{
1486 mWidth = mTexture->getWidth();
1487 mHeight = mTexture->getHeight();
1488}
1489
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001490}