blob: 715ada5a1099185998b9ee5d1f2b94566b8aad0a [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>
16
17#include "common/debug.h"
18
19#include "libGLESv2/main.h"
20#include "libGLESv2/mathutil.h"
21#include "libGLESv2/utilities.h"
22#include "libGLESv2/Blit.h"
23#include "libGLESv2/Framebuffer.h"
24
25namespace gl
26{
27
28Texture::Image::Image()
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +000029 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000030{
31}
32
33Texture::Image::~Image()
34{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000035 if (surface)
36 {
37 surface->Release();
38 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000039}
40
41Texture::Texture(GLuint id) : RefCountObject(id)
42{
daniel@transgaming.comaed18322011-03-21 16:38:13 +000043 mWidth = 0;
44 mHeight = 0;
45
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000046 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
47 mMagFilter = GL_LINEAR;
48 mWrapS = GL_REPEAT;
49 mWrapT = GL_REPEAT;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000050 mDirtyParameters = true;
51
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000052 mIsRenderable = false;
53 mType = GL_UNSIGNED_BYTE;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000054}
55
56Texture::~Texture()
57{
58}
59
60Blit *Texture::getBlitter()
61{
62 Context *context = getContext();
63 return context->getBlitter();
64}
65
66// Returns true on successful filter state update (valid enum parameter)
67bool Texture::setMinFilter(GLenum filter)
68{
69 switch (filter)
70 {
71 case GL_NEAREST:
72 case GL_LINEAR:
73 case GL_NEAREST_MIPMAP_NEAREST:
74 case GL_LINEAR_MIPMAP_NEAREST:
75 case GL_NEAREST_MIPMAP_LINEAR:
76 case GL_LINEAR_MIPMAP_LINEAR:
77 {
78 if (mMinFilter != filter)
79 {
80 mMinFilter = filter;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000081 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000082 }
83 return true;
84 }
85 default:
86 return false;
87 }
88}
89
90// Returns true on successful filter state update (valid enum parameter)
91bool Texture::setMagFilter(GLenum filter)
92{
93 switch (filter)
94 {
95 case GL_NEAREST:
96 case GL_LINEAR:
97 {
98 if (mMagFilter != filter)
99 {
100 mMagFilter = filter;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000101 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000102 }
103 return true;
104 }
105 default:
106 return false;
107 }
108}
109
110// Returns true on successful wrap state update (valid enum parameter)
111bool Texture::setWrapS(GLenum wrap)
112{
113 switch (wrap)
114 {
115 case GL_REPEAT:
116 case GL_CLAMP_TO_EDGE:
117 case GL_MIRRORED_REPEAT:
118 {
119 if (mWrapS != wrap)
120 {
121 mWrapS = wrap;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000122 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000123 }
124 return true;
125 }
126 default:
127 return false;
128 }
129}
130
131// Returns true on successful wrap state update (valid enum parameter)
132bool Texture::setWrapT(GLenum wrap)
133{
134 switch (wrap)
135 {
136 case GL_REPEAT:
137 case GL_CLAMP_TO_EDGE:
138 case GL_MIRRORED_REPEAT:
139 {
140 if (mWrapT != wrap)
141 {
142 mWrapT = wrap;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000143 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000144 }
145 return true;
146 }
147 default:
148 return false;
149 }
150}
151
152GLenum Texture::getMinFilter() const
153{
154 return mMinFilter;
155}
156
157GLenum Texture::getMagFilter() const
158{
159 return mMagFilter;
160}
161
162GLenum Texture::getWrapS() const
163{
164 return mWrapS;
165}
166
167GLenum Texture::getWrapT() const
168{
169 return mWrapT;
170}
171
172GLsizei Texture::getWidth() const
173{
174 return mWidth;
175}
176
177GLsizei Texture::getHeight() const
178{
179 return mHeight;
180}
181
182bool Texture::isFloatingPoint() const
183{
184 return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
185}
186
187bool Texture::isRenderableFormat() const
188{
189 D3DFORMAT format = getD3DFormat();
190
191 switch(format)
192 {
193 case D3DFMT_L8:
194 case D3DFMT_A8L8:
195 case D3DFMT_DXT1:
196 return false;
197 case D3DFMT_A8R8G8B8:
198 case D3DFMT_X8R8G8B8:
199 case D3DFMT_A16B16G16R16F:
200 case D3DFMT_A32B32G32R32F:
201 return true;
202 default:
203 UNREACHABLE();
204 }
205
206 return false;
207}
208
209// Selects an internal Direct3D 9 format for storing an Image
210D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
211{
212 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
213 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
214 {
215 return D3DFMT_DXT1;
216 }
217 else if (type == GL_FLOAT)
218 {
219 return D3DFMT_A32B32G32R32F;
220 }
221 else if (type == GL_HALF_FLOAT_OES)
222 {
223 return D3DFMT_A16B16G16R16F;
224 }
225 else if (type == GL_UNSIGNED_BYTE)
226 {
227 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
228 {
229 return D3DFMT_L8;
230 }
231 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
232 {
233 return D3DFMT_A8L8;
234 }
235 else if (format == GL_RGB)
236 {
237 return D3DFMT_X8R8G8B8;
238 }
239
240 return D3DFMT_A8R8G8B8;
241 }
242
243 return D3DFMT_A8R8G8B8;
244}
245
246// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
247// into the target pixel rectangle at output with outputPitch bytes in between each line.
248void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
249 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
250{
251 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
252 input = ((char*)input) - inputPitch * (height - 1);
253
254 switch (type)
255 {
256 case GL_UNSIGNED_BYTE:
257 switch (format)
258 {
259 case GL_ALPHA:
260 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
261 break;
262 case GL_LUMINANCE:
263 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
264 break;
265 case GL_LUMINANCE_ALPHA:
266 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
267 break;
268 case GL_RGB:
269 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
270 break;
271 case GL_RGBA:
272 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
273 break;
274 case GL_BGRA_EXT:
275 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
276 break;
277 default: UNREACHABLE();
278 }
279 break;
280 case GL_UNSIGNED_SHORT_5_6_5:
281 switch (format)
282 {
283 case GL_RGB:
284 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
285 break;
286 default: UNREACHABLE();
287 }
288 break;
289 case GL_UNSIGNED_SHORT_4_4_4_4:
290 switch (format)
291 {
292 case GL_RGBA:
293 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
294 break;
295 default: UNREACHABLE();
296 }
297 break;
298 case GL_UNSIGNED_SHORT_5_5_5_1:
299 switch (format)
300 {
301 case GL_RGBA:
302 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
303 break;
304 default: UNREACHABLE();
305 }
306 break;
307 case GL_FLOAT:
308 switch (format)
309 {
310 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
311 case GL_ALPHA:
312 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
313 break;
314 case GL_LUMINANCE:
315 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
316 break;
317 case GL_LUMINANCE_ALPHA:
318 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
319 break;
320 case GL_RGB:
321 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
322 break;
323 case GL_RGBA:
324 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
325 break;
326 default: UNREACHABLE();
327 }
328 break;
329 case GL_HALF_FLOAT_OES:
330 switch (format)
331 {
332 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
333 case GL_ALPHA:
334 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
335 break;
336 case GL_LUMINANCE:
337 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
338 break;
339 case GL_LUMINANCE_ALPHA:
340 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
341 break;
342 case GL_RGB:
343 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
344 break;
345 case GL_RGBA:
346 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
347 break;
348 default: UNREACHABLE();
349 }
350 break;
351 default: UNREACHABLE();
352 }
353}
354
355void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
356 int inputPitch, const void *input, size_t outputPitch, void *output) const
357{
358 const unsigned char *source = NULL;
359 unsigned char *dest = NULL;
360
361 for (int y = 0; y < height; y++)
362 {
363 source = static_cast<const unsigned char*>(input) + y * inputPitch;
364 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
365 for (int x = 0; x < width; x++)
366 {
367 dest[4 * x + 0] = 0;
368 dest[4 * x + 1] = 0;
369 dest[4 * x + 2] = 0;
370 dest[4 * x + 3] = source[x];
371 }
372 }
373}
374
375void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
376 int inputPitch, const void *input, size_t outputPitch, void *output) const
377{
378 const float *source = NULL;
379 float *dest = NULL;
380
381 for (int y = 0; y < height; y++)
382 {
383 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
384 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
385 for (int x = 0; x < width; x++)
386 {
387 dest[4 * x + 0] = 0;
388 dest[4 * x + 1] = 0;
389 dest[4 * x + 2] = 0;
390 dest[4 * x + 3] = source[x];
391 }
392 }
393}
394
395void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
396 int inputPitch, const void *input, size_t outputPitch, void *output) const
397{
398 const unsigned short *source = NULL;
399 unsigned short *dest = NULL;
400
401 for (int y = 0; y < height; y++)
402 {
403 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
404 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
405 for (int x = 0; x < width; x++)
406 {
407 dest[4 * x + 0] = 0;
408 dest[4 * x + 1] = 0;
409 dest[4 * x + 2] = 0;
410 dest[4 * x + 3] = source[x];
411 }
412 }
413}
414
415void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
416 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
417{
418 const int destBytesPerPixel = native? 1: 4;
419 const unsigned char *source = NULL;
420 unsigned char *dest = NULL;
421
422 for (int y = 0; y < height; y++)
423 {
424 source = static_cast<const unsigned char*>(input) + y * inputPitch;
425 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
426
427 if (!native) // BGRA8 destination format
428 {
429 for (int x = 0; x < width; x++)
430 {
431 dest[4 * x + 0] = source[x];
432 dest[4 * x + 1] = source[x];
433 dest[4 * x + 2] = source[x];
434 dest[4 * x + 3] = 0xFF;
435 }
436 }
437 else // L8 destination format
438 {
439 memcpy(dest, source, width);
440 }
441 }
442}
443
444void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
445 int inputPitch, const void *input, size_t outputPitch, void *output) const
446{
447 const float *source = NULL;
448 float *dest = NULL;
449
450 for (int y = 0; y < height; y++)
451 {
452 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
453 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
454 for (int x = 0; x < width; x++)
455 {
456 dest[4 * x + 0] = source[x];
457 dest[4 * x + 1] = source[x];
458 dest[4 * x + 2] = source[x];
459 dest[4 * x + 3] = 1.0f;
460 }
461 }
462}
463
464void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
465 int inputPitch, const void *input, size_t outputPitch, void *output) const
466{
467 const unsigned short *source = NULL;
468 unsigned short *dest = NULL;
469
470 for (int y = 0; y < height; y++)
471 {
472 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
473 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
474 for (int x = 0; x < width; x++)
475 {
476 dest[4 * x + 0] = source[x];
477 dest[4 * x + 1] = source[x];
478 dest[4 * x + 2] = source[x];
479 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
480 }
481 }
482}
483
484void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
485 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
486{
487 const int destBytesPerPixel = native? 2: 4;
488 const unsigned char *source = NULL;
489 unsigned char *dest = NULL;
490
491 for (int y = 0; y < height; y++)
492 {
493 source = static_cast<const unsigned char*>(input) + y * inputPitch;
494 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
495
496 if (!native) // BGRA8 destination format
497 {
498 for (int x = 0; x < width; x++)
499 {
500 dest[4 * x + 0] = source[2*x+0];
501 dest[4 * x + 1] = source[2*x+0];
502 dest[4 * x + 2] = source[2*x+0];
503 dest[4 * x + 3] = source[2*x+1];
504 }
505 }
506 else
507 {
508 memcpy(dest, source, width * 2);
509 }
510 }
511}
512
513void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
514 int inputPitch, const void *input, size_t outputPitch, void *output) const
515{
516 const float *source = NULL;
517 float *dest = NULL;
518
519 for (int y = 0; y < height; y++)
520 {
521 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
522 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
523 for (int x = 0; x < width; x++)
524 {
525 dest[4 * x + 0] = source[2*x+0];
526 dest[4 * x + 1] = source[2*x+0];
527 dest[4 * x + 2] = source[2*x+0];
528 dest[4 * x + 3] = source[2*x+1];
529 }
530 }
531}
532
533void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
534 int inputPitch, const void *input, size_t outputPitch, void *output) const
535{
536 const unsigned short *source = NULL;
537 unsigned short *dest = NULL;
538
539 for (int y = 0; y < height; y++)
540 {
541 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
542 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
543 for (int x = 0; x < width; x++)
544 {
545 dest[4 * x + 0] = source[2*x+0];
546 dest[4 * x + 1] = source[2*x+0];
547 dest[4 * x + 2] = source[2*x+0];
548 dest[4 * x + 3] = source[2*x+1];
549 }
550 }
551}
552
553void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
554 int inputPitch, const void *input, size_t outputPitch, void *output) const
555{
556 const unsigned char *source = NULL;
557 unsigned char *dest = NULL;
558
559 for (int y = 0; y < height; y++)
560 {
561 source = static_cast<const unsigned char*>(input) + y * inputPitch;
562 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
563 for (int x = 0; x < width; x++)
564 {
565 dest[4 * x + 0] = source[x * 3 + 2];
566 dest[4 * x + 1] = source[x * 3 + 1];
567 dest[4 * x + 2] = source[x * 3 + 0];
568 dest[4 * x + 3] = 0xFF;
569 }
570 }
571}
572
573void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
574 int inputPitch, const void *input, size_t outputPitch, void *output) const
575{
576 const unsigned short *source = NULL;
577 unsigned char *dest = NULL;
578
579 for (int y = 0; y < height; y++)
580 {
581 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
582 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
583 for (int x = 0; x < width; x++)
584 {
585 unsigned short rgba = source[x];
586 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
587 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
588 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
589 dest[4 * x + 3] = 0xFF;
590 }
591 }
592}
593
594void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
595 int inputPitch, const void *input, size_t outputPitch, void *output) const
596{
597 const float *source = NULL;
598 float *dest = NULL;
599
600 for (int y = 0; y < height; y++)
601 {
602 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
603 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
604 for (int x = 0; x < width; x++)
605 {
606 dest[4 * x + 0] = source[x * 3 + 0];
607 dest[4 * x + 1] = source[x * 3 + 1];
608 dest[4 * x + 2] = source[x * 3 + 2];
609 dest[4 * x + 3] = 1.0f;
610 }
611 }
612}
613
614void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
615 int inputPitch, const void *input, size_t outputPitch, void *output) const
616{
617 const unsigned short *source = NULL;
618 unsigned short *dest = NULL;
619
620 for (int y = 0; y < height; y++)
621 {
622 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
623 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
624 for (int x = 0; x < width; x++)
625 {
626 dest[4 * x + 0] = source[x * 3 + 0];
627 dest[4 * x + 1] = source[x * 3 + 1];
628 dest[4 * x + 2] = source[x * 3 + 2];
629 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
630 }
631 }
632}
633
634void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
635 int inputPitch, const void *input, size_t outputPitch, void *output) const
636{
637 const unsigned char *source = NULL;
638 unsigned char *dest = NULL;
639
640 for (int y = 0; y < height; y++)
641 {
642 source = static_cast<const unsigned char*>(input) + y * inputPitch;
643 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
644 for (int x = 0; x < width; x++)
645 {
646 dest[4 * x + 0] = source[x * 4 + 2];
647 dest[4 * x + 1] = source[x * 4 + 1];
648 dest[4 * x + 2] = source[x * 4 + 0];
649 dest[4 * x + 3] = source[x * 4 + 3];
650 }
651 }
652}
653
654void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
655 int inputPitch, const void *input, size_t outputPitch, void *output) const
656{
657 const unsigned short *source = NULL;
658 unsigned char *dest = NULL;
659
660 for (int y = 0; y < height; y++)
661 {
662 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
663 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
664 for (int x = 0; x < width; x++)
665 {
666 unsigned short rgba = source[x];
667 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
668 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
669 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
670 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
671 }
672 }
673}
674
675void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
676 int inputPitch, const void *input, size_t outputPitch, void *output) const
677{
678 const unsigned short *source = NULL;
679 unsigned char *dest = NULL;
680
681 for (int y = 0; y < height; y++)
682 {
683 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
684 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
685 for (int x = 0; x < width; x++)
686 {
687 unsigned short rgba = source[x];
688 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
689 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
690 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
691 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
692 }
693 }
694}
695
696void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
697 int inputPitch, const void *input, size_t outputPitch, void *output) const
698{
699 const float *source = NULL;
700 float *dest = NULL;
701
702 for (int y = 0; y < height; y++)
703 {
704 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
705 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
706 memcpy(dest, source, width * 16);
707 }
708}
709
710void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
711 int inputPitch, const void *input, size_t outputPitch, void *output) const
712{
713 const unsigned char *source = NULL;
714 unsigned char *dest = NULL;
715
716 for (int y = 0; y < height; y++)
717 {
718 source = static_cast<const unsigned char*>(input) + y * inputPitch;
719 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
720 memcpy(dest, source, width * 8);
721 }
722}
723
724void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
725 int inputPitch, const void *input, size_t outputPitch, void *output) const
726{
727 const unsigned char *source = NULL;
728 unsigned char *dest = NULL;
729
730 for (int y = 0; y < height; y++)
731 {
732 source = static_cast<const unsigned char*>(input) + y * inputPitch;
733 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
734 memcpy(dest, source, width*4);
735 }
736}
737
738void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
739 int inputPitch, const void *input, size_t outputPitch, void *output) const
740{
741 ASSERT(xoffset % 4 == 0);
742 ASSERT(yoffset % 4 == 0);
743 ASSERT(width % 4 == 0 || width == 2 || width == 1);
744 ASSERT(inputPitch % 8 == 0);
745 ASSERT(outputPitch % 8 == 0);
746
747 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
748 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
749
750 switch (height)
751 {
752 case 1:
753 // Round width up in case it is 1.
754 for (int x = 0; x < (width + 1) / 2; x += 2)
755 {
756 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
757 dest[x] = source[x];
758
759 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
760 dest[x + 1] = source[x + 1];
761 }
762 break;
763 case 2:
764 // Round width up in case it is 1.
765 for (int x = 0; x < (width + 1) / 2; x += 2)
766 {
767 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
768 dest[x] = source[x];
769
770 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 2 rows being unused. Only the top 2 rows should be flipped.
771 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
772 ((source[x + 1] >> 8) & 0x000000FF);
773 }
774 break;
775 default:
776 ASSERT(height % 4 == 0);
777 for (int y = 0; y < height / 4; ++y)
778 {
779 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
780 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
781
782 // Round width up in case it is 1.
783 for (int x = 0; x < (width + 1) / 2; x += 2)
784 {
785 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
786 dest[x] = source[x];
787
788 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
789 dest[x + 1] = (source[x + 1] >> 24) |
790 ((source[x + 1] << 8) & 0x00FF0000) |
791 ((source[x + 1] >> 8) & 0x0000FF00) |
792 (source[x + 1] << 24);
793 }
794 }
795 break;
796 }
797}
798
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000799void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000800{
801 IDirect3DTexture9 *newTexture = NULL;
802 IDirect3DSurface9 *newSurface = NULL;
803
804 if (width != 0 && height != 0)
805 {
806 int levelToFetch = 0;
807 GLsizei requestWidth = width;
808 GLsizei requestHeight = height;
809 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
810 {
811 bool isMult4 = false;
812 int upsampleCount = 0;
813 while (!isMult4)
814 {
815 requestWidth <<= 1;
816 requestHeight <<= 1;
817 upsampleCount++;
818 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
819 {
820 isMult4 = true;
821 }
822 }
823 levelToFetch = upsampleCount;
824 }
825
826 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
827 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
828
829 if (FAILED(result))
830 {
831 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
832 return error(GL_OUT_OF_MEMORY);
833 }
834
835 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
836 newTexture->Release();
837 }
838
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000839 if (image->surface)
840 {
841 image->surface->Release();
842 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000843
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000844 image->surface = newSurface;
845
846 image->width = width;
847 image->height = height;
848 image->format = format;
849 image->type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000850}
851
852void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
853{
854 createSurface(width, height, format, type, img);
855
856 if (pixels != NULL && img->surface != NULL)
857 {
858 D3DSURFACE_DESC description;
859 img->surface->GetDesc(&description);
860
861 D3DLOCKED_RECT locked;
862 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
863
864 ASSERT(SUCCEEDED(result));
865
866 if (SUCCEEDED(result))
867 {
868 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
869 img->surface->UnlockRect();
870 }
871
872 img->dirty = true;
873 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000874}
875
876void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
877{
878 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
879
880 if (pixels != NULL && img->surface != NULL)
881 {
882 D3DLOCKED_RECT locked;
883 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
884
885 ASSERT(SUCCEEDED(result));
886
887 if (SUCCEEDED(result))
888 {
889 int inputPitch = ComputeCompressedPitch(width, format);
890 int inputSize = ComputeCompressedSize(width, height, format);
891 loadCompressedImageData(0, 0, width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
892 img->surface->UnlockRect();
893 }
894
895 img->dirty = true;
896 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000897}
898
899bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
900{
901 if (width + xoffset > img->width || height + yoffset > img->height)
902 {
903 error(GL_INVALID_VALUE);
904 return false;
905 }
906
907 if (!img->surface)
908 {
909 createSurface(img->width, img->height, format, type, img);
910 }
911
912 if (pixels != NULL && img->surface != NULL)
913 {
914 D3DSURFACE_DESC description;
915 img->surface->GetDesc(&description);
916
917 D3DLOCKED_RECT locked;
918 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
919
920 ASSERT(SUCCEEDED(result));
921
922 if (SUCCEEDED(result))
923 {
924 loadImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
925 img->surface->UnlockRect();
926 }
927
928 img->dirty = true;
929 }
930
931 return true;
932}
933
934bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
935{
936 if (width + xoffset > img->width || height + yoffset > img->height)
937 {
938 error(GL_INVALID_VALUE);
939 return false;
940 }
941
942 if (format != getInternalFormat())
943 {
944 error(GL_INVALID_OPERATION);
945 return false;
946 }
947
948 if (!img->surface)
949 {
950 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
951 }
952
953 if (pixels != NULL && img->surface != NULL)
954 {
955 RECT updateRegion;
956 updateRegion.left = xoffset;
957 updateRegion.right = xoffset + width;
958 updateRegion.bottom = yoffset + height;
959 updateRegion.top = yoffset;
960
961 D3DLOCKED_RECT locked;
962 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
963
964 ASSERT(SUCCEEDED(result));
965
966 if (SUCCEEDED(result))
967 {
968 int inputPitch = ComputeCompressedPitch(width, format);
969 int inputSize = ComputeCompressedSize(width, height, format);
970 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
971 img->surface->UnlockRect();
972 }
973
974 img->dirty = true;
975 }
976
977 return true;
978}
979
980// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +0000981void Texture::copyNonRenderable(Image *image, GLenum format, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000982{
983 IDirect3DDevice9 *device = getDevice();
984 IDirect3DSurface9 *surface = NULL;
985 D3DSURFACE_DESC description;
986 renderTarget->GetDesc(&description);
987
988 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
989
990 if (!SUCCEEDED(result))
991 {
992 ERR("Could not create matching destination surface.");
993 return error(GL_OUT_OF_MEMORY);
994 }
995
996 result = device->GetRenderTargetData(renderTarget, surface);
997
998 if (!SUCCEEDED(result))
999 {
1000 ERR("GetRenderTargetData unexpectedly failed.");
1001 surface->Release();
1002 return error(GL_OUT_OF_MEMORY);
1003 }
1004
1005 D3DLOCKED_RECT sourceLock = {0};
1006 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
1007 result = surface->LockRect(&sourceLock, &sourceRect, 0);
1008
1009 if (FAILED(result))
1010 {
1011 ERR("Failed to lock the source surface (rectangle might be invalid).");
1012 surface->UnlockRect();
1013 surface->Release();
1014 return error(GL_OUT_OF_MEMORY);
1015 }
1016
1017 if (!image->surface)
1018 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001019 createSurface(width, height, format, mType, image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001020 }
1021
1022 if (image->surface == NULL)
1023 {
1024 ERR("Failed to create an image surface.");
1025 surface->UnlockRect();
1026 surface->Release();
1027 return error(GL_OUT_OF_MEMORY);
1028 }
1029
1030 D3DLOCKED_RECT destLock = {0};
1031 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1032 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1033 result = image->surface->LockRect(&destLock, &destRect, 0);
1034
1035 if (FAILED(result))
1036 {
1037 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1038 surface->UnlockRect();
1039 surface->Release();
1040 return error(GL_OUT_OF_MEMORY);
1041 }
1042
1043 if (destLock.pBits && sourceLock.pBits)
1044 {
1045 unsigned char *source = (unsigned char*)sourceLock.pBits;
1046 unsigned char *dest = (unsigned char*)destLock.pBits;
1047
1048 switch (description.Format)
1049 {
1050 case D3DFMT_X8R8G8B8:
1051 case D3DFMT_A8R8G8B8:
1052 switch(getD3DFormat())
1053 {
1054 case D3DFMT_L8:
1055 for(int y = 0; y < height; y++)
1056 {
1057 for(int x = 0; x < width; x++)
1058 {
1059 dest[x] = source[x * 4 + 2];
1060 }
1061
1062 source += sourceLock.Pitch;
1063 dest += destLock.Pitch;
1064 }
1065 break;
1066 case D3DFMT_A8L8:
1067 for(int y = 0; y < height; y++)
1068 {
1069 for(int x = 0; x < width; x++)
1070 {
1071 dest[x * 2 + 0] = source[x * 4 + 2];
1072 dest[x * 2 + 1] = source[x * 4 + 3];
1073 }
1074
1075 source += sourceLock.Pitch;
1076 dest += destLock.Pitch;
1077 }
1078 break;
1079 default:
1080 UNREACHABLE();
1081 }
1082 break;
1083 case D3DFMT_R5G6B5:
1084 switch(getD3DFormat())
1085 {
1086 case D3DFMT_L8:
1087 for(int y = 0; y < height; y++)
1088 {
1089 for(int x = 0; x < width; x++)
1090 {
1091 unsigned char red = source[x * 2 + 1] & 0xF8;
1092 dest[x] = red | (red >> 5);
1093 }
1094
1095 source += sourceLock.Pitch;
1096 dest += destLock.Pitch;
1097 }
1098 break;
1099 default:
1100 UNREACHABLE();
1101 }
1102 break;
1103 case D3DFMT_A1R5G5B5:
1104 switch(getD3DFormat())
1105 {
1106 case D3DFMT_L8:
1107 for(int y = 0; y < height; y++)
1108 {
1109 for(int x = 0; x < width; x++)
1110 {
1111 unsigned char red = source[x * 2 + 1] & 0x7C;
1112 dest[x] = (red << 1) | (red >> 4);
1113 }
1114
1115 source += sourceLock.Pitch;
1116 dest += destLock.Pitch;
1117 }
1118 break;
1119 case D3DFMT_A8L8:
1120 for(int y = 0; y < height; y++)
1121 {
1122 for(int x = 0; x < width; x++)
1123 {
1124 unsigned char red = source[x * 2 + 1] & 0x7C;
1125 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1126 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1127 }
1128
1129 source += sourceLock.Pitch;
1130 dest += destLock.Pitch;
1131 }
1132 break;
1133 default:
1134 UNREACHABLE();
1135 }
1136 break;
1137 default:
1138 UNREACHABLE();
1139 }
1140
1141 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001142 }
1143
1144 image->surface->UnlockRect();
1145 surface->UnlockRect();
1146 surface->Release();
1147}
1148
1149D3DFORMAT Texture::getD3DFormat() const
1150{
1151 return selectFormat(getInternalFormat(), mType);
1152}
1153
1154IDirect3DBaseTexture9 *Texture::getTexture()
1155{
1156 if (!isComplete())
1157 {
1158 return NULL;
1159 }
1160
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001161 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001162 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001163 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001164 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001165
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001166 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001167
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001168 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001169}
1170
1171bool Texture::isDirty() const
1172{
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001173 return true;//(mDirty || mDirtyMetaData || dirtyImageData());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001174}
1175
1176// Returns the top-level texture surface as a render target
1177void Texture::needRenderTarget()
1178{
1179 if (!mIsRenderable)
1180 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001181 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001182 }
1183
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001184 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001185}
1186
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001187GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1188{
1189 if (isPow2(width) && isPow2(height))
1190 {
1191 return maxlevel;
1192 }
1193 else
1194 {
1195 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1196 return 1;
1197 }
1198}
1199
1200GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1201{
1202 return creationLevels(size, size, maxlevel);
1203}
1204
1205int Texture::levelCount() const
1206{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001207 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001208}
1209
1210Texture2D::Texture2D(GLuint id) : Texture(id)
1211{
1212 mTexture = NULL;
1213}
1214
1215Texture2D::~Texture2D()
1216{
1217 mColorbufferProxy.set(NULL);
1218
1219 if (mTexture)
1220 {
1221 mTexture->Release();
1222 mTexture = NULL;
1223 }
1224}
1225
1226GLenum Texture2D::getTarget() const
1227{
1228 return GL_TEXTURE_2D;
1229}
1230
1231GLenum Texture2D::getInternalFormat() const
1232{
1233 return mImageArray[0].format;
1234}
1235
1236// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1237// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
1238// Call this when a particular level of the texture must be defined with a specific format, width and height.
1239//
1240// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
1241// a new height and width for the texture by working backwards from the given width and height.
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001242bool Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001243{
1244 bool widthOkay = (mWidth >> level == width);
1245 bool heightOkay = (mHeight >> level == height);
1246
1247 bool sizeOkay = ((widthOkay && heightOkay)
1248 || (widthOkay && mHeight >> level == 0 && height == 1)
1249 || (heightOkay && mWidth >> level == 0 && width == 1));
1250
1251 bool typeOkay = (type == mType);
1252
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001253 bool textureOkay = (sizeOkay && typeOkay && format == mImageArray[0].format);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001254
1255 if (!textureOkay)
1256 {
1257 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
1258 mImageArray[0].format, mWidth, mHeight,
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001259 format, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001260
1261 // Purge all the levels and the texture.
1262
1263 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1264 {
1265 if (mImageArray[i].surface != NULL)
1266 {
1267 mImageArray[i].dirty = false;
1268
1269 mImageArray[i].surface->Release();
1270 mImageArray[i].surface = NULL;
1271 }
1272 }
1273
1274 if (mTexture != NULL)
1275 {
1276 mTexture->Release();
1277 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001278 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001279 }
1280
1281 mWidth = width << level;
1282 mHeight = height << level;
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001283 mImageArray[0].format = format;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001284 mType = type;
1285 }
1286
1287 return !textureOkay;
1288}
1289
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001290void 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 +00001291{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001292 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001293
1294 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
1295}
1296
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001297void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001298{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001299 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001300
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001301 Texture::setCompressedImage(width, height, format, imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001302}
1303
1304void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1305{
1306 ASSERT(mImageArray[level].surface != NULL);
1307
1308 if (level < levelCount())
1309 {
1310 IDirect3DSurface9 *destLevel = NULL;
1311 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1312
1313 ASSERT(SUCCEEDED(result));
1314
1315 if (SUCCEEDED(result))
1316 {
1317 Image *img = &mImageArray[level];
1318
1319 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
1320
1321 POINT destPoint;
1322 destPoint.x = sourceRect.left;
1323 destPoint.y = sourceRect.top;
1324
1325 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1326 ASSERT(SUCCEEDED(result));
1327
1328 destLevel->Release();
1329
1330 img->dirty = false;
1331 }
1332 }
1333}
1334
1335void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1336{
1337 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1338 {
1339 commitRect(level, xoffset, yoffset, width, height);
1340 }
1341}
1342
1343void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1344{
1345 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1346 {
1347 commitRect(level, xoffset, yoffset, width, height);
1348 }
1349}
1350
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001351void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001352{
1353 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1354
1355 if (!renderTarget)
1356 {
1357 ERR("Failed to retrieve the render target.");
1358 return error(GL_OUT_OF_MEMORY);
1359 }
1360
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001361 bool redefined = redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001362
1363 if (!isRenderableFormat())
1364 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001365 copyNonRenderable(&mImageArray[level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001366 }
1367 else
1368 {
1369 if (redefined)
1370 {
1371 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001372 }
1373 else
1374 {
1375 needRenderTarget();
1376 }
1377
1378 if (width != 0 && height != 0 && level < levelCount())
1379 {
1380 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1381 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1382 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1383 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1384 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1385
1386 IDirect3DSurface9 *dest;
1387 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1388
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001389 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001390 dest->Release();
1391 }
1392 }
1393
1394 mImageArray[level].width = width;
1395 mImageArray[level].height = height;
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001396 mImageArray[level].format = format;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001397 mImageArray[level].type = GL_UNSIGNED_BYTE;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001398}
1399
1400void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1401{
1402 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1403 {
1404 return error(GL_INVALID_VALUE);
1405 }
1406
1407 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1408
1409 if (!renderTarget)
1410 {
1411 ERR("Failed to retrieve the render target.");
1412 return error(GL_OUT_OF_MEMORY);
1413 }
1414
1415 bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
1416
1417 if (!isRenderableFormat())
1418 {
1419 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1420 }
1421 else
1422 {
1423 if (redefined)
1424 {
1425 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001426 }
1427 else
1428 {
1429 needRenderTarget();
1430 }
1431
1432 if (level < levelCount())
1433 {
1434 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1435 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1436 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1437 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1438 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1439
1440 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1441
1442 IDirect3DSurface9 *dest;
1443 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1444
1445 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1446 dest->Release();
1447 }
1448 }
1449}
1450
1451// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1452bool Texture2D::isComplete() const
1453{
1454 GLsizei width = mImageArray[0].width;
1455 GLsizei height = mImageArray[0].height;
1456
1457 if (width <= 0 || height <= 0)
1458 {
1459 return false;
1460 }
1461
1462 bool mipmapping = false;
1463
1464 switch (mMinFilter)
1465 {
1466 case GL_NEAREST:
1467 case GL_LINEAR:
1468 mipmapping = false;
1469 break;
1470 case GL_NEAREST_MIPMAP_NEAREST:
1471 case GL_LINEAR_MIPMAP_NEAREST:
1472 case GL_NEAREST_MIPMAP_LINEAR:
1473 case GL_LINEAR_MIPMAP_LINEAR:
1474 mipmapping = true;
1475 break;
1476 default: UNREACHABLE();
1477 }
1478
1479 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1480 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1481 {
1482 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1483 {
1484 return false;
1485 }
1486 }
1487
1488
1489 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1490 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1491 {
1492 return false;
1493 }
1494
1495 if (mipmapping)
1496 {
1497 if (!isPow2(width) || !isPow2(height))
1498 {
1499 return false;
1500 }
1501
1502 int q = log2(std::max(width, height));
1503
1504 for (int level = 1; level <= q; level++)
1505 {
1506 if (mImageArray[level].format != mImageArray[0].format)
1507 {
1508 return false;
1509 }
1510
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001511 if (mImageArray[level].type != mImageArray[0].type)
1512 {
1513 return false;
1514 }
1515
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001516 if (mImageArray[level].width != std::max(1, width >> level))
1517 {
1518 return false;
1519 }
1520
1521 if (mImageArray[level].height != std::max(1, height >> level))
1522 {
1523 return false;
1524 }
1525 }
1526 }
1527
1528 return true;
1529}
1530
1531bool Texture2D::isCompressed() const
1532{
1533 return IsCompressed(getInternalFormat());
1534}
1535
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001536IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1537{
1538 return mTexture;
1539}
1540
1541// Constructs a Direct3D 9 texture resource from the texture images
1542void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001543{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001544 IDirect3DDevice9 *device = getDevice();
1545 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
1546
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001547 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001548 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
1549
1550 if (FAILED(result))
1551 {
1552 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001553 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001554 }
1555
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001556 if (mTexture)
1557 {
1558 mTexture->Release();
1559 }
1560
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001561 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001562 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001563}
1564
1565void Texture2D::updateTexture()
1566{
1567 IDirect3DDevice9 *device = getDevice();
1568
1569 int levels = levelCount();
1570
1571 for (int level = 0; level < levels; level++)
1572 {
1573 if (mImageArray[level].dirty)
1574 {
1575 IDirect3DSurface9 *levelSurface = NULL;
1576 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1577
1578 ASSERT(SUCCEEDED(result));
1579
1580 if (SUCCEEDED(result))
1581 {
1582 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1583 ASSERT(SUCCEEDED(result));
1584
1585 levelSurface->Release();
1586
1587 mImageArray[level].dirty = false;
1588 }
1589 }
1590 }
1591}
1592
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001593void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001594{
1595 IDirect3DTexture9 *texture = NULL;
1596
1597 if (mWidth != 0 && mHeight != 0)
1598 {
1599 egl::Display *display = getDisplay();
1600 IDirect3DDevice9 *device = getDevice();
1601 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
1602
1603 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
1604
1605 if (FAILED(result))
1606 {
1607 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001608 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001609 }
1610
1611 if (mTexture != NULL)
1612 {
1613 int levels = levelCount();
1614 for (int i = 0; i < levels; i++)
1615 {
1616 IDirect3DSurface9 *source;
1617 result = mTexture->GetSurfaceLevel(i, &source);
1618
1619 if (FAILED(result))
1620 {
1621 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1622
1623 texture->Release();
1624
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001625 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001626 }
1627
1628 IDirect3DSurface9 *dest;
1629 result = texture->GetSurfaceLevel(i, &dest);
1630
1631 if (FAILED(result))
1632 {
1633 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1634
1635 texture->Release();
1636 source->Release();
1637
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001638 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001639 }
1640
1641 display->endScene();
1642 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1643
1644 if (FAILED(result))
1645 {
1646 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1647
1648 texture->Release();
1649 source->Release();
1650 dest->Release();
1651
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001652 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001653 }
1654
1655 source->Release();
1656 dest->Release();
1657 }
1658 }
1659 }
1660
1661 if (mTexture != NULL)
1662 {
1663 mTexture->Release();
1664 }
1665
1666 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001667 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001668}
1669
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001670void Texture2D::generateMipmaps()
1671{
1672 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1673 {
1674 return error(GL_INVALID_OPERATION);
1675 }
1676
1677 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1678 unsigned int q = log2(std::max(mWidth, mHeight));
1679 for (unsigned int i = 1; i <= q; i++)
1680 {
1681 if (mImageArray[i].surface != NULL)
1682 {
1683 mImageArray[i].surface->Release();
1684 mImageArray[i].surface = NULL;
1685 }
1686
1687 mImageArray[i].dirty = false;
1688
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001689 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1690 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001691 mImageArray[i].format = mImageArray[0].format;
1692 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001693 }
1694
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001695 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001696 {
1697 if (mTexture == NULL)
1698 {
1699 ERR(" failed because mTexture was null.");
1700 return;
1701 }
1702
1703 for (unsigned int i = 1; i <= q; i++)
1704 {
1705 IDirect3DSurface9 *upper = NULL;
1706 IDirect3DSurface9 *lower = NULL;
1707
1708 mTexture->GetSurfaceLevel(i-1, &upper);
1709 mTexture->GetSurfaceLevel(i, &lower);
1710
1711 if (upper != NULL && lower != NULL)
1712 {
1713 getBlitter()->boxFilter(upper, lower);
1714 }
1715
1716 if (upper != NULL) upper->Release();
1717 if (lower != NULL) lower->Release();
1718 }
1719 }
1720 else
1721 {
1722 for (unsigned int i = 1; i <= q; i++)
1723 {
1724 createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
1725 if (mImageArray[i].surface == NULL)
1726 {
1727 return error(GL_OUT_OF_MEMORY);
1728 }
1729
1730 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1731 {
1732 ERR(" failed to load filter %d to %d.", i - 1, i);
1733 }
1734
1735 mImageArray[i].dirty = true;
1736 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001737 }
1738}
1739
1740Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1741{
1742 if (target != GL_TEXTURE_2D)
1743 {
1744 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1745 }
1746
1747 if (mColorbufferProxy.get() == NULL)
1748 {
1749 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1750 }
1751
1752 return mColorbufferProxy.get();
1753}
1754
1755IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1756{
1757 ASSERT(target == GL_TEXTURE_2D);
1758
1759 needRenderTarget();
1760
1761 if (mTexture == NULL)
1762 {
1763 return NULL;
1764 }
1765
1766 IDirect3DSurface9 *renderTarget = NULL;
1767 mTexture->GetSurfaceLevel(0, &renderTarget);
1768
1769 return renderTarget;
1770}
1771
1772TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1773{
1774 mTexture = NULL;
1775}
1776
1777TextureCubeMap::~TextureCubeMap()
1778{
1779 for (int i = 0; i < 6; i++)
1780 {
1781 mFaceProxies[i].set(NULL);
1782 }
1783
1784 if (mTexture)
1785 {
1786 mTexture->Release();
1787 mTexture = NULL;
1788 }
1789}
1790
1791GLenum TextureCubeMap::getTarget() const
1792{
1793 return GL_TEXTURE_CUBE_MAP;
1794}
1795
1796GLenum TextureCubeMap::getInternalFormat() const
1797{
1798 return mImageArray[0][0].format;
1799}
1800
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001801void 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 +00001802{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001803 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001804}
1805
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001806void 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 +00001807{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001808 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001809}
1810
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001811void 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 +00001812{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001813 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001814}
1815
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001816void 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 +00001817{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001818 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001819}
1820
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001821void 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 +00001822{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001823 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001824}
1825
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001826void 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 +00001827{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001828 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001829}
1830
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001831void 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 +00001832{
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001833 redefineTexture(level, format, width, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001834
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001835 Texture::setCompressedImage(width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001836}
1837
1838void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1839{
1840 int face = faceIndex(faceTarget);
1841 ASSERT(mImageArray[face][level].surface != NULL);
1842
1843 if (level < levelCount())
1844 {
1845 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1846 ASSERT(destLevel != NULL);
1847
1848 if (destLevel != NULL)
1849 {
1850 Image *img = &mImageArray[face][level];
1851
1852 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
1853
1854 POINT destPoint;
1855 destPoint.x = sourceRect.left;
1856 destPoint.y = sourceRect.top;
1857
1858 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1859 ASSERT(SUCCEEDED(result));
1860
1861 destLevel->Release();
1862
1863 img->dirty = false;
1864 }
1865 }
1866}
1867
1868void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1869{
1870 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1871 {
1872 commitRect(target, level, xoffset, yoffset, width, height);
1873 }
1874}
1875
1876void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1877{
1878 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1879 {
1880 commitRect(target, level, xoffset, yoffset, width, height);
1881 }
1882}
1883
1884// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1885bool TextureCubeMap::isComplete() const
1886{
1887 int size = mImageArray[0][0].width;
1888
1889 if (size <= 0)
1890 {
1891 return false;
1892 }
1893
1894 bool mipmapping;
1895
1896 switch (mMinFilter)
1897 {
1898 case GL_NEAREST:
1899 case GL_LINEAR:
1900 mipmapping = false;
1901 break;
1902 case GL_NEAREST_MIPMAP_NEAREST:
1903 case GL_LINEAR_MIPMAP_NEAREST:
1904 case GL_NEAREST_MIPMAP_LINEAR:
1905 case GL_LINEAR_MIPMAP_LINEAR:
1906 mipmapping = true;
1907 break;
1908 default: UNREACHABLE();
1909 }
1910
1911 for (int face = 0; face < 6; face++)
1912 {
1913 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1914 {
1915 return false;
1916 }
1917 }
1918
1919 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1920 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1921 {
1922 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1923 {
1924 return false;
1925 }
1926 }
1927
1928 if (mipmapping)
1929 {
1930 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1931 {
1932 return false;
1933 }
1934
1935 int q = log2(size);
1936
1937 for (int face = 0; face < 6; face++)
1938 {
1939 for (int level = 1; level <= q; level++)
1940 {
1941 if (mImageArray[face][level].format != mImageArray[0][0].format)
1942 {
1943 return false;
1944 }
1945
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001946 if (mImageArray[face][level].type != mImageArray[0][0].type)
1947 {
1948 return false;
1949 }
1950
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001951 if (mImageArray[face][level].width != std::max(1, size >> level))
1952 {
1953 return false;
1954 }
1955
1956 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1957 }
1958 }
1959 }
1960
1961 return true;
1962}
1963
1964bool TextureCubeMap::isCompressed() const
1965{
1966 return IsCompressed(getInternalFormat());
1967}
1968
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001969IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1970{
1971 return mTexture;
1972}
1973
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001974// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001975void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001976{
1977 IDirect3DDevice9 *device = getDevice();
1978 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
1979
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001980 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001981 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
1982
1983 if (FAILED(result))
1984 {
1985 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001986 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001987 }
1988
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001989 if (mTexture)
1990 {
1991 mTexture->Release();
1992 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001993
1994 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001995 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001996}
1997
1998void TextureCubeMap::updateTexture()
1999{
2000 IDirect3DDevice9 *device = getDevice();
2001
2002 for (int face = 0; face < 6; face++)
2003 {
2004 int levels = levelCount();
2005 for (int level = 0; level < levels; level++)
2006 {
2007 Image *img = &mImageArray[face][level];
2008
2009 if (img->dirty)
2010 {
2011 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2012 ASSERT(levelSurface != NULL);
2013
2014 if (levelSurface != NULL)
2015 {
2016 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
2017 ASSERT(SUCCEEDED(result));
2018
2019 levelSurface->Release();
2020
2021 img->dirty = false;
2022 }
2023 }
2024 }
2025 }
2026}
2027
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002028void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002029{
2030 IDirect3DCubeTexture9 *texture = NULL;
2031
2032 if (mWidth != 0)
2033 {
2034 egl::Display *display = getDisplay();
2035 IDirect3DDevice9 *device = getDevice();
2036 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
2037
2038 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
2039
2040 if (FAILED(result))
2041 {
2042 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002043 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002044 }
2045
2046 if (mTexture != NULL)
2047 {
2048 int levels = levelCount();
2049 for (int f = 0; f < 6; f++)
2050 {
2051 for (int i = 0; i < levels; i++)
2052 {
2053 IDirect3DSurface9 *source;
2054 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2055
2056 if (FAILED(result))
2057 {
2058 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2059
2060 texture->Release();
2061
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002062 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002063 }
2064
2065 IDirect3DSurface9 *dest;
2066 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2067
2068 if (FAILED(result))
2069 {
2070 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2071
2072 texture->Release();
2073 source->Release();
2074
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002075 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002076 }
2077
2078 display->endScene();
2079 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2080
2081 if (FAILED(result))
2082 {
2083 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2084
2085 texture->Release();
2086 source->Release();
2087 dest->Release();
2088
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002089 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002090 }
2091 }
2092 }
2093 }
2094 }
2095
2096 if (mTexture != NULL)
2097 {
2098 mTexture->Release();
2099 }
2100
2101 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002102 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002103}
2104
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002105void TextureCubeMap::setImage(int face, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002106{
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002107 redefineTexture(level, format, width, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002108
2109 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
2110}
2111
2112unsigned int TextureCubeMap::faceIndex(GLenum face)
2113{
2114 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2115 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2116 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2117 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2118 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2119
2120 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2121}
2122
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002123// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
2124// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
2125// Call this when a particular level of the texture must be defined with a specific format, width and height.
2126//
2127// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
2128// a new size for the texture by working backwards from the given size.
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002129bool TextureCubeMap::redefineTexture(GLint level, GLenum format, GLsizei width, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002130{
2131 // Are these settings compatible with level 0?
2132 bool sizeOkay = (mImageArray[0][0].width >> level == width);
2133
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002134 bool textureOkay = (sizeOkay && format == mImageArray[0][0].format);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002135
2136 if (!textureOkay)
2137 {
2138 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
2139 mImageArray[0][0].format, mImageArray[0][0].width,
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002140 format, width);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002141
2142 // Purge all the levels and the texture.
2143 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2144 {
2145 for (int f = 0; f < 6; f++)
2146 {
2147 if (mImageArray[f][i].surface != NULL)
2148 {
2149 mImageArray[f][i].dirty = false;
2150
2151 mImageArray[f][i].surface->Release();
2152 mImageArray[f][i].surface = NULL;
2153 }
2154 }
2155 }
2156
2157 if (mTexture != NULL)
2158 {
2159 mTexture->Release();
2160 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002161 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002162 }
2163
2164 mWidth = width << level;
2165 mImageArray[0][0].width = width << level;
2166 mHeight = width << level;
2167 mImageArray[0][0].height = width << level;
2168
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002169 mImageArray[0][0].format = format;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002170 mImageArray[0][0].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002171 }
2172
2173 return !textureOkay;
2174}
2175
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002176void 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 +00002177{
2178 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2179
2180 if (!renderTarget)
2181 {
2182 ERR("Failed to retrieve the render target.");
2183 return error(GL_OUT_OF_MEMORY);
2184 }
2185
2186 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002187 bool redefined = redefineTexture(level, format, width, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002188
2189 if (!isRenderableFormat())
2190 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002191 copyNonRenderable(&mImageArray[faceindex][level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002192 }
2193 else
2194 {
2195 if (redefined)
2196 {
2197 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002198 }
2199 else
2200 {
2201 needRenderTarget();
2202 }
2203
2204 ASSERT(width == height);
2205
2206 if (width > 0 && level < levelCount())
2207 {
2208 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2209 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2210 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2211 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2212 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2213
2214 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2215
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002216 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002217 dest->Release();
2218 }
2219 }
2220
2221 mImageArray[faceindex][level].width = width;
2222 mImageArray[faceindex][level].height = height;
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002223 mImageArray[faceindex][level].format = format;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002224 mImageArray[faceindex][level].type = GL_UNSIGNED_BYTE;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002225}
2226
2227IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2228{
2229 if (mTexture == NULL)
2230 {
2231 UNREACHABLE();
2232 return NULL;
2233 }
2234
2235 IDirect3DSurface9 *surface = NULL;
2236
2237 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2238
2239 return (SUCCEEDED(hr)) ? surface : NULL;
2240}
2241
2242void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2243{
2244 GLsizei size = mImageArray[faceIndex(target)][level].width;
2245
2246 if (xoffset + width > size || yoffset + height > size)
2247 {
2248 return error(GL_INVALID_VALUE);
2249 }
2250
2251 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2252
2253 if (!renderTarget)
2254 {
2255 ERR("Failed to retrieve the render target.");
2256 return error(GL_OUT_OF_MEMORY);
2257 }
2258
2259 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002260 bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002261
2262 if (!isRenderableFormat())
2263 {
2264 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2265 }
2266 else
2267 {
2268 if (redefined)
2269 {
2270 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002271 }
2272 else
2273 {
2274 needRenderTarget();
2275 }
2276
2277 if (level < levelCount())
2278 {
2279 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2280 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2281 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2282 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2283 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2284
2285 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2286
2287 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2288
2289 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2290 dest->Release();
2291 }
2292 }
2293}
2294
2295bool TextureCubeMap::isCubeComplete() const
2296{
2297 if (mImageArray[0][0].width == 0)
2298 {
2299 return false;
2300 }
2301
2302 for (unsigned int f = 1; f < 6; f++)
2303 {
2304 if (mImageArray[f][0].width != mImageArray[0][0].width
2305 || mImageArray[f][0].format != mImageArray[0][0].format)
2306 {
2307 return false;
2308 }
2309 }
2310
2311 return true;
2312}
2313
2314void TextureCubeMap::generateMipmaps()
2315{
2316 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2317 {
2318 return error(GL_INVALID_OPERATION);
2319 }
2320
2321 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2322 unsigned int q = log2(mImageArray[0][0].width);
2323 for (unsigned int f = 0; f < 6; f++)
2324 {
2325 for (unsigned int i = 1; i <= q; i++)
2326 {
2327 if (mImageArray[f][i].surface != NULL)
2328 {
2329 mImageArray[f][i].surface->Release();
2330 mImageArray[f][i].surface = NULL;
2331 }
2332
2333 mImageArray[f][i].dirty = false;
2334
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002335 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2336 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002337 mImageArray[f][i].format = mImageArray[f][0].format;
2338 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002339 }
2340 }
2341
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002342 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002343 {
2344 if (mTexture == NULL)
2345 {
2346 return;
2347 }
2348
2349 for (unsigned int f = 0; f < 6; f++)
2350 {
2351 for (unsigned int i = 1; i <= q; i++)
2352 {
2353 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2354 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2355
2356 if (upper != NULL && lower != NULL)
2357 {
2358 getBlitter()->boxFilter(upper, lower);
2359 }
2360
2361 if (upper != NULL) upper->Release();
2362 if (lower != NULL) lower->Release();
2363 }
2364 }
2365 }
2366 else
2367 {
2368 for (unsigned int f = 0; f < 6; f++)
2369 {
2370 for (unsigned int i = 1; i <= q; i++)
2371 {
2372 createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
2373 if (mImageArray[f][i].surface == NULL)
2374 {
2375 return error(GL_OUT_OF_MEMORY);
2376 }
2377
2378 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2379 {
2380 ERR(" failed to load filter %d to %d.", i - 1, i);
2381 }
2382
2383 mImageArray[f][i].dirty = true;
2384 }
2385 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002386 }
2387}
2388
2389Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2390{
2391 if (!IsCubemapTextureTarget(target))
2392 {
2393 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2394 }
2395
2396 unsigned int face = faceIndex(target);
2397
2398 if (mFaceProxies[face].get() == NULL)
2399 {
2400 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2401 }
2402
2403 return mFaceProxies[face].get();
2404}
2405
2406IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2407{
2408 ASSERT(IsCubemapTextureTarget(target));
2409
2410 needRenderTarget();
2411
2412 if (mTexture == NULL)
2413 {
2414 return NULL;
2415 }
2416
2417 IDirect3DSurface9 *renderTarget = NULL;
2418 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2419
2420 return renderTarget;
2421}
2422
2423}