blob: 6591e741029cfaec8be9420ab5efb60904e8f9de [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +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
11#include "libGLESv2/Texture.h"
12
13#include <d3dx9tex.h>
14
15#include <algorithm>
jbauman@chromium.orgf1f28c82011-05-12 20:53:34 +000016#include <intrin.h>
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000017
18#include "common/debug.h"
19
jbauman@chromium.orgae345802011-03-30 22:04:25 +000020#include "libEGL/Display.h"
21
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000022#include "libGLESv2/main.h"
23#include "libGLESv2/mathutil.h"
24#include "libGLESv2/utilities.h"
25#include "libGLESv2/Blit.h"
26#include "libGLESv2/Framebuffer.h"
27
28namespace gl
29{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000030unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000031
daniel@transgaming.comde631782011-11-09 17:45:04 +000032Image::Image()
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000033 : mWidth(0), mHeight(0), mDirty(false), mSurface(NULL), mFormat(GL_NONE), mType(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000034{
35}
36
daniel@transgaming.comde631782011-11-09 17:45:04 +000037Image::~Image()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000038{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000039 if (mSurface)
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000040 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000041 mSurface->Release();
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000042 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000043}
44
daniel@transgaming.com41634052011-11-09 17:46:24 +000045bool Image::redefine(GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000046{
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000047 if (mWidth != width ||
48 mHeight != height ||
49 mFormat != format ||
50 mType != type)
51 {
daniel@transgaming.com41634052011-11-09 17:46:24 +000052 mWidth = width;
53 mHeight = height;
54 mFormat = format;
55 mType = type;
56
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000057 if (mSurface)
58 {
59 mSurface->Release();
60 mSurface = NULL;
61 }
daniel@transgaming.com41634052011-11-09 17:46:24 +000062
63 return true;
daniel@transgaming.com4c0a7712011-11-09 17:45:19 +000064 }
65
daniel@transgaming.com41634052011-11-09 17:46:24 +000066 return false;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +000067}
68
69void Image::createSurface()
70{
71 if(mSurface)
72 {
73 return;
74 }
75
76 IDirect3DTexture9 *newTexture = NULL;
77 IDirect3DSurface9 *newSurface = NULL;
78
79 if (mWidth != 0 && mHeight != 0)
80 {
81 int levelToFetch = 0;
82 GLsizei requestWidth = mWidth;
83 GLsizei requestHeight = mHeight;
84 if (IsCompressed(mFormat) && (mWidth % 4 != 0 || mHeight % 4 != 0))
85 {
86 bool isMult4 = false;
87 int upsampleCount = 0;
88 while (!isMult4)
89 {
90 requestWidth <<= 1;
91 requestHeight <<= 1;
92 upsampleCount++;
93 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
94 {
95 isMult4 = true;
96 }
97 }
98 levelToFetch = upsampleCount;
99 }
100
101 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, getD3DFormat(),
102 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
103
104 if (FAILED(result))
105 {
106 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000107 ERR("Creating image surface failed.");
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000108 return error(GL_OUT_OF_MEMORY);
109 }
110
111 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
112 newTexture->Release();
113 }
114
115 mSurface = newSurface;
daniel@transgaming.com839fb9b2011-11-09 17:45:43 +0000116 mDirty = false;
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000117}
118
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +0000119HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
120{
121 createSurface();
122
123 HRESULT result = D3DERR_INVALIDCALL;
124
125 if (mSurface)
126 {
127 result = mSurface->LockRect(lockedRect, rect, 0);
128 ASSERT(SUCCEEDED(result));
129
130 mDirty = true;
131 }
132
133 return result;
134}
135
136void Image::unlock()
137{
138 if (mSurface)
139 {
140 HRESULT result = mSurface->UnlockRect();
141 ASSERT(SUCCEEDED(result));
142 }
143}
144
daniel@transgaming.comde631782011-11-09 17:45:04 +0000145bool Image::isRenderable() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000146{
147 switch(getD3DFormat())
148 {
149 case D3DFMT_L8:
150 case D3DFMT_A8L8:
151 case D3DFMT_DXT1:
gman@chromium.org50c526d2011-08-10 05:19:44 +0000152 case D3DFMT_DXT3:
153 case D3DFMT_DXT5:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000154 return false;
155 case D3DFMT_A8R8G8B8:
156 case D3DFMT_X8R8G8B8:
157 case D3DFMT_A16B16G16R16F:
158 case D3DFMT_A32B32G32R32F:
159 return true;
160 default:
161 UNREACHABLE();
162 }
163
164 return false;
165}
166
daniel@transgaming.comde631782011-11-09 17:45:04 +0000167D3DFORMAT Image::getD3DFormat() const
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000168{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000169 if (mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
170 mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000171 {
172 return D3DFMT_DXT1;
173 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000174 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000175 {
176 return D3DFMT_DXT3;
177 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000178 else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
gman@chromium.org50c526d2011-08-10 05:19:44 +0000179 {
180 return D3DFMT_DXT5;
181 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000182 else if (mType == GL_FLOAT)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000183 {
184 return D3DFMT_A32B32G32R32F;
185 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000186 else if (mType == GL_HALF_FLOAT_OES)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000187 {
188 return D3DFMT_A16B16G16R16F;
189 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000190 else if (mType == GL_UNSIGNED_BYTE)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000191 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000192 if (mFormat == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000193 {
194 return D3DFMT_L8;
195 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000196 else if (mFormat == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000197 {
198 return D3DFMT_A8L8;
199 }
daniel@transgaming.comdff362f2011-11-09 17:45:08 +0000200 else if (mFormat == GL_RGB)
daniel@transgaming.com549bdef2011-03-29 00:57:01 +0000201 {
202 return D3DFMT_X8R8G8B8;
203 }
204
205 return D3DFMT_A8R8G8B8;
206 }
207
208 return D3DFMT_A8R8G8B8;
209}
210
daniel@transgaming.com73de05a2011-11-09 17:45:24 +0000211IDirect3DSurface9 *Image::getSurface()
212{
213 createSurface();
214
215 return mSurface;
216}
217
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000218// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
219// into the target pixel rectangle at output with outputPitch bytes in between each line.
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000220void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum type,
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000221 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
222{
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000223 GLsizei inputPitch = -ComputePitch(width, mFormat, type, unpackAlignment);
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000224 input = ((char*)input) - inputPitch * (height - 1);
225
226 switch (type)
227 {
228 case GL_UNSIGNED_BYTE:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000229 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000230 {
231 case GL_ALPHA:
232 loadAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
233 break;
234 case GL_LUMINANCE:
235 loadLuminanceData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_L8);
236 break;
237 case GL_LUMINANCE_ALPHA:
238 loadLuminanceAlphaData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, getD3DFormat() == D3DFMT_A8L8);
239 break;
240 case GL_RGB:
241 loadRGBUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
242 break;
243 case GL_RGBA:
244 if (supportsSSE2())
245 {
246 loadRGBAUByteDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
247 }
248 else
249 {
250 loadRGBAUByteData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
251 }
252 break;
253 case GL_BGRA_EXT:
254 loadBGRAData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
255 break;
256 default: UNREACHABLE();
257 }
258 break;
259 case GL_UNSIGNED_SHORT_5_6_5:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000260 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000261 {
262 case GL_RGB:
263 loadRGB565Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
264 break;
265 default: UNREACHABLE();
266 }
267 break;
268 case GL_UNSIGNED_SHORT_4_4_4_4:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000269 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000270 {
271 case GL_RGBA:
272 loadRGBA4444Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
273 break;
274 default: UNREACHABLE();
275 }
276 break;
277 case GL_UNSIGNED_SHORT_5_5_5_1:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000278 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000279 {
280 case GL_RGBA:
281 loadRGBA5551Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
282 break;
283 default: UNREACHABLE();
284 }
285 break;
286 case GL_FLOAT:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000287 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000288 {
289 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
290 case GL_ALPHA:
291 loadAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
292 break;
293 case GL_LUMINANCE:
294 loadLuminanceFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
295 break;
296 case GL_LUMINANCE_ALPHA:
297 loadLuminanceAlphaFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
298 break;
299 case GL_RGB:
300 loadRGBFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
301 break;
302 case GL_RGBA:
303 loadRGBAFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
304 break;
305 default: UNREACHABLE();
306 }
307 break;
308 case GL_HALF_FLOAT_OES:
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +0000309 switch (mFormat)
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +0000310 {
311 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
312 case GL_ALPHA:
313 loadAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
314 break;
315 case GL_LUMINANCE:
316 loadLuminanceHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
317 break;
318 case GL_LUMINANCE_ALPHA:
319 loadLuminanceAlphaHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
320 break;
321 case GL_RGB:
322 loadRGBHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
323 break;
324 case GL_RGBA:
325 loadRGBAHalfFloatData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
326 break;
327 default: UNREACHABLE();
328 }
329 break;
330 default: UNREACHABLE();
331 }
332}
333
334void Image::loadAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
335 int inputPitch, const void *input, size_t outputPitch, void *output) const
336{
337 const unsigned char *source = NULL;
338 unsigned char *dest = NULL;
339
340 for (int y = 0; y < height; y++)
341 {
342 source = static_cast<const unsigned char*>(input) + y * inputPitch;
343 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
344 for (int x = 0; x < width; x++)
345 {
346 dest[4 * x + 0] = 0;
347 dest[4 * x + 1] = 0;
348 dest[4 * x + 2] = 0;
349 dest[4 * x + 3] = source[x];
350 }
351 }
352}
353
354void Image::loadAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
355 int inputPitch, const void *input, size_t outputPitch, void *output) const
356{
357 const float *source = NULL;
358 float *dest = NULL;
359
360 for (int y = 0; y < height; y++)
361 {
362 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
363 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
364 for (int x = 0; x < width; x++)
365 {
366 dest[4 * x + 0] = 0;
367 dest[4 * x + 1] = 0;
368 dest[4 * x + 2] = 0;
369 dest[4 * x + 3] = source[x];
370 }
371 }
372}
373
374void Image::loadAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
375 int inputPitch, const void *input, size_t outputPitch, void *output) const
376{
377 const unsigned short *source = NULL;
378 unsigned short *dest = NULL;
379
380 for (int y = 0; y < height; y++)
381 {
382 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
383 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
384 for (int x = 0; x < width; x++)
385 {
386 dest[4 * x + 0] = 0;
387 dest[4 * x + 1] = 0;
388 dest[4 * x + 2] = 0;
389 dest[4 * x + 3] = source[x];
390 }
391 }
392}
393
394void Image::loadLuminanceData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
395 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
396{
397 const int destBytesPerPixel = native? 1: 4;
398 const unsigned char *source = NULL;
399 unsigned char *dest = NULL;
400
401 for (int y = 0; y < height; y++)
402 {
403 source = static_cast<const unsigned char*>(input) + y * inputPitch;
404 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
405
406 if (!native) // BGRA8 destination format
407 {
408 for (int x = 0; x < width; x++)
409 {
410 dest[4 * x + 0] = source[x];
411 dest[4 * x + 1] = source[x];
412 dest[4 * x + 2] = source[x];
413 dest[4 * x + 3] = 0xFF;
414 }
415 }
416 else // L8 destination format
417 {
418 memcpy(dest, source, width);
419 }
420 }
421}
422
423void Image::loadLuminanceFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
424 int inputPitch, const void *input, size_t outputPitch, void *output) const
425{
426 const float *source = NULL;
427 float *dest = NULL;
428
429 for (int y = 0; y < height; y++)
430 {
431 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
432 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
433 for (int x = 0; x < width; x++)
434 {
435 dest[4 * x + 0] = source[x];
436 dest[4 * x + 1] = source[x];
437 dest[4 * x + 2] = source[x];
438 dest[4 * x + 3] = 1.0f;
439 }
440 }
441}
442
443void Image::loadLuminanceHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
444 int inputPitch, const void *input, size_t outputPitch, void *output) const
445{
446 const unsigned short *source = NULL;
447 unsigned short *dest = NULL;
448
449 for (int y = 0; y < height; y++)
450 {
451 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
452 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
453 for (int x = 0; x < width; x++)
454 {
455 dest[4 * x + 0] = source[x];
456 dest[4 * x + 1] = source[x];
457 dest[4 * x + 2] = source[x];
458 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
459 }
460 }
461}
462
463void Image::loadLuminanceAlphaData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
464 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
465{
466 const int destBytesPerPixel = native? 2: 4;
467 const unsigned char *source = NULL;
468 unsigned char *dest = NULL;
469
470 for (int y = 0; y < height; y++)
471 {
472 source = static_cast<const unsigned char*>(input) + y * inputPitch;
473 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
474
475 if (!native) // BGRA8 destination format
476 {
477 for (int x = 0; x < width; x++)
478 {
479 dest[4 * x + 0] = source[2*x+0];
480 dest[4 * x + 1] = source[2*x+0];
481 dest[4 * x + 2] = source[2*x+0];
482 dest[4 * x + 3] = source[2*x+1];
483 }
484 }
485 else
486 {
487 memcpy(dest, source, width * 2);
488 }
489 }
490}
491
492void Image::loadLuminanceAlphaFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
493 int inputPitch, const void *input, size_t outputPitch, void *output) const
494{
495 const float *source = NULL;
496 float *dest = NULL;
497
498 for (int y = 0; y < height; y++)
499 {
500 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
501 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
502 for (int x = 0; x < width; x++)
503 {
504 dest[4 * x + 0] = source[2*x+0];
505 dest[4 * x + 1] = source[2*x+0];
506 dest[4 * x + 2] = source[2*x+0];
507 dest[4 * x + 3] = source[2*x+1];
508 }
509 }
510}
511
512void Image::loadLuminanceAlphaHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
513 int inputPitch, const void *input, size_t outputPitch, void *output) const
514{
515 const unsigned short *source = NULL;
516 unsigned short *dest = NULL;
517
518 for (int y = 0; y < height; y++)
519 {
520 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
521 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
522 for (int x = 0; x < width; x++)
523 {
524 dest[4 * x + 0] = source[2*x+0];
525 dest[4 * x + 1] = source[2*x+0];
526 dest[4 * x + 2] = source[2*x+0];
527 dest[4 * x + 3] = source[2*x+1];
528 }
529 }
530}
531
532void Image::loadRGBUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
533 int inputPitch, const void *input, size_t outputPitch, void *output) const
534{
535 const unsigned char *source = NULL;
536 unsigned char *dest = NULL;
537
538 for (int y = 0; y < height; y++)
539 {
540 source = static_cast<const unsigned char*>(input) + y * inputPitch;
541 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
542 for (int x = 0; x < width; x++)
543 {
544 dest[4 * x + 0] = source[x * 3 + 2];
545 dest[4 * x + 1] = source[x * 3 + 1];
546 dest[4 * x + 2] = source[x * 3 + 0];
547 dest[4 * x + 3] = 0xFF;
548 }
549 }
550}
551
552void Image::loadRGB565Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
553 int inputPitch, const void *input, size_t outputPitch, void *output) const
554{
555 const unsigned short *source = NULL;
556 unsigned char *dest = NULL;
557
558 for (int y = 0; y < height; y++)
559 {
560 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
561 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
562 for (int x = 0; x < width; x++)
563 {
564 unsigned short rgba = source[x];
565 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
566 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
567 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
568 dest[4 * x + 3] = 0xFF;
569 }
570 }
571}
572
573void Image::loadRGBFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
574 int inputPitch, const void *input, size_t outputPitch, void *output) const
575{
576 const float *source = NULL;
577 float *dest = NULL;
578
579 for (int y = 0; y < height; y++)
580 {
581 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
582 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
583 for (int x = 0; x < width; x++)
584 {
585 dest[4 * x + 0] = source[x * 3 + 0];
586 dest[4 * x + 1] = source[x * 3 + 1];
587 dest[4 * x + 2] = source[x * 3 + 2];
588 dest[4 * x + 3] = 1.0f;
589 }
590 }
591}
592
593void Image::loadRGBHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
594 int inputPitch, const void *input, size_t outputPitch, void *output) const
595{
596 const unsigned short *source = NULL;
597 unsigned short *dest = NULL;
598
599 for (int y = 0; y < height; y++)
600 {
601 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
602 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
603 for (int x = 0; x < width; x++)
604 {
605 dest[4 * x + 0] = source[x * 3 + 0];
606 dest[4 * x + 1] = source[x * 3 + 1];
607 dest[4 * x + 2] = source[x * 3 + 2];
608 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
609 }
610 }
611}
612
613void Image::loadRGBAUByteDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
614 int inputPitch, const void *input, size_t outputPitch, void *output) const
615{
616 const unsigned int *source = NULL;
617 unsigned int *dest = NULL;
618 __m128i brMask = _mm_set1_epi32(0x00ff00ff);
619
620 for (int y = 0; y < height; y++)
621 {
622 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
623 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
624 int x = 0;
625
626 // Make output writes aligned
627 for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
628 {
629 unsigned int rgba = source[x];
630 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
631 }
632
633 for (; x + 3 < width; x += 4)
634 {
635 __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
636 // Mask out g and a, which don't change
637 __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
638 // Mask out b and r
639 __m128i brComponents = _mm_and_si128(sourceData, brMask);
640 // Swap b and r
641 __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
642 __m128i result = _mm_or_si128(gaComponents, brSwapped);
643 _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
644 }
645
646 // Perform leftover writes
647 for (; x < width; x++)
648 {
649 unsigned int rgba = source[x];
650 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
651 }
652 }
653}
654
655void Image::loadRGBAUByteData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
656 int inputPitch, const void *input, size_t outputPitch, void *output) const
657{
658 const unsigned int *source = NULL;
659 unsigned int *dest = NULL;
660 for (int y = 0; y < height; y++)
661 {
662 source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
663 dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
664
665 for (int x = 0; x < width; x++)
666 {
667 unsigned int rgba = source[x];
668 dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
669 }
670 }
671}
672
673void Image::loadRGBA4444Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
674 int inputPitch, const void *input, size_t outputPitch, void *output) const
675{
676 const unsigned short *source = NULL;
677 unsigned char *dest = NULL;
678
679 for (int y = 0; y < height; y++)
680 {
681 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
682 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
683 for (int x = 0; x < width; x++)
684 {
685 unsigned short rgba = source[x];
686 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
687 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
688 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
689 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
690 }
691 }
692}
693
694void Image::loadRGBA5551Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
695 int inputPitch, const void *input, size_t outputPitch, void *output) const
696{
697 const unsigned short *source = NULL;
698 unsigned char *dest = NULL;
699
700 for (int y = 0; y < height; y++)
701 {
702 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
703 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
704 for (int x = 0; x < width; x++)
705 {
706 unsigned short rgba = source[x];
707 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
708 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
709 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
710 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
711 }
712 }
713}
714
715void Image::loadRGBAFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
716 int inputPitch, const void *input, size_t outputPitch, void *output) const
717{
718 const float *source = NULL;
719 float *dest = NULL;
720
721 for (int y = 0; y < height; y++)
722 {
723 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
724 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
725 memcpy(dest, source, width * 16);
726 }
727}
728
729void Image::loadRGBAHalfFloatData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
730 int inputPitch, const void *input, size_t outputPitch, void *output) const
731{
732 const unsigned char *source = NULL;
733 unsigned char *dest = NULL;
734
735 for (int y = 0; y < height; y++)
736 {
737 source = static_cast<const unsigned char*>(input) + y * inputPitch;
738 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
739 memcpy(dest, source, width * 8);
740 }
741}
742
743void Image::loadBGRAData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
744 int inputPitch, const void *input, size_t outputPitch, void *output) const
745{
746 const unsigned char *source = NULL;
747 unsigned char *dest = NULL;
748
749 for (int y = 0; y < height; y++)
750 {
751 source = static_cast<const unsigned char*>(input) + y * inputPitch;
752 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
753 memcpy(dest, source, width*4);
754 }
755}
756
757void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
758 int inputPitch, const void *input, size_t outputPitch, void *output) const {
759 switch (getD3DFormat())
760 {
761 case D3DFMT_DXT1:
762 loadDXT1Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
763 break;
764 case D3DFMT_DXT3:
765 loadDXT3Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
766 break;
767 case D3DFMT_DXT5:
768 loadDXT5Data(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
769 break;
770 }
771}
772
773static void FlipCopyDXT1BlockFull(const unsigned int* source, unsigned int* dest) {
774 // A DXT1 block layout is:
775 // [0-1] color0.
776 // [2-3] color1.
777 // [4-7] color bitmap, 2 bits per pixel.
778 // So each of the 4-7 bytes represents one line, flipping a block is just
779 // flipping those bytes.
780
781 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
782 dest[0] = source[0];
783
784 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
785 dest[1] = (source[1] >> 24) |
786 ((source[1] << 8) & 0x00FF0000) |
787 ((source[1] >> 8) & 0x0000FF00) |
788 (source[1] << 24);
789}
790
791// Flips the first 2 lines of a DXT1 block in the y direction.
792static void FlipCopyDXT1BlockHalf(const unsigned int* source, unsigned int* dest) {
793 // See layout above.
794 dest[0] = source[0];
795 dest[1] = ((source[1] << 8) & 0x0000FF00) |
796 ((source[1] >> 8) & 0x000000FF);
797}
798
799// Flips a full DXT3 block in the y direction.
800static void FlipCopyDXT3BlockFull(const unsigned int* source, unsigned int* dest) {
801 // A DXT3 block layout is:
802 // [0-7] alpha bitmap, 4 bits per pixel.
803 // [8-15] a DXT1 block.
804
805 // First and Second 32 bits are 4bit per pixel alpha and need to be flipped.
806 dest[0] = (source[1] >> 16) | (source[1] << 16);
807 dest[1] = (source[0] >> 16) | (source[0] << 16);
808
809 // And flip the DXT1 block using the above function.
810 FlipCopyDXT1BlockFull(source + 2, dest + 2);
811}
812
813// Flips the first 2 lines of a DXT3 block in the y direction.
814static void FlipCopyDXT3BlockHalf(const unsigned int* source, unsigned int* dest) {
815 // See layout above.
816 dest[0] = (source[1] >> 16) | (source[1] << 16);
817 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
818}
819
820// Flips a full DXT5 block in the y direction.
821static void FlipCopyDXT5BlockFull(const unsigned int* source, unsigned int* dest) {
822 // A DXT5 block layout is:
823 // [0] alpha0.
824 // [1] alpha1.
825 // [2-7] alpha bitmap, 3 bits per pixel.
826 // [8-15] a DXT1 block.
827
828 // The alpha bitmap doesn't easily map lines to bytes, so we have to
829 // interpret it correctly. Extracted from
830 // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
831 //
832 // The 6 "bits" bytes of the block are decoded into one 48-bit integer:
833 //
834 // bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
835 // 256 * (bits_4 + 256 * bits_5))))
836 //
837 // bits is a 48-bit unsigned integer, from which a three-bit control code
838 // is extracted for a texel at location (x,y) in the block using:
839 //
840 // code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
841 //
842 // where bit 47 is the most significant and bit 0 is the least
843 // significant bit.
844 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
845 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
846 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
847 unsigned int line_2_3 = sourceBytes[5] + 256 * (sourceBytes[6] + 256 * sourceBytes[7]);
848 // swap lines 0 and 1 in line_0_1.
849 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
850 ((line_0_1 & 0xfff000) >> 12);
851 // swap lines 2 and 3 in line_2_3.
852 unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
853 ((line_2_3 & 0xfff000) >> 12);
854 destBytes[0] = sourceBytes[0];
855 destBytes[1] = sourceBytes[1];
856 destBytes[2] = line_3_2 & 0xff;
857 destBytes[3] = (line_3_2 & 0xff00) >> 8;
858 destBytes[4] = (line_3_2 & 0xff0000) >> 16;
859 destBytes[5] = line_1_0 & 0xff;
860 destBytes[6] = (line_1_0 & 0xff00) >> 8;
861 destBytes[7] = (line_1_0 & 0xff0000) >> 16;
862
863 // And flip the DXT1 block using the above function.
864 FlipCopyDXT1BlockFull(source + 2, dest + 2);
865}
866
867// Flips the first 2 lines of a DXT5 block in the y direction.
868static void FlipCopyDXT5BlockHalf(const unsigned int* source, unsigned int* dest) {
869 // See layout above.
870 const unsigned char* sourceBytes = static_cast<const unsigned char*>(static_cast<const void*>(source));
871 unsigned char* destBytes = static_cast<unsigned char*>(static_cast<void*>(dest));
872 unsigned int line_0_1 = sourceBytes[2] + 256 * (sourceBytes[3] + 256 * sourceBytes[4]);
873 unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
874 ((line_0_1 & 0xfff000) >> 12);
875 destBytes[0] = sourceBytes[0];
876 destBytes[1] = sourceBytes[1];
877 destBytes[2] = line_1_0 & 0xff;
878 destBytes[3] = (line_1_0 & 0xff00) >> 8;
879 destBytes[4] = (line_1_0 & 0xff0000) >> 16;
880 FlipCopyDXT1BlockHalf(source + 2, dest + 2);
881}
882
883void Image::loadDXT1Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
884 int inputPitch, const void *input, size_t outputPitch, void *output) const
885{
886 ASSERT(xoffset % 4 == 0);
887 ASSERT(yoffset % 4 == 0);
888 ASSERT(width % 4 == 0 || width == 2 || width == 1);
889 ASSERT(inputPitch % 8 == 0);
890 ASSERT(outputPitch % 8 == 0);
891
892 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
893 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
894
895 // Round width up in case it is less than 4.
896 int blocksAcross = (width + 3) / 4;
897 int intsAcross = blocksAcross * 2;
898
899 switch (height)
900 {
901 case 1:
902 for (int x = 0; x < intsAcross; x += 2)
903 {
904 // just copy the block
905 dest[x] = source[x];
906 dest[x + 1] = source[x + 1];
907 }
908 break;
909 case 2:
910 for (int x = 0; x < intsAcross; x += 2)
911 {
912 FlipCopyDXT1BlockHalf(source + x, dest + x);
913 }
914 break;
915 default:
916 ASSERT(height % 4 == 0);
917 for (int y = 0; y < height / 4; ++y)
918 {
919 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
920 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
921
922 for (int x = 0; x < intsAcross; x += 2)
923 {
924 FlipCopyDXT1BlockFull(source + x, dest + x);
925 }
926 }
927 break;
928 }
929}
930
931void Image::loadDXT3Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
932 int inputPitch, const void *input, size_t outputPitch, void *output) const
933{
934 ASSERT(xoffset % 4 == 0);
935 ASSERT(yoffset % 4 == 0);
936 ASSERT(width % 4 == 0 || width == 2 || width == 1);
937 ASSERT(inputPitch % 16 == 0);
938 ASSERT(outputPitch % 16 == 0);
939
940 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
941 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
942
943 // Round width up in case it is less than 4.
944 int blocksAcross = (width + 3) / 4;
945 int intsAcross = blocksAcross * 4;
946
947 switch (height)
948 {
949 case 1:
950 for (int x = 0; x < intsAcross; x += 4)
951 {
952 // just copy the block
953 dest[x] = source[x];
954 dest[x + 1] = source[x + 1];
955 dest[x + 2] = source[x + 2];
956 dest[x + 3] = source[x + 3];
957 }
958 break;
959 case 2:
960 for (int x = 0; x < intsAcross; x += 4)
961 {
962 FlipCopyDXT3BlockHalf(source + x, dest + x);
963 }
964 break;
965 default:
966 ASSERT(height % 4 == 0);
967 for (int y = 0; y < height / 4; ++y)
968 {
969 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
970 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
971
972 for (int x = 0; x < intsAcross; x += 4)
973 {
974 FlipCopyDXT3BlockFull(source + x, dest + x);
975 }
976 }
977 break;
978 }
979}
980
981void Image::loadDXT5Data(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
982 int inputPitch, const void *input, size_t outputPitch, void *output) const
983{
984 ASSERT(xoffset % 4 == 0);
985 ASSERT(yoffset % 4 == 0);
986 ASSERT(width % 4 == 0 || width == 2 || width == 1);
987 ASSERT(inputPitch % 16 == 0);
988 ASSERT(outputPitch % 16 == 0);
989
990 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
991 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
992
993 // Round width up in case it is less than 4.
994 int blocksAcross = (width + 3) / 4;
995 int intsAcross = blocksAcross * 4;
996
997 switch (height)
998 {
999 case 1:
1000 for (int x = 0; x < intsAcross; x += 4)
1001 {
1002 // just copy the block
1003 dest[x] = source[x];
1004 dest[x + 1] = source[x + 1];
1005 dest[x + 2] = source[x + 2];
1006 dest[x + 3] = source[x + 3];
1007 }
1008 break;
1009 case 2:
1010 for (int x = 0; x < intsAcross; x += 4)
1011 {
1012 FlipCopyDXT5BlockHalf(source + x, dest + x);
1013 }
1014 break;
1015 default:
1016 ASSERT(height % 4 == 0);
1017 for (int y = 0; y < height / 4; ++y)
1018 {
1019 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
1020 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
1021
1022 for (int x = 0; x < intsAcross; x += 4)
1023 {
1024 FlipCopyDXT5BlockFull(source + x, dest + x);
1025 }
1026 }
1027 break;
1028 }
1029}
1030
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00001031// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
1032void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
1033{
1034 IDirect3DDevice9 *device = getDevice();
1035 IDirect3DSurface9 *renderTargetData = NULL;
1036 D3DSURFACE_DESC description;
1037 renderTarget->GetDesc(&description);
1038
1039 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
1040
1041 if (FAILED(result))
1042 {
1043 ERR("Could not create matching destination surface.");
1044 return error(GL_OUT_OF_MEMORY);
1045 }
1046
1047 result = device->GetRenderTargetData(renderTarget, renderTargetData);
1048
1049 if (FAILED(result))
1050 {
1051 ERR("GetRenderTargetData unexpectedly failed.");
1052 renderTargetData->Release();
1053 return error(GL_OUT_OF_MEMORY);
1054 }
1055
1056 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
1057 int destYOffset = transformPixelYOffset(yoffset, height, mHeight);
1058 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1059
1060 if (isRenderable())
1061 {
1062 result = D3DXLoadSurfaceFromSurface(getSurface(), NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
1063
1064 if (FAILED(result))
1065 {
1066 ERR("Copying surfaces unexpectedly failed.");
1067 renderTargetData->Release();
1068 return error(GL_OUT_OF_MEMORY);
1069 }
1070 }
1071 else
1072 {
1073 D3DLOCKED_RECT sourceLock = {0};
1074 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
1075
1076 if (FAILED(result))
1077 {
1078 ERR("Failed to lock the source surface (rectangle might be invalid).");
1079 renderTargetData->Release();
1080 return error(GL_OUT_OF_MEMORY);
1081 }
1082
1083 D3DLOCKED_RECT destLock = {0};
1084 result = lock(&destLock, &destRect);
1085
1086 if (FAILED(result))
1087 {
1088 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1089 renderTargetData->UnlockRect();
1090 renderTargetData->Release();
1091 return error(GL_OUT_OF_MEMORY);
1092 }
1093
1094 if (destLock.pBits && sourceLock.pBits)
1095 {
1096 unsigned char *source = (unsigned char*)sourceLock.pBits;
1097 unsigned char *dest = (unsigned char*)destLock.pBits;
1098
1099 switch (description.Format)
1100 {
1101 case D3DFMT_X8R8G8B8:
1102 case D3DFMT_A8R8G8B8:
1103 switch(getD3DFormat())
1104 {
1105 case D3DFMT_L8:
1106 for(int y = 0; y < height; y++)
1107 {
1108 for(int x = 0; x < width; x++)
1109 {
1110 dest[x] = source[x * 4 + 2];
1111 }
1112
1113 source += sourceLock.Pitch;
1114 dest += destLock.Pitch;
1115 }
1116 break;
1117 case D3DFMT_A8L8:
1118 for(int y = 0; y < height; y++)
1119 {
1120 for(int x = 0; x < width; x++)
1121 {
1122 dest[x * 2 + 0] = source[x * 4 + 2];
1123 dest[x * 2 + 1] = source[x * 4 + 3];
1124 }
1125
1126 source += sourceLock.Pitch;
1127 dest += destLock.Pitch;
1128 }
1129 break;
1130 default:
1131 UNREACHABLE();
1132 }
1133 break;
1134 case D3DFMT_R5G6B5:
1135 switch(getD3DFormat())
1136 {
1137 case D3DFMT_L8:
1138 for(int y = 0; y < height; y++)
1139 {
1140 for(int x = 0; x < width; x++)
1141 {
1142 unsigned char red = source[x * 2 + 1] & 0xF8;
1143 dest[x] = red | (red >> 5);
1144 }
1145
1146 source += sourceLock.Pitch;
1147 dest += destLock.Pitch;
1148 }
1149 break;
1150 default:
1151 UNREACHABLE();
1152 }
1153 break;
1154 case D3DFMT_A1R5G5B5:
1155 switch(getD3DFormat())
1156 {
1157 case D3DFMT_L8:
1158 for(int y = 0; y < height; y++)
1159 {
1160 for(int x = 0; x < width; x++)
1161 {
1162 unsigned char red = source[x * 2 + 1] & 0x7C;
1163 dest[x] = (red << 1) | (red >> 4);
1164 }
1165
1166 source += sourceLock.Pitch;
1167 dest += destLock.Pitch;
1168 }
1169 break;
1170 case D3DFMT_A8L8:
1171 for(int y = 0; y < height; y++)
1172 {
1173 for(int x = 0; x < width; x++)
1174 {
1175 unsigned char red = source[x * 2 + 1] & 0x7C;
1176 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1177 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1178 }
1179
1180 source += sourceLock.Pitch;
1181 dest += destLock.Pitch;
1182 }
1183 break;
1184 default:
1185 UNREACHABLE();
1186 }
1187 break;
1188 default:
1189 UNREACHABLE();
1190 }
1191 }
1192
1193 unlock();
1194 renderTargetData->UnlockRect();
1195 }
1196
1197 renderTargetData->Release();
1198
1199 mDirty = true;
1200}
1201
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001202TextureStorage::TextureStorage(bool renderable) : mIsRenderable(renderable)
1203{
1204}
1205
1206TextureStorage::~TextureStorage()
1207{
1208}
1209
1210bool TextureStorage::isRenderable()
1211{
1212 return mIsRenderable;
1213}
1214
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001215Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001216{
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001217 mSerial = 0;
1218
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001219 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
1220 mMagFilter = GL_LINEAR;
1221 mWrapS = GL_REPEAT;
1222 mWrapT = GL_REPEAT;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001223 mDirtyParameters = true;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001224
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001225 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001226}
1227
1228Texture::~Texture()
1229{
1230}
1231
1232Blit *Texture::getBlitter()
1233{
1234 Context *context = getContext();
1235 return context->getBlitter();
1236}
1237
1238// Returns true on successful filter state update (valid enum parameter)
1239bool Texture::setMinFilter(GLenum filter)
1240{
1241 switch (filter)
1242 {
1243 case GL_NEAREST:
1244 case GL_LINEAR:
1245 case GL_NEAREST_MIPMAP_NEAREST:
1246 case GL_LINEAR_MIPMAP_NEAREST:
1247 case GL_NEAREST_MIPMAP_LINEAR:
1248 case GL_LINEAR_MIPMAP_LINEAR:
1249 {
1250 if (mMinFilter != filter)
1251 {
1252 mMinFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001253 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001254 }
1255 return true;
1256 }
1257 default:
1258 return false;
1259 }
1260}
1261
1262// Returns true on successful filter state update (valid enum parameter)
1263bool Texture::setMagFilter(GLenum filter)
1264{
1265 switch (filter)
1266 {
1267 case GL_NEAREST:
1268 case GL_LINEAR:
1269 {
1270 if (mMagFilter != filter)
1271 {
1272 mMagFilter = filter;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001273 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001274 }
1275 return true;
1276 }
1277 default:
1278 return false;
1279 }
1280}
1281
1282// Returns true on successful wrap state update (valid enum parameter)
1283bool Texture::setWrapS(GLenum wrap)
1284{
1285 switch (wrap)
1286 {
1287 case GL_REPEAT:
1288 case GL_CLAMP_TO_EDGE:
1289 case GL_MIRRORED_REPEAT:
1290 {
1291 if (mWrapS != wrap)
1292 {
1293 mWrapS = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001294 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001295 }
1296 return true;
1297 }
1298 default:
1299 return false;
1300 }
1301}
1302
1303// Returns true on successful wrap state update (valid enum parameter)
1304bool Texture::setWrapT(GLenum wrap)
1305{
1306 switch (wrap)
1307 {
1308 case GL_REPEAT:
1309 case GL_CLAMP_TO_EDGE:
1310 case GL_MIRRORED_REPEAT:
1311 {
1312 if (mWrapT != wrap)
1313 {
1314 mWrapT = wrap;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001315 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001316 }
1317 return true;
1318 }
1319 default:
1320 return false;
1321 }
1322}
1323
1324GLenum Texture::getMinFilter() const
1325{
1326 return mMinFilter;
1327}
1328
1329GLenum Texture::getMagFilter() const
1330{
1331 return mMagFilter;
1332}
1333
1334GLenum Texture::getWrapS() const
1335{
1336 return mWrapS;
1337}
1338
1339GLenum Texture::getWrapT() const
1340{
1341 return mWrapT;
1342}
1343
daniel@transgaming.com61208202011-03-21 16:38:50 +00001344void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001345{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001346 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001347 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001348 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001349 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001350
1351 if (SUCCEEDED(result))
1352 {
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +00001353 image->loadData(0, 0, image->getWidth(), image->getHeight(), image->getType(), unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001354 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001355 }
1356
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001357 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001358 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001359}
1360
daniel@transgaming.com61208202011-03-21 16:38:50 +00001361void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001362{
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001363 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001364 {
1365 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001366 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001367
1368 if (SUCCEEDED(result))
1369 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001370 int inputPitch = ComputeCompressedPitch(image->getWidth(), image->getFormat());
1371 int inputSize = ComputeCompressedSize(image->getWidth(), image->getHeight(), image->getFormat());
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001372 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001373 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001374 }
1375
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001376 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001377 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001378}
1379
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001380bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001381{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001382 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001383 {
1384 error(GL_INVALID_VALUE);
1385 return false;
1386 }
1387
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001388 if (IsCompressed(image->getFormat()))
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001389 {
1390 error(GL_INVALID_OPERATION);
1391 return false;
1392 }
1393
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001394 if (format != image->getFormat())
jbauman@chromium.orge2f954c2011-05-03 20:45:27 +00001395 {
1396 error(GL_INVALID_OPERATION);
1397 return false;
1398 }
1399
daniel@transgaming.com73de05a2011-11-09 17:45:24 +00001400 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001401 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001402 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001403 HRESULT result = image->lock(&locked, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001404
1405 if (SUCCEEDED(result))
1406 {
daniel@transgaming.com0c67f3c2011-11-09 17:45:38 +00001407 image->loadData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001408 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001409 }
1410
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001411 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001412 }
1413
1414 return true;
1415}
1416
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001417bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001418{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001419 if (width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001420 {
1421 error(GL_INVALID_VALUE);
1422 return false;
1423 }
1424
1425 if (format != getInternalFormat())
1426 {
1427 error(GL_INVALID_OPERATION);
1428 return false;
1429 }
1430
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001431 if (pixels != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001432 {
1433 RECT updateRegion;
1434 updateRegion.left = xoffset;
1435 updateRegion.right = xoffset + width;
1436 updateRegion.bottom = yoffset + height;
1437 updateRegion.top = yoffset;
1438
1439 D3DLOCKED_RECT locked;
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001440 HRESULT result = image->lock(&locked, &updateRegion);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001441
1442 if (SUCCEEDED(result))
1443 {
1444 int inputPitch = ComputeCompressedPitch(width, format);
1445 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comf749f0e2011-11-09 17:45:34 +00001446 image->loadCompressedData(xoffset, transformPixelYOffset(yoffset, height, image->getHeight()), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001447 image->unlock();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001448 }
1449
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001450 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001451 }
1452
1453 return true;
1454}
1455
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001456IDirect3DBaseTexture9 *Texture::getTexture()
1457{
1458 if (!isComplete())
1459 {
1460 return NULL;
1461 }
1462
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001463 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001464 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001465 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001466 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001467
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001468 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001469
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001470 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001471}
1472
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001473bool Texture::hasDirtyParameters() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001474{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001475 return mDirtyParameters;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001476}
1477
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001478bool Texture::hasDirtyImages() const
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001479{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001480 return mDirtyImages;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001481}
1482
1483void Texture::resetDirty()
1484{
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001485 mDirtyParameters = false;
1486 mDirtyImages = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001487}
1488
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001489unsigned int Texture::getSerial() const
1490{
1491 return mSerial;
1492}
1493
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001494GLint Texture::creationLevels(GLsizei width, GLsizei height) const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001495{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001496 if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001497 {
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001498 return 0; // Maximum number of levels
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001499 }
1500 else
1501 {
1502 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1503 return 1;
1504 }
1505}
1506
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001507GLint Texture::creationLevels(GLsizei size) const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001508{
daniel@transgaming.comf81103a2011-11-09 17:46:28 +00001509 return creationLevels(size, size);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001510}
1511
1512int Texture::levelCount() const
1513{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001514 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001515}
1516
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001517unsigned int Texture::issueSerial()
1518{
1519 return mCurrentSerial++;
1520}
1521
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001522TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(true)
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001523{
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001524 mTexture = surfaceTexture;
1525}
1526
1527TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, int width, int height, bool renderable) : TextureStorage(renderable)
1528{
1529 IDirect3DDevice9 *device = getDevice();
1530
1531 mTexture = NULL;
1532 HRESULT result = device->CreateTexture(width, height, levels, renderable ? D3DUSAGE_RENDERTARGET : 0, format, D3DPOOL_DEFAULT, &mTexture, NULL);
1533
1534 if (FAILED(result))
1535 {
1536 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1537 error(GL_OUT_OF_MEMORY);
1538 }
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001539}
1540
1541TextureStorage2D::~TextureStorage2D()
1542{
1543 mTexture->Release();
1544}
1545
1546IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level)
1547{
1548 IDirect3DSurface9 *surface = NULL;
1549
1550 if (mTexture)
1551 {
1552 HRESULT result = mTexture->GetSurfaceLevel(level, &surface);
1553 ASSERT(SUCCEEDED(result));
1554 }
1555
1556 return surface;
1557}
1558
1559IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const
1560{
1561 return mTexture;
1562}
1563
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001564Texture2D::Texture2D(GLuint id) : Texture(id)
1565{
1566 mTexture = NULL;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001567 mSurface = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001568}
1569
1570Texture2D::~Texture2D()
1571{
1572 mColorbufferProxy.set(NULL);
1573
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001574 delete mTexture;
1575 mTexture = NULL;
1576
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001577 if (mSurface)
1578 {
1579 mSurface->setBoundTexture(NULL);
1580 mSurface = NULL;
1581 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001582}
1583
1584GLenum Texture2D::getTarget() const
1585{
1586 return GL_TEXTURE_2D;
1587}
1588
daniel@transgaming.com61208202011-03-21 16:38:50 +00001589GLsizei Texture2D::getWidth() const
1590{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001591 return mImageArray[0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001592}
1593
1594GLsizei Texture2D::getHeight() const
1595{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001596 return mImageArray[0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001597}
1598
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001599GLenum Texture2D::getInternalFormat() const
1600{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001601 return mImageArray[0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001602}
1603
daniel@transgaming.com61208202011-03-21 16:38:50 +00001604GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001605{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001606 return mImageArray[0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001607}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001608
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001609D3DFORMAT Texture2D::getD3DFormat() const
1610{
1611 return mImageArray[0].getD3DFormat();
1612}
1613
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001614void Texture2D::redefineImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001615{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001616 releaseTexImage();
1617
daniel@transgaming.com41634052011-11-09 17:46:24 +00001618 bool redefined = mImageArray[level].redefine(format, width, height, type);
daniel@transgaming.comc9ba4ad2011-11-09 17:44:35 +00001619
daniel@transgaming.com41634052011-11-09 17:46:24 +00001620 if (mTexture && redefined)
daniel@transgaming.com61208202011-03-21 16:38:50 +00001621 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001622 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1623 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001624 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001625 }
1626
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001627 delete mTexture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001628 mTexture = NULL;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001629 mSerial = 0;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001630 mDirtyImages = true;
apatrick@chromium.org57a2cd62011-06-08 00:04:07 +00001631 mColorbufferProxy.set(NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001632 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001633}
1634
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001635void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001636{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001637 redefineImage(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001638
daniel@transgaming.com61208202011-03-21 16:38:50 +00001639 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001640}
1641
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001642void Texture2D::bindTexImage(egl::Surface *surface)
1643{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001644 releaseTexImage();
1645
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001646 GLenum format;
1647
1648 switch(surface->getFormat())
1649 {
1650 case D3DFMT_A8R8G8B8:
1651 format = GL_RGBA;
1652 break;
1653 case D3DFMT_X8R8G8B8:
1654 format = GL_RGB;
1655 break;
1656 default:
1657 UNIMPLEMENTED();
1658 return;
1659 }
1660
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001661 mImageArray[0].redefine(format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE);
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001662
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001663 delete mTexture;
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001664 mTexture = new TextureStorage2D(surface->getOffscreenTexture());
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001665 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00001666 mColorbufferProxy.set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001667 mDirtyImages = true;
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001668 mSurface = surface;
1669 mSurface->setBoundTexture(this);
1670}
1671
1672void Texture2D::releaseTexImage()
1673{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001674 if (mSurface)
1675 {
1676 mSurface->setBoundTexture(NULL);
1677 mSurface = NULL;
1678
1679 if (mTexture)
1680 {
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001681 delete mTexture;
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001682 mTexture = NULL;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001683 mSerial = 0;
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00001684 mColorbufferProxy.set(NULL);
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001685 }
1686
1687 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1688 {
1689 mImageArray[i].redefine(GL_RGBA, 0, 0, GL_UNSIGNED_BYTE);
1690 }
1691 }
jbauman@chromium.orgae345802011-03-30 22:04:25 +00001692}
1693
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001694void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001695{
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001696 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001697
daniel@transgaming.com61208202011-03-21 16:38:50 +00001698 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001699}
1700
1701void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1702{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001703 ASSERT(mImageArray[level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001704
1705 if (level < levelCount())
1706 {
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001707 IDirect3DSurface9 *destLevel = mTexture->getSurfaceLevel(level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001708
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001709 if (destLevel)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001710 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001711 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001712
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001713 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001714 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001715
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001716 HRESULT result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001717 ASSERT(SUCCEEDED(result));
1718
1719 destLevel->Release();
1720
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001721 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001722 }
1723 }
1724}
1725
1726void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1727{
1728 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1729 {
1730 commitRect(level, xoffset, yoffset, width, height);
1731 }
1732}
1733
1734void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1735{
1736 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1737 {
1738 commitRect(level, xoffset, yoffset, width, height);
1739 }
1740}
1741
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001742void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001743{
1744 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1745
1746 if (!renderTarget)
1747 {
1748 ERR("Failed to retrieve the render target.");
1749 return error(GL_OUT_OF_MEMORY);
1750 }
1751
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00001752 redefineImage(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001753
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001754 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001755 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00001756 mImageArray[level].copy(0, 0, x, y, width, height, renderTarget);
1757 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001758 }
1759 else
1760 {
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001761 if (!mTexture || !mTexture->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001762 {
1763 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001764 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00001765
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001766 mImageArray[level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001767
1768 if (width != 0 && height != 0 && level < levelCount())
1769 {
1770 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1771 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1772 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1773 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1774 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00001775
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001776 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001777
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001778 IDirect3DSurface9 *dest = mTexture->getSurfaceLevel(level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001779
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001780 if (dest)
1781 {
1782 getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest);
1783 dest->Release();
1784 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001785 }
1786 }
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001787
1788 renderTarget->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001789}
1790
1791void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1792{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001793 if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001794 {
1795 return error(GL_INVALID_VALUE);
1796 }
1797
1798 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1799
1800 if (!renderTarget)
1801 {
1802 ERR("Failed to retrieve the render target.");
1803 return error(GL_OUT_OF_MEMORY);
1804 }
1805
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001806 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001807 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00001808 mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget);
1809 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001810 }
1811 else
1812 {
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001813 if (!mTexture || !mTexture->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001814 {
1815 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001816 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001817
1818 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001819
1820 if (level < levelCount())
1821 {
1822 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1823 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1824 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1825 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1826 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1827
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001828 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001829
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001830 IDirect3DSurface9 *dest = mTexture->getSurfaceLevel(level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001831
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001832 if (dest)
1833 {
1834 getBlitter()->copy(renderTarget, sourceRect, mImageArray[0].getFormat(), xoffset, destYOffset, dest);
1835 dest->Release();
1836 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001837 }
1838 }
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001839
1840 renderTarget->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001841}
1842
1843// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1844bool Texture2D::isComplete() const
1845{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001846 GLsizei width = mImageArray[0].getWidth();
1847 GLsizei height = mImageArray[0].getHeight();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001848
1849 if (width <= 0 || height <= 0)
1850 {
1851 return false;
1852 }
1853
1854 bool mipmapping = false;
1855
1856 switch (mMinFilter)
1857 {
1858 case GL_NEAREST:
1859 case GL_LINEAR:
1860 mipmapping = false;
1861 break;
1862 case GL_NEAREST_MIPMAP_NEAREST:
1863 case GL_LINEAR_MIPMAP_NEAREST:
1864 case GL_NEAREST_MIPMAP_LINEAR:
1865 case GL_LINEAR_MIPMAP_LINEAR:
1866 mipmapping = true;
1867 break;
1868 default: UNREACHABLE();
1869 }
1870
daniel@transgaming.combbeffbb2011-11-09 17:46:11 +00001871 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
1872 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001873 {
1874 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1875 {
1876 return false;
1877 }
1878 }
1879
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001880 bool npot = getContext()->supportsNonPower2Texture();
1881
1882 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001883 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001884 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
1885 (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1886 {
1887 return false;
1888 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001889 }
1890
1891 if (mipmapping)
1892 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001893 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001894 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00001895 if (!isPow2(width) || !isPow2(height))
1896 {
1897 return false;
1898 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001899 }
1900
1901 int q = log2(std::max(width, height));
1902
1903 for (int level = 1; level <= q; level++)
1904 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001905 if (mImageArray[level].getFormat() != mImageArray[0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001906 {
1907 return false;
1908 }
1909
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001910 if (mImageArray[level].getType() != mImageArray[0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001911 {
1912 return false;
1913 }
1914
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001915 if (mImageArray[level].getWidth() != std::max(1, width >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001916 {
1917 return false;
1918 }
1919
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001920 if (mImageArray[level].getHeight() != std::max(1, height >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001921 {
1922 return false;
1923 }
1924 }
1925 }
1926
1927 return true;
1928}
1929
1930bool Texture2D::isCompressed() const
1931{
1932 return IsCompressed(getInternalFormat());
1933}
1934
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001935IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1936{
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001937 return mTexture ? mTexture->getBaseTexture() : NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001938}
1939
1940// Constructs a Direct3D 9 texture resource from the texture images
1941void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001942{
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001943 GLsizei width = mImageArray[0].getWidth();
1944 GLsizei height = mImageArray[0].getHeight();
1945 GLint levels = creationLevels(width, height);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001946 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001947
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001948 delete mTexture;
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001949 mTexture = new TextureStorage2D(levels, format, width, height, false);
1950
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00001951 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00001952 mColorbufferProxy.set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00001953 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001954}
1955
1956void Texture2D::updateTexture()
1957{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001958 int levels = levelCount();
1959
1960 for (int level = 0; level < levels; level++)
1961 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00001962 Image *image = &mImageArray[level];
1963
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00001964 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001965 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001966 commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001967 }
1968 }
1969}
1970
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001971void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001972{
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00001973 TextureStorage2D *newTexture = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001974
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00001975 if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001976 {
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001977 GLsizei width = mImageArray[0].getWidth();
1978 GLsizei height = mImageArray[0].getHeight();
1979 GLint levels = creationLevels(width, height);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001980 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001981
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001982 newTexture = new TextureStorage2D(levels, format, width, height, true);
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00001983
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001984 if (mTexture != NULL)
1985 {
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001986 egl::Display *display = getDisplay();
1987 IDirect3DDevice9 *device = display->getDevice();
1988
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001989 int levels = levelCount();
1990 for (int i = 0; i < levels; i++)
1991 {
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00001992 IDirect3DSurface9 *source = mTexture->getSurfaceLevel(i);
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00001993 IDirect3DSurface9 *dest = newTexture->getSurfaceLevel(i);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001994
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001995 if (source && dest)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001996 {
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00001997 display->endScene();
1998 HRESULT result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001999
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002000 if (FAILED(result))
2001 {
2002 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002003
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002004 delete newTexture;
2005 source->Release();
2006 dest->Release();
2007
2008 return error(GL_OUT_OF_MEMORY);
2009 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002010 }
2011
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002012 if (source) source->Release();
2013 if (dest) dest->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002014 }
2015 }
2016 }
2017
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002018 delete mTexture;
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002019 mTexture = newTexture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002020 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002021 mColorbufferProxy.set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002022 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002023}
2024
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002025void Texture2D::generateMipmaps()
2026{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002027 if (!getContext()->supportsNonPower2Texture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002028 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002029 if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002030 {
2031 return error(GL_INVALID_OPERATION);
2032 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002033 }
2034
2035 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002036 unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight()));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002037 for (unsigned int i = 1; i <= q; i++)
2038 {
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00002039 redefineImage(i, mImageArray[0].getFormat(),
2040 std::max(mImageArray[0].getWidth() >> i, 1),
2041 std::max(mImageArray[0].getHeight() >> i, 1),
2042 mImageArray[0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002043 }
2044
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002045 if (mTexture && mTexture->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002046 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002047 for (unsigned int i = 1; i <= q; i++)
2048 {
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002049 IDirect3DSurface9 *upper = mTexture->getSurfaceLevel(i - 1);
2050 IDirect3DSurface9 *lower = mTexture->getSurfaceLevel(i);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002051
2052 if (upper != NULL && lower != NULL)
2053 {
2054 getBlitter()->boxFilter(upper, lower);
2055 }
2056
2057 if (upper != NULL) upper->Release();
2058 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002059
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002060 mImageArray[i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002061 }
2062 }
2063 else
2064 {
2065 for (unsigned int i = 1; i <= q; i++)
2066 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002067 if (mImageArray[i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002068 {
2069 return error(GL_OUT_OF_MEMORY);
2070 }
2071
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002072 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].getSurface(), NULL, NULL, mImageArray[i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002073 {
2074 ERR(" failed to load filter %d to %d.", i - 1, i);
2075 }
2076
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002077 mImageArray[i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002078 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002079 }
2080}
2081
2082Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
2083{
2084 if (target != GL_TEXTURE_2D)
2085 {
2086 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2087 }
2088
2089 if (mColorbufferProxy.get() == NULL)
2090 {
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002091 mColorbufferProxy.set(new Renderbuffer(id(), new RenderbufferTexture(this, target)));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002092 }
2093
2094 return mColorbufferProxy.get();
2095}
2096
2097IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
2098{
2099 ASSERT(target == GL_TEXTURE_2D);
2100
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002101 if (!mTexture || !mTexture->isRenderable())
daniel@transgaming.com61208202011-03-21 16:38:50 +00002102 {
2103 convertToRenderTarget();
2104 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002105
2106 if (mTexture == NULL)
2107 {
2108 return NULL;
2109 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002110
2111 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002112
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002113 return mTexture->getSurfaceLevel(0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002114}
2115
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002116TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, int size, bool renderable) : TextureStorage(renderable)
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002117{
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002118 IDirect3DDevice9 *device = getDevice();
2119
2120 mTexture = NULL;
2121 HRESULT result = device->CreateCubeTexture(size, levels, renderable ? D3DUSAGE_RENDERTARGET : 0, format, D3DPOOL_DEFAULT, &mTexture, NULL);
2122
2123 if (FAILED(result))
2124 {
2125 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2126 error(GL_OUT_OF_MEMORY);
2127 }
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002128}
2129
2130TextureStorageCubeMap::~TextureStorageCubeMap()
2131{
2132 mTexture->Release();
2133}
2134
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002135IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level)
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002136{
2137 IDirect3DSurface9 *surface = NULL;
2138
2139 if (mTexture)
2140 {
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002141 HRESULT result = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(faceTarget), level, &surface);
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002142 ASSERT(SUCCEEDED(result));
2143 }
2144
2145 return surface;
2146}
2147
2148IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const
2149{
2150 return mTexture;
2151}
2152
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002153TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
2154{
2155 mTexture = NULL;
2156}
2157
2158TextureCubeMap::~TextureCubeMap()
2159{
2160 for (int i = 0; i < 6; i++)
2161 {
2162 mFaceProxies[i].set(NULL);
2163 }
2164
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002165 delete mTexture;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002166}
2167
2168GLenum TextureCubeMap::getTarget() const
2169{
2170 return GL_TEXTURE_CUBE_MAP;
2171}
2172
daniel@transgaming.com61208202011-03-21 16:38:50 +00002173GLsizei TextureCubeMap::getWidth() const
2174{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002175 return mImageArray[0][0].getWidth();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002176}
2177
2178GLsizei TextureCubeMap::getHeight() const
2179{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002180 return mImageArray[0][0].getHeight();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002181}
2182
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183GLenum TextureCubeMap::getInternalFormat() const
2184{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002185 return mImageArray[0][0].getFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002186}
2187
daniel@transgaming.com61208202011-03-21 16:38:50 +00002188GLenum TextureCubeMap::getType() const
2189{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002190 return mImageArray[0][0].getType();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002191}
2192
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002193D3DFORMAT TextureCubeMap::getD3DFormat() const
2194{
2195 return mImageArray[0][0].getD3DFormat();
2196}
2197
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002198void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002199{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002200 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002201}
2202
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002203void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002204{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002205 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002206}
2207
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002208void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002209{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002210 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002211}
2212
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002213void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002214{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002215 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002216}
2217
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002218void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002219{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002220 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002221}
2222
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002223void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002224{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002225 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002226}
2227
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002228void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002229{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002230 redefineImage(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002231
daniel@transgaming.com61208202011-03-21 16:38:50 +00002232 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002233}
2234
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002235void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002236{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002237 ASSERT(mImageArray[face][level].getSurface() != NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002238
2239 if (level < levelCount())
2240 {
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002241 IDirect3DSurface9 *destLevel = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002242 ASSERT(destLevel != NULL);
2243
2244 if (destLevel != NULL)
2245 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002246 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002247
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002248 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->getHeight());
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002249 POINT destPoint = {sourceRect.left, sourceRect.top};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002250
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002251 HRESULT result = getDevice()->UpdateSurface(image->getSurface(), &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002252 ASSERT(SUCCEEDED(result));
2253
2254 destLevel->Release();
2255
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002256 image->markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002257 }
2258 }
2259}
2260
2261void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
2262{
2263 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
2264 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002265 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002266 }
2267}
2268
2269void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
2270{
2271 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
2272 {
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002273 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002274 }
2275}
2276
2277// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
2278bool TextureCubeMap::isComplete() const
2279{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002280 int size = mImageArray[0][0].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002281
2282 if (size <= 0)
2283 {
2284 return false;
2285 }
2286
2287 bool mipmapping;
2288
2289 switch (mMinFilter)
2290 {
2291 case GL_NEAREST:
2292 case GL_LINEAR:
2293 mipmapping = false;
2294 break;
2295 case GL_NEAREST_MIPMAP_NEAREST:
2296 case GL_LINEAR_MIPMAP_NEAREST:
2297 case GL_NEAREST_MIPMAP_LINEAR:
2298 case GL_LINEAR_MIPMAP_LINEAR:
2299 mipmapping = true;
2300 break;
2301 default: UNREACHABLE();
2302 }
2303
2304 for (int face = 0; face < 6; face++)
2305 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002306 if (mImageArray[face][0].getWidth() != size || mImageArray[face][0].getHeight() != size)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002307 {
2308 return false;
2309 }
2310 }
2311
daniel@transgaming.combbeffbb2011-11-09 17:46:11 +00002312 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) ||
2313 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsFloat16LinearFilter()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002314 {
2315 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
2316 {
2317 return false;
2318 }
2319 }
2320
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002321 bool npot = getContext()->supportsNonPower2Texture();
2322
2323 if (!npot)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002324 {
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002325 if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002326 {
2327 return false;
2328 }
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002329 }
2330
2331 if (mipmapping)
2332 {
2333 if (!npot)
2334 {
2335 if (!isPow2(size))
2336 {
2337 return false;
2338 }
2339 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002340
2341 int q = log2(size);
2342
2343 for (int face = 0; face < 6; face++)
2344 {
2345 for (int level = 1; level <= q; level++)
2346 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002347 if (mImageArray[face][level].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002348 {
2349 return false;
2350 }
2351
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002352 if (mImageArray[face][level].getType() != mImageArray[0][0].getType())
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002353 {
2354 return false;
2355 }
2356
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002357 if (mImageArray[face][level].getWidth() != std::max(1, size >> level))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002358 {
2359 return false;
2360 }
2361
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002362 ASSERT(mImageArray[face][level].getHeight() == mImageArray[face][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002363 }
2364 }
2365 }
2366
2367 return true;
2368}
2369
2370bool TextureCubeMap::isCompressed() const
2371{
2372 return IsCompressed(getInternalFormat());
2373}
2374
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002375IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
2376{
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002377 return mTexture ? mTexture->getBaseTexture() : NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002378}
2379
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002380// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002381void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002382{
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002383 GLsizei size = mImageArray[0][0].getWidth();
2384 GLint levels = creationLevels(size, 0);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002385 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002386
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002387 delete mTexture;
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002388 mTexture = new TextureStorageCubeMap(levels, format, size, false);
2389
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002390 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002391 for(int face = 0; face < 6; face++) mFaceProxies[face].set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002392 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002393}
2394
2395void TextureCubeMap::updateTexture()
2396{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002397 for (int face = 0; face < 6; face++)
2398 {
2399 int levels = levelCount();
2400 for (int level = 0; level < levels; level++)
2401 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002402 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002403
daniel@transgaming.com5cce3ff2011-11-09 17:45:14 +00002404 if (image->isDirty())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002405 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002406 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002407 }
2408 }
2409 }
2410}
2411
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002412void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002413{
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002414 TextureStorageCubeMap *newTexture = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002415
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002416 if (mImageArray[0][0].getWidth() != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002417 {
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002418 GLsizei size = mImageArray[0][0].getWidth();
2419 GLint levels = creationLevels(size, 0);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002420 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002421
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002422 newTexture = new TextureStorageCubeMap(levels, format, size, true);
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002423
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002424 if (mTexture != NULL)
2425 {
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002426 egl::Display *display = getDisplay();
2427 IDirect3DDevice9 *device = display->getDevice();
2428
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002429 int levels = levelCount();
2430 for (int f = 0; f < 6; f++)
2431 {
2432 for (int i = 0; i < levels; i++)
2433 {
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002434 IDirect3DSurface9 *source = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2435 IDirect3DSurface9 *dest = newTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002436
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002437 if (source && dest)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002438 {
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002439 display->endScene();
2440 HRESULT result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002441
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002442 if (FAILED(result))
2443 {
2444 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002445
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002446 delete newTexture;
2447 source->Release();
2448 dest->Release();
2449
2450 return error(GL_OUT_OF_MEMORY);
2451 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002452 }
daniel@transgaming.coma1a86202011-08-09 13:41:08 +00002453
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002454 if (source) source->Release();
2455 if (dest) dest->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002456 }
2457 }
2458 }
2459 }
2460
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002461 delete mTexture;
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002462 mTexture = newTexture;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002463 mSerial = issueSerial();
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002464 for(int face = 0; face < 6; face++) mFaceProxies[face].set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002465 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002466}
2467
daniel@transgaming.com61208202011-03-21 16:38:50 +00002468void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002469{
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002470 redefineImage(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002471
daniel@transgaming.com61208202011-03-21 16:38:50 +00002472 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002473}
2474
2475unsigned int TextureCubeMap::faceIndex(GLenum face)
2476{
2477 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2478 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2479 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2480 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2481 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2482
2483 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2484}
2485
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002486void TextureCubeMap::redefineImage(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002487{
daniel@transgaming.com41634052011-11-09 17:46:24 +00002488 bool redefined = mImageArray[face][level].redefine(format, width, height, type);
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002489
daniel@transgaming.com41634052011-11-09 17:46:24 +00002490 if (mTexture && redefined)
daniel@transgaming.com61208202011-03-21 16:38:50 +00002491 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002492 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2493 {
2494 for (int f = 0; f < 6; f++)
2495 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002496 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002497 }
2498 }
2499
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002500 delete mTexture;
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002501 mTexture = NULL;
daniel@transgaming.comc1fde762011-11-09 17:46:07 +00002502 mSerial = 0;
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002503 for(int face = 0; face < 6; face++) mFaceProxies[face].set(NULL);
daniel@transgaming.com0da803b2011-11-09 17:44:58 +00002504 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002505 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002506}
2507
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002508void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002509{
2510 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2511
2512 if (!renderTarget)
2513 {
2514 ERR("Failed to retrieve the render target.");
2515 return error(GL_OUT_OF_MEMORY);
2516 }
2517
2518 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com68ae2992011-11-09 17:44:49 +00002519 redefineImage(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002520
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002521 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002522 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00002523 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2524 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002525 }
2526 else
2527 {
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002528 if (!mTexture || !mTexture->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002529 {
2530 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002531 }
daniel@transgaming.com3b3c1d42011-06-08 20:38:09 +00002532
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002533 mImageArray[faceindex][level].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002534
2535 ASSERT(width == height);
2536
2537 if (width > 0 && level < levelCount())
2538 {
2539 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2540 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2541 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2542 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2543 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2544
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002545 GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comeef864a2011-04-22 11:33:27 +00002546
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002547 IDirect3DSurface9 *dest = mTexture->getCubeMapSurface(target, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002548
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002549 if (dest)
2550 {
2551 getBlitter()->copy(renderTarget, sourceRect, format, 0, destYOffset, dest);
2552 dest->Release();
2553 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002554 }
2555 }
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002556
2557 renderTarget->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002558}
2559
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002560void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2561{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002562 GLsizei size = mImageArray[faceIndex(target)][level].getWidth();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002563
2564 if (xoffset + width > size || yoffset + height > size)
2565 {
2566 return error(GL_INVALID_VALUE);
2567 }
2568
2569 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2570
2571 if (!renderTarget)
2572 {
2573 ERR("Failed to retrieve the render target.");
2574 return error(GL_OUT_OF_MEMORY);
2575 }
2576
2577 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com01dae852011-11-09 17:44:53 +00002578
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002579 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002580 {
daniel@transgaming.com90cfcc92011-11-09 17:45:48 +00002581 mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget);
2582 mDirtyImages = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002583 }
2584 else
2585 {
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002586 if (!mTexture || !mTexture->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002587 {
2588 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002589 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002590
2591 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002592
2593 if (level < levelCount())
2594 {
2595 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2596 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2597 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2598 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2599 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2600
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002601 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002602
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002603 IDirect3DSurface9 *dest = mTexture->getCubeMapSurface(target, level);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002604
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002605 if (dest)
2606 {
2607 getBlitter()->copy(renderTarget, sourceRect, mImageArray[0][0].getFormat(), xoffset, destYOffset, dest);
2608 dest->Release();
2609 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002610 }
2611 }
daniel@transgaming.com5e4dbb32011-11-11 04:10:18 +00002612
2613 renderTarget->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002614}
2615
2616bool TextureCubeMap::isCubeComplete() const
2617{
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002618 if (mImageArray[0][0].getWidth() == 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002619 {
2620 return false;
2621 }
2622
2623 for (unsigned int f = 1; f < 6; f++)
2624 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002625 if (mImageArray[f][0].getWidth() != mImageArray[0][0].getWidth()
2626 || mImageArray[f][0].getFormat() != mImageArray[0][0].getFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002627 {
2628 return false;
2629 }
2630 }
2631
2632 return true;
2633}
2634
2635void TextureCubeMap::generateMipmaps()
2636{
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002637 if (!isCubeComplete())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002638 {
2639 return error(GL_INVALID_OPERATION);
2640 }
2641
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002642 if (!getContext()->supportsNonPower2Texture())
2643 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002644 if (!isPow2(mImageArray[0][0].getWidth()))
daniel@transgaming.com4f9ef0d2011-05-30 23:51:19 +00002645 {
2646 return error(GL_INVALID_OPERATION);
2647 }
2648 }
2649
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002650 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002651 unsigned int q = log2(mImageArray[0][0].getWidth());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002652 for (unsigned int f = 0; f < 6; f++)
2653 {
2654 for (unsigned int i = 1; i <= q; i++)
2655 {
daniel@transgaming.com1a01e832011-11-09 17:45:57 +00002656 redefineImage(f, i, mImageArray[f][0].getFormat(),
2657 std::max(mImageArray[f][0].getWidth() >> i, 1),
2658 std::max(mImageArray[f][0].getWidth() >> i, 1),
2659 mImageArray[f][0].getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002660 }
2661 }
2662
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002663 if (mTexture && mTexture->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002664 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002665 for (unsigned int f = 0; f < 6; f++)
2666 {
2667 for (unsigned int i = 1; i <= q; i++)
2668 {
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002669 IDirect3DSurface9 *upper = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2670 IDirect3DSurface9 *lower = mTexture->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002671
2672 if (upper != NULL && lower != NULL)
2673 {
2674 getBlitter()->boxFilter(upper, lower);
2675 }
2676
2677 if (upper != NULL) upper->Release();
2678 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002679
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002680 mImageArray[f][i].markClean();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002681 }
2682 }
2683 }
2684 else
2685 {
2686 for (unsigned int f = 0; f < 6; f++)
2687 {
2688 for (unsigned int i = 1; i <= q; i++)
2689 {
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002690 if (mImageArray[f][i].getSurface() == NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002691 {
2692 return error(GL_OUT_OF_MEMORY);
2693 }
2694
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002695 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].getSurface(), NULL, NULL, mImageArray[f][i - 1].getSurface(), NULL, NULL, D3DX_FILTER_BOX, 0)))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002696 {
2697 ERR(" failed to load filter %d to %d.", i - 1, i);
2698 }
2699
daniel@transgaming.comdff362f2011-11-09 17:45:08 +00002700 mImageArray[f][i].markDirty();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002701 }
2702 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002703 }
2704}
2705
2706Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2707{
2708 if (!IsCubemapTextureTarget(target))
2709 {
2710 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2711 }
2712
2713 unsigned int face = faceIndex(target);
2714
2715 if (mFaceProxies[face].get() == NULL)
2716 {
daniel@transgaming.comd14558a2011-11-09 17:46:18 +00002717 mFaceProxies[face].set(new Renderbuffer(id(), new RenderbufferTexture(this, target)));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002718 }
2719
2720 return mFaceProxies[face].get();
2721}
2722
2723IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2724{
2725 ASSERT(IsCubemapTextureTarget(target));
2726
daniel@transgaming.comdc82bf92011-11-11 04:10:08 +00002727 if (!mTexture || !mTexture->isRenderable())
daniel@transgaming.com61208202011-03-21 16:38:50 +00002728 {
2729 convertToRenderTarget();
2730 }
2731
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002732 if (mTexture == NULL)
2733 {
2734 return NULL;
2735 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002736
2737 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002738
daniel@transgaming.comafa8ef32011-11-11 04:10:13 +00002739 return mTexture->getCubeMapSurface(target, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002740}
2741
daniel@transgaming.comb612f882011-11-09 17:44:31 +00002742}