blob: 81d8d74cafc19506f594e7a360c2f2086662aa55 [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
799void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
800{
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
839 if (img->surface) img->surface->Release();
840 img->surface = newSurface;
841
842 img->width = width;
843 img->height = height;
844 img->format = format;
845}
846
847void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
848{
849 createSurface(width, height, format, type, img);
850
851 if (pixels != NULL && img->surface != NULL)
852 {
853 D3DSURFACE_DESC description;
854 img->surface->GetDesc(&description);
855
856 D3DLOCKED_RECT locked;
857 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
858
859 ASSERT(SUCCEEDED(result));
860
861 if (SUCCEEDED(result))
862 {
863 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
864 img->surface->UnlockRect();
865 }
866
867 img->dirty = true;
868 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000869}
870
871void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
872{
873 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
874
875 if (pixels != NULL && img->surface != NULL)
876 {
877 D3DLOCKED_RECT locked;
878 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
879
880 ASSERT(SUCCEEDED(result));
881
882 if (SUCCEEDED(result))
883 {
884 int inputPitch = ComputeCompressedPitch(width, format);
885 int inputSize = ComputeCompressedSize(width, height, format);
886 loadCompressedImageData(0, 0, width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
887 img->surface->UnlockRect();
888 }
889
890 img->dirty = true;
891 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000892}
893
894bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
895{
896 if (width + xoffset > img->width || height + yoffset > img->height)
897 {
898 error(GL_INVALID_VALUE);
899 return false;
900 }
901
902 if (!img->surface)
903 {
904 createSurface(img->width, img->height, format, type, img);
905 }
906
907 if (pixels != NULL && img->surface != NULL)
908 {
909 D3DSURFACE_DESC description;
910 img->surface->GetDesc(&description);
911
912 D3DLOCKED_RECT locked;
913 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
914
915 ASSERT(SUCCEEDED(result));
916
917 if (SUCCEEDED(result))
918 {
919 loadImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
920 img->surface->UnlockRect();
921 }
922
923 img->dirty = true;
924 }
925
926 return true;
927}
928
929bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
930{
931 if (width + xoffset > img->width || height + yoffset > img->height)
932 {
933 error(GL_INVALID_VALUE);
934 return false;
935 }
936
937 if (format != getInternalFormat())
938 {
939 error(GL_INVALID_OPERATION);
940 return false;
941 }
942
943 if (!img->surface)
944 {
945 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
946 }
947
948 if (pixels != NULL && img->surface != NULL)
949 {
950 RECT updateRegion;
951 updateRegion.left = xoffset;
952 updateRegion.right = xoffset + width;
953 updateRegion.bottom = yoffset + height;
954 updateRegion.top = yoffset;
955
956 D3DLOCKED_RECT locked;
957 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
958
959 ASSERT(SUCCEEDED(result));
960
961 if (SUCCEEDED(result))
962 {
963 int inputPitch = ComputeCompressedPitch(width, format);
964 int inputSize = ComputeCompressedSize(width, height, format);
965 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, img->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
966 img->surface->UnlockRect();
967 }
968
969 img->dirty = true;
970 }
971
972 return true;
973}
974
975// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +0000976void 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 +0000977{
978 IDirect3DDevice9 *device = getDevice();
979 IDirect3DSurface9 *surface = NULL;
980 D3DSURFACE_DESC description;
981 renderTarget->GetDesc(&description);
982
983 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
984
985 if (!SUCCEEDED(result))
986 {
987 ERR("Could not create matching destination surface.");
988 return error(GL_OUT_OF_MEMORY);
989 }
990
991 result = device->GetRenderTargetData(renderTarget, surface);
992
993 if (!SUCCEEDED(result))
994 {
995 ERR("GetRenderTargetData unexpectedly failed.");
996 surface->Release();
997 return error(GL_OUT_OF_MEMORY);
998 }
999
1000 D3DLOCKED_RECT sourceLock = {0};
1001 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
1002 result = surface->LockRect(&sourceLock, &sourceRect, 0);
1003
1004 if (FAILED(result))
1005 {
1006 ERR("Failed to lock the source surface (rectangle might be invalid).");
1007 surface->UnlockRect();
1008 surface->Release();
1009 return error(GL_OUT_OF_MEMORY);
1010 }
1011
1012 if (!image->surface)
1013 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001014 createSurface(width, height, format, mType, image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001015 }
1016
1017 if (image->surface == NULL)
1018 {
1019 ERR("Failed to create an image surface.");
1020 surface->UnlockRect();
1021 surface->Release();
1022 return error(GL_OUT_OF_MEMORY);
1023 }
1024
1025 D3DLOCKED_RECT destLock = {0};
1026 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1027 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1028 result = image->surface->LockRect(&destLock, &destRect, 0);
1029
1030 if (FAILED(result))
1031 {
1032 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1033 surface->UnlockRect();
1034 surface->Release();
1035 return error(GL_OUT_OF_MEMORY);
1036 }
1037
1038 if (destLock.pBits && sourceLock.pBits)
1039 {
1040 unsigned char *source = (unsigned char*)sourceLock.pBits;
1041 unsigned char *dest = (unsigned char*)destLock.pBits;
1042
1043 switch (description.Format)
1044 {
1045 case D3DFMT_X8R8G8B8:
1046 case D3DFMT_A8R8G8B8:
1047 switch(getD3DFormat())
1048 {
1049 case D3DFMT_L8:
1050 for(int y = 0; y < height; y++)
1051 {
1052 for(int x = 0; x < width; x++)
1053 {
1054 dest[x] = source[x * 4 + 2];
1055 }
1056
1057 source += sourceLock.Pitch;
1058 dest += destLock.Pitch;
1059 }
1060 break;
1061 case D3DFMT_A8L8:
1062 for(int y = 0; y < height; y++)
1063 {
1064 for(int x = 0; x < width; x++)
1065 {
1066 dest[x * 2 + 0] = source[x * 4 + 2];
1067 dest[x * 2 + 1] = source[x * 4 + 3];
1068 }
1069
1070 source += sourceLock.Pitch;
1071 dest += destLock.Pitch;
1072 }
1073 break;
1074 default:
1075 UNREACHABLE();
1076 }
1077 break;
1078 case D3DFMT_R5G6B5:
1079 switch(getD3DFormat())
1080 {
1081 case D3DFMT_L8:
1082 for(int y = 0; y < height; y++)
1083 {
1084 for(int x = 0; x < width; x++)
1085 {
1086 unsigned char red = source[x * 2 + 1] & 0xF8;
1087 dest[x] = red | (red >> 5);
1088 }
1089
1090 source += sourceLock.Pitch;
1091 dest += destLock.Pitch;
1092 }
1093 break;
1094 default:
1095 UNREACHABLE();
1096 }
1097 break;
1098 case D3DFMT_A1R5G5B5:
1099 switch(getD3DFormat())
1100 {
1101 case D3DFMT_L8:
1102 for(int y = 0; y < height; y++)
1103 {
1104 for(int x = 0; x < width; x++)
1105 {
1106 unsigned char red = source[x * 2 + 1] & 0x7C;
1107 dest[x] = (red << 1) | (red >> 4);
1108 }
1109
1110 source += sourceLock.Pitch;
1111 dest += destLock.Pitch;
1112 }
1113 break;
1114 case D3DFMT_A8L8:
1115 for(int y = 0; y < height; y++)
1116 {
1117 for(int x = 0; x < width; x++)
1118 {
1119 unsigned char red = source[x * 2 + 1] & 0x7C;
1120 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1121 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1122 }
1123
1124 source += sourceLock.Pitch;
1125 dest += destLock.Pitch;
1126 }
1127 break;
1128 default:
1129 UNREACHABLE();
1130 }
1131 break;
1132 default:
1133 UNREACHABLE();
1134 }
1135
1136 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001137 }
1138
1139 image->surface->UnlockRect();
1140 surface->UnlockRect();
1141 surface->Release();
1142}
1143
1144D3DFORMAT Texture::getD3DFormat() const
1145{
1146 return selectFormat(getInternalFormat(), mType);
1147}
1148
1149IDirect3DBaseTexture9 *Texture::getTexture()
1150{
1151 if (!isComplete())
1152 {
1153 return NULL;
1154 }
1155
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001156 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001157 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001158 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001159 }
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001160
1161 if (dirtyImageData())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001162 {
1163 updateTexture();
1164 }
1165
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001166 ASSERT(!dirtyImageData());
1167
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
1184 if (dirtyImageData())
1185 {
1186 updateTexture();
1187 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001188}
1189
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001190GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1191{
1192 if (isPow2(width) && isPow2(height))
1193 {
1194 return maxlevel;
1195 }
1196 else
1197 {
1198 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1199 return 1;
1200 }
1201}
1202
1203GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1204{
1205 return creationLevels(size, size, maxlevel);
1206}
1207
1208int Texture::levelCount() const
1209{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001210 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001211}
1212
1213Texture2D::Texture2D(GLuint id) : Texture(id)
1214{
1215 mTexture = NULL;
1216}
1217
1218Texture2D::~Texture2D()
1219{
1220 mColorbufferProxy.set(NULL);
1221
1222 if (mTexture)
1223 {
1224 mTexture->Release();
1225 mTexture = NULL;
1226 }
1227}
1228
1229GLenum Texture2D::getTarget() const
1230{
1231 return GL_TEXTURE_2D;
1232}
1233
1234GLenum Texture2D::getInternalFormat() const
1235{
1236 return mImageArray[0].format;
1237}
1238
1239// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1240// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
1241// Call this when a particular level of the texture must be defined with a specific format, width and height.
1242//
1243// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
1244// 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 +00001245bool Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001246{
1247 bool widthOkay = (mWidth >> level == width);
1248 bool heightOkay = (mHeight >> level == height);
1249
1250 bool sizeOkay = ((widthOkay && heightOkay)
1251 || (widthOkay && mHeight >> level == 0 && height == 1)
1252 || (heightOkay && mWidth >> level == 0 && width == 1));
1253
1254 bool typeOkay = (type == mType);
1255
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001256 bool textureOkay = (sizeOkay && typeOkay && format == mImageArray[0].format);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001257
1258 if (!textureOkay)
1259 {
1260 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
1261 mImageArray[0].format, mWidth, mHeight,
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001262 format, width, height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001263
1264 // Purge all the levels and the texture.
1265
1266 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1267 {
1268 if (mImageArray[i].surface != NULL)
1269 {
1270 mImageArray[i].dirty = false;
1271
1272 mImageArray[i].surface->Release();
1273 mImageArray[i].surface = NULL;
1274 }
1275 }
1276
1277 if (mTexture != NULL)
1278 {
1279 mTexture->Release();
1280 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001281 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001282 }
1283
1284 mWidth = width << level;
1285 mHeight = height << level;
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001286 mImageArray[0].format = format;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001287 mType = type;
1288 }
1289
1290 return !textureOkay;
1291}
1292
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001293void 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 +00001294{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001295 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001296
1297 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
1298}
1299
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001300void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001301{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001302 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001303
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001304 Texture::setCompressedImage(width, height, format, imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001305}
1306
1307void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1308{
1309 ASSERT(mImageArray[level].surface != NULL);
1310
1311 if (level < levelCount())
1312 {
1313 IDirect3DSurface9 *destLevel = NULL;
1314 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1315
1316 ASSERT(SUCCEEDED(result));
1317
1318 if (SUCCEEDED(result))
1319 {
1320 Image *img = &mImageArray[level];
1321
1322 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
1323
1324 POINT destPoint;
1325 destPoint.x = sourceRect.left;
1326 destPoint.y = sourceRect.top;
1327
1328 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1329 ASSERT(SUCCEEDED(result));
1330
1331 destLevel->Release();
1332
1333 img->dirty = false;
1334 }
1335 }
1336}
1337
1338void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1339{
1340 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1341 {
1342 commitRect(level, xoffset, yoffset, width, height);
1343 }
1344}
1345
1346void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1347{
1348 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1349 {
1350 commitRect(level, xoffset, yoffset, width, height);
1351 }
1352}
1353
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001354void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001355{
1356 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1357
1358 if (!renderTarget)
1359 {
1360 ERR("Failed to retrieve the render target.");
1361 return error(GL_OUT_OF_MEMORY);
1362 }
1363
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001364 bool redefined = redefineTexture(level, format, width, height, mType);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001365
1366 if (!isRenderableFormat())
1367 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001368 copyNonRenderable(&mImageArray[level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001369 }
1370 else
1371 {
1372 if (redefined)
1373 {
1374 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001375 }
1376 else
1377 {
1378 needRenderTarget();
1379 }
1380
1381 if (width != 0 && height != 0 && level < levelCount())
1382 {
1383 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1384 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1385 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1386 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1387 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1388
1389 IDirect3DSurface9 *dest;
1390 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1391
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001392 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001393 dest->Release();
1394 }
1395 }
1396
1397 mImageArray[level].width = width;
1398 mImageArray[level].height = height;
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001399 mImageArray[level].format = format;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001400}
1401
1402void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1403{
1404 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1405 {
1406 return error(GL_INVALID_VALUE);
1407 }
1408
1409 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1410
1411 if (!renderTarget)
1412 {
1413 ERR("Failed to retrieve the render target.");
1414 return error(GL_OUT_OF_MEMORY);
1415 }
1416
1417 bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
1418
1419 if (!isRenderableFormat())
1420 {
1421 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1422 }
1423 else
1424 {
1425 if (redefined)
1426 {
1427 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001428 }
1429 else
1430 {
1431 needRenderTarget();
1432 }
1433
1434 if (level < levelCount())
1435 {
1436 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1437 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1438 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1439 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1440 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1441
1442 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1443
1444 IDirect3DSurface9 *dest;
1445 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1446
1447 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1448 dest->Release();
1449 }
1450 }
1451}
1452
1453// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1454bool Texture2D::isComplete() const
1455{
1456 GLsizei width = mImageArray[0].width;
1457 GLsizei height = mImageArray[0].height;
1458
1459 if (width <= 0 || height <= 0)
1460 {
1461 return false;
1462 }
1463
1464 bool mipmapping = false;
1465
1466 switch (mMinFilter)
1467 {
1468 case GL_NEAREST:
1469 case GL_LINEAR:
1470 mipmapping = false;
1471 break;
1472 case GL_NEAREST_MIPMAP_NEAREST:
1473 case GL_LINEAR_MIPMAP_NEAREST:
1474 case GL_NEAREST_MIPMAP_LINEAR:
1475 case GL_LINEAR_MIPMAP_LINEAR:
1476 mipmapping = true;
1477 break;
1478 default: UNREACHABLE();
1479 }
1480
1481 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1482 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1483 {
1484 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1485 {
1486 return false;
1487 }
1488 }
1489
1490
1491 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1492 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1493 {
1494 return false;
1495 }
1496
1497 if (mipmapping)
1498 {
1499 if (!isPow2(width) || !isPow2(height))
1500 {
1501 return false;
1502 }
1503
1504 int q = log2(std::max(width, height));
1505
1506 for (int level = 1; level <= q; level++)
1507 {
1508 if (mImageArray[level].format != mImageArray[0].format)
1509 {
1510 return false;
1511 }
1512
1513 if (mImageArray[level].width != std::max(1, width >> level))
1514 {
1515 return false;
1516 }
1517
1518 if (mImageArray[level].height != std::max(1, height >> level))
1519 {
1520 return false;
1521 }
1522 }
1523 }
1524
1525 return true;
1526}
1527
1528bool Texture2D::isCompressed() const
1529{
1530 return IsCompressed(getInternalFormat());
1531}
1532
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001533IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1534{
1535 return mTexture;
1536}
1537
1538// Constructs a Direct3D 9 texture resource from the texture images
1539void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001540{
1541 IDirect3DTexture9 *texture;
1542
1543 IDirect3DDevice9 *device = getDevice();
1544 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
1545
1546 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
1547
1548 if (FAILED(result))
1549 {
1550 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001551 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001552 }
1553
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001554 if (mTexture)
1555 {
1556 mTexture->Release();
1557 }
1558
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001559 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001560 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001561}
1562
1563void Texture2D::updateTexture()
1564{
1565 IDirect3DDevice9 *device = getDevice();
1566
1567 int levels = levelCount();
1568
1569 for (int level = 0; level < levels; level++)
1570 {
1571 if (mImageArray[level].dirty)
1572 {
1573 IDirect3DSurface9 *levelSurface = NULL;
1574 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1575
1576 ASSERT(SUCCEEDED(result));
1577
1578 if (SUCCEEDED(result))
1579 {
1580 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1581 ASSERT(SUCCEEDED(result));
1582
1583 levelSurface->Release();
1584
1585 mImageArray[level].dirty = false;
1586 }
1587 }
1588 }
1589}
1590
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001591void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001592{
1593 IDirect3DTexture9 *texture = NULL;
1594
1595 if (mWidth != 0 && mHeight != 0)
1596 {
1597 egl::Display *display = getDisplay();
1598 IDirect3DDevice9 *device = getDevice();
1599 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
1600
1601 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
1602
1603 if (FAILED(result))
1604 {
1605 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001606 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001607 }
1608
1609 if (mTexture != NULL)
1610 {
1611 int levels = levelCount();
1612 for (int i = 0; i < levels; i++)
1613 {
1614 IDirect3DSurface9 *source;
1615 result = mTexture->GetSurfaceLevel(i, &source);
1616
1617 if (FAILED(result))
1618 {
1619 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1620
1621 texture->Release();
1622
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001623 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001624 }
1625
1626 IDirect3DSurface9 *dest;
1627 result = texture->GetSurfaceLevel(i, &dest);
1628
1629 if (FAILED(result))
1630 {
1631 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1632
1633 texture->Release();
1634 source->Release();
1635
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001636 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001637 }
1638
1639 display->endScene();
1640 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1641
1642 if (FAILED(result))
1643 {
1644 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1645
1646 texture->Release();
1647 source->Release();
1648 dest->Release();
1649
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001650 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001651 }
1652
1653 source->Release();
1654 dest->Release();
1655 }
1656 }
1657 }
1658
1659 if (mTexture != NULL)
1660 {
1661 mTexture->Release();
1662 }
1663
1664 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001665 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001666}
1667
1668bool Texture2D::dirtyImageData() const
1669{
1670 int q = log2(std::max(mWidth, mHeight));
1671
1672 for (int i = 0; i <= q; i++)
1673 {
1674 if (mImageArray[i].dirty) return true;
1675 }
1676
1677 return false;
1678}
1679
1680void Texture2D::generateMipmaps()
1681{
1682 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1683 {
1684 return error(GL_INVALID_OPERATION);
1685 }
1686
1687 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1688 unsigned int q = log2(std::max(mWidth, mHeight));
1689 for (unsigned int i = 1; i <= q; i++)
1690 {
1691 if (mImageArray[i].surface != NULL)
1692 {
1693 mImageArray[i].surface->Release();
1694 mImageArray[i].surface = NULL;
1695 }
1696
1697 mImageArray[i].dirty = false;
1698
1699 mImageArray[i].format = mImageArray[0].format;
1700 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1701 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1702 }
1703
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001704 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001705 {
1706 if (mTexture == NULL)
1707 {
1708 ERR(" failed because mTexture was null.");
1709 return;
1710 }
1711
1712 for (unsigned int i = 1; i <= q; i++)
1713 {
1714 IDirect3DSurface9 *upper = NULL;
1715 IDirect3DSurface9 *lower = NULL;
1716
1717 mTexture->GetSurfaceLevel(i-1, &upper);
1718 mTexture->GetSurfaceLevel(i, &lower);
1719
1720 if (upper != NULL && lower != NULL)
1721 {
1722 getBlitter()->boxFilter(upper, lower);
1723 }
1724
1725 if (upper != NULL) upper->Release();
1726 if (lower != NULL) lower->Release();
1727 }
1728 }
1729 else
1730 {
1731 for (unsigned int i = 1; i <= q; i++)
1732 {
1733 createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
1734 if (mImageArray[i].surface == NULL)
1735 {
1736 return error(GL_OUT_OF_MEMORY);
1737 }
1738
1739 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1740 {
1741 ERR(" failed to load filter %d to %d.", i - 1, i);
1742 }
1743
1744 mImageArray[i].dirty = true;
1745 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001746 }
1747}
1748
1749Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1750{
1751 if (target != GL_TEXTURE_2D)
1752 {
1753 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1754 }
1755
1756 if (mColorbufferProxy.get() == NULL)
1757 {
1758 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1759 }
1760
1761 return mColorbufferProxy.get();
1762}
1763
1764IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1765{
1766 ASSERT(target == GL_TEXTURE_2D);
1767
1768 needRenderTarget();
1769
1770 if (mTexture == NULL)
1771 {
1772 return NULL;
1773 }
1774
1775 IDirect3DSurface9 *renderTarget = NULL;
1776 mTexture->GetSurfaceLevel(0, &renderTarget);
1777
1778 return renderTarget;
1779}
1780
1781TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1782{
1783 mTexture = NULL;
1784}
1785
1786TextureCubeMap::~TextureCubeMap()
1787{
1788 for (int i = 0; i < 6; i++)
1789 {
1790 mFaceProxies[i].set(NULL);
1791 }
1792
1793 if (mTexture)
1794 {
1795 mTexture->Release();
1796 mTexture = NULL;
1797 }
1798}
1799
1800GLenum TextureCubeMap::getTarget() const
1801{
1802 return GL_TEXTURE_CUBE_MAP;
1803}
1804
1805GLenum TextureCubeMap::getInternalFormat() const
1806{
1807 return mImageArray[0][0].format;
1808}
1809
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001810void 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 +00001811{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001812 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001813}
1814
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001815void 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 +00001816{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001817 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001818}
1819
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001820void 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 +00001821{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001822 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001823}
1824
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001825void 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 +00001826{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001827 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001828}
1829
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001830void 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 +00001831{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001832 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001833}
1834
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001835void 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 +00001836{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001837 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001838}
1839
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001840void 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 +00001841{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001842 redefineTexture(level, format, width);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001843
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001844 Texture::setCompressedImage(width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001845}
1846
1847void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1848{
1849 int face = faceIndex(faceTarget);
1850 ASSERT(mImageArray[face][level].surface != NULL);
1851
1852 if (level < levelCount())
1853 {
1854 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1855 ASSERT(destLevel != NULL);
1856
1857 if (destLevel != NULL)
1858 {
1859 Image *img = &mImageArray[face][level];
1860
1861 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, img->height);;
1862
1863 POINT destPoint;
1864 destPoint.x = sourceRect.left;
1865 destPoint.y = sourceRect.top;
1866
1867 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1868 ASSERT(SUCCEEDED(result));
1869
1870 destLevel->Release();
1871
1872 img->dirty = false;
1873 }
1874 }
1875}
1876
1877void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1878{
1879 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1880 {
1881 commitRect(target, level, xoffset, yoffset, width, height);
1882 }
1883}
1884
1885void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1886{
1887 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1888 {
1889 commitRect(target, level, xoffset, yoffset, width, height);
1890 }
1891}
1892
1893// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1894bool TextureCubeMap::isComplete() const
1895{
1896 int size = mImageArray[0][0].width;
1897
1898 if (size <= 0)
1899 {
1900 return false;
1901 }
1902
1903 bool mipmapping;
1904
1905 switch (mMinFilter)
1906 {
1907 case GL_NEAREST:
1908 case GL_LINEAR:
1909 mipmapping = false;
1910 break;
1911 case GL_NEAREST_MIPMAP_NEAREST:
1912 case GL_LINEAR_MIPMAP_NEAREST:
1913 case GL_NEAREST_MIPMAP_LINEAR:
1914 case GL_LINEAR_MIPMAP_LINEAR:
1915 mipmapping = true;
1916 break;
1917 default: UNREACHABLE();
1918 }
1919
1920 for (int face = 0; face < 6; face++)
1921 {
1922 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1923 {
1924 return false;
1925 }
1926 }
1927
1928 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1929 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1930 {
1931 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1932 {
1933 return false;
1934 }
1935 }
1936
1937 if (mipmapping)
1938 {
1939 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1940 {
1941 return false;
1942 }
1943
1944 int q = log2(size);
1945
1946 for (int face = 0; face < 6; face++)
1947 {
1948 for (int level = 1; level <= q; level++)
1949 {
1950 if (mImageArray[face][level].format != mImageArray[0][0].format)
1951 {
1952 return false;
1953 }
1954
1955 if (mImageArray[face][level].width != std::max(1, size >> level))
1956 {
1957 return false;
1958 }
1959
1960 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1961 }
1962 }
1963 }
1964
1965 return true;
1966}
1967
1968bool TextureCubeMap::isCompressed() const
1969{
1970 return IsCompressed(getInternalFormat());
1971}
1972
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001973IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1974{
1975 return mTexture;
1976}
1977
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001978// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001979void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001980{
1981 IDirect3DDevice9 *device = getDevice();
1982 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
1983
1984 IDirect3DCubeTexture9 *texture;
1985
1986 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
1987
1988 if (FAILED(result))
1989 {
1990 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001991 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001992 }
1993
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001994 if (mTexture)
1995 {
1996 mTexture->Release();
1997 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001998
1999 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002000 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002001}
2002
2003void TextureCubeMap::updateTexture()
2004{
2005 IDirect3DDevice9 *device = getDevice();
2006
2007 for (int face = 0; face < 6; face++)
2008 {
2009 int levels = levelCount();
2010 for (int level = 0; level < levels; level++)
2011 {
2012 Image *img = &mImageArray[face][level];
2013
2014 if (img->dirty)
2015 {
2016 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2017 ASSERT(levelSurface != NULL);
2018
2019 if (levelSurface != NULL)
2020 {
2021 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
2022 ASSERT(SUCCEEDED(result));
2023
2024 levelSurface->Release();
2025
2026 img->dirty = false;
2027 }
2028 }
2029 }
2030 }
2031}
2032
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002033void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002034{
2035 IDirect3DCubeTexture9 *texture = NULL;
2036
2037 if (mWidth != 0)
2038 {
2039 egl::Display *display = getDisplay();
2040 IDirect3DDevice9 *device = getDevice();
2041 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
2042
2043 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
2044
2045 if (FAILED(result))
2046 {
2047 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002048 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002049 }
2050
2051 if (mTexture != NULL)
2052 {
2053 int levels = levelCount();
2054 for (int f = 0; f < 6; f++)
2055 {
2056 for (int i = 0; i < levels; i++)
2057 {
2058 IDirect3DSurface9 *source;
2059 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2060
2061 if (FAILED(result))
2062 {
2063 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2064
2065 texture->Release();
2066
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002067 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002068 }
2069
2070 IDirect3DSurface9 *dest;
2071 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2072
2073 if (FAILED(result))
2074 {
2075 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2076
2077 texture->Release();
2078 source->Release();
2079
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002080 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002081 }
2082
2083 display->endScene();
2084 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2085
2086 if (FAILED(result))
2087 {
2088 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2089
2090 texture->Release();
2091 source->Release();
2092 dest->Release();
2093
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002094 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002095 }
2096 }
2097 }
2098 }
2099 }
2100
2101 if (mTexture != NULL)
2102 {
2103 mTexture->Release();
2104 }
2105
2106 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002107 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002108}
2109
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002110void 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 +00002111{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002112 redefineTexture(level, format, width);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002113
2114 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
2115}
2116
2117unsigned int TextureCubeMap::faceIndex(GLenum face)
2118{
2119 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2120 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2121 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2122 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2123 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2124
2125 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2126}
2127
2128bool TextureCubeMap::dirtyImageData() const
2129{
2130 int q = log2(mWidth);
2131
2132 for (int f = 0; f < 6; f++)
2133 {
2134 for (int i = 0; i <= q; i++)
2135 {
2136 if (mImageArray[f][i].dirty) return true;
2137 }
2138 }
2139
2140 return false;
2141}
2142
2143// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
2144// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
2145// Call this when a particular level of the texture must be defined with a specific format, width and height.
2146//
2147// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
2148// a new size for the texture by working backwards from the given size.
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002149bool TextureCubeMap::redefineTexture(GLint level, GLenum format, GLsizei width)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002150{
2151 // Are these settings compatible with level 0?
2152 bool sizeOkay = (mImageArray[0][0].width >> level == width);
2153
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002154 bool textureOkay = (sizeOkay && format == mImageArray[0][0].format);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002155
2156 if (!textureOkay)
2157 {
2158 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
2159 mImageArray[0][0].format, mImageArray[0][0].width,
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002160 format, width);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002161
2162 // Purge all the levels and the texture.
2163 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2164 {
2165 for (int f = 0; f < 6; f++)
2166 {
2167 if (mImageArray[f][i].surface != NULL)
2168 {
2169 mImageArray[f][i].dirty = false;
2170
2171 mImageArray[f][i].surface->Release();
2172 mImageArray[f][i].surface = NULL;
2173 }
2174 }
2175 }
2176
2177 if (mTexture != NULL)
2178 {
2179 mTexture->Release();
2180 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002181 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002182 }
2183
2184 mWidth = width << level;
2185 mImageArray[0][0].width = width << level;
2186 mHeight = width << level;
2187 mImageArray[0][0].height = width << level;
2188
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002189 mImageArray[0][0].format = format;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002190 }
2191
2192 return !textureOkay;
2193}
2194
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002195void 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 +00002196{
2197 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2198
2199 if (!renderTarget)
2200 {
2201 ERR("Failed to retrieve the render target.");
2202 return error(GL_OUT_OF_MEMORY);
2203 }
2204
2205 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002206 bool redefined = redefineTexture(level, format, width);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002207
2208 if (!isRenderableFormat())
2209 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002210 copyNonRenderable(&mImageArray[faceindex][level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002211 }
2212 else
2213 {
2214 if (redefined)
2215 {
2216 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002217 }
2218 else
2219 {
2220 needRenderTarget();
2221 }
2222
2223 ASSERT(width == height);
2224
2225 if (width > 0 && level < levelCount())
2226 {
2227 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2228 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2229 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2230 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2231 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2232
2233 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2234
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002235 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002236 dest->Release();
2237 }
2238 }
2239
2240 mImageArray[faceindex][level].width = width;
2241 mImageArray[faceindex][level].height = height;
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002242 mImageArray[faceindex][level].format = format;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002243}
2244
2245IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2246{
2247 if (mTexture == NULL)
2248 {
2249 UNREACHABLE();
2250 return NULL;
2251 }
2252
2253 IDirect3DSurface9 *surface = NULL;
2254
2255 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2256
2257 return (SUCCEEDED(hr)) ? surface : NULL;
2258}
2259
2260void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2261{
2262 GLsizei size = mImageArray[faceIndex(target)][level].width;
2263
2264 if (xoffset + width > size || yoffset + height > size)
2265 {
2266 return error(GL_INVALID_VALUE);
2267 }
2268
2269 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2270
2271 if (!renderTarget)
2272 {
2273 ERR("Failed to retrieve the render target.");
2274 return error(GL_OUT_OF_MEMORY);
2275 }
2276
2277 unsigned int faceindex = faceIndex(target);
2278 bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
2279
2280 if (!isRenderableFormat())
2281 {
2282 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2283 }
2284 else
2285 {
2286 if (redefined)
2287 {
2288 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002289 }
2290 else
2291 {
2292 needRenderTarget();
2293 }
2294
2295 if (level < levelCount())
2296 {
2297 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2298 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2299 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2300 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2301 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2302
2303 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2304
2305 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2306
2307 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2308 dest->Release();
2309 }
2310 }
2311}
2312
2313bool TextureCubeMap::isCubeComplete() const
2314{
2315 if (mImageArray[0][0].width == 0)
2316 {
2317 return false;
2318 }
2319
2320 for (unsigned int f = 1; f < 6; f++)
2321 {
2322 if (mImageArray[f][0].width != mImageArray[0][0].width
2323 || mImageArray[f][0].format != mImageArray[0][0].format)
2324 {
2325 return false;
2326 }
2327 }
2328
2329 return true;
2330}
2331
2332void TextureCubeMap::generateMipmaps()
2333{
2334 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2335 {
2336 return error(GL_INVALID_OPERATION);
2337 }
2338
2339 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2340 unsigned int q = log2(mImageArray[0][0].width);
2341 for (unsigned int f = 0; f < 6; f++)
2342 {
2343 for (unsigned int i = 1; i <= q; i++)
2344 {
2345 if (mImageArray[f][i].surface != NULL)
2346 {
2347 mImageArray[f][i].surface->Release();
2348 mImageArray[f][i].surface = NULL;
2349 }
2350
2351 mImageArray[f][i].dirty = false;
2352
2353 mImageArray[f][i].format = mImageArray[f][0].format;
2354 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2355 mImageArray[f][i].height = mImageArray[f][i].width;
2356 }
2357 }
2358
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002359 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002360 {
2361 if (mTexture == NULL)
2362 {
2363 return;
2364 }
2365
2366 for (unsigned int f = 0; f < 6; f++)
2367 {
2368 for (unsigned int i = 1; i <= q; i++)
2369 {
2370 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2371 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2372
2373 if (upper != NULL && lower != NULL)
2374 {
2375 getBlitter()->boxFilter(upper, lower);
2376 }
2377
2378 if (upper != NULL) upper->Release();
2379 if (lower != NULL) lower->Release();
2380 }
2381 }
2382 }
2383 else
2384 {
2385 for (unsigned int f = 0; f < 6; f++)
2386 {
2387 for (unsigned int i = 1; i <= q; i++)
2388 {
2389 createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
2390 if (mImageArray[f][i].surface == NULL)
2391 {
2392 return error(GL_OUT_OF_MEMORY);
2393 }
2394
2395 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2396 {
2397 ERR(" failed to load filter %d to %d.", i - 1, i);
2398 }
2399
2400 mImageArray[f][i].dirty = true;
2401 }
2402 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002403 }
2404}
2405
2406Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2407{
2408 if (!IsCubemapTextureTarget(target))
2409 {
2410 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2411 }
2412
2413 unsigned int face = faceIndex(target);
2414
2415 if (mFaceProxies[face].get() == NULL)
2416 {
2417 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2418 }
2419
2420 return mFaceProxies[face].get();
2421}
2422
2423IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2424{
2425 ASSERT(IsCubemapTextureTarget(target));
2426
2427 needRenderTarget();
2428
2429 if (mTexture == NULL)
2430 {
2431 return NULL;
2432 }
2433
2434 IDirect3DSurface9 *renderTarget = NULL;
2435 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2436
2437 return renderTarget;
2438}
2439
2440}