blob: a9c158abb60b242d93330041981c325946aa5f8b [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()
29 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
30{
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.comaed18322011-03-21 16:38:13 +00001165
1166 if (dirtyImageData())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001167 {
1168 updateTexture();
1169 }
1170
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001171 ASSERT(!dirtyImageData());
1172
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001173 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001174}
1175
1176bool Texture::isDirty() const
1177{
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001178 return true;//(mDirty || mDirtyMetaData || dirtyImageData());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001179}
1180
1181// Returns the top-level texture surface as a render target
1182void Texture::needRenderTarget()
1183{
1184 if (!mIsRenderable)
1185 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001186 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001187 }
1188
1189 if (dirtyImageData())
1190 {
1191 updateTexture();
1192 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001193}
1194
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001195GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1196{
1197 if (isPow2(width) && isPow2(height))
1198 {
1199 return maxlevel;
1200 }
1201 else
1202 {
1203 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1204 return 1;
1205 }
1206}
1207
1208GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1209{
1210 return creationLevels(size, size, maxlevel);
1211}
1212
1213int Texture::levelCount() const
1214{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001215 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001216}
1217
1218Texture2D::Texture2D(GLuint id) : Texture(id)
1219{
1220 mTexture = NULL;
1221}
1222
1223Texture2D::~Texture2D()
1224{
1225 mColorbufferProxy.set(NULL);
1226
1227 if (mTexture)
1228 {
1229 mTexture->Release();
1230 mTexture = NULL;
1231 }
1232}
1233
1234GLenum Texture2D::getTarget() const
1235{
1236 return GL_TEXTURE_2D;
1237}
1238
1239GLenum Texture2D::getInternalFormat() const
1240{
1241 return mImageArray[0].format;
1242}
1243
1244// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1245// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
1246// Call this when a particular level of the texture must be defined with a specific format, width and height.
1247//
1248// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
1249// 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 +00001250bool Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001251{
1252 bool widthOkay = (mWidth >> level == width);
1253 bool heightOkay = (mHeight >> level == height);
1254
1255 bool sizeOkay = ((widthOkay && heightOkay)
1256 || (widthOkay && mHeight >> level == 0 && height == 1)
1257 || (heightOkay && mWidth >> level == 0 && width == 1));
1258
1259 bool typeOkay = (type == mType);
1260
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001261 bool textureOkay = (sizeOkay && typeOkay && format == mImageArray[0].format);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001262
1263 if (!textureOkay)
1264 {
1265 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
1266 mImageArray[0].format, mWidth, mHeight,
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001267 format, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001268
1269 // Purge all the levels and the texture.
1270
1271 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1272 {
1273 if (mImageArray[i].surface != NULL)
1274 {
1275 mImageArray[i].dirty = false;
1276
1277 mImageArray[i].surface->Release();
1278 mImageArray[i].surface = NULL;
1279 }
1280 }
1281
1282 if (mTexture != NULL)
1283 {
1284 mTexture->Release();
1285 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001286 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001287 }
1288
1289 mWidth = width << level;
1290 mHeight = height << level;
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001291 mImageArray[0].format = format;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001292 mType = type;
1293 }
1294
1295 return !textureOkay;
1296}
1297
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001298void 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 +00001299{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001300 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001301
1302 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
1303}
1304
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001305void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001306{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001307 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001308
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001309 Texture::setCompressedImage(width, height, format, imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001310}
1311
1312void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1313{
1314 ASSERT(mImageArray[level].surface != NULL);
1315
1316 if (level < levelCount())
1317 {
1318 IDirect3DSurface9 *destLevel = NULL;
1319 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1320
1321 ASSERT(SUCCEEDED(result));
1322
1323 if (SUCCEEDED(result))
1324 {
1325 Image *img = &mImageArray[level];
1326
1327 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
1328
1329 POINT destPoint;
1330 destPoint.x = sourceRect.left;
1331 destPoint.y = sourceRect.top;
1332
1333 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1334 ASSERT(SUCCEEDED(result));
1335
1336 destLevel->Release();
1337
1338 img->dirty = false;
1339 }
1340 }
1341}
1342
1343void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1344{
1345 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1346 {
1347 commitRect(level, xoffset, yoffset, width, height);
1348 }
1349}
1350
1351void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1352{
1353 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1354 {
1355 commitRect(level, xoffset, yoffset, width, height);
1356 }
1357}
1358
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001359void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001360{
1361 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1362
1363 if (!renderTarget)
1364 {
1365 ERR("Failed to retrieve the render target.");
1366 return error(GL_OUT_OF_MEMORY);
1367 }
1368
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001369 bool redefined = redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001370
1371 if (!isRenderableFormat())
1372 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001373 copyNonRenderable(&mImageArray[level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001374 }
1375 else
1376 {
1377 if (redefined)
1378 {
1379 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001380 }
1381 else
1382 {
1383 needRenderTarget();
1384 }
1385
1386 if (width != 0 && height != 0 && level < levelCount())
1387 {
1388 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1389 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1390 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1391 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1392 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1393
1394 IDirect3DSurface9 *dest;
1395 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1396
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001397 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001398 dest->Release();
1399 }
1400 }
1401
1402 mImageArray[level].width = width;
1403 mImageArray[level].height = height;
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001404 mImageArray[level].format = format;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001405 mImageArray[level].type = GL_UNSIGNED_BYTE;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001406}
1407
1408void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1409{
1410 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1411 {
1412 return error(GL_INVALID_VALUE);
1413 }
1414
1415 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1416
1417 if (!renderTarget)
1418 {
1419 ERR("Failed to retrieve the render target.");
1420 return error(GL_OUT_OF_MEMORY);
1421 }
1422
1423 bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
1424
1425 if (!isRenderableFormat())
1426 {
1427 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1428 }
1429 else
1430 {
1431 if (redefined)
1432 {
1433 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001434 }
1435 else
1436 {
1437 needRenderTarget();
1438 }
1439
1440 if (level < levelCount())
1441 {
1442 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1443 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1444 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1445 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1446 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1447
1448 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1449
1450 IDirect3DSurface9 *dest;
1451 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1452
1453 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1454 dest->Release();
1455 }
1456 }
1457}
1458
1459// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1460bool Texture2D::isComplete() const
1461{
1462 GLsizei width = mImageArray[0].width;
1463 GLsizei height = mImageArray[0].height;
1464
1465 if (width <= 0 || height <= 0)
1466 {
1467 return false;
1468 }
1469
1470 bool mipmapping = false;
1471
1472 switch (mMinFilter)
1473 {
1474 case GL_NEAREST:
1475 case GL_LINEAR:
1476 mipmapping = false;
1477 break;
1478 case GL_NEAREST_MIPMAP_NEAREST:
1479 case GL_LINEAR_MIPMAP_NEAREST:
1480 case GL_NEAREST_MIPMAP_LINEAR:
1481 case GL_LINEAR_MIPMAP_LINEAR:
1482 mipmapping = true;
1483 break;
1484 default: UNREACHABLE();
1485 }
1486
1487 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1488 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1489 {
1490 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1491 {
1492 return false;
1493 }
1494 }
1495
1496
1497 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1498 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1499 {
1500 return false;
1501 }
1502
1503 if (mipmapping)
1504 {
1505 if (!isPow2(width) || !isPow2(height))
1506 {
1507 return false;
1508 }
1509
1510 int q = log2(std::max(width, height));
1511
1512 for (int level = 1; level <= q; level++)
1513 {
1514 if (mImageArray[level].format != mImageArray[0].format)
1515 {
1516 return false;
1517 }
1518
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001519 if (mImageArray[level].type != mImageArray[0].type)
1520 {
1521 return false;
1522 }
1523
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001524 if (mImageArray[level].width != std::max(1, width >> level))
1525 {
1526 return false;
1527 }
1528
1529 if (mImageArray[level].height != std::max(1, height >> level))
1530 {
1531 return false;
1532 }
1533 }
1534 }
1535
1536 return true;
1537}
1538
1539bool Texture2D::isCompressed() const
1540{
1541 return IsCompressed(getInternalFormat());
1542}
1543
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001544IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1545{
1546 return mTexture;
1547}
1548
1549// Constructs a Direct3D 9 texture resource from the texture images
1550void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001551{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001552 IDirect3DDevice9 *device = getDevice();
1553 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
1554
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001555 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001556 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
1557
1558 if (FAILED(result))
1559 {
1560 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001561 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001562 }
1563
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001564 if (mTexture)
1565 {
1566 mTexture->Release();
1567 }
1568
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001569 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001570 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001571}
1572
1573void Texture2D::updateTexture()
1574{
1575 IDirect3DDevice9 *device = getDevice();
1576
1577 int levels = levelCount();
1578
1579 for (int level = 0; level < levels; level++)
1580 {
1581 if (mImageArray[level].dirty)
1582 {
1583 IDirect3DSurface9 *levelSurface = NULL;
1584 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1585
1586 ASSERT(SUCCEEDED(result));
1587
1588 if (SUCCEEDED(result))
1589 {
1590 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1591 ASSERT(SUCCEEDED(result));
1592
1593 levelSurface->Release();
1594
1595 mImageArray[level].dirty = false;
1596 }
1597 }
1598 }
1599}
1600
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001601void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001602{
1603 IDirect3DTexture9 *texture = NULL;
1604
1605 if (mWidth != 0 && mHeight != 0)
1606 {
1607 egl::Display *display = getDisplay();
1608 IDirect3DDevice9 *device = getDevice();
1609 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
1610
1611 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
1612
1613 if (FAILED(result))
1614 {
1615 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001616 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001617 }
1618
1619 if (mTexture != NULL)
1620 {
1621 int levels = levelCount();
1622 for (int i = 0; i < levels; i++)
1623 {
1624 IDirect3DSurface9 *source;
1625 result = mTexture->GetSurfaceLevel(i, &source);
1626
1627 if (FAILED(result))
1628 {
1629 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1630
1631 texture->Release();
1632
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001633 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001634 }
1635
1636 IDirect3DSurface9 *dest;
1637 result = texture->GetSurfaceLevel(i, &dest);
1638
1639 if (FAILED(result))
1640 {
1641 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1642
1643 texture->Release();
1644 source->Release();
1645
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001646 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001647 }
1648
1649 display->endScene();
1650 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1651
1652 if (FAILED(result))
1653 {
1654 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1655
1656 texture->Release();
1657 source->Release();
1658 dest->Release();
1659
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001660 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001661 }
1662
1663 source->Release();
1664 dest->Release();
1665 }
1666 }
1667 }
1668
1669 if (mTexture != NULL)
1670 {
1671 mTexture->Release();
1672 }
1673
1674 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001675 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001676}
1677
1678bool Texture2D::dirtyImageData() const
1679{
1680 int q = log2(std::max(mWidth, mHeight));
1681
1682 for (int i = 0; i <= q; i++)
1683 {
1684 if (mImageArray[i].dirty) return true;
1685 }
1686
1687 return false;
1688}
1689
1690void Texture2D::generateMipmaps()
1691{
1692 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1693 {
1694 return error(GL_INVALID_OPERATION);
1695 }
1696
1697 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1698 unsigned int q = log2(std::max(mWidth, mHeight));
1699 for (unsigned int i = 1; i <= q; i++)
1700 {
1701 if (mImageArray[i].surface != NULL)
1702 {
1703 mImageArray[i].surface->Release();
1704 mImageArray[i].surface = NULL;
1705 }
1706
1707 mImageArray[i].dirty = false;
1708
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001709 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1710 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001711 mImageArray[i].format = mImageArray[0].format;
1712 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001713 }
1714
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001715 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001716 {
1717 if (mTexture == NULL)
1718 {
1719 ERR(" failed because mTexture was null.");
1720 return;
1721 }
1722
1723 for (unsigned int i = 1; i <= q; i++)
1724 {
1725 IDirect3DSurface9 *upper = NULL;
1726 IDirect3DSurface9 *lower = NULL;
1727
1728 mTexture->GetSurfaceLevel(i-1, &upper);
1729 mTexture->GetSurfaceLevel(i, &lower);
1730
1731 if (upper != NULL && lower != NULL)
1732 {
1733 getBlitter()->boxFilter(upper, lower);
1734 }
1735
1736 if (upper != NULL) upper->Release();
1737 if (lower != NULL) lower->Release();
1738 }
1739 }
1740 else
1741 {
1742 for (unsigned int i = 1; i <= q; i++)
1743 {
1744 createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
1745 if (mImageArray[i].surface == NULL)
1746 {
1747 return error(GL_OUT_OF_MEMORY);
1748 }
1749
1750 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1751 {
1752 ERR(" failed to load filter %d to %d.", i - 1, i);
1753 }
1754
1755 mImageArray[i].dirty = true;
1756 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001757 }
1758}
1759
1760Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1761{
1762 if (target != GL_TEXTURE_2D)
1763 {
1764 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1765 }
1766
1767 if (mColorbufferProxy.get() == NULL)
1768 {
1769 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1770 }
1771
1772 return mColorbufferProxy.get();
1773}
1774
1775IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1776{
1777 ASSERT(target == GL_TEXTURE_2D);
1778
1779 needRenderTarget();
1780
1781 if (mTexture == NULL)
1782 {
1783 return NULL;
1784 }
1785
1786 IDirect3DSurface9 *renderTarget = NULL;
1787 mTexture->GetSurfaceLevel(0, &renderTarget);
1788
1789 return renderTarget;
1790}
1791
1792TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1793{
1794 mTexture = NULL;
1795}
1796
1797TextureCubeMap::~TextureCubeMap()
1798{
1799 for (int i = 0; i < 6; i++)
1800 {
1801 mFaceProxies[i].set(NULL);
1802 }
1803
1804 if (mTexture)
1805 {
1806 mTexture->Release();
1807 mTexture = NULL;
1808 }
1809}
1810
1811GLenum TextureCubeMap::getTarget() const
1812{
1813 return GL_TEXTURE_CUBE_MAP;
1814}
1815
1816GLenum TextureCubeMap::getInternalFormat() const
1817{
1818 return mImageArray[0][0].format;
1819}
1820
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001821void 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 +00001822{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001823 setImage(0, 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::setImageNegX(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(1, 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::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001832{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001833 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001834}
1835
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001836void 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 +00001837{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001838 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001839}
1840
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001841void 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 +00001842{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001843 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001844}
1845
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001846void 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 +00001847{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001848 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001849}
1850
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001851void 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 +00001852{
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001853 redefineTexture(level, format, width, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001854
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001855 Texture::setCompressedImage(width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001856}
1857
1858void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1859{
1860 int face = faceIndex(faceTarget);
1861 ASSERT(mImageArray[face][level].surface != NULL);
1862
1863 if (level < levelCount())
1864 {
1865 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1866 ASSERT(destLevel != NULL);
1867
1868 if (destLevel != NULL)
1869 {
1870 Image *img = &mImageArray[face][level];
1871
1872 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
1873
1874 POINT destPoint;
1875 destPoint.x = sourceRect.left;
1876 destPoint.y = sourceRect.top;
1877
1878 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1879 ASSERT(SUCCEEDED(result));
1880
1881 destLevel->Release();
1882
1883 img->dirty = false;
1884 }
1885 }
1886}
1887
1888void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1889{
1890 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1891 {
1892 commitRect(target, level, xoffset, yoffset, width, height);
1893 }
1894}
1895
1896void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1897{
1898 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1899 {
1900 commitRect(target, level, xoffset, yoffset, width, height);
1901 }
1902}
1903
1904// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1905bool TextureCubeMap::isComplete() const
1906{
1907 int size = mImageArray[0][0].width;
1908
1909 if (size <= 0)
1910 {
1911 return false;
1912 }
1913
1914 bool mipmapping;
1915
1916 switch (mMinFilter)
1917 {
1918 case GL_NEAREST:
1919 case GL_LINEAR:
1920 mipmapping = false;
1921 break;
1922 case GL_NEAREST_MIPMAP_NEAREST:
1923 case GL_LINEAR_MIPMAP_NEAREST:
1924 case GL_NEAREST_MIPMAP_LINEAR:
1925 case GL_LINEAR_MIPMAP_LINEAR:
1926 mipmapping = true;
1927 break;
1928 default: UNREACHABLE();
1929 }
1930
1931 for (int face = 0; face < 6; face++)
1932 {
1933 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1934 {
1935 return false;
1936 }
1937 }
1938
1939 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1940 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1941 {
1942 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1943 {
1944 return false;
1945 }
1946 }
1947
1948 if (mipmapping)
1949 {
1950 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1951 {
1952 return false;
1953 }
1954
1955 int q = log2(size);
1956
1957 for (int face = 0; face < 6; face++)
1958 {
1959 for (int level = 1; level <= q; level++)
1960 {
1961 if (mImageArray[face][level].format != mImageArray[0][0].format)
1962 {
1963 return false;
1964 }
1965
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001966 if (mImageArray[face][level].type != mImageArray[0][0].type)
1967 {
1968 return false;
1969 }
1970
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001971 if (mImageArray[face][level].width != std::max(1, size >> level))
1972 {
1973 return false;
1974 }
1975
1976 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1977 }
1978 }
1979 }
1980
1981 return true;
1982}
1983
1984bool TextureCubeMap::isCompressed() const
1985{
1986 return IsCompressed(getInternalFormat());
1987}
1988
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001989IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1990{
1991 return mTexture;
1992}
1993
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001994// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001995void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001996{
1997 IDirect3DDevice9 *device = getDevice();
1998 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
1999
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002000 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002001 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
2002
2003 if (FAILED(result))
2004 {
2005 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002006 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002007 }
2008
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002009 if (mTexture)
2010 {
2011 mTexture->Release();
2012 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002013
2014 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002015 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002016}
2017
2018void TextureCubeMap::updateTexture()
2019{
2020 IDirect3DDevice9 *device = getDevice();
2021
2022 for (int face = 0; face < 6; face++)
2023 {
2024 int levels = levelCount();
2025 for (int level = 0; level < levels; level++)
2026 {
2027 Image *img = &mImageArray[face][level];
2028
2029 if (img->dirty)
2030 {
2031 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2032 ASSERT(levelSurface != NULL);
2033
2034 if (levelSurface != NULL)
2035 {
2036 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
2037 ASSERT(SUCCEEDED(result));
2038
2039 levelSurface->Release();
2040
2041 img->dirty = false;
2042 }
2043 }
2044 }
2045 }
2046}
2047
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002048void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002049{
2050 IDirect3DCubeTexture9 *texture = NULL;
2051
2052 if (mWidth != 0)
2053 {
2054 egl::Display *display = getDisplay();
2055 IDirect3DDevice9 *device = getDevice();
2056 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
2057
2058 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
2059
2060 if (FAILED(result))
2061 {
2062 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002063 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002064 }
2065
2066 if (mTexture != NULL)
2067 {
2068 int levels = levelCount();
2069 for (int f = 0; f < 6; f++)
2070 {
2071 for (int i = 0; i < levels; i++)
2072 {
2073 IDirect3DSurface9 *source;
2074 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2075
2076 if (FAILED(result))
2077 {
2078 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2079
2080 texture->Release();
2081
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002082 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002083 }
2084
2085 IDirect3DSurface9 *dest;
2086 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2087
2088 if (FAILED(result))
2089 {
2090 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2091
2092 texture->Release();
2093 source->Release();
2094
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002095 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002096 }
2097
2098 display->endScene();
2099 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2100
2101 if (FAILED(result))
2102 {
2103 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2104
2105 texture->Release();
2106 source->Release();
2107 dest->Release();
2108
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002109 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002110 }
2111 }
2112 }
2113 }
2114 }
2115
2116 if (mTexture != NULL)
2117 {
2118 mTexture->Release();
2119 }
2120
2121 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002122 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002123}
2124
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002125void 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 +00002126{
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002127 redefineTexture(level, format, width, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002128
2129 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
2130}
2131
2132unsigned int TextureCubeMap::faceIndex(GLenum face)
2133{
2134 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2135 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2136 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2137 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2138 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2139
2140 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2141}
2142
2143bool TextureCubeMap::dirtyImageData() const
2144{
2145 int q = log2(mWidth);
2146
2147 for (int f = 0; f < 6; f++)
2148 {
2149 for (int i = 0; i <= q; i++)
2150 {
2151 if (mImageArray[f][i].dirty) return true;
2152 }
2153 }
2154
2155 return false;
2156}
2157
2158// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
2159// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
2160// Call this when a particular level of the texture must be defined with a specific format, width and height.
2161//
2162// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
2163// a new size for the texture by working backwards from the given size.
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002164bool TextureCubeMap::redefineTexture(GLint level, GLenum format, GLsizei width, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002165{
2166 // Are these settings compatible with level 0?
2167 bool sizeOkay = (mImageArray[0][0].width >> level == width);
2168
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002169 bool textureOkay = (sizeOkay && format == mImageArray[0][0].format);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002170
2171 if (!textureOkay)
2172 {
2173 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
2174 mImageArray[0][0].format, mImageArray[0][0].width,
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002175 format, width);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002176
2177 // Purge all the levels and the texture.
2178 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2179 {
2180 for (int f = 0; f < 6; f++)
2181 {
2182 if (mImageArray[f][i].surface != NULL)
2183 {
2184 mImageArray[f][i].dirty = false;
2185
2186 mImageArray[f][i].surface->Release();
2187 mImageArray[f][i].surface = NULL;
2188 }
2189 }
2190 }
2191
2192 if (mTexture != NULL)
2193 {
2194 mTexture->Release();
2195 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002196 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002197 }
2198
2199 mWidth = width << level;
2200 mImageArray[0][0].width = width << level;
2201 mHeight = width << level;
2202 mImageArray[0][0].height = width << level;
2203
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002204 mImageArray[0][0].format = format;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002205 mImageArray[0][0].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002206 }
2207
2208 return !textureOkay;
2209}
2210
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002211void 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 +00002212{
2213 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2214
2215 if (!renderTarget)
2216 {
2217 ERR("Failed to retrieve the render target.");
2218 return error(GL_OUT_OF_MEMORY);
2219 }
2220
2221 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002222 bool redefined = redefineTexture(level, format, width, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002223
2224 if (!isRenderableFormat())
2225 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002226 copyNonRenderable(&mImageArray[faceindex][level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002227 }
2228 else
2229 {
2230 if (redefined)
2231 {
2232 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002233 }
2234 else
2235 {
2236 needRenderTarget();
2237 }
2238
2239 ASSERT(width == height);
2240
2241 if (width > 0 && level < levelCount())
2242 {
2243 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2244 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2245 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2246 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2247 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2248
2249 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2250
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002251 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002252 dest->Release();
2253 }
2254 }
2255
2256 mImageArray[faceindex][level].width = width;
2257 mImageArray[faceindex][level].height = height;
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002258 mImageArray[faceindex][level].format = format;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002259 mImageArray[faceindex][level].type = GL_UNSIGNED_BYTE;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002260}
2261
2262IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2263{
2264 if (mTexture == NULL)
2265 {
2266 UNREACHABLE();
2267 return NULL;
2268 }
2269
2270 IDirect3DSurface9 *surface = NULL;
2271
2272 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2273
2274 return (SUCCEEDED(hr)) ? surface : NULL;
2275}
2276
2277void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2278{
2279 GLsizei size = mImageArray[faceIndex(target)][level].width;
2280
2281 if (xoffset + width > size || yoffset + height > size)
2282 {
2283 return error(GL_INVALID_VALUE);
2284 }
2285
2286 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2287
2288 if (!renderTarget)
2289 {
2290 ERR("Failed to retrieve the render target.");
2291 return error(GL_OUT_OF_MEMORY);
2292 }
2293
2294 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002295 bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002296
2297 if (!isRenderableFormat())
2298 {
2299 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2300 }
2301 else
2302 {
2303 if (redefined)
2304 {
2305 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002306 }
2307 else
2308 {
2309 needRenderTarget();
2310 }
2311
2312 if (level < levelCount())
2313 {
2314 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2315 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2316 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2317 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2318 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2319
2320 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2321
2322 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2323
2324 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2325 dest->Release();
2326 }
2327 }
2328}
2329
2330bool TextureCubeMap::isCubeComplete() const
2331{
2332 if (mImageArray[0][0].width == 0)
2333 {
2334 return false;
2335 }
2336
2337 for (unsigned int f = 1; f < 6; f++)
2338 {
2339 if (mImageArray[f][0].width != mImageArray[0][0].width
2340 || mImageArray[f][0].format != mImageArray[0][0].format)
2341 {
2342 return false;
2343 }
2344 }
2345
2346 return true;
2347}
2348
2349void TextureCubeMap::generateMipmaps()
2350{
2351 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2352 {
2353 return error(GL_INVALID_OPERATION);
2354 }
2355
2356 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2357 unsigned int q = log2(mImageArray[0][0].width);
2358 for (unsigned int f = 0; f < 6; f++)
2359 {
2360 for (unsigned int i = 1; i <= q; i++)
2361 {
2362 if (mImageArray[f][i].surface != NULL)
2363 {
2364 mImageArray[f][i].surface->Release();
2365 mImageArray[f][i].surface = NULL;
2366 }
2367
2368 mImageArray[f][i].dirty = false;
2369
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002370 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2371 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002372 mImageArray[f][i].format = mImageArray[f][0].format;
2373 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002374 }
2375 }
2376
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002377 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002378 {
2379 if (mTexture == NULL)
2380 {
2381 return;
2382 }
2383
2384 for (unsigned int f = 0; f < 6; f++)
2385 {
2386 for (unsigned int i = 1; i <= q; i++)
2387 {
2388 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2389 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2390
2391 if (upper != NULL && lower != NULL)
2392 {
2393 getBlitter()->boxFilter(upper, lower);
2394 }
2395
2396 if (upper != NULL) upper->Release();
2397 if (lower != NULL) lower->Release();
2398 }
2399 }
2400 }
2401 else
2402 {
2403 for (unsigned int f = 0; f < 6; f++)
2404 {
2405 for (unsigned int i = 1; i <= q; i++)
2406 {
2407 createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
2408 if (mImageArray[f][i].surface == NULL)
2409 {
2410 return error(GL_OUT_OF_MEMORY);
2411 }
2412
2413 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2414 {
2415 ERR(" failed to load filter %d to %d.", i - 1, i);
2416 }
2417
2418 mImageArray[f][i].dirty = true;
2419 }
2420 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002421 }
2422}
2423
2424Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2425{
2426 if (!IsCubemapTextureTarget(target))
2427 {
2428 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2429 }
2430
2431 unsigned int face = faceIndex(target);
2432
2433 if (mFaceProxies[face].get() == NULL)
2434 {
2435 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2436 }
2437
2438 return mFaceProxies[face].get();
2439}
2440
2441IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2442{
2443 ASSERT(IsCubemapTextureTarget(target));
2444
2445 needRenderTarget();
2446
2447 if (mTexture == NULL)
2448 {
2449 return NULL;
2450 }
2451
2452 IDirect3DSurface9 *renderTarget = NULL;
2453 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2454
2455 return renderTarget;
2456}
2457
2458}