blob: 104f7f5007769c15cce3969426ad71f569c10796 [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
13#include <d3dx9tex.h>
14
15#include <algorithm>
16
17#include "common/debug.h"
18
19#include "libGLESv2/main.h"
20#include "libGLESv2/mathutil.h"
21#include "libGLESv2/utilities.h"
22#include "libGLESv2/Blit.h"
23#include "libGLESv2/Framebuffer.h"
24
25namespace gl
26{
27
28Texture::Image::Image()
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +000029 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000030{
31}
32
33Texture::Image::~Image()
34{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000035 if (surface)
36 {
37 surface->Release();
38 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000039}
40
41Texture::Texture(GLuint id) : RefCountObject(id)
42{
43 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
44 mMagFilter = GL_LINEAR;
45 mWrapS = GL_REPEAT;
46 mWrapT = GL_REPEAT;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000047 mDirtyParameters = true;
48
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000049 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000050}
51
52Texture::~Texture()
53{
54}
55
56Blit *Texture::getBlitter()
57{
58 Context *context = getContext();
59 return context->getBlitter();
60}
61
62// Returns true on successful filter state update (valid enum parameter)
63bool Texture::setMinFilter(GLenum filter)
64{
65 switch (filter)
66 {
67 case GL_NEAREST:
68 case GL_LINEAR:
69 case GL_NEAREST_MIPMAP_NEAREST:
70 case GL_LINEAR_MIPMAP_NEAREST:
71 case GL_NEAREST_MIPMAP_LINEAR:
72 case GL_LINEAR_MIPMAP_LINEAR:
73 {
74 if (mMinFilter != filter)
75 {
76 mMinFilter = filter;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000077 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000078 }
79 return true;
80 }
81 default:
82 return false;
83 }
84}
85
86// Returns true on successful filter state update (valid enum parameter)
87bool Texture::setMagFilter(GLenum filter)
88{
89 switch (filter)
90 {
91 case GL_NEAREST:
92 case GL_LINEAR:
93 {
94 if (mMagFilter != filter)
95 {
96 mMagFilter = filter;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000097 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000098 }
99 return true;
100 }
101 default:
102 return false;
103 }
104}
105
106// Returns true on successful wrap state update (valid enum parameter)
107bool Texture::setWrapS(GLenum wrap)
108{
109 switch (wrap)
110 {
111 case GL_REPEAT:
112 case GL_CLAMP_TO_EDGE:
113 case GL_MIRRORED_REPEAT:
114 {
115 if (mWrapS != wrap)
116 {
117 mWrapS = wrap;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000118 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000119 }
120 return true;
121 }
122 default:
123 return false;
124 }
125}
126
127// Returns true on successful wrap state update (valid enum parameter)
128bool Texture::setWrapT(GLenum wrap)
129{
130 switch (wrap)
131 {
132 case GL_REPEAT:
133 case GL_CLAMP_TO_EDGE:
134 case GL_MIRRORED_REPEAT:
135 {
136 if (mWrapT != wrap)
137 {
138 mWrapT = wrap;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000139 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000140 }
141 return true;
142 }
143 default:
144 return false;
145 }
146}
147
148GLenum Texture::getMinFilter() const
149{
150 return mMinFilter;
151}
152
153GLenum Texture::getMagFilter() const
154{
155 return mMagFilter;
156}
157
158GLenum Texture::getWrapS() const
159{
160 return mWrapS;
161}
162
163GLenum Texture::getWrapT() const
164{
165 return mWrapT;
166}
167
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000168bool Texture::isFloatingPoint() const
169{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000170 return (getType() == GL_FLOAT || getType() == GL_HALF_FLOAT_OES);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000171}
172
173bool Texture::isRenderableFormat() const
174{
175 D3DFORMAT format = getD3DFormat();
176
177 switch(format)
178 {
179 case D3DFMT_L8:
180 case D3DFMT_A8L8:
181 case D3DFMT_DXT1:
182 return false;
183 case D3DFMT_A8R8G8B8:
184 case D3DFMT_X8R8G8B8:
185 case D3DFMT_A16B16G16R16F:
186 case D3DFMT_A32B32G32R32F:
187 return true;
188 default:
189 UNREACHABLE();
190 }
191
192 return false;
193}
194
195// Selects an internal Direct3D 9 format for storing an Image
196D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
197{
198 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
199 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
200 {
201 return D3DFMT_DXT1;
202 }
203 else if (type == GL_FLOAT)
204 {
205 return D3DFMT_A32B32G32R32F;
206 }
207 else if (type == GL_HALF_FLOAT_OES)
208 {
209 return D3DFMT_A16B16G16R16F;
210 }
211 else if (type == GL_UNSIGNED_BYTE)
212 {
213 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
214 {
215 return D3DFMT_L8;
216 }
217 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
218 {
219 return D3DFMT_A8L8;
220 }
221 else if (format == GL_RGB)
222 {
223 return D3DFMT_X8R8G8B8;
224 }
225
226 return D3DFMT_A8R8G8B8;
227 }
228
229 return D3DFMT_A8R8G8B8;
230}
231
232// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
233// into the target pixel rectangle at output with outputPitch bytes in between each line.
234void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
235 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
236{
237 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
238 input = ((char*)input) - inputPitch * (height - 1);
239
240 switch (type)
241 {
242 case GL_UNSIGNED_BYTE:
243 switch (format)
244 {
245 case GL_ALPHA:
246 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
247 break;
248 case GL_LUMINANCE:
249 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
250 break;
251 case GL_LUMINANCE_ALPHA:
252 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
253 break;
254 case GL_RGB:
255 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
256 break;
257 case GL_RGBA:
258 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
259 break;
260 case GL_BGRA_EXT:
261 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
262 break;
263 default: UNREACHABLE();
264 }
265 break;
266 case GL_UNSIGNED_SHORT_5_6_5:
267 switch (format)
268 {
269 case GL_RGB:
270 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
271 break;
272 default: UNREACHABLE();
273 }
274 break;
275 case GL_UNSIGNED_SHORT_4_4_4_4:
276 switch (format)
277 {
278 case GL_RGBA:
279 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
280 break;
281 default: UNREACHABLE();
282 }
283 break;
284 case GL_UNSIGNED_SHORT_5_5_5_1:
285 switch (format)
286 {
287 case GL_RGBA:
288 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
289 break;
290 default: UNREACHABLE();
291 }
292 break;
293 case GL_FLOAT:
294 switch (format)
295 {
296 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
297 case GL_ALPHA:
298 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
299 break;
300 case GL_LUMINANCE:
301 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
302 break;
303 case GL_LUMINANCE_ALPHA:
304 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
305 break;
306 case GL_RGB:
307 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
308 break;
309 case GL_RGBA:
310 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
311 break;
312 default: UNREACHABLE();
313 }
314 break;
315 case GL_HALF_FLOAT_OES:
316 switch (format)
317 {
318 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
319 case GL_ALPHA:
320 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
321 break;
322 case GL_LUMINANCE:
323 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
324 break;
325 case GL_LUMINANCE_ALPHA:
326 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
327 break;
328 case GL_RGB:
329 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
330 break;
331 case GL_RGBA:
332 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
333 break;
334 default: UNREACHABLE();
335 }
336 break;
337 default: UNREACHABLE();
338 }
339}
340
341void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
342 int inputPitch, const void *input, size_t outputPitch, void *output) const
343{
344 const unsigned char *source = NULL;
345 unsigned char *dest = NULL;
346
347 for (int y = 0; y < height; y++)
348 {
349 source = static_cast<const unsigned char*>(input) + y * inputPitch;
350 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
351 for (int x = 0; x < width; x++)
352 {
353 dest[4 * x + 0] = 0;
354 dest[4 * x + 1] = 0;
355 dest[4 * x + 2] = 0;
356 dest[4 * x + 3] = source[x];
357 }
358 }
359}
360
361void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
362 int inputPitch, const void *input, size_t outputPitch, void *output) const
363{
364 const float *source = NULL;
365 float *dest = NULL;
366
367 for (int y = 0; y < height; y++)
368 {
369 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
370 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
371 for (int x = 0; x < width; x++)
372 {
373 dest[4 * x + 0] = 0;
374 dest[4 * x + 1] = 0;
375 dest[4 * x + 2] = 0;
376 dest[4 * x + 3] = source[x];
377 }
378 }
379}
380
381void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
382 int inputPitch, const void *input, size_t outputPitch, void *output) const
383{
384 const unsigned short *source = NULL;
385 unsigned short *dest = NULL;
386
387 for (int y = 0; y < height; y++)
388 {
389 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
390 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
391 for (int x = 0; x < width; x++)
392 {
393 dest[4 * x + 0] = 0;
394 dest[4 * x + 1] = 0;
395 dest[4 * x + 2] = 0;
396 dest[4 * x + 3] = source[x];
397 }
398 }
399}
400
401void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
402 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
403{
404 const int destBytesPerPixel = native? 1: 4;
405 const unsigned char *source = NULL;
406 unsigned char *dest = NULL;
407
408 for (int y = 0; y < height; y++)
409 {
410 source = static_cast<const unsigned char*>(input) + y * inputPitch;
411 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
412
413 if (!native) // BGRA8 destination format
414 {
415 for (int x = 0; x < width; x++)
416 {
417 dest[4 * x + 0] = source[x];
418 dest[4 * x + 1] = source[x];
419 dest[4 * x + 2] = source[x];
420 dest[4 * x + 3] = 0xFF;
421 }
422 }
423 else // L8 destination format
424 {
425 memcpy(dest, source, width);
426 }
427 }
428}
429
430void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
431 int inputPitch, const void *input, size_t outputPitch, void *output) const
432{
433 const float *source = NULL;
434 float *dest = NULL;
435
436 for (int y = 0; y < height; y++)
437 {
438 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
439 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
440 for (int x = 0; x < width; x++)
441 {
442 dest[4 * x + 0] = source[x];
443 dest[4 * x + 1] = source[x];
444 dest[4 * x + 2] = source[x];
445 dest[4 * x + 3] = 1.0f;
446 }
447 }
448}
449
450void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
451 int inputPitch, const void *input, size_t outputPitch, void *output) const
452{
453 const unsigned short *source = NULL;
454 unsigned short *dest = NULL;
455
456 for (int y = 0; y < height; y++)
457 {
458 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
459 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
460 for (int x = 0; x < width; x++)
461 {
462 dest[4 * x + 0] = source[x];
463 dest[4 * x + 1] = source[x];
464 dest[4 * x + 2] = source[x];
465 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
466 }
467 }
468}
469
470void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
471 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
472{
473 const int destBytesPerPixel = native? 2: 4;
474 const unsigned char *source = NULL;
475 unsigned char *dest = NULL;
476
477 for (int y = 0; y < height; y++)
478 {
479 source = static_cast<const unsigned char*>(input) + y * inputPitch;
480 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
481
482 if (!native) // BGRA8 destination format
483 {
484 for (int x = 0; x < width; x++)
485 {
486 dest[4 * x + 0] = source[2*x+0];
487 dest[4 * x + 1] = source[2*x+0];
488 dest[4 * x + 2] = source[2*x+0];
489 dest[4 * x + 3] = source[2*x+1];
490 }
491 }
492 else
493 {
494 memcpy(dest, source, width * 2);
495 }
496 }
497}
498
499void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
500 int inputPitch, const void *input, size_t outputPitch, void *output) const
501{
502 const float *source = NULL;
503 float *dest = NULL;
504
505 for (int y = 0; y < height; y++)
506 {
507 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
508 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
509 for (int x = 0; x < width; x++)
510 {
511 dest[4 * x + 0] = source[2*x+0];
512 dest[4 * x + 1] = source[2*x+0];
513 dest[4 * x + 2] = source[2*x+0];
514 dest[4 * x + 3] = source[2*x+1];
515 }
516 }
517}
518
519void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
520 int inputPitch, const void *input, size_t outputPitch, void *output) const
521{
522 const unsigned short *source = NULL;
523 unsigned short *dest = NULL;
524
525 for (int y = 0; y < height; y++)
526 {
527 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
528 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
529 for (int x = 0; x < width; x++)
530 {
531 dest[4 * x + 0] = source[2*x+0];
532 dest[4 * x + 1] = source[2*x+0];
533 dest[4 * x + 2] = source[2*x+0];
534 dest[4 * x + 3] = source[2*x+1];
535 }
536 }
537}
538
539void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
540 int inputPitch, const void *input, size_t outputPitch, void *output) const
541{
542 const unsigned char *source = NULL;
543 unsigned char *dest = NULL;
544
545 for (int y = 0; y < height; y++)
546 {
547 source = static_cast<const unsigned char*>(input) + y * inputPitch;
548 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
549 for (int x = 0; x < width; x++)
550 {
551 dest[4 * x + 0] = source[x * 3 + 2];
552 dest[4 * x + 1] = source[x * 3 + 1];
553 dest[4 * x + 2] = source[x * 3 + 0];
554 dest[4 * x + 3] = 0xFF;
555 }
556 }
557}
558
559void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
560 int inputPitch, const void *input, size_t outputPitch, void *output) const
561{
562 const unsigned short *source = NULL;
563 unsigned char *dest = NULL;
564
565 for (int y = 0; y < height; y++)
566 {
567 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
568 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
569 for (int x = 0; x < width; x++)
570 {
571 unsigned short rgba = source[x];
572 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
573 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
574 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
575 dest[4 * x + 3] = 0xFF;
576 }
577 }
578}
579
580void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
581 int inputPitch, const void *input, size_t outputPitch, void *output) const
582{
583 const float *source = NULL;
584 float *dest = NULL;
585
586 for (int y = 0; y < height; y++)
587 {
588 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
589 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
590 for (int x = 0; x < width; x++)
591 {
592 dest[4 * x + 0] = source[x * 3 + 0];
593 dest[4 * x + 1] = source[x * 3 + 1];
594 dest[4 * x + 2] = source[x * 3 + 2];
595 dest[4 * x + 3] = 1.0f;
596 }
597 }
598}
599
600void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
601 int inputPitch, const void *input, size_t outputPitch, void *output) const
602{
603 const unsigned short *source = NULL;
604 unsigned short *dest = NULL;
605
606 for (int y = 0; y < height; y++)
607 {
608 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
609 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
610 for (int x = 0; x < width; x++)
611 {
612 dest[4 * x + 0] = source[x * 3 + 0];
613 dest[4 * x + 1] = source[x * 3 + 1];
614 dest[4 * x + 2] = source[x * 3 + 2];
615 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
616 }
617 }
618}
619
620void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
621 int inputPitch, const void *input, size_t outputPitch, void *output) const
622{
623 const unsigned char *source = NULL;
624 unsigned char *dest = NULL;
625
626 for (int y = 0; y < height; y++)
627 {
628 source = static_cast<const unsigned char*>(input) + y * inputPitch;
629 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
630 for (int x = 0; x < width; x++)
631 {
632 dest[4 * x + 0] = source[x * 4 + 2];
633 dest[4 * x + 1] = source[x * 4 + 1];
634 dest[4 * x + 2] = source[x * 4 + 0];
635 dest[4 * x + 3] = source[x * 4 + 3];
636 }
637 }
638}
639
640void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
641 int inputPitch, const void *input, size_t outputPitch, void *output) const
642{
643 const unsigned short *source = NULL;
644 unsigned char *dest = NULL;
645
646 for (int y = 0; y < height; y++)
647 {
648 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
649 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
650 for (int x = 0; x < width; x++)
651 {
652 unsigned short rgba = source[x];
653 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
654 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
655 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
656 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
657 }
658 }
659}
660
661void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
662 int inputPitch, const void *input, size_t outputPitch, void *output) const
663{
664 const unsigned short *source = NULL;
665 unsigned char *dest = NULL;
666
667 for (int y = 0; y < height; y++)
668 {
669 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
670 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
671 for (int x = 0; x < width; x++)
672 {
673 unsigned short rgba = source[x];
674 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
675 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
676 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
677 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
678 }
679 }
680}
681
682void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
683 int inputPitch, const void *input, size_t outputPitch, void *output) const
684{
685 const float *source = NULL;
686 float *dest = NULL;
687
688 for (int y = 0; y < height; y++)
689 {
690 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
691 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
692 memcpy(dest, source, width * 16);
693 }
694}
695
696void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
697 int inputPitch, const void *input, size_t outputPitch, void *output) const
698{
699 const unsigned char *source = NULL;
700 unsigned char *dest = NULL;
701
702 for (int y = 0; y < height; y++)
703 {
704 source = static_cast<const unsigned char*>(input) + y * inputPitch;
705 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
706 memcpy(dest, source, width * 8);
707 }
708}
709
710void Texture::loadBGRAImageData(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 * 4;
720 memcpy(dest, source, width*4);
721 }
722}
723
724void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
725 int inputPitch, const void *input, size_t outputPitch, void *output) const
726{
727 ASSERT(xoffset % 4 == 0);
728 ASSERT(yoffset % 4 == 0);
729 ASSERT(width % 4 == 0 || width == 2 || width == 1);
730 ASSERT(inputPitch % 8 == 0);
731 ASSERT(outputPitch % 8 == 0);
732
733 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
734 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
735
736 switch (height)
737 {
738 case 1:
739 // Round width up in case it is 1.
740 for (int x = 0; x < (width + 1) / 2; x += 2)
741 {
742 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
743 dest[x] = source[x];
744
745 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
746 dest[x + 1] = source[x + 1];
747 }
748 break;
749 case 2:
750 // Round width up in case it is 1.
751 for (int x = 0; x < (width + 1) / 2; x += 2)
752 {
753 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
754 dest[x] = source[x];
755
756 // 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.
757 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
758 ((source[x + 1] >> 8) & 0x000000FF);
759 }
760 break;
761 default:
762 ASSERT(height % 4 == 0);
763 for (int y = 0; y < height / 4; ++y)
764 {
765 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
766 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
767
768 // Round width up in case it is 1.
769 for (int x = 0; x < (width + 1) / 2; x += 2)
770 {
771 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
772 dest[x] = source[x];
773
774 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
775 dest[x + 1] = (source[x + 1] >> 24) |
776 ((source[x + 1] << 8) & 0x00FF0000) |
777 ((source[x + 1] >> 8) & 0x0000FF00) |
778 (source[x + 1] << 24);
779 }
780 }
781 break;
782 }
783}
784
daniel@transgaming.com61208202011-03-21 16:38:50 +0000785void Texture::createSurface(Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000786{
787 IDirect3DTexture9 *newTexture = NULL;
788 IDirect3DSurface9 *newSurface = NULL;
789
daniel@transgaming.com61208202011-03-21 16:38:50 +0000790 if (image->width != 0 && image->height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000791 {
792 int levelToFetch = 0;
daniel@transgaming.com61208202011-03-21 16:38:50 +0000793 GLsizei requestWidth = image->width;
794 GLsizei requestHeight = image->height;
795 if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000796 {
797 bool isMult4 = false;
798 int upsampleCount = 0;
799 while (!isMult4)
800 {
801 requestWidth <<= 1;
802 requestHeight <<= 1;
803 upsampleCount++;
804 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
805 {
806 isMult4 = true;
807 }
808 }
809 levelToFetch = upsampleCount;
810 }
811
daniel@transgaming.com61208202011-03-21 16:38:50 +0000812 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(image->format, image->type),
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000813 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
814
815 if (FAILED(result))
816 {
817 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
818 return error(GL_OUT_OF_MEMORY);
819 }
820
821 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
822 newTexture->Release();
823 }
824
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000825 if (image->surface)
826 {
827 image->surface->Release();
828 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000829
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000830 image->surface = newSurface;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000831}
832
daniel@transgaming.com61208202011-03-21 16:38:50 +0000833void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000834{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000835 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000836
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000837 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000838 {
839 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000840 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000841
842 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000843 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000844
845 ASSERT(SUCCEEDED(result));
846
847 if (SUCCEEDED(result))
848 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000849 loadImageData(0, 0, image->width, image->height, image->format, image->type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000850 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000851 }
852
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000853 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000854 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000855}
856
daniel@transgaming.com61208202011-03-21 16:38:50 +0000857void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000858{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000859 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000860
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000861 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000862 {
863 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000864 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000865
866 ASSERT(SUCCEEDED(result));
867
868 if (SUCCEEDED(result))
869 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000870 int inputPitch = ComputeCompressedPitch(image->width, image->format);
871 int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
872 loadCompressedImageData(0, 0, image->width, image->height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000873 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000874 }
875
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000876 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000877 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000878}
879
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000880bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000881{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000882 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000883 {
884 error(GL_INVALID_VALUE);
885 return false;
886 }
887
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000888 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000889 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000890 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000891 }
892
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000893 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000894 {
895 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000896 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000897
898 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000899 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000900
901 ASSERT(SUCCEEDED(result));
902
903 if (SUCCEEDED(result))
904 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000905 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
906 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000907 }
908
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000909 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000910 }
911
912 return true;
913}
914
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000915bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000916{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000917 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000918 {
919 error(GL_INVALID_VALUE);
920 return false;
921 }
922
923 if (format != getInternalFormat())
924 {
925 error(GL_INVALID_OPERATION);
926 return false;
927 }
928
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000929 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000930 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000931 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000932 }
933
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000934 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000935 {
936 RECT updateRegion;
937 updateRegion.left = xoffset;
938 updateRegion.right = xoffset + width;
939 updateRegion.bottom = yoffset + height;
940 updateRegion.top = yoffset;
941
942 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000943 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000944
945 ASSERT(SUCCEEDED(result));
946
947 if (SUCCEEDED(result))
948 {
949 int inputPitch = ComputeCompressedPitch(width, format);
950 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000951 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
952 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000953 }
954
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000955 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000956 }
957
958 return true;
959}
960
961// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +0000962void 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 +0000963{
964 IDirect3DDevice9 *device = getDevice();
965 IDirect3DSurface9 *surface = NULL;
966 D3DSURFACE_DESC description;
967 renderTarget->GetDesc(&description);
968
969 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
970
971 if (!SUCCEEDED(result))
972 {
973 ERR("Could not create matching destination surface.");
974 return error(GL_OUT_OF_MEMORY);
975 }
976
977 result = device->GetRenderTargetData(renderTarget, surface);
978
979 if (!SUCCEEDED(result))
980 {
981 ERR("GetRenderTargetData unexpectedly failed.");
982 surface->Release();
983 return error(GL_OUT_OF_MEMORY);
984 }
985
986 D3DLOCKED_RECT sourceLock = {0};
987 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
988 result = surface->LockRect(&sourceLock, &sourceRect, 0);
989
990 if (FAILED(result))
991 {
992 ERR("Failed to lock the source surface (rectangle might be invalid).");
993 surface->UnlockRect();
994 surface->Release();
995 return error(GL_OUT_OF_MEMORY);
996 }
997
998 if (!image->surface)
999 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001000 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001001 }
1002
1003 if (image->surface == NULL)
1004 {
1005 ERR("Failed to create an image surface.");
1006 surface->UnlockRect();
1007 surface->Release();
1008 return error(GL_OUT_OF_MEMORY);
1009 }
1010
1011 D3DLOCKED_RECT destLock = {0};
1012 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1013 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1014 result = image->surface->LockRect(&destLock, &destRect, 0);
1015
1016 if (FAILED(result))
1017 {
1018 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1019 surface->UnlockRect();
1020 surface->Release();
1021 return error(GL_OUT_OF_MEMORY);
1022 }
1023
1024 if (destLock.pBits && sourceLock.pBits)
1025 {
1026 unsigned char *source = (unsigned char*)sourceLock.pBits;
1027 unsigned char *dest = (unsigned char*)destLock.pBits;
1028
1029 switch (description.Format)
1030 {
1031 case D3DFMT_X8R8G8B8:
1032 case D3DFMT_A8R8G8B8:
1033 switch(getD3DFormat())
1034 {
1035 case D3DFMT_L8:
1036 for(int y = 0; y < height; y++)
1037 {
1038 for(int x = 0; x < width; x++)
1039 {
1040 dest[x] = source[x * 4 + 2];
1041 }
1042
1043 source += sourceLock.Pitch;
1044 dest += destLock.Pitch;
1045 }
1046 break;
1047 case D3DFMT_A8L8:
1048 for(int y = 0; y < height; y++)
1049 {
1050 for(int x = 0; x < width; x++)
1051 {
1052 dest[x * 2 + 0] = source[x * 4 + 2];
1053 dest[x * 2 + 1] = source[x * 4 + 3];
1054 }
1055
1056 source += sourceLock.Pitch;
1057 dest += destLock.Pitch;
1058 }
1059 break;
1060 default:
1061 UNREACHABLE();
1062 }
1063 break;
1064 case D3DFMT_R5G6B5:
1065 switch(getD3DFormat())
1066 {
1067 case D3DFMT_L8:
1068 for(int y = 0; y < height; y++)
1069 {
1070 for(int x = 0; x < width; x++)
1071 {
1072 unsigned char red = source[x * 2 + 1] & 0xF8;
1073 dest[x] = red | (red >> 5);
1074 }
1075
1076 source += sourceLock.Pitch;
1077 dest += destLock.Pitch;
1078 }
1079 break;
1080 default:
1081 UNREACHABLE();
1082 }
1083 break;
1084 case D3DFMT_A1R5G5B5:
1085 switch(getD3DFormat())
1086 {
1087 case D3DFMT_L8:
1088 for(int y = 0; y < height; y++)
1089 {
1090 for(int x = 0; x < width; x++)
1091 {
1092 unsigned char red = source[x * 2 + 1] & 0x7C;
1093 dest[x] = (red << 1) | (red >> 4);
1094 }
1095
1096 source += sourceLock.Pitch;
1097 dest += destLock.Pitch;
1098 }
1099 break;
1100 case D3DFMT_A8L8:
1101 for(int y = 0; y < height; y++)
1102 {
1103 for(int x = 0; x < width; x++)
1104 {
1105 unsigned char red = source[x * 2 + 1] & 0x7C;
1106 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1107 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1108 }
1109
1110 source += sourceLock.Pitch;
1111 dest += destLock.Pitch;
1112 }
1113 break;
1114 default:
1115 UNREACHABLE();
1116 }
1117 break;
1118 default:
1119 UNREACHABLE();
1120 }
1121
1122 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001123 }
1124
1125 image->surface->UnlockRect();
1126 surface->UnlockRect();
1127 surface->Release();
1128}
1129
1130D3DFORMAT Texture::getD3DFormat() const
1131{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001132 return selectFormat(getInternalFormat(), getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001133}
1134
1135IDirect3DBaseTexture9 *Texture::getTexture()
1136{
1137 if (!isComplete())
1138 {
1139 return NULL;
1140 }
1141
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001142 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001143 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001144 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001145 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001146
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001147 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001148
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001149 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001150}
1151
1152bool Texture::isDirty() const
1153{
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001154 return true;//(mDirty || mDirtyMetaData || dirtyImageData());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001155}
1156
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001157GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1158{
1159 if (isPow2(width) && isPow2(height))
1160 {
1161 return maxlevel;
1162 }
1163 else
1164 {
1165 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1166 return 1;
1167 }
1168}
1169
1170GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1171{
1172 return creationLevels(size, size, maxlevel);
1173}
1174
1175int Texture::levelCount() const
1176{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001177 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001178}
1179
1180Texture2D::Texture2D(GLuint id) : Texture(id)
1181{
1182 mTexture = NULL;
1183}
1184
1185Texture2D::~Texture2D()
1186{
1187 mColorbufferProxy.set(NULL);
1188
1189 if (mTexture)
1190 {
1191 mTexture->Release();
1192 mTexture = NULL;
1193 }
1194}
1195
1196GLenum Texture2D::getTarget() const
1197{
1198 return GL_TEXTURE_2D;
1199}
1200
daniel@transgaming.com61208202011-03-21 16:38:50 +00001201GLsizei Texture2D::getWidth() const
1202{
1203 return mImageArray[0].width;
1204}
1205
1206GLsizei Texture2D::getHeight() const
1207{
1208 return mImageArray[0].height;
1209}
1210
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001211GLenum Texture2D::getInternalFormat() const
1212{
1213 return mImageArray[0].format;
1214}
1215
daniel@transgaming.com61208202011-03-21 16:38:50 +00001216GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001217{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001218 return mImageArray[0].type;
1219}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001220
daniel@transgaming.com61208202011-03-21 16:38:50 +00001221void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1222{
1223 mImageArray[level].width = width;
1224 mImageArray[level].height = height;
1225 mImageArray[level].format = format;
1226 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001227
daniel@transgaming.com61208202011-03-21 16:38:50 +00001228 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001229 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001230 return;
1231 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001232
daniel@transgaming.com61208202011-03-21 16:38:50 +00001233 D3DSURFACE_DESC texture;
1234 mTexture->GetLevelDesc(0, &texture);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001235
daniel@transgaming.com61208202011-03-21 16:38:50 +00001236 bool widthOkay = (texture.Width >> level == width) || (texture.Width >> level == 0 && width == 1);
1237 bool heightOkay = (texture.Height >> level == height) || (texture.Height >> level == 0 && height == 1);
1238 bool textureOkay = (widthOkay && heightOkay && texture.Format == selectFormat(format, type));
1239
1240 if (!textureOkay) // Purge all the levels and the texture.
1241 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001242 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1243 {
1244 if (mImageArray[i].surface != NULL)
1245 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001246 mImageArray[i].surface->Release();
1247 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001248 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001249 }
1250 }
1251
1252 if (mTexture != NULL)
1253 {
1254 mTexture->Release();
1255 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001256 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001257 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001258 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001259}
1260
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001261void 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 +00001262{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001263 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001264
daniel@transgaming.com61208202011-03-21 16:38:50 +00001265 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001266}
1267
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001268void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001269{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001270 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001271
daniel@transgaming.com61208202011-03-21 16:38:50 +00001272 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001273}
1274
1275void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1276{
1277 ASSERT(mImageArray[level].surface != NULL);
1278
1279 if (level < levelCount())
1280 {
1281 IDirect3DSurface9 *destLevel = NULL;
1282 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1283
1284 ASSERT(SUCCEEDED(result));
1285
1286 if (SUCCEEDED(result))
1287 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001288 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001289
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001290 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001291
1292 POINT destPoint;
1293 destPoint.x = sourceRect.left;
1294 destPoint.y = sourceRect.top;
1295
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001296 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001297 ASSERT(SUCCEEDED(result));
1298
1299 destLevel->Release();
1300
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001301 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001302 }
1303 }
1304}
1305
1306void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1307{
1308 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1309 {
1310 commitRect(level, xoffset, yoffset, width, height);
1311 }
1312}
1313
1314void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1315{
1316 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1317 {
1318 commitRect(level, xoffset, yoffset, width, height);
1319 }
1320}
1321
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001322void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001323{
1324 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1325
1326 if (!renderTarget)
1327 {
1328 ERR("Failed to retrieve the render target.");
1329 return error(GL_OUT_OF_MEMORY);
1330 }
1331
daniel@transgaming.com61208202011-03-21 16:38:50 +00001332 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001333
1334 if (!isRenderableFormat())
1335 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001336 copyNonRenderable(&mImageArray[level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001337 }
1338 else
1339 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001340 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001341 {
1342 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001343 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001344
1345 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001346
1347 if (width != 0 && height != 0 && level < levelCount())
1348 {
1349 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1350 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1351 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1352 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1353 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1354
1355 IDirect3DSurface9 *dest;
1356 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1357
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001358 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001359 dest->Release();
1360 }
1361 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001362}
1363
1364void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1365{
1366 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1367 {
1368 return error(GL_INVALID_VALUE);
1369 }
1370
1371 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1372
1373 if (!renderTarget)
1374 {
1375 ERR("Failed to retrieve the render target.");
1376 return error(GL_OUT_OF_MEMORY);
1377 }
1378
daniel@transgaming.com61208202011-03-21 16:38:50 +00001379 redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001380
1381 if (!isRenderableFormat())
1382 {
1383 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1384 }
1385 else
1386 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001387 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001388 {
1389 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001390 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001391
1392 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001393
1394 if (level < levelCount())
1395 {
1396 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1397 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1398 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1399 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1400 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1401
1402 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1403
1404 IDirect3DSurface9 *dest;
1405 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1406
1407 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1408 dest->Release();
1409 }
1410 }
1411}
1412
1413// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1414bool Texture2D::isComplete() const
1415{
1416 GLsizei width = mImageArray[0].width;
1417 GLsizei height = mImageArray[0].height;
1418
1419 if (width <= 0 || height <= 0)
1420 {
1421 return false;
1422 }
1423
1424 bool mipmapping = false;
1425
1426 switch (mMinFilter)
1427 {
1428 case GL_NEAREST:
1429 case GL_LINEAR:
1430 mipmapping = false;
1431 break;
1432 case GL_NEAREST_MIPMAP_NEAREST:
1433 case GL_LINEAR_MIPMAP_NEAREST:
1434 case GL_NEAREST_MIPMAP_LINEAR:
1435 case GL_LINEAR_MIPMAP_LINEAR:
1436 mipmapping = true;
1437 break;
1438 default: UNREACHABLE();
1439 }
1440
1441 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1442 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1443 {
1444 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1445 {
1446 return false;
1447 }
1448 }
1449
1450
1451 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1452 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1453 {
1454 return false;
1455 }
1456
1457 if (mipmapping)
1458 {
1459 if (!isPow2(width) || !isPow2(height))
1460 {
1461 return false;
1462 }
1463
1464 int q = log2(std::max(width, height));
1465
1466 for (int level = 1; level <= q; level++)
1467 {
1468 if (mImageArray[level].format != mImageArray[0].format)
1469 {
1470 return false;
1471 }
1472
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001473 if (mImageArray[level].type != mImageArray[0].type)
1474 {
1475 return false;
1476 }
1477
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001478 if (mImageArray[level].width != std::max(1, width >> level))
1479 {
1480 return false;
1481 }
1482
1483 if (mImageArray[level].height != std::max(1, height >> level))
1484 {
1485 return false;
1486 }
1487 }
1488 }
1489
1490 return true;
1491}
1492
1493bool Texture2D::isCompressed() const
1494{
1495 return IsCompressed(getInternalFormat());
1496}
1497
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001498IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1499{
1500 return mTexture;
1501}
1502
1503// Constructs a Direct3D 9 texture resource from the texture images
1504void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001505{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001506 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001507 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1508 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001509
daniel@transgaming.com61208202011-03-21 16:38:50 +00001510 IDirect3DTexture9 *texture = NULL;
1511 HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001512
1513 if (FAILED(result))
1514 {
1515 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001516 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001517 }
1518
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001519 if (mTexture)
1520 {
1521 mTexture->Release();
1522 }
1523
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001524 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001525 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001526}
1527
1528void Texture2D::updateTexture()
1529{
1530 IDirect3DDevice9 *device = getDevice();
1531
1532 int levels = levelCount();
1533
1534 for (int level = 0; level < levels; level++)
1535 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001536 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001537 {
1538 IDirect3DSurface9 *levelSurface = NULL;
1539 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1540
1541 ASSERT(SUCCEEDED(result));
1542
1543 if (SUCCEEDED(result))
1544 {
1545 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1546 ASSERT(SUCCEEDED(result));
1547
1548 levelSurface->Release();
1549
1550 mImageArray[level].dirty = false;
1551 }
1552 }
1553 }
1554}
1555
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001556void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001557{
1558 IDirect3DTexture9 *texture = NULL;
1559
daniel@transgaming.com61208202011-03-21 16:38:50 +00001560 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001561 {
1562 egl::Display *display = getDisplay();
1563 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001564 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1565 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001566
daniel@transgaming.com61208202011-03-21 16:38:50 +00001567 HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001568
1569 if (FAILED(result))
1570 {
1571 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001572 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001573 }
1574
1575 if (mTexture != NULL)
1576 {
1577 int levels = levelCount();
1578 for (int i = 0; i < levels; i++)
1579 {
1580 IDirect3DSurface9 *source;
1581 result = mTexture->GetSurfaceLevel(i, &source);
1582
1583 if (FAILED(result))
1584 {
1585 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1586
1587 texture->Release();
1588
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001589 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001590 }
1591
1592 IDirect3DSurface9 *dest;
1593 result = texture->GetSurfaceLevel(i, &dest);
1594
1595 if (FAILED(result))
1596 {
1597 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1598
1599 texture->Release();
1600 source->Release();
1601
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001602 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001603 }
1604
1605 display->endScene();
1606 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1607
1608 if (FAILED(result))
1609 {
1610 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1611
1612 texture->Release();
1613 source->Release();
1614 dest->Release();
1615
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 source->Release();
1620 dest->Release();
1621 }
1622 }
1623 }
1624
1625 if (mTexture != NULL)
1626 {
1627 mTexture->Release();
1628 }
1629
1630 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001631 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001632}
1633
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001634void Texture2D::generateMipmaps()
1635{
1636 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1637 {
1638 return error(GL_INVALID_OPERATION);
1639 }
1640
1641 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001642 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001643 for (unsigned int i = 1; i <= q; i++)
1644 {
1645 if (mImageArray[i].surface != NULL)
1646 {
1647 mImageArray[i].surface->Release();
1648 mImageArray[i].surface = NULL;
1649 }
1650
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001651 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1652 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001653 mImageArray[i].format = mImageArray[0].format;
1654 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001655 }
1656
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001657 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001658 {
1659 if (mTexture == NULL)
1660 {
1661 ERR(" failed because mTexture was null.");
1662 return;
1663 }
1664
1665 for (unsigned int i = 1; i <= q; i++)
1666 {
1667 IDirect3DSurface9 *upper = NULL;
1668 IDirect3DSurface9 *lower = NULL;
1669
1670 mTexture->GetSurfaceLevel(i-1, &upper);
1671 mTexture->GetSurfaceLevel(i, &lower);
1672
1673 if (upper != NULL && lower != NULL)
1674 {
1675 getBlitter()->boxFilter(upper, lower);
1676 }
1677
1678 if (upper != NULL) upper->Release();
1679 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001680
1681 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001682 }
1683 }
1684 else
1685 {
1686 for (unsigned int i = 1; i <= q; i++)
1687 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001688 createSurface(&mImageArray[i]);
1689
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001690 if (mImageArray[i].surface == NULL)
1691 {
1692 return error(GL_OUT_OF_MEMORY);
1693 }
1694
1695 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1696 {
1697 ERR(" failed to load filter %d to %d.", i - 1, i);
1698 }
1699
1700 mImageArray[i].dirty = true;
1701 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001702 }
1703}
1704
1705Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1706{
1707 if (target != GL_TEXTURE_2D)
1708 {
1709 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1710 }
1711
1712 if (mColorbufferProxy.get() == NULL)
1713 {
1714 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1715 }
1716
1717 return mColorbufferProxy.get();
1718}
1719
1720IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1721{
1722 ASSERT(target == GL_TEXTURE_2D);
1723
daniel@transgaming.com61208202011-03-21 16:38:50 +00001724 if (!mIsRenderable)
1725 {
1726 convertToRenderTarget();
1727 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001728
1729 if (mTexture == NULL)
1730 {
1731 return NULL;
1732 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001733
1734 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001735
1736 IDirect3DSurface9 *renderTarget = NULL;
1737 mTexture->GetSurfaceLevel(0, &renderTarget);
1738
1739 return renderTarget;
1740}
1741
1742TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1743{
1744 mTexture = NULL;
1745}
1746
1747TextureCubeMap::~TextureCubeMap()
1748{
1749 for (int i = 0; i < 6; i++)
1750 {
1751 mFaceProxies[i].set(NULL);
1752 }
1753
1754 if (mTexture)
1755 {
1756 mTexture->Release();
1757 mTexture = NULL;
1758 }
1759}
1760
1761GLenum TextureCubeMap::getTarget() const
1762{
1763 return GL_TEXTURE_CUBE_MAP;
1764}
1765
daniel@transgaming.com61208202011-03-21 16:38:50 +00001766GLsizei TextureCubeMap::getWidth() const
1767{
1768 return mImageArray[0][0].width;
1769}
1770
1771GLsizei TextureCubeMap::getHeight() const
1772{
1773 return mImageArray[0][0].height;
1774}
1775
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001776GLenum TextureCubeMap::getInternalFormat() const
1777{
1778 return mImageArray[0][0].format;
1779}
1780
daniel@transgaming.com61208202011-03-21 16:38:50 +00001781GLenum TextureCubeMap::getType() const
1782{
1783 return mImageArray[0][0].type;
1784}
1785
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001786void 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 +00001787{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001788 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001789}
1790
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001791void 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 +00001792{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001793 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001794}
1795
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001796void 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 +00001797{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001798 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001799}
1800
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001801void 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 +00001802{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001803 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001804}
1805
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001806void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001807{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001808 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001809}
1810
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001811void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001812{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001813 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001814}
1815
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001816void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001817{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001818 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001819
daniel@transgaming.com61208202011-03-21 16:38:50 +00001820 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001821}
1822
1823void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1824{
1825 int face = faceIndex(faceTarget);
1826 ASSERT(mImageArray[face][level].surface != NULL);
1827
1828 if (level < levelCount())
1829 {
1830 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1831 ASSERT(destLevel != NULL);
1832
1833 if (destLevel != NULL)
1834 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001835 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001836
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001837 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001838
1839 POINT destPoint;
1840 destPoint.x = sourceRect.left;
1841 destPoint.y = sourceRect.top;
1842
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001843 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001844 ASSERT(SUCCEEDED(result));
1845
1846 destLevel->Release();
1847
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001848 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001849 }
1850 }
1851}
1852
1853void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1854{
1855 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1856 {
1857 commitRect(target, level, xoffset, yoffset, width, height);
1858 }
1859}
1860
1861void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1862{
1863 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1864 {
1865 commitRect(target, level, xoffset, yoffset, width, height);
1866 }
1867}
1868
1869// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1870bool TextureCubeMap::isComplete() const
1871{
1872 int size = mImageArray[0][0].width;
1873
1874 if (size <= 0)
1875 {
1876 return false;
1877 }
1878
1879 bool mipmapping;
1880
1881 switch (mMinFilter)
1882 {
1883 case GL_NEAREST:
1884 case GL_LINEAR:
1885 mipmapping = false;
1886 break;
1887 case GL_NEAREST_MIPMAP_NEAREST:
1888 case GL_LINEAR_MIPMAP_NEAREST:
1889 case GL_NEAREST_MIPMAP_LINEAR:
1890 case GL_LINEAR_MIPMAP_LINEAR:
1891 mipmapping = true;
1892 break;
1893 default: UNREACHABLE();
1894 }
1895
1896 for (int face = 0; face < 6; face++)
1897 {
1898 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1899 {
1900 return false;
1901 }
1902 }
1903
1904 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1905 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1906 {
1907 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1908 {
1909 return false;
1910 }
1911 }
1912
1913 if (mipmapping)
1914 {
1915 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1916 {
1917 return false;
1918 }
1919
1920 int q = log2(size);
1921
1922 for (int face = 0; face < 6; face++)
1923 {
1924 for (int level = 1; level <= q; level++)
1925 {
1926 if (mImageArray[face][level].format != mImageArray[0][0].format)
1927 {
1928 return false;
1929 }
1930
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001931 if (mImageArray[face][level].type != mImageArray[0][0].type)
1932 {
1933 return false;
1934 }
1935
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001936 if (mImageArray[face][level].width != std::max(1, size >> level))
1937 {
1938 return false;
1939 }
1940
1941 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1942 }
1943 }
1944 }
1945
1946 return true;
1947}
1948
1949bool TextureCubeMap::isCompressed() const
1950{
1951 return IsCompressed(getInternalFormat());
1952}
1953
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001954IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1955{
1956 return mTexture;
1957}
1958
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001959// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001960void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001961{
1962 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001963 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
1964 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001965
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001966 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001967 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001968
1969 if (FAILED(result))
1970 {
1971 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001972 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001973 }
1974
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001975 if (mTexture)
1976 {
1977 mTexture->Release();
1978 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001979
1980 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001981 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001982}
1983
1984void TextureCubeMap::updateTexture()
1985{
1986 IDirect3DDevice9 *device = getDevice();
1987
1988 for (int face = 0; face < 6; face++)
1989 {
1990 int levels = levelCount();
1991 for (int level = 0; level < levels; level++)
1992 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001993 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001994
daniel@transgaming.com61208202011-03-21 16:38:50 +00001995 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001996 {
1997 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
1998 ASSERT(levelSurface != NULL);
1999
2000 if (levelSurface != NULL)
2001 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002002 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002003 ASSERT(SUCCEEDED(result));
2004
2005 levelSurface->Release();
2006
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002007 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002008 }
2009 }
2010 }
2011 }
2012}
2013
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002014void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002015{
2016 IDirect3DCubeTexture9 *texture = NULL;
2017
daniel@transgaming.com61208202011-03-21 16:38:50 +00002018 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002019 {
2020 egl::Display *display = getDisplay();
2021 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002022 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
2023 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002024
daniel@transgaming.com61208202011-03-21 16:38:50 +00002025 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002026
2027 if (FAILED(result))
2028 {
2029 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002030 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002031 }
2032
2033 if (mTexture != NULL)
2034 {
2035 int levels = levelCount();
2036 for (int f = 0; f < 6; f++)
2037 {
2038 for (int i = 0; i < levels; i++)
2039 {
2040 IDirect3DSurface9 *source;
2041 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2042
2043 if (FAILED(result))
2044 {
2045 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2046
2047 texture->Release();
2048
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002049 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002050 }
2051
2052 IDirect3DSurface9 *dest;
2053 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2054
2055 if (FAILED(result))
2056 {
2057 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2058
2059 texture->Release();
2060 source->Release();
2061
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002062 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002063 }
2064
2065 display->endScene();
2066 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2067
2068 if (FAILED(result))
2069 {
2070 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2071
2072 texture->Release();
2073 source->Release();
2074 dest->Release();
2075
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002076 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002077 }
2078 }
2079 }
2080 }
2081 }
2082
2083 if (mTexture != NULL)
2084 {
2085 mTexture->Release();
2086 }
2087
2088 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002089 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002090}
2091
daniel@transgaming.com61208202011-03-21 16:38:50 +00002092void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002093{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002094 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002095
daniel@transgaming.com61208202011-03-21 16:38:50 +00002096 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002097}
2098
2099unsigned int TextureCubeMap::faceIndex(GLenum face)
2100{
2101 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2102 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2103 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2104 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2105 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2106
2107 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2108}
2109
daniel@transgaming.com61208202011-03-21 16:38:50 +00002110void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002111{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002112 mImageArray[face][level].width = width;
2113 mImageArray[face][level].height = height;
2114 mImageArray[face][level].format = format;
2115 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002116
daniel@transgaming.com61208202011-03-21 16:38:50 +00002117 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002118 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002119 return;
2120 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002121
daniel@transgaming.com61208202011-03-21 16:38:50 +00002122 D3DSURFACE_DESC texture;
2123 mTexture->GetLevelDesc(0, &texture);
2124
2125 bool sizeOkay = (texture.Width >> level == width);
2126 bool textureOkay = (sizeOkay && texture.Format == selectFormat(format, type));
2127
2128 if (!textureOkay) // Purge all the levels and the texture.
2129 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002130 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2131 {
2132 for (int f = 0; f < 6; f++)
2133 {
2134 if (mImageArray[f][i].surface != NULL)
2135 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002136 mImageArray[f][i].surface->Release();
2137 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002138 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002139 }
2140 }
2141 }
2142
2143 if (mTexture != NULL)
2144 {
2145 mTexture->Release();
2146 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002147 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002148 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002149 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002150}
2151
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002152void 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 +00002153{
2154 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2155
2156 if (!renderTarget)
2157 {
2158 ERR("Failed to retrieve the render target.");
2159 return error(GL_OUT_OF_MEMORY);
2160 }
2161
2162 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002163 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002164
2165 if (!isRenderableFormat())
2166 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002167 copyNonRenderable(&mImageArray[faceindex][level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002168 }
2169 else
2170 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002171 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002172 {
2173 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002174 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002175
2176 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002177
2178 ASSERT(width == height);
2179
2180 if (width > 0 && level < levelCount())
2181 {
2182 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2183 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2184 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2185 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2186 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2187
2188 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2189
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002190 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002191 dest->Release();
2192 }
2193 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002194}
2195
2196IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2197{
2198 if (mTexture == NULL)
2199 {
2200 UNREACHABLE();
2201 return NULL;
2202 }
2203
2204 IDirect3DSurface9 *surface = NULL;
2205
2206 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2207
2208 return (SUCCEEDED(hr)) ? surface : NULL;
2209}
2210
2211void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2212{
2213 GLsizei size = mImageArray[faceIndex(target)][level].width;
2214
2215 if (xoffset + width > size || yoffset + height > size)
2216 {
2217 return error(GL_INVALID_VALUE);
2218 }
2219
2220 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2221
2222 if (!renderTarget)
2223 {
2224 ERR("Failed to retrieve the render target.");
2225 return error(GL_OUT_OF_MEMORY);
2226 }
2227
2228 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002229 redefineTexture(0, 0, mImageArray[0][0].format, mImageArray[0][0].width, mImageArray[0][0].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002230
2231 if (!isRenderableFormat())
2232 {
2233 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2234 }
2235 else
2236 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002237 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002238 {
2239 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002240 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002241
2242 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002243
2244 if (level < levelCount())
2245 {
2246 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2247 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2248 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2249 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2250 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2251
2252 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2253
2254 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2255
2256 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2257 dest->Release();
2258 }
2259 }
2260}
2261
2262bool TextureCubeMap::isCubeComplete() const
2263{
2264 if (mImageArray[0][0].width == 0)
2265 {
2266 return false;
2267 }
2268
2269 for (unsigned int f = 1; f < 6; f++)
2270 {
2271 if (mImageArray[f][0].width != mImageArray[0][0].width
2272 || mImageArray[f][0].format != mImageArray[0][0].format)
2273 {
2274 return false;
2275 }
2276 }
2277
2278 return true;
2279}
2280
2281void TextureCubeMap::generateMipmaps()
2282{
2283 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2284 {
2285 return error(GL_INVALID_OPERATION);
2286 }
2287
2288 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2289 unsigned int q = log2(mImageArray[0][0].width);
2290 for (unsigned int f = 0; f < 6; f++)
2291 {
2292 for (unsigned int i = 1; i <= q; i++)
2293 {
2294 if (mImageArray[f][i].surface != NULL)
2295 {
2296 mImageArray[f][i].surface->Release();
2297 mImageArray[f][i].surface = NULL;
2298 }
2299
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002300 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2301 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002302 mImageArray[f][i].format = mImageArray[f][0].format;
2303 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002304 }
2305 }
2306
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002307 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002308 {
2309 if (mTexture == NULL)
2310 {
2311 return;
2312 }
2313
2314 for (unsigned int f = 0; f < 6; f++)
2315 {
2316 for (unsigned int i = 1; i <= q; i++)
2317 {
2318 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2319 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2320
2321 if (upper != NULL && lower != NULL)
2322 {
2323 getBlitter()->boxFilter(upper, lower);
2324 }
2325
2326 if (upper != NULL) upper->Release();
2327 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002328
2329 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002330 }
2331 }
2332 }
2333 else
2334 {
2335 for (unsigned int f = 0; f < 6; f++)
2336 {
2337 for (unsigned int i = 1; i <= q; i++)
2338 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002339 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002340 if (mImageArray[f][i].surface == NULL)
2341 {
2342 return error(GL_OUT_OF_MEMORY);
2343 }
2344
2345 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2346 {
2347 ERR(" failed to load filter %d to %d.", i - 1, i);
2348 }
2349
2350 mImageArray[f][i].dirty = true;
2351 }
2352 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002353 }
2354}
2355
2356Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2357{
2358 if (!IsCubemapTextureTarget(target))
2359 {
2360 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2361 }
2362
2363 unsigned int face = faceIndex(target);
2364
2365 if (mFaceProxies[face].get() == NULL)
2366 {
2367 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2368 }
2369
2370 return mFaceProxies[face].get();
2371}
2372
2373IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2374{
2375 ASSERT(IsCubemapTextureTarget(target));
2376
daniel@transgaming.com61208202011-03-21 16:38:50 +00002377 if (!mIsRenderable)
2378 {
2379 convertToRenderTarget();
2380 }
2381
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002382 if (mTexture == NULL)
2383 {
2384 return NULL;
2385 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002386
2387 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002388
2389 IDirect3DSurface9 *renderTarget = NULL;
2390 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2391
2392 return renderTarget;
2393}
2394
2395}