blob: d8d6cc1255abcf81760a528e978694fe9f9bde10 [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::isRenderableFormat() const
169{
170 D3DFORMAT format = getD3DFormat();
171
172 switch(format)
173 {
174 case D3DFMT_L8:
175 case D3DFMT_A8L8:
176 case D3DFMT_DXT1:
177 return false;
178 case D3DFMT_A8R8G8B8:
179 case D3DFMT_X8R8G8B8:
180 case D3DFMT_A16B16G16R16F:
181 case D3DFMT_A32B32G32R32F:
182 return true;
183 default:
184 UNREACHABLE();
185 }
186
187 return false;
188}
189
190// Selects an internal Direct3D 9 format for storing an Image
191D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
192{
193 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
194 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
195 {
196 return D3DFMT_DXT1;
197 }
198 else if (type == GL_FLOAT)
199 {
200 return D3DFMT_A32B32G32R32F;
201 }
202 else if (type == GL_HALF_FLOAT_OES)
203 {
204 return D3DFMT_A16B16G16R16F;
205 }
206 else if (type == GL_UNSIGNED_BYTE)
207 {
208 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
209 {
210 return D3DFMT_L8;
211 }
212 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
213 {
214 return D3DFMT_A8L8;
215 }
216 else if (format == GL_RGB)
217 {
218 return D3DFMT_X8R8G8B8;
219 }
220
221 return D3DFMT_A8R8G8B8;
222 }
223
224 return D3DFMT_A8R8G8B8;
225}
226
227// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
228// into the target pixel rectangle at output with outputPitch bytes in between each line.
229void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
230 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
231{
232 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
233 input = ((char*)input) - inputPitch * (height - 1);
234
235 switch (type)
236 {
237 case GL_UNSIGNED_BYTE:
238 switch (format)
239 {
240 case GL_ALPHA:
241 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
242 break;
243 case GL_LUMINANCE:
244 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
245 break;
246 case GL_LUMINANCE_ALPHA:
247 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
248 break;
249 case GL_RGB:
250 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
251 break;
252 case GL_RGBA:
253 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
254 break;
255 case GL_BGRA_EXT:
256 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
257 break;
258 default: UNREACHABLE();
259 }
260 break;
261 case GL_UNSIGNED_SHORT_5_6_5:
262 switch (format)
263 {
264 case GL_RGB:
265 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
266 break;
267 default: UNREACHABLE();
268 }
269 break;
270 case GL_UNSIGNED_SHORT_4_4_4_4:
271 switch (format)
272 {
273 case GL_RGBA:
274 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
275 break;
276 default: UNREACHABLE();
277 }
278 break;
279 case GL_UNSIGNED_SHORT_5_5_5_1:
280 switch (format)
281 {
282 case GL_RGBA:
283 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
284 break;
285 default: UNREACHABLE();
286 }
287 break;
288 case GL_FLOAT:
289 switch (format)
290 {
291 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
292 case GL_ALPHA:
293 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
294 break;
295 case GL_LUMINANCE:
296 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
297 break;
298 case GL_LUMINANCE_ALPHA:
299 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
300 break;
301 case GL_RGB:
302 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
303 break;
304 case GL_RGBA:
305 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
306 break;
307 default: UNREACHABLE();
308 }
309 break;
310 case GL_HALF_FLOAT_OES:
311 switch (format)
312 {
313 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
314 case GL_ALPHA:
315 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
316 break;
317 case GL_LUMINANCE:
318 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
319 break;
320 case GL_LUMINANCE_ALPHA:
321 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
322 break;
323 case GL_RGB:
324 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
325 break;
326 case GL_RGBA:
327 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
328 break;
329 default: UNREACHABLE();
330 }
331 break;
332 default: UNREACHABLE();
333 }
334}
335
336void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
337 int inputPitch, const void *input, size_t outputPitch, void *output) const
338{
339 const unsigned char *source = NULL;
340 unsigned char *dest = NULL;
341
342 for (int y = 0; y < height; y++)
343 {
344 source = static_cast<const unsigned char*>(input) + y * inputPitch;
345 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
346 for (int x = 0; x < width; x++)
347 {
348 dest[4 * x + 0] = 0;
349 dest[4 * x + 1] = 0;
350 dest[4 * x + 2] = 0;
351 dest[4 * x + 3] = source[x];
352 }
353 }
354}
355
356void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
357 int inputPitch, const void *input, size_t outputPitch, void *output) const
358{
359 const float *source = NULL;
360 float *dest = NULL;
361
362 for (int y = 0; y < height; y++)
363 {
364 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
365 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
366 for (int x = 0; x < width; x++)
367 {
368 dest[4 * x + 0] = 0;
369 dest[4 * x + 1] = 0;
370 dest[4 * x + 2] = 0;
371 dest[4 * x + 3] = source[x];
372 }
373 }
374}
375
376void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
377 int inputPitch, const void *input, size_t outputPitch, void *output) const
378{
379 const unsigned short *source = NULL;
380 unsigned short *dest = NULL;
381
382 for (int y = 0; y < height; y++)
383 {
384 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
385 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
386 for (int x = 0; x < width; x++)
387 {
388 dest[4 * x + 0] = 0;
389 dest[4 * x + 1] = 0;
390 dest[4 * x + 2] = 0;
391 dest[4 * x + 3] = source[x];
392 }
393 }
394}
395
396void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
397 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
398{
399 const int destBytesPerPixel = native? 1: 4;
400 const unsigned char *source = NULL;
401 unsigned char *dest = NULL;
402
403 for (int y = 0; y < height; y++)
404 {
405 source = static_cast<const unsigned char*>(input) + y * inputPitch;
406 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
407
408 if (!native) // BGRA8 destination format
409 {
410 for (int x = 0; x < width; x++)
411 {
412 dest[4 * x + 0] = source[x];
413 dest[4 * x + 1] = source[x];
414 dest[4 * x + 2] = source[x];
415 dest[4 * x + 3] = 0xFF;
416 }
417 }
418 else // L8 destination format
419 {
420 memcpy(dest, source, width);
421 }
422 }
423}
424
425void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
426 int inputPitch, const void *input, size_t outputPitch, void *output) const
427{
428 const float *source = NULL;
429 float *dest = NULL;
430
431 for (int y = 0; y < height; y++)
432 {
433 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
434 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
435 for (int x = 0; x < width; x++)
436 {
437 dest[4 * x + 0] = source[x];
438 dest[4 * x + 1] = source[x];
439 dest[4 * x + 2] = source[x];
440 dest[4 * x + 3] = 1.0f;
441 }
442 }
443}
444
445void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
446 int inputPitch, const void *input, size_t outputPitch, void *output) const
447{
448 const unsigned short *source = NULL;
449 unsigned short *dest = NULL;
450
451 for (int y = 0; y < height; y++)
452 {
453 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
454 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
455 for (int x = 0; x < width; x++)
456 {
457 dest[4 * x + 0] = source[x];
458 dest[4 * x + 1] = source[x];
459 dest[4 * x + 2] = source[x];
460 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
461 }
462 }
463}
464
465void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
466 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
467{
468 const int destBytesPerPixel = native? 2: 4;
469 const unsigned char *source = NULL;
470 unsigned char *dest = NULL;
471
472 for (int y = 0; y < height; y++)
473 {
474 source = static_cast<const unsigned char*>(input) + y * inputPitch;
475 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
476
477 if (!native) // BGRA8 destination format
478 {
479 for (int x = 0; x < width; x++)
480 {
481 dest[4 * x + 0] = source[2*x+0];
482 dest[4 * x + 1] = source[2*x+0];
483 dest[4 * x + 2] = source[2*x+0];
484 dest[4 * x + 3] = source[2*x+1];
485 }
486 }
487 else
488 {
489 memcpy(dest, source, width * 2);
490 }
491 }
492}
493
494void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
495 int inputPitch, const void *input, size_t outputPitch, void *output) const
496{
497 const float *source = NULL;
498 float *dest = NULL;
499
500 for (int y = 0; y < height; y++)
501 {
502 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
503 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
504 for (int x = 0; x < width; x++)
505 {
506 dest[4 * x + 0] = source[2*x+0];
507 dest[4 * x + 1] = source[2*x+0];
508 dest[4 * x + 2] = source[2*x+0];
509 dest[4 * x + 3] = source[2*x+1];
510 }
511 }
512}
513
514void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
515 int inputPitch, const void *input, size_t outputPitch, void *output) const
516{
517 const unsigned short *source = NULL;
518 unsigned short *dest = NULL;
519
520 for (int y = 0; y < height; y++)
521 {
522 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
523 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
524 for (int x = 0; x < width; x++)
525 {
526 dest[4 * x + 0] = source[2*x+0];
527 dest[4 * x + 1] = source[2*x+0];
528 dest[4 * x + 2] = source[2*x+0];
529 dest[4 * x + 3] = source[2*x+1];
530 }
531 }
532}
533
534void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
535 int inputPitch, const void *input, size_t outputPitch, void *output) const
536{
537 const unsigned char *source = NULL;
538 unsigned char *dest = NULL;
539
540 for (int y = 0; y < height; y++)
541 {
542 source = static_cast<const unsigned char*>(input) + y * inputPitch;
543 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
544 for (int x = 0; x < width; x++)
545 {
546 dest[4 * x + 0] = source[x * 3 + 2];
547 dest[4 * x + 1] = source[x * 3 + 1];
548 dest[4 * x + 2] = source[x * 3 + 0];
549 dest[4 * x + 3] = 0xFF;
550 }
551 }
552}
553
554void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
555 int inputPitch, const void *input, size_t outputPitch, void *output) const
556{
557 const unsigned short *source = NULL;
558 unsigned char *dest = NULL;
559
560 for (int y = 0; y < height; y++)
561 {
562 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
563 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
564 for (int x = 0; x < width; x++)
565 {
566 unsigned short rgba = source[x];
567 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
568 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
569 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
570 dest[4 * x + 3] = 0xFF;
571 }
572 }
573}
574
575void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
576 int inputPitch, const void *input, size_t outputPitch, void *output) const
577{
578 const float *source = NULL;
579 float *dest = NULL;
580
581 for (int y = 0; y < height; y++)
582 {
583 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
584 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
585 for (int x = 0; x < width; x++)
586 {
587 dest[4 * x + 0] = source[x * 3 + 0];
588 dest[4 * x + 1] = source[x * 3 + 1];
589 dest[4 * x + 2] = source[x * 3 + 2];
590 dest[4 * x + 3] = 1.0f;
591 }
592 }
593}
594
595void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
596 int inputPitch, const void *input, size_t outputPitch, void *output) const
597{
598 const unsigned short *source = NULL;
599 unsigned short *dest = NULL;
600
601 for (int y = 0; y < height; y++)
602 {
603 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
604 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
605 for (int x = 0; x < width; x++)
606 {
607 dest[4 * x + 0] = source[x * 3 + 0];
608 dest[4 * x + 1] = source[x * 3 + 1];
609 dest[4 * x + 2] = source[x * 3 + 2];
610 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
611 }
612 }
613}
614
615void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
616 int inputPitch, const void *input, size_t outputPitch, void *output) const
617{
618 const unsigned char *source = NULL;
619 unsigned char *dest = NULL;
620
621 for (int y = 0; y < height; y++)
622 {
623 source = static_cast<const unsigned char*>(input) + y * inputPitch;
624 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
625 for (int x = 0; x < width; x++)
626 {
627 dest[4 * x + 0] = source[x * 4 + 2];
628 dest[4 * x + 1] = source[x * 4 + 1];
629 dest[4 * x + 2] = source[x * 4 + 0];
630 dest[4 * x + 3] = source[x * 4 + 3];
631 }
632 }
633}
634
635void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
636 int inputPitch, const void *input, size_t outputPitch, void *output) const
637{
638 const unsigned short *source = NULL;
639 unsigned char *dest = NULL;
640
641 for (int y = 0; y < height; y++)
642 {
643 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
644 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
645 for (int x = 0; x < width; x++)
646 {
647 unsigned short rgba = source[x];
648 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
649 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
650 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
651 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
652 }
653 }
654}
655
656void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
657 int inputPitch, const void *input, size_t outputPitch, void *output) const
658{
659 const unsigned short *source = NULL;
660 unsigned char *dest = NULL;
661
662 for (int y = 0; y < height; y++)
663 {
664 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
665 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
666 for (int x = 0; x < width; x++)
667 {
668 unsigned short rgba = source[x];
669 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
670 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
671 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
672 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
673 }
674 }
675}
676
677void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
678 int inputPitch, const void *input, size_t outputPitch, void *output) const
679{
680 const float *source = NULL;
681 float *dest = NULL;
682
683 for (int y = 0; y < height; y++)
684 {
685 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
686 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
687 memcpy(dest, source, width * 16);
688 }
689}
690
691void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
692 int inputPitch, const void *input, size_t outputPitch, void *output) const
693{
694 const unsigned char *source = NULL;
695 unsigned char *dest = NULL;
696
697 for (int y = 0; y < height; y++)
698 {
699 source = static_cast<const unsigned char*>(input) + y * inputPitch;
700 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
701 memcpy(dest, source, width * 8);
702 }
703}
704
705void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
706 int inputPitch, const void *input, size_t outputPitch, void *output) const
707{
708 const unsigned char *source = NULL;
709 unsigned char *dest = NULL;
710
711 for (int y = 0; y < height; y++)
712 {
713 source = static_cast<const unsigned char*>(input) + y * inputPitch;
714 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
715 memcpy(dest, source, width*4);
716 }
717}
718
719void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
720 int inputPitch, const void *input, size_t outputPitch, void *output) const
721{
722 ASSERT(xoffset % 4 == 0);
723 ASSERT(yoffset % 4 == 0);
724 ASSERT(width % 4 == 0 || width == 2 || width == 1);
725 ASSERT(inputPitch % 8 == 0);
726 ASSERT(outputPitch % 8 == 0);
727
728 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
729 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
730
731 switch (height)
732 {
733 case 1:
734 // Round width up in case it is 1.
735 for (int x = 0; x < (width + 1) / 2; x += 2)
736 {
737 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
738 dest[x] = source[x];
739
740 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
741 dest[x + 1] = source[x + 1];
742 }
743 break;
744 case 2:
745 // Round width up in case it is 1.
746 for (int x = 0; x < (width + 1) / 2; x += 2)
747 {
748 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
749 dest[x] = source[x];
750
751 // 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.
752 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
753 ((source[x + 1] >> 8) & 0x000000FF);
754 }
755 break;
756 default:
757 ASSERT(height % 4 == 0);
758 for (int y = 0; y < height / 4; ++y)
759 {
760 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
761 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
762
763 // Round width up in case it is 1.
764 for (int x = 0; x < (width + 1) / 2; x += 2)
765 {
766 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
767 dest[x] = source[x];
768
769 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
770 dest[x + 1] = (source[x + 1] >> 24) |
771 ((source[x + 1] << 8) & 0x00FF0000) |
772 ((source[x + 1] >> 8) & 0x0000FF00) |
773 (source[x + 1] << 24);
774 }
775 }
776 break;
777 }
778}
779
daniel@transgaming.com61208202011-03-21 16:38:50 +0000780void Texture::createSurface(Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000781{
782 IDirect3DTexture9 *newTexture = NULL;
783 IDirect3DSurface9 *newSurface = NULL;
784
daniel@transgaming.com61208202011-03-21 16:38:50 +0000785 if (image->width != 0 && image->height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000786 {
787 int levelToFetch = 0;
daniel@transgaming.com61208202011-03-21 16:38:50 +0000788 GLsizei requestWidth = image->width;
789 GLsizei requestHeight = image->height;
790 if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000791 {
792 bool isMult4 = false;
793 int upsampleCount = 0;
794 while (!isMult4)
795 {
796 requestWidth <<= 1;
797 requestHeight <<= 1;
798 upsampleCount++;
799 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
800 {
801 isMult4 = true;
802 }
803 }
804 levelToFetch = upsampleCount;
805 }
806
daniel@transgaming.com61208202011-03-21 16:38:50 +0000807 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(image->format, image->type),
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000808 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
809
810 if (FAILED(result))
811 {
812 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
813 return error(GL_OUT_OF_MEMORY);
814 }
815
816 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
817 newTexture->Release();
818 }
819
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000820 if (image->surface)
821 {
822 image->surface->Release();
823 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000824
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000825 image->surface = newSurface;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000826}
827
daniel@transgaming.com61208202011-03-21 16:38:50 +0000828void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000829{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000830 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000831
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000832 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000833 {
834 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000835 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000836
837 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000838 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000839
840 ASSERT(SUCCEEDED(result));
841
842 if (SUCCEEDED(result))
843 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000844 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 +0000845 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000846 }
847
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000848 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000849 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000850}
851
daniel@transgaming.com61208202011-03-21 16:38:50 +0000852void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000853{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000854 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000855
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000856 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000857 {
858 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000859 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000860
861 ASSERT(SUCCEEDED(result));
862
863 if (SUCCEEDED(result))
864 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000865 int inputPitch = ComputeCompressedPitch(image->width, image->format);
866 int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
867 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 +0000868 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000869 }
870
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000871 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000872 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000873}
874
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000875bool 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 +0000876{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000877 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000878 {
879 error(GL_INVALID_VALUE);
880 return false;
881 }
882
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000883 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000884 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000885 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000886 }
887
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000888 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000889 {
890 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000891 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000892
893 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000894 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000895
896 ASSERT(SUCCEEDED(result));
897
898 if (SUCCEEDED(result))
899 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000900 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
901 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000902 }
903
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000904 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000905 }
906
907 return true;
908}
909
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000910bool 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 +0000911{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000912 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000913 {
914 error(GL_INVALID_VALUE);
915 return false;
916 }
917
918 if (format != getInternalFormat())
919 {
920 error(GL_INVALID_OPERATION);
921 return false;
922 }
923
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000924 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000925 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000926 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000927 }
928
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000929 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000930 {
931 RECT updateRegion;
932 updateRegion.left = xoffset;
933 updateRegion.right = xoffset + width;
934 updateRegion.bottom = yoffset + height;
935 updateRegion.top = yoffset;
936
937 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000938 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000939
940 ASSERT(SUCCEEDED(result));
941
942 if (SUCCEEDED(result))
943 {
944 int inputPitch = ComputeCompressedPitch(width, format);
945 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000946 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
947 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000948 }
949
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000950 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000951 }
952
953 return true;
954}
955
956// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +0000957void 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 +0000958{
959 IDirect3DDevice9 *device = getDevice();
960 IDirect3DSurface9 *surface = NULL;
961 D3DSURFACE_DESC description;
962 renderTarget->GetDesc(&description);
963
964 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
965
966 if (!SUCCEEDED(result))
967 {
968 ERR("Could not create matching destination surface.");
969 return error(GL_OUT_OF_MEMORY);
970 }
971
972 result = device->GetRenderTargetData(renderTarget, surface);
973
974 if (!SUCCEEDED(result))
975 {
976 ERR("GetRenderTargetData unexpectedly failed.");
977 surface->Release();
978 return error(GL_OUT_OF_MEMORY);
979 }
980
981 D3DLOCKED_RECT sourceLock = {0};
982 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
983 result = surface->LockRect(&sourceLock, &sourceRect, 0);
984
985 if (FAILED(result))
986 {
987 ERR("Failed to lock the source surface (rectangle might be invalid).");
988 surface->UnlockRect();
989 surface->Release();
990 return error(GL_OUT_OF_MEMORY);
991 }
992
993 if (!image->surface)
994 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000995 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000996 }
997
998 if (image->surface == NULL)
999 {
1000 ERR("Failed to create an image surface.");
1001 surface->UnlockRect();
1002 surface->Release();
1003 return error(GL_OUT_OF_MEMORY);
1004 }
1005
1006 D3DLOCKED_RECT destLock = {0};
1007 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1008 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1009 result = image->surface->LockRect(&destLock, &destRect, 0);
1010
1011 if (FAILED(result))
1012 {
1013 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1014 surface->UnlockRect();
1015 surface->Release();
1016 return error(GL_OUT_OF_MEMORY);
1017 }
1018
1019 if (destLock.pBits && sourceLock.pBits)
1020 {
1021 unsigned char *source = (unsigned char*)sourceLock.pBits;
1022 unsigned char *dest = (unsigned char*)destLock.pBits;
1023
1024 switch (description.Format)
1025 {
1026 case D3DFMT_X8R8G8B8:
1027 case D3DFMT_A8R8G8B8:
1028 switch(getD3DFormat())
1029 {
1030 case D3DFMT_L8:
1031 for(int y = 0; y < height; y++)
1032 {
1033 for(int x = 0; x < width; x++)
1034 {
1035 dest[x] = source[x * 4 + 2];
1036 }
1037
1038 source += sourceLock.Pitch;
1039 dest += destLock.Pitch;
1040 }
1041 break;
1042 case D3DFMT_A8L8:
1043 for(int y = 0; y < height; y++)
1044 {
1045 for(int x = 0; x < width; x++)
1046 {
1047 dest[x * 2 + 0] = source[x * 4 + 2];
1048 dest[x * 2 + 1] = source[x * 4 + 3];
1049 }
1050
1051 source += sourceLock.Pitch;
1052 dest += destLock.Pitch;
1053 }
1054 break;
1055 default:
1056 UNREACHABLE();
1057 }
1058 break;
1059 case D3DFMT_R5G6B5:
1060 switch(getD3DFormat())
1061 {
1062 case D3DFMT_L8:
1063 for(int y = 0; y < height; y++)
1064 {
1065 for(int x = 0; x < width; x++)
1066 {
1067 unsigned char red = source[x * 2 + 1] & 0xF8;
1068 dest[x] = red | (red >> 5);
1069 }
1070
1071 source += sourceLock.Pitch;
1072 dest += destLock.Pitch;
1073 }
1074 break;
1075 default:
1076 UNREACHABLE();
1077 }
1078 break;
1079 case D3DFMT_A1R5G5B5:
1080 switch(getD3DFormat())
1081 {
1082 case D3DFMT_L8:
1083 for(int y = 0; y < height; y++)
1084 {
1085 for(int x = 0; x < width; x++)
1086 {
1087 unsigned char red = source[x * 2 + 1] & 0x7C;
1088 dest[x] = (red << 1) | (red >> 4);
1089 }
1090
1091 source += sourceLock.Pitch;
1092 dest += destLock.Pitch;
1093 }
1094 break;
1095 case D3DFMT_A8L8:
1096 for(int y = 0; y < height; y++)
1097 {
1098 for(int x = 0; x < width; x++)
1099 {
1100 unsigned char red = source[x * 2 + 1] & 0x7C;
1101 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1102 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1103 }
1104
1105 source += sourceLock.Pitch;
1106 dest += destLock.Pitch;
1107 }
1108 break;
1109 default:
1110 UNREACHABLE();
1111 }
1112 break;
1113 default:
1114 UNREACHABLE();
1115 }
1116
1117 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001118 }
1119
1120 image->surface->UnlockRect();
1121 surface->UnlockRect();
1122 surface->Release();
1123}
1124
1125D3DFORMAT Texture::getD3DFormat() const
1126{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001127 return selectFormat(getInternalFormat(), getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001128}
1129
1130IDirect3DBaseTexture9 *Texture::getTexture()
1131{
1132 if (!isComplete())
1133 {
1134 return NULL;
1135 }
1136
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001137 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001138 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001139 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001140 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001141
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001142 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001143
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001144 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001145}
1146
1147bool Texture::isDirty() const
1148{
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001149 return true;//(mDirty || mDirtyMetaData || dirtyImageData());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001150}
1151
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001152GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1153{
1154 if (isPow2(width) && isPow2(height))
1155 {
1156 return maxlevel;
1157 }
1158 else
1159 {
1160 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1161 return 1;
1162 }
1163}
1164
1165GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1166{
1167 return creationLevels(size, size, maxlevel);
1168}
1169
1170int Texture::levelCount() const
1171{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001172 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001173}
1174
1175Texture2D::Texture2D(GLuint id) : Texture(id)
1176{
1177 mTexture = NULL;
1178}
1179
1180Texture2D::~Texture2D()
1181{
1182 mColorbufferProxy.set(NULL);
1183
1184 if (mTexture)
1185 {
1186 mTexture->Release();
1187 mTexture = NULL;
1188 }
1189}
1190
1191GLenum Texture2D::getTarget() const
1192{
1193 return GL_TEXTURE_2D;
1194}
1195
daniel@transgaming.com61208202011-03-21 16:38:50 +00001196GLsizei Texture2D::getWidth() const
1197{
1198 return mImageArray[0].width;
1199}
1200
1201GLsizei Texture2D::getHeight() const
1202{
1203 return mImageArray[0].height;
1204}
1205
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001206GLenum Texture2D::getInternalFormat() const
1207{
1208 return mImageArray[0].format;
1209}
1210
daniel@transgaming.com61208202011-03-21 16:38:50 +00001211GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001212{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001213 return mImageArray[0].type;
1214}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001215
daniel@transgaming.com61208202011-03-21 16:38:50 +00001216void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1217{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001218 GLsizei textureWidth = mImageArray[0].width;
1219 GLsizei textureHeight = mImageArray[0].height;
1220 GLenum textureFormat = mImageArray[0].format;
1221 GLenum textureType = mImageArray[0].type;
1222
daniel@transgaming.com61208202011-03-21 16:38:50 +00001223 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.com94a4f032011-03-21 16:38:55 +00001233 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1234 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1235 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001236
1237 if (!textureOkay) // Purge all the levels and the texture.
1238 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001239 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1240 {
1241 if (mImageArray[i].surface != NULL)
1242 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001243 mImageArray[i].surface->Release();
1244 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001245 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001246 }
1247 }
1248
1249 if (mTexture != NULL)
1250 {
1251 mTexture->Release();
1252 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001253 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001254 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001255 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001256}
1257
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001258void 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 +00001259{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001260 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001261
daniel@transgaming.com61208202011-03-21 16:38:50 +00001262 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001263}
1264
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001265void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001266{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001267 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001268
daniel@transgaming.com61208202011-03-21 16:38:50 +00001269 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001270}
1271
1272void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1273{
1274 ASSERT(mImageArray[level].surface != NULL);
1275
1276 if (level < levelCount())
1277 {
1278 IDirect3DSurface9 *destLevel = NULL;
1279 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1280
1281 ASSERT(SUCCEEDED(result));
1282
1283 if (SUCCEEDED(result))
1284 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001285 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001286
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001287 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001288
1289 POINT destPoint;
1290 destPoint.x = sourceRect.left;
1291 destPoint.y = sourceRect.top;
1292
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001293 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001294 ASSERT(SUCCEEDED(result));
1295
1296 destLevel->Release();
1297
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001298 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001299 }
1300 }
1301}
1302
1303void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1304{
1305 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1306 {
1307 commitRect(level, xoffset, yoffset, width, height);
1308 }
1309}
1310
1311void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1312{
1313 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1314 {
1315 commitRect(level, xoffset, yoffset, width, height);
1316 }
1317}
1318
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001319void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001320{
1321 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1322
1323 if (!renderTarget)
1324 {
1325 ERR("Failed to retrieve the render target.");
1326 return error(GL_OUT_OF_MEMORY);
1327 }
1328
daniel@transgaming.com61208202011-03-21 16:38:50 +00001329 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001330
1331 if (!isRenderableFormat())
1332 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001333 copyNonRenderable(&mImageArray[level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001334 }
1335 else
1336 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001337 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001338 {
1339 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001340 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001341
1342 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001343
1344 if (width != 0 && height != 0 && level < levelCount())
1345 {
1346 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1347 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1348 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1349 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1350 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1351
1352 IDirect3DSurface9 *dest;
1353 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1354
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001355 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001356 dest->Release();
1357 }
1358 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001359}
1360
1361void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1362{
1363 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1364 {
1365 return error(GL_INVALID_VALUE);
1366 }
1367
1368 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1369
1370 if (!renderTarget)
1371 {
1372 ERR("Failed to retrieve the render target.");
1373 return error(GL_OUT_OF_MEMORY);
1374 }
1375
daniel@transgaming.com61208202011-03-21 16:38:50 +00001376 redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001377
daniel@transgaming.comf4e36032011-03-21 16:38:59 +00001378 if (!isRenderableFormat() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001379 {
1380 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1381 }
1382 else
1383 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001384 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001385 {
1386 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001387 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001388
1389 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001390
1391 if (level < levelCount())
1392 {
1393 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1394 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1395 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1396 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1397 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1398
1399 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1400
1401 IDirect3DSurface9 *dest;
1402 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1403
1404 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1405 dest->Release();
1406 }
1407 }
1408}
1409
1410// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1411bool Texture2D::isComplete() const
1412{
1413 GLsizei width = mImageArray[0].width;
1414 GLsizei height = mImageArray[0].height;
1415
1416 if (width <= 0 || height <= 0)
1417 {
1418 return false;
1419 }
1420
1421 bool mipmapping = false;
1422
1423 switch (mMinFilter)
1424 {
1425 case GL_NEAREST:
1426 case GL_LINEAR:
1427 mipmapping = false;
1428 break;
1429 case GL_NEAREST_MIPMAP_NEAREST:
1430 case GL_LINEAR_MIPMAP_NEAREST:
1431 case GL_NEAREST_MIPMAP_LINEAR:
1432 case GL_LINEAR_MIPMAP_LINEAR:
1433 mipmapping = true;
1434 break;
1435 default: UNREACHABLE();
1436 }
1437
1438 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1439 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1440 {
1441 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1442 {
1443 return false;
1444 }
1445 }
1446
1447
1448 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1449 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1450 {
1451 return false;
1452 }
1453
1454 if (mipmapping)
1455 {
1456 if (!isPow2(width) || !isPow2(height))
1457 {
1458 return false;
1459 }
1460
1461 int q = log2(std::max(width, height));
1462
1463 for (int level = 1; level <= q; level++)
1464 {
1465 if (mImageArray[level].format != mImageArray[0].format)
1466 {
1467 return false;
1468 }
1469
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001470 if (mImageArray[level].type != mImageArray[0].type)
1471 {
1472 return false;
1473 }
1474
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001475 if (mImageArray[level].width != std::max(1, width >> level))
1476 {
1477 return false;
1478 }
1479
1480 if (mImageArray[level].height != std::max(1, height >> level))
1481 {
1482 return false;
1483 }
1484 }
1485 }
1486
1487 return true;
1488}
1489
1490bool Texture2D::isCompressed() const
1491{
1492 return IsCompressed(getInternalFormat());
1493}
1494
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001495IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1496{
1497 return mTexture;
1498}
1499
1500// Constructs a Direct3D 9 texture resource from the texture images
1501void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001502{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001503 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001504 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1505 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001506
daniel@transgaming.com61208202011-03-21 16:38:50 +00001507 IDirect3DTexture9 *texture = NULL;
1508 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 +00001509
1510 if (FAILED(result))
1511 {
1512 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001513 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001514 }
1515
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001516 if (mTexture)
1517 {
1518 mTexture->Release();
1519 }
1520
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001521 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001522 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001523}
1524
1525void Texture2D::updateTexture()
1526{
1527 IDirect3DDevice9 *device = getDevice();
1528
1529 int levels = levelCount();
1530
1531 for (int level = 0; level < levels; level++)
1532 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001533 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001534 {
1535 IDirect3DSurface9 *levelSurface = NULL;
1536 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1537
1538 ASSERT(SUCCEEDED(result));
1539
1540 if (SUCCEEDED(result))
1541 {
1542 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1543 ASSERT(SUCCEEDED(result));
1544
1545 levelSurface->Release();
1546
1547 mImageArray[level].dirty = false;
1548 }
1549 }
1550 }
1551}
1552
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001553void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001554{
1555 IDirect3DTexture9 *texture = NULL;
1556
daniel@transgaming.com61208202011-03-21 16:38:50 +00001557 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001558 {
1559 egl::Display *display = getDisplay();
1560 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001561 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1562 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001563
daniel@transgaming.com61208202011-03-21 16:38:50 +00001564 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 +00001565
1566 if (FAILED(result))
1567 {
1568 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001569 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001570 }
1571
1572 if (mTexture != NULL)
1573 {
1574 int levels = levelCount();
1575 for (int i = 0; i < levels; i++)
1576 {
1577 IDirect3DSurface9 *source;
1578 result = mTexture->GetSurfaceLevel(i, &source);
1579
1580 if (FAILED(result))
1581 {
1582 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1583
1584 texture->Release();
1585
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001586 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001587 }
1588
1589 IDirect3DSurface9 *dest;
1590 result = texture->GetSurfaceLevel(i, &dest);
1591
1592 if (FAILED(result))
1593 {
1594 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1595
1596 texture->Release();
1597 source->Release();
1598
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001599 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001600 }
1601
1602 display->endScene();
1603 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1604
1605 if (FAILED(result))
1606 {
1607 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1608
1609 texture->Release();
1610 source->Release();
1611 dest->Release();
1612
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001613 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001614 }
1615
1616 source->Release();
1617 dest->Release();
1618 }
1619 }
1620 }
1621
1622 if (mTexture != NULL)
1623 {
1624 mTexture->Release();
1625 }
1626
1627 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001628 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001629}
1630
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001631void Texture2D::generateMipmaps()
1632{
1633 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1634 {
1635 return error(GL_INVALID_OPERATION);
1636 }
1637
1638 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001639 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001640 for (unsigned int i = 1; i <= q; i++)
1641 {
1642 if (mImageArray[i].surface != NULL)
1643 {
1644 mImageArray[i].surface->Release();
1645 mImageArray[i].surface = NULL;
1646 }
1647
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001648 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1649 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001650 mImageArray[i].format = mImageArray[0].format;
1651 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001652 }
1653
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001654 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001655 {
1656 if (mTexture == NULL)
1657 {
1658 ERR(" failed because mTexture was null.");
1659 return;
1660 }
1661
1662 for (unsigned int i = 1; i <= q; i++)
1663 {
1664 IDirect3DSurface9 *upper = NULL;
1665 IDirect3DSurface9 *lower = NULL;
1666
1667 mTexture->GetSurfaceLevel(i-1, &upper);
1668 mTexture->GetSurfaceLevel(i, &lower);
1669
1670 if (upper != NULL && lower != NULL)
1671 {
1672 getBlitter()->boxFilter(upper, lower);
1673 }
1674
1675 if (upper != NULL) upper->Release();
1676 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001677
1678 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001679 }
1680 }
1681 else
1682 {
1683 for (unsigned int i = 1; i <= q; i++)
1684 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001685 createSurface(&mImageArray[i]);
1686
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001687 if (mImageArray[i].surface == NULL)
1688 {
1689 return error(GL_OUT_OF_MEMORY);
1690 }
1691
1692 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1693 {
1694 ERR(" failed to load filter %d to %d.", i - 1, i);
1695 }
1696
1697 mImageArray[i].dirty = true;
1698 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001699 }
1700}
1701
1702Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1703{
1704 if (target != GL_TEXTURE_2D)
1705 {
1706 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1707 }
1708
1709 if (mColorbufferProxy.get() == NULL)
1710 {
1711 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1712 }
1713
1714 return mColorbufferProxy.get();
1715}
1716
1717IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1718{
1719 ASSERT(target == GL_TEXTURE_2D);
1720
daniel@transgaming.com61208202011-03-21 16:38:50 +00001721 if (!mIsRenderable)
1722 {
1723 convertToRenderTarget();
1724 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001725
1726 if (mTexture == NULL)
1727 {
1728 return NULL;
1729 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001730
1731 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001732
1733 IDirect3DSurface9 *renderTarget = NULL;
1734 mTexture->GetSurfaceLevel(0, &renderTarget);
1735
1736 return renderTarget;
1737}
1738
1739TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1740{
1741 mTexture = NULL;
1742}
1743
1744TextureCubeMap::~TextureCubeMap()
1745{
1746 for (int i = 0; i < 6; i++)
1747 {
1748 mFaceProxies[i].set(NULL);
1749 }
1750
1751 if (mTexture)
1752 {
1753 mTexture->Release();
1754 mTexture = NULL;
1755 }
1756}
1757
1758GLenum TextureCubeMap::getTarget() const
1759{
1760 return GL_TEXTURE_CUBE_MAP;
1761}
1762
daniel@transgaming.com61208202011-03-21 16:38:50 +00001763GLsizei TextureCubeMap::getWidth() const
1764{
1765 return mImageArray[0][0].width;
1766}
1767
1768GLsizei TextureCubeMap::getHeight() const
1769{
1770 return mImageArray[0][0].height;
1771}
1772
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001773GLenum TextureCubeMap::getInternalFormat() const
1774{
1775 return mImageArray[0][0].format;
1776}
1777
daniel@transgaming.com61208202011-03-21 16:38:50 +00001778GLenum TextureCubeMap::getType() const
1779{
1780 return mImageArray[0][0].type;
1781}
1782
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001783void 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 +00001784{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001785 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001786}
1787
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001788void 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 +00001789{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001790 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001791}
1792
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001793void 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 +00001794{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001795 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001796}
1797
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001798void 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 +00001799{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001800 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001801}
1802
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001803void 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 +00001804{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001805 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001806}
1807
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001808void 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 +00001809{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001810 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001811}
1812
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001813void 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 +00001814{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001815 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001816
daniel@transgaming.com61208202011-03-21 16:38:50 +00001817 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001818}
1819
1820void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1821{
1822 int face = faceIndex(faceTarget);
1823 ASSERT(mImageArray[face][level].surface != NULL);
1824
1825 if (level < levelCount())
1826 {
1827 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1828 ASSERT(destLevel != NULL);
1829
1830 if (destLevel != NULL)
1831 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001832 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001833
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001834 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001835
1836 POINT destPoint;
1837 destPoint.x = sourceRect.left;
1838 destPoint.y = sourceRect.top;
1839
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001840 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001841 ASSERT(SUCCEEDED(result));
1842
1843 destLevel->Release();
1844
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001845 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001846 }
1847 }
1848}
1849
1850void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1851{
1852 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1853 {
1854 commitRect(target, level, xoffset, yoffset, width, height);
1855 }
1856}
1857
1858void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1859{
1860 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1861 {
1862 commitRect(target, level, xoffset, yoffset, width, height);
1863 }
1864}
1865
1866// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1867bool TextureCubeMap::isComplete() const
1868{
1869 int size = mImageArray[0][0].width;
1870
1871 if (size <= 0)
1872 {
1873 return false;
1874 }
1875
1876 bool mipmapping;
1877
1878 switch (mMinFilter)
1879 {
1880 case GL_NEAREST:
1881 case GL_LINEAR:
1882 mipmapping = false;
1883 break;
1884 case GL_NEAREST_MIPMAP_NEAREST:
1885 case GL_LINEAR_MIPMAP_NEAREST:
1886 case GL_NEAREST_MIPMAP_LINEAR:
1887 case GL_LINEAR_MIPMAP_LINEAR:
1888 mipmapping = true;
1889 break;
1890 default: UNREACHABLE();
1891 }
1892
1893 for (int face = 0; face < 6; face++)
1894 {
1895 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1896 {
1897 return false;
1898 }
1899 }
1900
1901 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1902 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1903 {
1904 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1905 {
1906 return false;
1907 }
1908 }
1909
1910 if (mipmapping)
1911 {
1912 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1913 {
1914 return false;
1915 }
1916
1917 int q = log2(size);
1918
1919 for (int face = 0; face < 6; face++)
1920 {
1921 for (int level = 1; level <= q; level++)
1922 {
1923 if (mImageArray[face][level].format != mImageArray[0][0].format)
1924 {
1925 return false;
1926 }
1927
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001928 if (mImageArray[face][level].type != mImageArray[0][0].type)
1929 {
1930 return false;
1931 }
1932
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001933 if (mImageArray[face][level].width != std::max(1, size >> level))
1934 {
1935 return false;
1936 }
1937
1938 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1939 }
1940 }
1941 }
1942
1943 return true;
1944}
1945
1946bool TextureCubeMap::isCompressed() const
1947{
1948 return IsCompressed(getInternalFormat());
1949}
1950
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001951IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1952{
1953 return mTexture;
1954}
1955
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001956// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001957void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001958{
1959 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001960 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
1961 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001962
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001963 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001964 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001965
1966 if (FAILED(result))
1967 {
1968 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001969 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001970 }
1971
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001972 if (mTexture)
1973 {
1974 mTexture->Release();
1975 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001976
1977 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001978 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001979}
1980
1981void TextureCubeMap::updateTexture()
1982{
1983 IDirect3DDevice9 *device = getDevice();
1984
1985 for (int face = 0; face < 6; face++)
1986 {
1987 int levels = levelCount();
1988 for (int level = 0; level < levels; level++)
1989 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001990 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001991
daniel@transgaming.com61208202011-03-21 16:38:50 +00001992 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001993 {
1994 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
1995 ASSERT(levelSurface != NULL);
1996
1997 if (levelSurface != NULL)
1998 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001999 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002000 ASSERT(SUCCEEDED(result));
2001
2002 levelSurface->Release();
2003
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002004 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002005 }
2006 }
2007 }
2008 }
2009}
2010
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002011void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002012{
2013 IDirect3DCubeTexture9 *texture = NULL;
2014
daniel@transgaming.com61208202011-03-21 16:38:50 +00002015 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002016 {
2017 egl::Display *display = getDisplay();
2018 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002019 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
2020 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002021
daniel@transgaming.com61208202011-03-21 16:38:50 +00002022 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002023
2024 if (FAILED(result))
2025 {
2026 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002027 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002028 }
2029
2030 if (mTexture != NULL)
2031 {
2032 int levels = levelCount();
2033 for (int f = 0; f < 6; f++)
2034 {
2035 for (int i = 0; i < levels; i++)
2036 {
2037 IDirect3DSurface9 *source;
2038 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2039
2040 if (FAILED(result))
2041 {
2042 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2043
2044 texture->Release();
2045
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002046 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002047 }
2048
2049 IDirect3DSurface9 *dest;
2050 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2051
2052 if (FAILED(result))
2053 {
2054 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2055
2056 texture->Release();
2057 source->Release();
2058
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002059 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002060 }
2061
2062 display->endScene();
2063 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2064
2065 if (FAILED(result))
2066 {
2067 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2068
2069 texture->Release();
2070 source->Release();
2071 dest->Release();
2072
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002073 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002074 }
2075 }
2076 }
2077 }
2078 }
2079
2080 if (mTexture != NULL)
2081 {
2082 mTexture->Release();
2083 }
2084
2085 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002086 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002087}
2088
daniel@transgaming.com61208202011-03-21 16:38:50 +00002089void 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 +00002090{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002091 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002092
daniel@transgaming.com61208202011-03-21 16:38:50 +00002093 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002094}
2095
2096unsigned int TextureCubeMap::faceIndex(GLenum face)
2097{
2098 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2099 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2100 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2101 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2102 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2103
2104 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2105}
2106
daniel@transgaming.com61208202011-03-21 16:38:50 +00002107void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002108{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002109 GLsizei textureWidth = mImageArray[0][0].width;
2110 GLsizei textureHeight = mImageArray[0][0].height;
2111 GLenum textureFormat = mImageArray[0][0].format;
2112 GLenum textureType = mImageArray[0][0].type;
2113
daniel@transgaming.com61208202011-03-21 16:38:50 +00002114 mImageArray[face][level].width = width;
2115 mImageArray[face][level].height = height;
2116 mImageArray[face][level].format = format;
2117 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002118
daniel@transgaming.com61208202011-03-21 16:38:50 +00002119 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002120 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002121 return;
2122 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002123
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002124 bool sizeOkay = (textureWidth >> level == width);
2125 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002126
2127 if (!textureOkay) // Purge all the levels and the texture.
2128 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002129 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2130 {
2131 for (int f = 0; f < 6; f++)
2132 {
2133 if (mImageArray[f][i].surface != NULL)
2134 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002135 mImageArray[f][i].surface->Release();
2136 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002137 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002138 }
2139 }
2140 }
2141
2142 if (mTexture != NULL)
2143 {
2144 mTexture->Release();
2145 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002146 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002147 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002148 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002149}
2150
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002151void 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 +00002152{
2153 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2154
2155 if (!renderTarget)
2156 {
2157 ERR("Failed to retrieve the render target.");
2158 return error(GL_OUT_OF_MEMORY);
2159 }
2160
2161 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002162 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002163
daniel@transgaming.comf4e36032011-03-21 16:38:59 +00002164 if (!isRenderableFormat() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002165 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002166 copyNonRenderable(&mImageArray[faceindex][level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002167 }
2168 else
2169 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002170 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002171 {
2172 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002173 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002174
2175 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002176
2177 ASSERT(width == height);
2178
2179 if (width > 0 && level < levelCount())
2180 {
2181 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2182 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2183 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2184 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2185 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2186
2187 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2188
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002189 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002190 dest->Release();
2191 }
2192 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002193}
2194
2195IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2196{
2197 if (mTexture == NULL)
2198 {
2199 UNREACHABLE();
2200 return NULL;
2201 }
2202
2203 IDirect3DSurface9 *surface = NULL;
2204
2205 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2206
2207 return (SUCCEEDED(hr)) ? surface : NULL;
2208}
2209
2210void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2211{
2212 GLsizei size = mImageArray[faceIndex(target)][level].width;
2213
2214 if (xoffset + width > size || yoffset + height > size)
2215 {
2216 return error(GL_INVALID_VALUE);
2217 }
2218
2219 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2220
2221 if (!renderTarget)
2222 {
2223 ERR("Failed to retrieve the render target.");
2224 return error(GL_OUT_OF_MEMORY);
2225 }
2226
2227 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002228 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 +00002229
2230 if (!isRenderableFormat())
2231 {
2232 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2233 }
2234 else
2235 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002236 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002237 {
2238 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002239 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002240
2241 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002242
2243 if (level < levelCount())
2244 {
2245 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2246 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2247 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2248 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2249 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2250
2251 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2252
2253 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2254
2255 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2256 dest->Release();
2257 }
2258 }
2259}
2260
2261bool TextureCubeMap::isCubeComplete() const
2262{
2263 if (mImageArray[0][0].width == 0)
2264 {
2265 return false;
2266 }
2267
2268 for (unsigned int f = 1; f < 6; f++)
2269 {
2270 if (mImageArray[f][0].width != mImageArray[0][0].width
2271 || mImageArray[f][0].format != mImageArray[0][0].format)
2272 {
2273 return false;
2274 }
2275 }
2276
2277 return true;
2278}
2279
2280void TextureCubeMap::generateMipmaps()
2281{
2282 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2283 {
2284 return error(GL_INVALID_OPERATION);
2285 }
2286
2287 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2288 unsigned int q = log2(mImageArray[0][0].width);
2289 for (unsigned int f = 0; f < 6; f++)
2290 {
2291 for (unsigned int i = 1; i <= q; i++)
2292 {
2293 if (mImageArray[f][i].surface != NULL)
2294 {
2295 mImageArray[f][i].surface->Release();
2296 mImageArray[f][i].surface = NULL;
2297 }
2298
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002299 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2300 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002301 mImageArray[f][i].format = mImageArray[f][0].format;
2302 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002303 }
2304 }
2305
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002306 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002307 {
2308 if (mTexture == NULL)
2309 {
2310 return;
2311 }
2312
2313 for (unsigned int f = 0; f < 6; f++)
2314 {
2315 for (unsigned int i = 1; i <= q; i++)
2316 {
2317 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2318 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2319
2320 if (upper != NULL && lower != NULL)
2321 {
2322 getBlitter()->boxFilter(upper, lower);
2323 }
2324
2325 if (upper != NULL) upper->Release();
2326 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002327
2328 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002329 }
2330 }
2331 }
2332 else
2333 {
2334 for (unsigned int f = 0; f < 6; f++)
2335 {
2336 for (unsigned int i = 1; i <= q; i++)
2337 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002338 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002339 if (mImageArray[f][i].surface == NULL)
2340 {
2341 return error(GL_OUT_OF_MEMORY);
2342 }
2343
2344 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2345 {
2346 ERR(" failed to load filter %d to %d.", i - 1, i);
2347 }
2348
2349 mImageArray[f][i].dirty = true;
2350 }
2351 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002352 }
2353}
2354
2355Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2356{
2357 if (!IsCubemapTextureTarget(target))
2358 {
2359 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2360 }
2361
2362 unsigned int face = faceIndex(target);
2363
2364 if (mFaceProxies[face].get() == NULL)
2365 {
2366 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2367 }
2368
2369 return mFaceProxies[face].get();
2370}
2371
2372IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2373{
2374 ASSERT(IsCubemapTextureTarget(target));
2375
daniel@transgaming.com61208202011-03-21 16:38:50 +00002376 if (!mIsRenderable)
2377 {
2378 convertToRenderTarget();
2379 }
2380
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002381 if (mTexture == NULL)
2382 {
2383 return NULL;
2384 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002385
2386 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002387
2388 IDirect3DSurface9 *renderTarget = NULL;
2389 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2390
2391 return renderTarget;
2392}
2393
2394}