blob: 6dfa7c85f0b6d27c80de5e2c1c82efd828cc34dd [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/Texture.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
daniel@transgaming.com16973022010-03-11 19:22:19 +000013#include <algorithm>
14
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000015#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/mathutil.h"
19#include "libGLESv2/utilities.h"
20#include "libGLESv2/Blit.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021
22namespace gl
23{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000024
25Texture::Image::Image()
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000026 : width(0), height(0), dirty(false), surface(NULL)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000027{
28}
29
30Texture::Image::~Image()
31{
32 if (surface) surface->Release();
33}
34
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000035Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036{
37 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
38 mMagFilter = GL_LINEAR;
39 mWrapS = GL_REPEAT;
40 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000041
daniel@transgaming.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{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000054 Context *context = getContext();
55 return context->getBlitter();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000056}
57
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000058// Returns true on successful filter state update (valid enum parameter)
59bool Texture::setMinFilter(GLenum filter)
60{
61 switch (filter)
62 {
63 case GL_NEAREST:
64 case GL_LINEAR:
65 case GL_NEAREST_MIPMAP_NEAREST:
66 case GL_LINEAR_MIPMAP_NEAREST:
67 case GL_NEAREST_MIPMAP_LINEAR:
68 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000069 {
70 if (mMinFilter != filter)
71 {
72 mMinFilter = filter;
73 mDirty = true;
74 }
75 return true;
76 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000077 default:
78 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000079 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080}
81
82// Returns true on successful filter state update (valid enum parameter)
83bool Texture::setMagFilter(GLenum filter)
84{
85 switch (filter)
86 {
87 case GL_NEAREST:
88 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000089 {
90 if (mMagFilter != filter)
91 {
92 mMagFilter = filter;
93 mDirty = true;
94 }
95 return true;
96 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000097 default:
98 return false;
99 }
100}
101
102// Returns true on successful wrap state update (valid enum parameter)
103bool Texture::setWrapS(GLenum wrap)
104{
105 switch (wrap)
106 {
107 case GL_REPEAT:
108 case GL_CLAMP_TO_EDGE:
109 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000110 {
111 if (mWrapS != wrap)
112 {
113 mWrapS = wrap;
114 mDirty = true;
115 }
116 return true;
117 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000118 default:
119 return false;
120 }
121}
122
123// Returns true on successful wrap state update (valid enum parameter)
124bool Texture::setWrapT(GLenum wrap)
125{
126 switch (wrap)
127 {
128 case GL_REPEAT:
129 case GL_CLAMP_TO_EDGE:
130 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000131 {
132 if (mWrapT != wrap)
133 {
134 mWrapT = wrap;
135 mDirty = true;
136 }
137 return true;
138 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000139 default:
140 return false;
141 }
142}
143
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000144GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145{
146 return mMinFilter;
147}
148
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000149GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000150{
151 return mMagFilter;
152}
153
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000154GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000155{
156 return mWrapS;
157}
158
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000159GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000160{
161 return mWrapT;
162}
163
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000164GLuint Texture::getWidth() const
165{
166 return mWidth;
167}
168
169GLuint Texture::getHeight() const
170{
171 return mHeight;
172}
173
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000175D3DFORMAT Texture::selectFormat(GLenum format)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000177 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000178}
179
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000180int Texture::imagePitch(const Image &img) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000182 return img.width * 4;
183}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000184
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000185// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
186// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
187void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000188 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000189{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000190 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000191
192 for (int y = 0; y < height; y++)
193 {
194 const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
195 const unsigned short *source16 = reinterpret_cast<const unsigned short*>(source);
196 unsigned char *dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
197
198 for (int x = 0; x < width; x++)
199 {
200 unsigned char r;
201 unsigned char g;
202 unsigned char b;
203 unsigned char a;
204
205 switch (format)
206 {
207 case GL_ALPHA:
208 a = source[x];
209 r = 0;
210 g = 0;
211 b = 0;
212 break;
213
214 case GL_LUMINANCE:
215 r = source[x];
216 g = source[x];
217 b = source[x];
218 a = 0xFF;
219 break;
220
221 case GL_LUMINANCE_ALPHA:
222 r = source[2*x+0];
223 g = source[2*x+0];
224 b = source[2*x+0];
225 a = source[2*x+1];
226 break;
227
228 case GL_RGB:
229 switch (type)
230 {
231 case GL_UNSIGNED_BYTE:
232 r = source[x * 3 + 0];
daniel@transgaming.com5ac52152010-04-13 19:53:38 +0000233 g = source[x * 3 + 1];
234 b = source[x * 3 + 2];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000235 a = 0xFF;
236 break;
237
238 case GL_UNSIGNED_SHORT_5_6_5:
239 {
240 unsigned short rgba = source16[x];
241
242 a = 0xFF;
243 b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
244 g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
245 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
246 }
247 break;
248
249 default: UNREACHABLE();
250 }
251 break;
252
253 case GL_RGBA:
254 switch (type)
255 {
256 case GL_UNSIGNED_BYTE:
257 r = source[x * 4 + 0];
258 g = source[x * 4 + 1];
259 b = source[x * 4 + 2];
260 a = source[x * 4 + 3];
261 break;
262
263 case GL_UNSIGNED_SHORT_4_4_4_4:
264 {
265 unsigned short rgba = source16[x];
266
267 a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
268 b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
269 g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
270 r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
271 }
272 break;
273
274 case GL_UNSIGNED_SHORT_5_5_5_1:
275 {
276 unsigned short rgba = source16[x];
277
278 a = (rgba & 0x0001) ? 0xFF : 0;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000279 b = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000280 g = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000281 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000282 }
283 break;
284
285 default: UNREACHABLE();
286 }
287 break;
288 default: UNREACHABLE();
289 }
290
291 dest[4 * x + 0] = b;
292 dest[4 * x + 1] = g;
293 dest[4 * x + 2] = r;
294 dest[4 * x + 3] = a;
295 }
296 }
297}
298
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000299void 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 +0000300{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000301 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000302
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000303 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000304 {
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000305 HRESULT result = getDevice()->CreateOffscreenPlainSurface(width, height, selectFormat(format), D3DPOOL_SYSTEMMEM, &newSurface, NULL);
306
307 if (FAILED(result))
308 {
309 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
310 return error(GL_OUT_OF_MEMORY);
311 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000312 }
313
314 if (img->surface) img->surface->Release();
315 img->surface = newSurface;
316
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000317 img->width = width;
318 img->height = height;
319 img->format = format;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000320
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000321 if (pixels != NULL && newSurface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000322 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000323 D3DLOCKED_RECT locked;
324 HRESULT result = newSurface->LockRect(&locked, NULL, 0);
325
326 ASSERT(SUCCEEDED(result));
327
328 if (SUCCEEDED(result))
329 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000330 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000331 newSurface->UnlockRect();
332 }
333
334 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000335 }
336
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000337 mDirtyMetaData = true;
338}
339
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000340void 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 +0000341{
342 if (width + xoffset > img->width || height + yoffset > img->height) return error(GL_INVALID_VALUE);
343
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000344 D3DLOCKED_RECT locked;
345 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000346
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000347 ASSERT(SUCCEEDED(result));
348
349 if (SUCCEEDED(result))
350 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000351 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000352 img->surface->UnlockRect();
353 }
354
355 img->dirty = true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000356}
357
358IDirect3DBaseTexture9 *Texture::getTexture()
359{
360 if (!isComplete())
361 {
362 return NULL;
363 }
364
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000365 if (mDirtyMetaData)
366 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000367 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000368 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000369 }
370
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000371 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000372 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000373 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000374 }
375
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000376 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000377 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000378
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000379 return mBaseTexture;
380}
381
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000382bool Texture::isDirty() const
383{
384 return (mDirty || mDirtyMetaData || dirtyImageData());
385}
386
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000387// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000388void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000389{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000390 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000391 {
392 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000393 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000394 }
395
396 if (dirtyImageData())
397 {
398 updateTexture();
399 }
400
401 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000402}
403
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000404void Texture::dropTexture()
405{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000406 if (mBaseTexture)
407 {
408 mBaseTexture = NULL;
409 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000410
411 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000412}
413
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000414void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000415{
416 mBaseTexture = newTexture;
417 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000418 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000419 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000420}
421
422
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000423GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
424{
425 if (isPow2(width) && isPow2(height))
426 {
427 return maxlevel;
428 }
429 else
430 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000431 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
432 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000433 }
434}
435
436GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
437{
438 return creationLevels(size, size, maxlevel);
439}
440
441int Texture::levelCount() const
442{
443 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
444}
445
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000446Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000447{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000449 mColorbufferProxy = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450}
451
452Texture2D::~Texture2D()
453{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000454 delete mColorbufferProxy;
455
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456 if (mTexture)
457 {
458 mTexture->Release();
459 mTexture = NULL;
460 }
461}
462
463GLenum Texture2D::getTarget() const
464{
465 return GL_TEXTURE_2D;
466}
467
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000468// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
469// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
470// Call this when a particular level of the texture must be defined with a specific format, width and height.
471//
472// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
473// a new height and width for the texture by working backwards from the given width and height.
474bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height)
475{
476 bool widthOkay = (mWidth >> level == width);
477 bool heightOkay = (mHeight >> level == height);
478
479 bool sizeOkay = ((widthOkay && heightOkay)
480 || (widthOkay && mHeight >> level == 0 && height == 1)
481 || (heightOkay && mWidth >> level == 0 && width == 1));
482
483 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
484
485 if (!textureOkay)
486 {
487 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
488 mImageArray[0].format, mWidth, mHeight,
489 internalFormat, width, height);
490
491 // Purge all the levels and the texture.
492
493 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
494 {
495 if (mImageArray[i].surface != NULL)
496 {
497 mImageArray[i].dirty = false;
498
499 mImageArray[i].surface->Release();
500 mImageArray[i].surface = NULL;
501 }
502 }
503
504 if (mTexture != NULL)
505 {
506 mTexture->Release();
507 mTexture = NULL;
508 dropTexture();
509 }
510
511 mWidth = width << level;
512 mHeight = height << level;
513 mImageArray[0].format = internalFormat;
514 }
515
516 return !textureOkay;
517}
518
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000519void 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 +0000520{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000521 redefineTexture(level, internalFormat, width, height);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000523 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524}
525
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000526void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
527{
528 ASSERT(mImageArray[level].surface != NULL);
529
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000530 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000531 {
532 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000533 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000534
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000535 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000536
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000537 if (SUCCEEDED(result))
538 {
539 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000540
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000541 RECT sourceRect;
542 sourceRect.left = xoffset;
543 sourceRect.top = yoffset;
544 sourceRect.right = xoffset + width;
545 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000546
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000547 POINT destPoint;
548 destPoint.x = xoffset;
549 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000550
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000551 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
552 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000553
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000554 destLevel->Release();
555
556 img->dirty = false;
557 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000558 }
559}
560
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000561void 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 +0000562{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000563 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000564 commitRect(level, xoffset, yoffset, width, height);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000565}
566
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000567void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000568{
569 if (redefineTexture(level, internalFormat, width, height))
570 {
571 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000572 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000573 }
574
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000575 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000576 {
577 RECT sourceRect;
578 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000579 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +0000580 sourceRect.top = y;
581 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000582
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000583 IDirect3DSurface9 *dest;
584 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000585
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000586 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
587 dest->Release();
588 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000589
590 mImageArray[level].width = width;
591 mImageArray[level].height = height;
592 mImageArray[level].format = internalFormat;
593}
594
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000595void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000596{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000597 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
598 {
599 return error(GL_INVALID_VALUE);
600 }
601
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000602 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
603 {
604 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000605 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000606 }
607 else
608 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +0000609 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000610 }
611
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000612 if (level < levelCount())
613 {
614 RECT sourceRect;
615 sourceRect.left = x;
616 sourceRect.right = x + width;
617 sourceRect.top = y;
618 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000619
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000620 IDirect3DSurface9 *dest;
621 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000622
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000623 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
624 dest->Release();
625 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000626}
627
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000628// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
629bool Texture2D::isComplete() const
630{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000631 GLsizei width = mImageArray[0].width;
632 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000633
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000634 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000635 {
636 return false;
637 }
638
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000639 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000640
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000641 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642 {
643 case GL_NEAREST:
644 case GL_LINEAR:
645 mipmapping = false;
646 break;
647 case GL_NEAREST_MIPMAP_NEAREST:
648 case GL_LINEAR_MIPMAP_NEAREST:
649 case GL_NEAREST_MIPMAP_LINEAR:
650 case GL_LINEAR_MIPMAP_LINEAR:
651 mipmapping = true;
652 break;
653 default: UNREACHABLE();
654 }
655
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +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.com4f39fd92010-03-08 20:26:45 +0000662 if (mipmapping)
663 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000664 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000665 {
666 return false;
667 }
668
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000669 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000670
671 for (int level = 1; level <= q; level++)
672 {
673 if (mImageArray[level].format != mImageArray[0].format)
674 {
675 return false;
676 }
677
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000678 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679 {
680 return false;
681 }
682
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000683 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000684 {
685 return false;
686 }
687 }
688 }
689
690 return true;
691}
692
693// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000694IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000695{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000696 IDirect3DTexture9 *texture;
697
698 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000699 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000700
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000701 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000702
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000703 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000704 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000705 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000706 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000707 }
708
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000709 if (mTexture) mTexture->Release();
710 mTexture = texture;
711 return texture;
712}
713
714void Texture2D::updateTexture()
715{
716 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000717
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000718 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000719
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000720 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000721 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000722 if (mImageArray[level].dirty)
723 {
724 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000725 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000726
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000727 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000728
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000729 if (SUCCEEDED(result))
730 {
731 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
732 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000733
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000734 levelSurface->Release();
735
736 mImageArray[level].dirty = false;
737 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000738 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000739 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000740}
741
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000742IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000743{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000744 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000745
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000746 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000747 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000748 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000749 IDirect3DDevice9 *device = getDevice();
750 D3DFORMAT format = selectFormat(mImageArray[0].format);
751
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000752 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 +0000753
754 if (FAILED(result))
755 {
756 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
757 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
758 }
759
760 if (mTexture != NULL)
761 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000762 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000763 for (int i = 0; i < levels; i++)
764 {
765 IDirect3DSurface9 *source;
766 result = mTexture->GetSurfaceLevel(i, &source);
767
768 if (FAILED(result))
769 {
770 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
771
772 texture->Release();
773
774 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
775 }
776
777 IDirect3DSurface9 *dest;
778 result = texture->GetSurfaceLevel(i, &dest);
779
780 if (FAILED(result))
781 {
782 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
783
784 texture->Release();
785 source->Release();
786
787 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
788 }
789
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000790 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000791 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
792
793 if (FAILED(result))
794 {
795 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
796
797 texture->Release();
798 source->Release();
799 dest->Release();
800
801 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
802 }
803
804 source->Release();
805 dest->Release();
806 }
807 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000808 }
809
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000810 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000811 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000812 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000813 }
814
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000815 mTexture = texture;
816 return mTexture;
817}
818
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000819bool Texture2D::dirtyImageData() const
820{
821 int q = log2(std::max(mWidth, mHeight));
822
823 for (int i = 0; i <= q; i++)
824 {
825 if (mImageArray[i].dirty) return true;
826 }
827
828 return false;
829}
830
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000831void Texture2D::generateMipmaps()
832{
833 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
834 {
835 return error(GL_INVALID_OPERATION);
836 }
837
838 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
839 unsigned int q = log2(std::max(mWidth, mHeight));
840 for (unsigned int i = 1; i <= q; i++)
841 {
842 if (mImageArray[i].surface != NULL)
843 {
844 mImageArray[i].surface->Release();
845 mImageArray[i].surface = NULL;
846 }
847
848 mImageArray[i].dirty = false;
849
850 mImageArray[i].format = mImageArray[0].format;
851 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
852 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
853 }
854
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000855 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000856
857 for (unsigned int i = 1; i <= q; i++)
858 {
859 IDirect3DSurface9 *upper = NULL;
860 IDirect3DSurface9 *lower = NULL;
861
862 mTexture->GetSurfaceLevel(i-1, &upper);
863 mTexture->GetSurfaceLevel(i, &lower);
864
865 if (upper != NULL && lower != NULL)
866 {
867 getBlitter()->boxFilter(upper, lower);
868 }
869
870 if (upper != NULL) upper->Release();
871 if (lower != NULL) lower->Release();
872 }
873}
874
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000875Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000876{
877 if (target != GL_TEXTURE_2D)
878 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000879 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000880 }
881
882 if (mColorbufferProxy == NULL)
883 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000884 mColorbufferProxy = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
885 mColorbufferProxy->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000886 }
887
888 return mColorbufferProxy;
889}
890
891IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
892{
893 ASSERT(target == GL_TEXTURE_2D);
894
895 needRenderTarget();
896
897 IDirect3DSurface9 *renderTarget = NULL;
898 mTexture->GetSurfaceLevel(0, &renderTarget);
899
900 return renderTarget;
901}
902
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000903TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000904{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000905 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000906
907 for (int i = 0; i < 6; i++)
908 {
909 mFaceProxies[i] = NULL;
910 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000911}
912
913TextureCubeMap::~TextureCubeMap()
914{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000915 for (int i = 0; i < 6; i++)
916 {
917 delete mFaceProxies[i];
918 }
919
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000920 if (mTexture)
921 {
922 mTexture->Release();
923 mTexture = NULL;
924 }
925}
926
927GLenum TextureCubeMap::getTarget() const
928{
929 return GL_TEXTURE_CUBE_MAP;
930}
931
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000932void 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 +0000933{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000934 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000935}
936
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000937void 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 +0000938{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000939 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000940}
941
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000942void 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 +0000943{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000944 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945}
946
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000947void TextureCubeMap::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 +0000948{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000949 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000950}
951
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000952void TextureCubeMap::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 +0000953{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000954 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000955}
956
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000957void TextureCubeMap::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 +0000958{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000959 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000960}
961
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000962void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
963{
964 int face = faceIndex(faceTarget);
965
966 ASSERT(mImageArray[face][level].surface != NULL);
967
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000968 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000969 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000970 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
971 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000972
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000973 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000974 {
975 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000976
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000977 RECT sourceRect;
978 sourceRect.left = xoffset;
979 sourceRect.top = yoffset;
980 sourceRect.right = xoffset + width;
981 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000982
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000983 POINT destPoint;
984 destPoint.x = xoffset;
985 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000986
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000987 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000988 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000989
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000990 destLevel->Release();
991
992 img->dirty = false;
993 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000994 }
995}
996
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000997void 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 +0000998{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000999 Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001000 commitRect(face, level, xoffset, yoffset, width, height);
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001001}
1002
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001003// 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 +00001004bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001005{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001006 int size = mImageArray[0][0].width;
1007
1008 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001009 {
1010 return false;
1011 }
1012
1013 bool mipmapping;
1014
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001015 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001016 {
1017 case GL_NEAREST:
1018 case GL_LINEAR:
1019 mipmapping = false;
1020 break;
1021 case GL_NEAREST_MIPMAP_NEAREST:
1022 case GL_LINEAR_MIPMAP_NEAREST:
1023 case GL_NEAREST_MIPMAP_LINEAR:
1024 case GL_LINEAR_MIPMAP_LINEAR:
1025 mipmapping = true;
1026 break;
1027 default: UNREACHABLE();
1028 }
1029
1030 for (int face = 0; face < 6; face++)
1031 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001032 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001033 {
1034 return false;
1035 }
1036 }
1037
1038 if (mipmapping)
1039 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001040 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1041 {
1042 return false;
1043 }
1044
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001045 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001046
1047 for (int face = 0; face < 6; face++)
1048 {
1049 for (int level = 1; level <= q; level++)
1050 {
1051 if (mImageArray[face][level].format != mImageArray[0][0].format)
1052 {
1053 return false;
1054 }
1055
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001056 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001057 {
1058 return false;
1059 }
1060
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001061 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001062 }
1063 }
1064 }
1065
1066 return true;
1067}
1068
1069// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001070IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001071{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001072 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001073 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001074
1075 IDirect3DCubeTexture9 *texture;
1076
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001077 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001078
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001079 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001080 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001081 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001082 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001083 }
1084
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001085 if (mTexture) mTexture->Release();
1086
1087 mTexture = texture;
1088 return mTexture;
1089}
1090
1091void TextureCubeMap::updateTexture()
1092{
1093 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001094
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001095 for (int face = 0; face < 6; face++)
1096 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001097 int levels = levelCount();
1098 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001099 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001100 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001101
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001102 if (img->dirty)
1103 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001104 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1105 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001106
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001107 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001108 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001109 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001110 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001111
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001112 levelSurface->Release();
1113
1114 img->dirty = false;
1115 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001116 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001117 }
1118 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001119}
1120
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001121IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1122{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001123 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001124
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001125 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001126 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001127 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001128 IDirect3DDevice9 *device = getDevice();
1129 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
1130
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001131 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001132
1133 if (FAILED(result))
1134 {
1135 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1136 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1137 }
1138
1139 if (mTexture != NULL)
1140 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001141 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001142 for (int f = 0; f < 6; f++)
1143 {
1144 for (int i = 0; i < levels; i++)
1145 {
1146 IDirect3DSurface9 *source;
1147 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1148
1149 if (FAILED(result))
1150 {
1151 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1152
1153 texture->Release();
1154
1155 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1156 }
1157
1158 IDirect3DSurface9 *dest;
1159 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1160
1161 if (FAILED(result))
1162 {
1163 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1164
1165 texture->Release();
1166 source->Release();
1167
1168 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1169 }
1170
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001171 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001172 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1173
1174 if (FAILED(result))
1175 {
1176 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1177
1178 texture->Release();
1179 source->Release();
1180 dest->Release();
1181
1182 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1183 }
1184 }
1185 }
1186 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001187 }
1188
1189 if (mTexture != NULL)
1190 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001191 mTexture->Release();
1192 }
1193
1194 mTexture = texture;
1195 return mTexture;
1196}
1197
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001198void 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 +00001199{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001200 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001201
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001202 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001203}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001204
1205unsigned int TextureCubeMap::faceIndex(GLenum face)
1206{
1207 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1208 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1209 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1210 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1211 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1212
1213 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1214}
1215
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001216bool TextureCubeMap::dirtyImageData() const
1217{
1218 int q = log2(mWidth);
1219
1220 for (int f = 0; f < 6; f++)
1221 {
1222 for (int i = 0; i <= q; i++)
1223 {
1224 if (mImageArray[f][i].dirty) return true;
1225 }
1226 }
1227
1228 return false;
1229}
1230
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001231// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1232// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1233// Call this when a particular level of the texture must be defined with a specific format, width and height.
1234//
1235// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1236// a new size for the texture by working backwards from the given size.
1237bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1238{
1239 // Are these settings compatible with level 0?
1240 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1241
1242 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1243
1244 if (!textureOkay)
1245 {
1246 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1247 mImageArray[0][0].format, mImageArray[0][0].width,
1248 internalFormat, width);
1249
1250 // Purge all the levels and the texture.
1251 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1252 {
1253 for (int f = 0; f < 6; f++)
1254 {
1255 if (mImageArray[f][i].surface != NULL)
1256 {
1257 mImageArray[f][i].dirty = false;
1258
1259 mImageArray[f][i].surface->Release();
1260 mImageArray[f][i].surface = NULL;
1261 }
1262 }
1263 }
1264
1265 if (mTexture != NULL)
1266 {
1267 mTexture->Release();
1268 mTexture = NULL;
1269 dropTexture();
1270 }
1271
1272 mWidth = width << level;
1273 mImageArray[0][0].width = width << level;
1274 mHeight = width << level;
1275 mImageArray[0][0].height = width << level;
1276
1277 mImageArray[0][0].format = internalFormat;
1278 }
1279
1280 return !textureOkay;
1281}
1282
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001283void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001284{
1285 unsigned int faceindex = faceIndex(face);
1286
1287 if (redefineTexture(level, internalFormat, width))
1288 {
1289 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001290 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001291 }
1292
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001293 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001294
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001295 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001296 {
1297 RECT sourceRect;
1298 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001299 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001300 sourceRect.top = y;
1301 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001302
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001303 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1304
1305 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1306 dest->Release();
1307 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001308
1309 mImageArray[faceindex][level].width = width;
1310 mImageArray[faceindex][level].height = height;
1311 mImageArray[faceindex][level].format = internalFormat;
1312}
1313
1314IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1315{
1316 unsigned int faceIndex;
1317
1318 if (faceIdentifier < 6)
1319 {
1320 faceIndex = faceIdentifier;
1321 }
1322 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1323 {
1324 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1325 }
1326 else
1327 {
1328 UNREACHABLE();
1329 faceIndex = 0;
1330 }
1331
1332 if (mTexture == NULL)
1333 {
1334 UNREACHABLE();
1335 return NULL;
1336 }
1337
1338 IDirect3DSurface9 *surface = NULL;
1339
1340 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1341
1342 return (SUCCEEDED(hr)) ? surface : NULL;
1343}
1344
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001345void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001346{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001347 GLsizei size = mImageArray[faceIndex(face)][level].width;
1348
1349 if (xoffset + width > size || yoffset + height > size)
1350 {
1351 return error(GL_INVALID_VALUE);
1352 }
1353
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001354 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1355 {
1356 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001357 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001358 }
1359 else
1360 {
1361 getRenderTarget(face);
1362 }
1363
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001364 if (level < levelCount())
1365 {
1366 RECT sourceRect;
1367 sourceRect.left = x;
1368 sourceRect.right = x + width;
1369 sourceRect.top = y;
1370 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001371
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001372 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001373
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001374 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1375 dest->Release();
1376 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001377}
1378
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001379bool TextureCubeMap::isCubeComplete() const
1380{
1381 if (mImageArray[0][0].width == 0)
1382 {
1383 return false;
1384 }
1385
1386 for (unsigned int f = 1; f < 6; f++)
1387 {
1388 if (mImageArray[f][0].width != mImageArray[0][0].width
1389 || mImageArray[f][0].format != mImageArray[0][0].format)
1390 {
1391 return false;
1392 }
1393 }
1394
1395 return true;
1396}
1397
1398void TextureCubeMap::generateMipmaps()
1399{
1400 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1401 {
1402 return error(GL_INVALID_OPERATION);
1403 }
1404
1405 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1406 unsigned int q = log2(mImageArray[0][0].width);
1407 for (unsigned int f = 0; f < 6; f++)
1408 {
1409 for (unsigned int i = 1; i <= q; i++)
1410 {
1411 if (mImageArray[f][i].surface != NULL)
1412 {
1413 mImageArray[f][i].surface->Release();
1414 mImageArray[f][i].surface = NULL;
1415 }
1416
1417 mImageArray[f][i].dirty = false;
1418
1419 mImageArray[f][i].format = mImageArray[f][0].format;
1420 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1421 mImageArray[f][i].height = mImageArray[f][i].width;
1422 }
1423 }
1424
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001425 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001426
1427 for (unsigned int f = 0; f < 6; f++)
1428 {
1429 for (unsigned int i = 1; i <= q; i++)
1430 {
1431 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1432 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1433
1434 if (upper != NULL && lower != NULL)
1435 {
1436 getBlitter()->boxFilter(upper, lower);
1437 }
1438
1439 if (upper != NULL) upper->Release();
1440 if (lower != NULL) lower->Release();
1441 }
1442 }
1443}
1444
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001445Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001446{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001447 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001448 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001449 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001450 }
1451
1452 unsigned int face = faceIndex(target);
1453
1454 if (mFaceProxies[face] == NULL)
1455 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001456 mFaceProxies[face] = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1457 mFaceProxies[face]->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001458 }
1459
1460 return mFaceProxies[face];
1461}
1462
1463IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1464{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001465 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001466
1467 needRenderTarget();
1468
1469 IDirect3DSurface9 *renderTarget = NULL;
1470 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
1471
1472 return renderTarget;
1473}
1474
1475Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
1476 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
1477{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001478 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001479}
1480
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001481void Texture::TextureColorbufferProxy::addRef() const
1482{
1483 mTexture->addRef();
1484}
1485
1486void Texture::TextureColorbufferProxy::release() const
1487{
1488 mTexture->release();
1489}
1490
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001491IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
1492{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001493 if (mRenderTarget) mRenderTarget->Release();
1494
1495 mRenderTarget = mTexture->getRenderTarget(mTarget);
1496
1497 return mRenderTarget;
1498}
1499
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001500int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001501{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001502 return mTexture->getWidth();
1503}
1504
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001505int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001506{
1507 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001508}
1509
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001510}