blob: 031cbbfd1ea1d525a07d19070898ba4173ab7591 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/Texture.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
daniel@transgaming.com16973022010-03-11 19:22:19 +000013#include <algorithm>
14
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000015#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/mathutil.h"
19#include "libGLESv2/utilities.h"
20#include "libGLESv2/Blit.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021
22namespace gl
23{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000024
25Texture::Image::Image()
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000026 : width(0), height(0), dirty(false), surface(NULL)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000027{
28}
29
30Texture::Image::~Image()
31{
32 if (surface) surface->Release();
33}
34
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000035Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036{
37 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
38 mMagFilter = GL_LINEAR;
39 mWrapS = GL_REPEAT;
40 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000041
daniel@transgaming.com31273552010-08-04 13:42:44 +000042 mWidth = 0;
43 mHeight = 0;
44
daniel@transgaming.com00c75962010-03-11 20:36:15 +000045 mDirtyMetaData = true;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000046 mDirty = true;
daniel@transgaming.com93a81472010-04-20 18:52:58 +000047 mIsRenderable = false;
daniel@transgaming.com0a311a42010-05-17 09:58:33 +000048 mBaseTexture = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000049}
50
51Texture::~Texture()
52{
53}
54
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000055Blit *Texture::getBlitter()
56{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000057 Context *context = getContext();
58 return context->getBlitter();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000059}
60
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000061// Returns true on successful filter state update (valid enum parameter)
62bool Texture::setMinFilter(GLenum filter)
63{
64 switch (filter)
65 {
66 case GL_NEAREST:
67 case GL_LINEAR:
68 case GL_NEAREST_MIPMAP_NEAREST:
69 case GL_LINEAR_MIPMAP_NEAREST:
70 case GL_NEAREST_MIPMAP_LINEAR:
71 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000072 {
73 if (mMinFilter != filter)
74 {
75 mMinFilter = filter;
76 mDirty = true;
77 }
78 return true;
79 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080 default:
81 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000082 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000083}
84
85// Returns true on successful filter state update (valid enum parameter)
86bool Texture::setMagFilter(GLenum filter)
87{
88 switch (filter)
89 {
90 case GL_NEAREST:
91 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000092 {
93 if (mMagFilter != filter)
94 {
95 mMagFilter = filter;
96 mDirty = true;
97 }
98 return true;
99 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100 default:
101 return false;
102 }
103}
104
105// Returns true on successful wrap state update (valid enum parameter)
106bool Texture::setWrapS(GLenum wrap)
107{
108 switch (wrap)
109 {
110 case GL_REPEAT:
111 case GL_CLAMP_TO_EDGE:
112 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000113 {
114 if (mWrapS != wrap)
115 {
116 mWrapS = wrap;
117 mDirty = true;
118 }
119 return true;
120 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000121 default:
122 return false;
123 }
124}
125
126// Returns true on successful wrap state update (valid enum parameter)
127bool Texture::setWrapT(GLenum wrap)
128{
129 switch (wrap)
130 {
131 case GL_REPEAT:
132 case GL_CLAMP_TO_EDGE:
133 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000134 {
135 if (mWrapT != wrap)
136 {
137 mWrapT = wrap;
138 mDirty = true;
139 }
140 return true;
141 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142 default:
143 return false;
144 }
145}
146
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000147GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148{
149 return mMinFilter;
150}
151
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000152GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000153{
154 return mMagFilter;
155}
156
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000157GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158{
159 return mWrapS;
160}
161
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000162GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163{
164 return mWrapT;
165}
166
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000167GLuint Texture::getWidth() const
168{
169 return mWidth;
170}
171
172GLuint Texture::getHeight() const
173{
174 return mHeight;
175}
176
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000178D3DFORMAT Texture::selectFormat(GLenum format)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000180 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181}
182
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000183int Texture::imagePitch(const Image &img) const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184{
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000185 return img.width * 4;
186}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000187
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000188// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
189// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
190void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000191 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000192{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000193 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000194
195 for (int y = 0; y < height; y++)
196 {
197 const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch;
198 const unsigned short *source16 = reinterpret_cast<const unsigned short*>(source);
199 unsigned char *dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
200
daniel@transgaming.coma9198d92010-08-08 04:49:56 +0000201 // fast path for EXT_texture_format_BGRA8888
202 if (format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE) {
203 memcpy(dest, source, width*4);
204 continue;
205 }
206
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000207 for (int x = 0; x < width; x++)
208 {
209 unsigned char r;
210 unsigned char g;
211 unsigned char b;
212 unsigned char a;
213
214 switch (format)
215 {
216 case GL_ALPHA:
217 a = source[x];
218 r = 0;
219 g = 0;
220 b = 0;
221 break;
222
223 case GL_LUMINANCE:
224 r = source[x];
225 g = source[x];
226 b = source[x];
227 a = 0xFF;
228 break;
229
230 case GL_LUMINANCE_ALPHA:
231 r = source[2*x+0];
232 g = source[2*x+0];
233 b = source[2*x+0];
234 a = source[2*x+1];
235 break;
236
237 case GL_RGB:
238 switch (type)
239 {
240 case GL_UNSIGNED_BYTE:
241 r = source[x * 3 + 0];
daniel@transgaming.com5ac52152010-04-13 19:53:38 +0000242 g = source[x * 3 + 1];
243 b = source[x * 3 + 2];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000244 a = 0xFF;
245 break;
246
247 case GL_UNSIGNED_SHORT_5_6_5:
248 {
249 unsigned short rgba = source16[x];
250
251 a = 0xFF;
252 b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
253 g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
254 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
255 }
256 break;
257
258 default: UNREACHABLE();
259 }
260 break;
261
262 case GL_RGBA:
263 switch (type)
264 {
265 case GL_UNSIGNED_BYTE:
266 r = source[x * 4 + 0];
267 g = source[x * 4 + 1];
268 b = source[x * 4 + 2];
269 a = source[x * 4 + 3];
270 break;
271
272 case GL_UNSIGNED_SHORT_4_4_4_4:
273 {
274 unsigned short rgba = source16[x];
275
276 a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
277 b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
278 g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
279 r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
280 }
281 break;
282
283 case GL_UNSIGNED_SHORT_5_5_5_1:
284 {
285 unsigned short rgba = source16[x];
286
287 a = (rgba & 0x0001) ? 0xFF : 0;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000288 b = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000289 g = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000290 r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000291 }
292 break;
293
294 default: UNREACHABLE();
295 }
296 break;
297 default: UNREACHABLE();
298 }
299
300 dest[4 * x + 0] = b;
301 dest[4 * x + 1] = g;
302 dest[4 * x + 2] = r;
303 dest[4 * x + 3] = a;
304 }
305 }
306}
307
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000308void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000309{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000310 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000311 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000312
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000313 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000314 {
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000315 //HRESULT result = getDevice()->CreateOffscreenPlainSurface(width, height, selectFormat(format), D3DPOOL_SYSTEMMEM, &newSurface, NULL);
316 HRESULT result = getDevice()->CreateTexture(width, height, 1, NULL, selectFormat(format), D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000317
318 if (FAILED(result))
319 {
320 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
321 return error(GL_OUT_OF_MEMORY);
322 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000323
324 newTexture->GetSurfaceLevel(0, &newSurface);
325 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000326 }
327
328 if (img->surface) img->surface->Release();
329 img->surface = newSurface;
330
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000331 img->width = width;
332 img->height = height;
333 img->format = format;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000334
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000335 if (pixels != NULL && newSurface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000337 D3DLOCKED_RECT locked;
338 HRESULT result = newSurface->LockRect(&locked, NULL, 0);
339
340 ASSERT(SUCCEEDED(result));
341
342 if (SUCCEEDED(result))
343 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000344 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000345 newSurface->UnlockRect();
346 }
347
348 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349 }
350
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000351 mDirtyMetaData = true;
352}
353
daniel@transgaming.com31273552010-08-04 13:42:44 +0000354bool 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 +0000355{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000356 if (width + xoffset > img->width || height + yoffset > img->height)
357 {
358 error(GL_INVALID_VALUE);
359 return false;
360 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000361
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000362 D3DLOCKED_RECT locked;
363 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000364
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000365 ASSERT(SUCCEEDED(result));
366
367 if (SUCCEEDED(result))
368 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000369 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000370 img->surface->UnlockRect();
371 }
372
373 img->dirty = true;
daniel@transgaming.com31273552010-08-04 13:42:44 +0000374 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000375}
376
377IDirect3DBaseTexture9 *Texture::getTexture()
378{
379 if (!isComplete())
380 {
381 return NULL;
382 }
383
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000384 if (mDirtyMetaData)
385 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000386 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000387 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000388 }
389
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000390 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000391 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000392 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000393 }
394
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000395 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000396 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000397
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000398 return mBaseTexture;
399}
400
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000401bool Texture::isDirty() const
402{
403 return (mDirty || mDirtyMetaData || dirtyImageData());
404}
405
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000406// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000407void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000408{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000409 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000410 {
411 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000412 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000413 }
414
415 if (dirtyImageData())
416 {
417 updateTexture();
418 }
419
420 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000421}
422
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000423void Texture::dropTexture()
424{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000425 if (mBaseTexture)
426 {
427 mBaseTexture = NULL;
428 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000429
430 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000431}
432
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000433void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000434{
435 mBaseTexture = newTexture;
436 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000437 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000438 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000439}
440
441
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000442GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
443{
444 if (isPow2(width) && isPow2(height))
445 {
446 return maxlevel;
447 }
448 else
449 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000450 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
451 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000452 }
453}
454
455GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
456{
457 return creationLevels(size, size, maxlevel);
458}
459
460int Texture::levelCount() const
461{
462 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
463}
464
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000465Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000466{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000468 mColorbufferProxy = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000469}
470
471Texture2D::~Texture2D()
472{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000473 delete mColorbufferProxy;
474
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475 if (mTexture)
476 {
477 mTexture->Release();
478 mTexture = NULL;
479 }
480}
481
482GLenum Texture2D::getTarget() const
483{
484 return GL_TEXTURE_2D;
485}
486
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000487// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
488// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
489// Call this when a particular level of the texture must be defined with a specific format, width and height.
490//
491// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
492// a new height and width for the texture by working backwards from the given width and height.
493bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height)
494{
495 bool widthOkay = (mWidth >> level == width);
496 bool heightOkay = (mHeight >> level == height);
497
498 bool sizeOkay = ((widthOkay && heightOkay)
499 || (widthOkay && mHeight >> level == 0 && height == 1)
500 || (heightOkay && mWidth >> level == 0 && width == 1));
501
502 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0].format);
503
504 if (!textureOkay)
505 {
506 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
507 mImageArray[0].format, mWidth, mHeight,
508 internalFormat, width, height);
509
510 // Purge all the levels and the texture.
511
512 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
513 {
514 if (mImageArray[i].surface != NULL)
515 {
516 mImageArray[i].dirty = false;
517
518 mImageArray[i].surface->Release();
519 mImageArray[i].surface = NULL;
520 }
521 }
522
523 if (mTexture != NULL)
524 {
525 mTexture->Release();
526 mTexture = NULL;
527 dropTexture();
528 }
529
530 mWidth = width << level;
531 mHeight = height << level;
532 mImageArray[0].format = internalFormat;
533 }
534
535 return !textureOkay;
536}
537
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000538void 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 +0000539{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000540 redefineTexture(level, internalFormat, width, height);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000541
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000542 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000543}
544
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000545void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
546{
547 ASSERT(mImageArray[level].surface != NULL);
548
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000549 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000550 {
551 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000552 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000553
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000554 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000555
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000556 if (SUCCEEDED(result))
557 {
558 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000559
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000560 RECT sourceRect;
561 sourceRect.left = xoffset;
562 sourceRect.top = yoffset;
563 sourceRect.right = xoffset + width;
564 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000565
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000566 POINT destPoint;
567 destPoint.x = xoffset;
568 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000569
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000570 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
571 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000572
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000573 destLevel->Release();
574
575 img->dirty = false;
576 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000577 }
578}
579
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000580void 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 +0000581{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000582 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
583 {
584 commitRect(level, xoffset, yoffset, width, height);
585 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000586}
587
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000588void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000589{
590 if (redefineTexture(level, internalFormat, width, height))
591 {
592 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000593 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000594 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +0000595 else
596 {
597 needRenderTarget();
598 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000599
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000600 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000601 {
602 RECT sourceRect;
603 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000604 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +0000605 sourceRect.top = y;
606 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000607
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000608 IDirect3DSurface9 *dest;
609 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000610
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000611 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
612 dest->Release();
613 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000614
615 mImageArray[level].width = width;
616 mImageArray[level].height = height;
617 mImageArray[level].format = internalFormat;
618}
619
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000620void 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 +0000621{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000622 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
623 {
624 return error(GL_INVALID_VALUE);
625 }
626
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000627 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height))
628 {
629 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000630 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000631 }
632 else
633 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +0000634 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000635 }
636
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000637 if (level < levelCount())
638 {
639 RECT sourceRect;
640 sourceRect.left = x;
641 sourceRect.right = x + width;
642 sourceRect.top = y;
643 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000644
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000645 IDirect3DSurface9 *dest;
646 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000647
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000648 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
649 dest->Release();
650 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000651}
652
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000653// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
654bool Texture2D::isComplete() const
655{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000656 GLsizei width = mImageArray[0].width;
657 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000658
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000659 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000660 {
661 return false;
662 }
663
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000664 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000665
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000666 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000667 {
668 case GL_NEAREST:
669 case GL_LINEAR:
670 mipmapping = false;
671 break;
672 case GL_NEAREST_MIPMAP_NEAREST:
673 case GL_LINEAR_MIPMAP_NEAREST:
674 case GL_NEAREST_MIPMAP_LINEAR:
675 case GL_LINEAR_MIPMAP_LINEAR:
676 mipmapping = true;
677 break;
678 default: UNREACHABLE();
679 }
680
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000681 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
682 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
683 {
684 return false;
685 }
686
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000687 if (mipmapping)
688 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000689 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000690 {
691 return false;
692 }
693
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000694 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000695
696 for (int level = 1; level <= q; level++)
697 {
698 if (mImageArray[level].format != mImageArray[0].format)
699 {
700 return false;
701 }
702
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000703 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000704 {
705 return false;
706 }
707
daniel@transgaming.comd99bd452010-04-22 13:35:25 +0000708 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000709 {
710 return false;
711 }
712 }
713 }
714
715 return true;
716}
717
718// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000719IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000720{
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000721 IDirect3DTexture9 *texture;
722
723 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000724 D3DFORMAT format = selectFormat(mImageArray[0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000725
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000726 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000727
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000728 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000729 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000730 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000731 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000732 }
733
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000734 if (mTexture) mTexture->Release();
735 mTexture = texture;
736 return texture;
737}
738
739void Texture2D::updateTexture()
740{
741 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000742
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000743 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000744
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000745 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000746 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000747 if (mImageArray[level].dirty)
748 {
749 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000750 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000751
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000752 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000753
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000754 if (SUCCEEDED(result))
755 {
756 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
757 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000758
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000759 levelSurface->Release();
760
761 mImageArray[level].dirty = false;
762 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000763 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000764 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000765}
766
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000767IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000768{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000769 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000770
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000771 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000772 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000773 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000774 IDirect3DDevice9 *device = getDevice();
775 D3DFORMAT format = selectFormat(mImageArray[0].format);
776
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000777 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 +0000778
779 if (FAILED(result))
780 {
781 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
782 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
783 }
784
785 if (mTexture != NULL)
786 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000787 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000788 for (int i = 0; i < levels; i++)
789 {
790 IDirect3DSurface9 *source;
791 result = mTexture->GetSurfaceLevel(i, &source);
792
793 if (FAILED(result))
794 {
795 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
796
797 texture->Release();
798
799 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
800 }
801
802 IDirect3DSurface9 *dest;
803 result = texture->GetSurfaceLevel(i, &dest);
804
805 if (FAILED(result))
806 {
807 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
808
809 texture->Release();
810 source->Release();
811
812 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
813 }
814
daniel@transgaming.comae072af2010-05-05 18:47:28 +0000815 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000816 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
817
818 if (FAILED(result))
819 {
820 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
821
822 texture->Release();
823 source->Release();
824 dest->Release();
825
826 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
827 }
828
829 source->Release();
830 dest->Release();
831 }
832 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000833 }
834
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000835 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000836 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000837 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000838 }
839
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000840 mTexture = texture;
841 return mTexture;
842}
843
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000844bool Texture2D::dirtyImageData() const
845{
846 int q = log2(std::max(mWidth, mHeight));
847
848 for (int i = 0; i <= q; i++)
849 {
850 if (mImageArray[i].dirty) return true;
851 }
852
853 return false;
854}
855
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000856void Texture2D::generateMipmaps()
857{
858 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
859 {
860 return error(GL_INVALID_OPERATION);
861 }
862
863 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
864 unsigned int q = log2(std::max(mWidth, mHeight));
865 for (unsigned int i = 1; i <= q; i++)
866 {
867 if (mImageArray[i].surface != NULL)
868 {
869 mImageArray[i].surface->Release();
870 mImageArray[i].surface = NULL;
871 }
872
873 mImageArray[i].dirty = false;
874
875 mImageArray[i].format = mImageArray[0].format;
876 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
877 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
878 }
879
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000880 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +0000881
882 for (unsigned int i = 1; i <= q; i++)
883 {
884 IDirect3DSurface9 *upper = NULL;
885 IDirect3DSurface9 *lower = NULL;
886
887 mTexture->GetSurfaceLevel(i-1, &upper);
888 mTexture->GetSurfaceLevel(i, &lower);
889
890 if (upper != NULL && lower != NULL)
891 {
892 getBlitter()->boxFilter(upper, lower);
893 }
894
895 if (upper != NULL) upper->Release();
896 if (lower != NULL) lower->Release();
897 }
898}
899
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000900Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000901{
902 if (target != GL_TEXTURE_2D)
903 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000904 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000905 }
906
907 if (mColorbufferProxy == NULL)
908 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000909 mColorbufferProxy = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
910 mColorbufferProxy->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000911 }
912
913 return mColorbufferProxy;
914}
915
916IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
917{
918 ASSERT(target == GL_TEXTURE_2D);
919
920 needRenderTarget();
921
922 IDirect3DSurface9 *renderTarget = NULL;
923 mTexture->GetSurfaceLevel(0, &renderTarget);
924
925 return renderTarget;
926}
927
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000928TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000929{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000930 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000931
932 for (int i = 0; i < 6; i++)
933 {
934 mFaceProxies[i] = NULL;
935 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000936}
937
938TextureCubeMap::~TextureCubeMap()
939{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000940 for (int i = 0; i < 6; i++)
941 {
942 delete mFaceProxies[i];
943 }
944
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945 if (mTexture)
946 {
947 mTexture->Release();
948 mTexture = NULL;
949 }
950}
951
952GLenum TextureCubeMap::getTarget() const
953{
954 return GL_TEXTURE_CUBE_MAP;
955}
956
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000957void 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 +0000958{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000959 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000960}
961
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000962void TextureCubeMap::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 +0000963{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000964 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000965}
966
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000967void TextureCubeMap::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 +0000968{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000969 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000970}
971
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000972void TextureCubeMap::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 +0000973{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000974 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000975}
976
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000977void TextureCubeMap::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 +0000978{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000979 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000980}
981
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000982void 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 +0000983{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000984 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000985}
986
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000987void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
988{
989 int face = faceIndex(faceTarget);
990
991 ASSERT(mImageArray[face][level].surface != NULL);
992
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000993 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000994 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000995 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
996 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000997
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000998 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000999 {
1000 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001001
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001002 RECT sourceRect;
1003 sourceRect.left = xoffset;
1004 sourceRect.top = yoffset;
1005 sourceRect.right = xoffset + width;
1006 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001007
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001008 POINT destPoint;
1009 destPoint.x = xoffset;
1010 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001011
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001012 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001013 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001014
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001015 destLevel->Release();
1016
1017 img->dirty = false;
1018 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001019 }
1020}
1021
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001022void 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 +00001023{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001024 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1025 {
1026 commitRect(face, level, xoffset, yoffset, width, height);
1027 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001028}
1029
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001030// 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 +00001031bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001032{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001033 int size = mImageArray[0][0].width;
1034
1035 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001036 {
1037 return false;
1038 }
1039
1040 bool mipmapping;
1041
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001042 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001043 {
1044 case GL_NEAREST:
1045 case GL_LINEAR:
1046 mipmapping = false;
1047 break;
1048 case GL_NEAREST_MIPMAP_NEAREST:
1049 case GL_LINEAR_MIPMAP_NEAREST:
1050 case GL_NEAREST_MIPMAP_LINEAR:
1051 case GL_LINEAR_MIPMAP_LINEAR:
1052 mipmapping = true;
1053 break;
1054 default: UNREACHABLE();
1055 }
1056
1057 for (int face = 0; face < 6; face++)
1058 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001059 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001060 {
1061 return false;
1062 }
1063 }
1064
1065 if (mipmapping)
1066 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001067 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1068 {
1069 return false;
1070 }
1071
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001072 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001073
1074 for (int face = 0; face < 6; face++)
1075 {
1076 for (int level = 1; level <= q; level++)
1077 {
1078 if (mImageArray[face][level].format != mImageArray[0][0].format)
1079 {
1080 return false;
1081 }
1082
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001083 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001084 {
1085 return false;
1086 }
1087
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001088 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001089 }
1090 }
1091 }
1092
1093 return true;
1094}
1095
1096// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001097IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001098{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001099 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001100 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001101
1102 IDirect3DCubeTexture9 *texture;
1103
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001104 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001105
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001106 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001107 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001108 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001109 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001110 }
1111
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001112 if (mTexture) mTexture->Release();
1113
1114 mTexture = texture;
1115 return mTexture;
1116}
1117
1118void TextureCubeMap::updateTexture()
1119{
1120 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001121
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001122 for (int face = 0; face < 6; face++)
1123 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001124 int levels = levelCount();
1125 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001126 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001127 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001128
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001129 if (img->dirty)
1130 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001131 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1132 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001133
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001134 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001135 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001136 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001137 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001138
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001139 levelSurface->Release();
1140
1141 img->dirty = false;
1142 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001143 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001144 }
1145 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001146}
1147
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001148IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1149{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001150 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001151
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001152 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001153 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001154 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001155 IDirect3DDevice9 *device = getDevice();
1156 D3DFORMAT format = selectFormat(mImageArray[0][0].format);
1157
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001158 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001159
1160 if (FAILED(result))
1161 {
1162 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1163 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1164 }
1165
1166 if (mTexture != NULL)
1167 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001168 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001169 for (int f = 0; f < 6; f++)
1170 {
1171 for (int i = 0; i < levels; i++)
1172 {
1173 IDirect3DSurface9 *source;
1174 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1175
1176 if (FAILED(result))
1177 {
1178 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1179
1180 texture->Release();
1181
1182 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1183 }
1184
1185 IDirect3DSurface9 *dest;
1186 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1187
1188 if (FAILED(result))
1189 {
1190 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1191
1192 texture->Release();
1193 source->Release();
1194
1195 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1196 }
1197
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001198 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001199 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1200
1201 if (FAILED(result))
1202 {
1203 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1204
1205 texture->Release();
1206 source->Release();
1207 dest->Release();
1208
1209 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1210 }
1211 }
1212 }
1213 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001214 }
1215
1216 if (mTexture != NULL)
1217 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001218 mTexture->Release();
1219 }
1220
1221 mTexture = texture;
1222 return mTexture;
1223}
1224
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001225void 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 +00001226{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001227 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001228
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001229 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001230}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001231
1232unsigned int TextureCubeMap::faceIndex(GLenum face)
1233{
1234 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1235 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1236 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1237 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1238 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1239
1240 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1241}
1242
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001243bool TextureCubeMap::dirtyImageData() const
1244{
1245 int q = log2(mWidth);
1246
1247 for (int f = 0; f < 6; f++)
1248 {
1249 for (int i = 0; i <= q; i++)
1250 {
1251 if (mImageArray[f][i].dirty) return true;
1252 }
1253 }
1254
1255 return false;
1256}
1257
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001258// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1259// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1260// Call this when a particular level of the texture must be defined with a specific format, width and height.
1261//
1262// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1263// a new size for the texture by working backwards from the given size.
1264bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1265{
1266 // Are these settings compatible with level 0?
1267 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1268
1269 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1270
1271 if (!textureOkay)
1272 {
1273 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1274 mImageArray[0][0].format, mImageArray[0][0].width,
1275 internalFormat, width);
1276
1277 // Purge all the levels and the texture.
1278 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1279 {
1280 for (int f = 0; f < 6; f++)
1281 {
1282 if (mImageArray[f][i].surface != NULL)
1283 {
1284 mImageArray[f][i].dirty = false;
1285
1286 mImageArray[f][i].surface->Release();
1287 mImageArray[f][i].surface = NULL;
1288 }
1289 }
1290 }
1291
1292 if (mTexture != NULL)
1293 {
1294 mTexture->Release();
1295 mTexture = NULL;
1296 dropTexture();
1297 }
1298
1299 mWidth = width << level;
1300 mImageArray[0][0].width = width << level;
1301 mHeight = width << level;
1302 mImageArray[0][0].height = width << level;
1303
1304 mImageArray[0][0].format = internalFormat;
1305 }
1306
1307 return !textureOkay;
1308}
1309
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001310void 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 +00001311{
1312 unsigned int faceindex = faceIndex(face);
1313
1314 if (redefineTexture(level, internalFormat, width))
1315 {
1316 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001317 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001318 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001319 else
1320 {
1321 needRenderTarget();
1322 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001323
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001324 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001325
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001326 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001327 {
1328 RECT sourceRect;
1329 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001330 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001331 sourceRect.top = y;
1332 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001333
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001334 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1335
1336 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1337 dest->Release();
1338 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001339
1340 mImageArray[faceindex][level].width = width;
1341 mImageArray[faceindex][level].height = height;
1342 mImageArray[faceindex][level].format = internalFormat;
1343}
1344
1345IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1346{
1347 unsigned int faceIndex;
1348
1349 if (faceIdentifier < 6)
1350 {
1351 faceIndex = faceIdentifier;
1352 }
1353 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1354 {
1355 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1356 }
1357 else
1358 {
1359 UNREACHABLE();
1360 faceIndex = 0;
1361 }
1362
1363 if (mTexture == NULL)
1364 {
1365 UNREACHABLE();
1366 return NULL;
1367 }
1368
1369 IDirect3DSurface9 *surface = NULL;
1370
1371 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1372
1373 return (SUCCEEDED(hr)) ? surface : NULL;
1374}
1375
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001376void 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 +00001377{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001378 GLsizei size = mImageArray[faceIndex(face)][level].width;
1379
1380 if (xoffset + width > size || yoffset + height > size)
1381 {
1382 return error(GL_INVALID_VALUE);
1383 }
1384
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001385 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1386 {
1387 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001388 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001389 }
1390 else
1391 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001392 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001393 }
1394
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001395 if (level < levelCount())
1396 {
1397 RECT sourceRect;
1398 sourceRect.left = x;
1399 sourceRect.right = x + width;
1400 sourceRect.top = y;
1401 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001402
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001403 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001404
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001405 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1406 dest->Release();
1407 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001408}
1409
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001410bool TextureCubeMap::isCubeComplete() const
1411{
1412 if (mImageArray[0][0].width == 0)
1413 {
1414 return false;
1415 }
1416
1417 for (unsigned int f = 1; f < 6; f++)
1418 {
1419 if (mImageArray[f][0].width != mImageArray[0][0].width
1420 || mImageArray[f][0].format != mImageArray[0][0].format)
1421 {
1422 return false;
1423 }
1424 }
1425
1426 return true;
1427}
1428
1429void TextureCubeMap::generateMipmaps()
1430{
1431 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1432 {
1433 return error(GL_INVALID_OPERATION);
1434 }
1435
1436 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1437 unsigned int q = log2(mImageArray[0][0].width);
1438 for (unsigned int f = 0; f < 6; f++)
1439 {
1440 for (unsigned int i = 1; i <= q; i++)
1441 {
1442 if (mImageArray[f][i].surface != NULL)
1443 {
1444 mImageArray[f][i].surface->Release();
1445 mImageArray[f][i].surface = NULL;
1446 }
1447
1448 mImageArray[f][i].dirty = false;
1449
1450 mImageArray[f][i].format = mImageArray[f][0].format;
1451 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1452 mImageArray[f][i].height = mImageArray[f][i].width;
1453 }
1454 }
1455
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001456 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001457
1458 for (unsigned int f = 0; f < 6; f++)
1459 {
1460 for (unsigned int i = 1; i <= q; i++)
1461 {
1462 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1463 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1464
1465 if (upper != NULL && lower != NULL)
1466 {
1467 getBlitter()->boxFilter(upper, lower);
1468 }
1469
1470 if (upper != NULL) upper->Release();
1471 if (lower != NULL) lower->Release();
1472 }
1473 }
1474}
1475
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001476Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001477{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001478 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001479 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001480 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001481 }
1482
1483 unsigned int face = faceIndex(target);
1484
1485 if (mFaceProxies[face] == NULL)
1486 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001487 mFaceProxies[face] = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1488 mFaceProxies[face]->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001489 }
1490
1491 return mFaceProxies[face];
1492}
1493
1494IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
1495{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001496 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001497
1498 needRenderTarget();
1499
1500 IDirect3DSurface9 *renderTarget = NULL;
1501 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
1502
1503 return renderTarget;
1504}
1505
1506Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
1507 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
1508{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00001509 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001510}
1511
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001512void Texture::TextureColorbufferProxy::addRef() const
1513{
1514 mTexture->addRef();
1515}
1516
1517void Texture::TextureColorbufferProxy::release() const
1518{
1519 mTexture->release();
1520}
1521
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001522IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
1523{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001524 if (mRenderTarget) mRenderTarget->Release();
1525
1526 mRenderTarget = mTexture->getRenderTarget(mTarget);
1527
1528 return mRenderTarget;
1529}
1530
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001531int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001532{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001533 return mTexture->getWidth();
1534}
1535
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001536int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00001537{
1538 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001539}
1540
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001541}