blob: 6bc12fa5d34eed616c0f2703c689a0e523c95365 [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.com38e76e52011-03-21 16:39:10 +000047 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000048
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.com38e76e52011-03-21 16:39:10 +000077 mDirty = 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.com38e76e52011-03-21 16:39:10 +000097 mDirty = 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.com38e76e52011-03-21 16:39:10 +0000118 mDirty = 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.com38e76e52011-03-21 16:39:10 +0000139 mDirty = 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.com38e76e52011-03-21 16:39:10 +0000849 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000850 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000851}
852
daniel@transgaming.com61208202011-03-21 16:38:50 +0000853void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000854{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000855 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000856
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000857 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000858 {
859 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000860 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000861
862 ASSERT(SUCCEEDED(result));
863
864 if (SUCCEEDED(result))
865 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000866 int inputPitch = ComputeCompressedPitch(image->width, image->format);
867 int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
868 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 +0000869 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000870 }
871
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000872 image->dirty = true;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +0000873 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000874 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000875}
876
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000877bool 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 +0000878{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000879 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000880 {
881 error(GL_INVALID_VALUE);
882 return false;
883 }
884
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000885 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000886 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000887 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000888 }
889
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000890 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000891 {
892 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000893 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000894
895 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000896 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000897
898 ASSERT(SUCCEEDED(result));
899
900 if (SUCCEEDED(result))
901 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000902 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
903 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000904 }
905
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000906 image->dirty = true;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +0000907 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000908 }
909
910 return true;
911}
912
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000913bool 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 +0000914{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000915 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000916 {
917 error(GL_INVALID_VALUE);
918 return false;
919 }
920
921 if (format != getInternalFormat())
922 {
923 error(GL_INVALID_OPERATION);
924 return false;
925 }
926
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000927 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000928 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000929 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000930 }
931
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000932 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000933 {
934 RECT updateRegion;
935 updateRegion.left = xoffset;
936 updateRegion.right = xoffset + width;
937 updateRegion.bottom = yoffset + height;
938 updateRegion.top = yoffset;
939
940 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000941 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000942
943 ASSERT(SUCCEEDED(result));
944
945 if (SUCCEEDED(result))
946 {
947 int inputPitch = ComputeCompressedPitch(width, format);
948 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000949 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
950 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000951 }
952
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000953 image->dirty = true;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +0000954 mDirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000955 }
956
957 return true;
958}
959
960// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +0000961void 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 +0000962{
963 IDirect3DDevice9 *device = getDevice();
964 IDirect3DSurface9 *surface = NULL;
965 D3DSURFACE_DESC description;
966 renderTarget->GetDesc(&description);
967
968 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
969
970 if (!SUCCEEDED(result))
971 {
972 ERR("Could not create matching destination surface.");
973 return error(GL_OUT_OF_MEMORY);
974 }
975
976 result = device->GetRenderTargetData(renderTarget, surface);
977
978 if (!SUCCEEDED(result))
979 {
980 ERR("GetRenderTargetData unexpectedly failed.");
981 surface->Release();
982 return error(GL_OUT_OF_MEMORY);
983 }
984
985 D3DLOCKED_RECT sourceLock = {0};
986 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
987 result = surface->LockRect(&sourceLock, &sourceRect, 0);
988
989 if (FAILED(result))
990 {
991 ERR("Failed to lock the source surface (rectangle might be invalid).");
992 surface->UnlockRect();
993 surface->Release();
994 return error(GL_OUT_OF_MEMORY);
995 }
996
997 if (!image->surface)
998 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000999 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001000 }
1001
1002 if (image->surface == NULL)
1003 {
1004 ERR("Failed to create an image surface.");
1005 surface->UnlockRect();
1006 surface->Release();
1007 return error(GL_OUT_OF_MEMORY);
1008 }
1009
1010 D3DLOCKED_RECT destLock = {0};
1011 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1012 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1013 result = image->surface->LockRect(&destLock, &destRect, 0);
1014
1015 if (FAILED(result))
1016 {
1017 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1018 surface->UnlockRect();
1019 surface->Release();
1020 return error(GL_OUT_OF_MEMORY);
1021 }
1022
1023 if (destLock.pBits && sourceLock.pBits)
1024 {
1025 unsigned char *source = (unsigned char*)sourceLock.pBits;
1026 unsigned char *dest = (unsigned char*)destLock.pBits;
1027
1028 switch (description.Format)
1029 {
1030 case D3DFMT_X8R8G8B8:
1031 case D3DFMT_A8R8G8B8:
1032 switch(getD3DFormat())
1033 {
1034 case D3DFMT_L8:
1035 for(int y = 0; y < height; y++)
1036 {
1037 for(int x = 0; x < width; x++)
1038 {
1039 dest[x] = source[x * 4 + 2];
1040 }
1041
1042 source += sourceLock.Pitch;
1043 dest += destLock.Pitch;
1044 }
1045 break;
1046 case D3DFMT_A8L8:
1047 for(int y = 0; y < height; y++)
1048 {
1049 for(int x = 0; x < width; x++)
1050 {
1051 dest[x * 2 + 0] = source[x * 4 + 2];
1052 dest[x * 2 + 1] = source[x * 4 + 3];
1053 }
1054
1055 source += sourceLock.Pitch;
1056 dest += destLock.Pitch;
1057 }
1058 break;
1059 default:
1060 UNREACHABLE();
1061 }
1062 break;
1063 case D3DFMT_R5G6B5:
1064 switch(getD3DFormat())
1065 {
1066 case D3DFMT_L8:
1067 for(int y = 0; y < height; y++)
1068 {
1069 for(int x = 0; x < width; x++)
1070 {
1071 unsigned char red = source[x * 2 + 1] & 0xF8;
1072 dest[x] = red | (red >> 5);
1073 }
1074
1075 source += sourceLock.Pitch;
1076 dest += destLock.Pitch;
1077 }
1078 break;
1079 default:
1080 UNREACHABLE();
1081 }
1082 break;
1083 case D3DFMT_A1R5G5B5:
1084 switch(getD3DFormat())
1085 {
1086 case D3DFMT_L8:
1087 for(int y = 0; y < height; y++)
1088 {
1089 for(int x = 0; x < width; x++)
1090 {
1091 unsigned char red = source[x * 2 + 1] & 0x7C;
1092 dest[x] = (red << 1) | (red >> 4);
1093 }
1094
1095 source += sourceLock.Pitch;
1096 dest += destLock.Pitch;
1097 }
1098 break;
1099 case D3DFMT_A8L8:
1100 for(int y = 0; y < height; y++)
1101 {
1102 for(int x = 0; x < width; x++)
1103 {
1104 unsigned char red = source[x * 2 + 1] & 0x7C;
1105 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1106 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1107 }
1108
1109 source += sourceLock.Pitch;
1110 dest += destLock.Pitch;
1111 }
1112 break;
1113 default:
1114 UNREACHABLE();
1115 }
1116 break;
1117 default:
1118 UNREACHABLE();
1119 }
1120
1121 image->dirty = true;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001122 mDirty = 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.com38e76e52011-03-21 16:39:10 +00001154 return mDirty;
1155}
1156
1157void Texture::resetDirty()
1158{
1159 mDirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001160}
1161
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001162GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1163{
1164 if (isPow2(width) && isPow2(height))
1165 {
1166 return maxlevel;
1167 }
1168 else
1169 {
1170 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1171 return 1;
1172 }
1173}
1174
1175GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1176{
1177 return creationLevels(size, size, maxlevel);
1178}
1179
1180int Texture::levelCount() const
1181{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001182 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001183}
1184
1185Texture2D::Texture2D(GLuint id) : Texture(id)
1186{
1187 mTexture = NULL;
1188}
1189
1190Texture2D::~Texture2D()
1191{
1192 mColorbufferProxy.set(NULL);
1193
1194 if (mTexture)
1195 {
1196 mTexture->Release();
1197 mTexture = NULL;
1198 }
1199}
1200
1201GLenum Texture2D::getTarget() const
1202{
1203 return GL_TEXTURE_2D;
1204}
1205
daniel@transgaming.com61208202011-03-21 16:38:50 +00001206GLsizei Texture2D::getWidth() const
1207{
1208 return mImageArray[0].width;
1209}
1210
1211GLsizei Texture2D::getHeight() const
1212{
1213 return mImageArray[0].height;
1214}
1215
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001216GLenum Texture2D::getInternalFormat() const
1217{
1218 return mImageArray[0].format;
1219}
1220
daniel@transgaming.com61208202011-03-21 16:38:50 +00001221GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001222{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001223 return mImageArray[0].type;
1224}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001225
daniel@transgaming.com61208202011-03-21 16:38:50 +00001226void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1227{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001228 GLsizei textureWidth = mImageArray[0].width;
1229 GLsizei textureHeight = mImageArray[0].height;
1230 GLenum textureFormat = mImageArray[0].format;
1231 GLenum textureType = mImageArray[0].type;
1232
daniel@transgaming.com61208202011-03-21 16:38:50 +00001233 mImageArray[level].width = width;
1234 mImageArray[level].height = height;
1235 mImageArray[level].format = format;
1236 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001237
daniel@transgaming.com61208202011-03-21 16:38:50 +00001238 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001239 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001240 return;
1241 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001242
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001243 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1244 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1245 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001246
1247 if (!textureOkay) // Purge all the levels and the texture.
1248 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001249 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1250 {
1251 if (mImageArray[i].surface != NULL)
1252 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001253 mImageArray[i].surface->Release();
1254 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001255 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001256 }
1257 }
1258
1259 if (mTexture != NULL)
1260 {
1261 mTexture->Release();
1262 mTexture = NULL;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001263 mDirty = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001264 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001265 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001266 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001267}
1268
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001269void 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 +00001270{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001271 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001272
daniel@transgaming.com61208202011-03-21 16:38:50 +00001273 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001274}
1275
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001276void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001277{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001278 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001279
daniel@transgaming.com61208202011-03-21 16:38:50 +00001280 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001281}
1282
1283void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1284{
1285 ASSERT(mImageArray[level].surface != NULL);
1286
1287 if (level < levelCount())
1288 {
1289 IDirect3DSurface9 *destLevel = NULL;
1290 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1291
1292 ASSERT(SUCCEEDED(result));
1293
1294 if (SUCCEEDED(result))
1295 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001296 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001297
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001298 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001299
1300 POINT destPoint;
1301 destPoint.x = sourceRect.left;
1302 destPoint.y = sourceRect.top;
1303
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001304 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001305 ASSERT(SUCCEEDED(result));
1306
1307 destLevel->Release();
1308
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001309 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001310 }
1311 }
1312}
1313
1314void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1315{
1316 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1317 {
1318 commitRect(level, xoffset, yoffset, width, height);
1319 }
1320}
1321
1322void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1323{
1324 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1325 {
1326 commitRect(level, xoffset, yoffset, width, height);
1327 }
1328}
1329
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001330void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001331{
1332 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1333
1334 if (!renderTarget)
1335 {
1336 ERR("Failed to retrieve the render target.");
1337 return error(GL_OUT_OF_MEMORY);
1338 }
1339
daniel@transgaming.com61208202011-03-21 16:38:50 +00001340 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001341
1342 if (!isRenderableFormat())
1343 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001344 copyNonRenderable(&mImageArray[level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001345 }
1346 else
1347 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001348 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001349 {
1350 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001351 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001352
1353 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001354
1355 if (width != 0 && height != 0 && level < levelCount())
1356 {
1357 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1358 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1359 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1360 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1361 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1362
1363 IDirect3DSurface9 *dest;
1364 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1365
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001366 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001367 dest->Release();
1368 }
1369 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001370}
1371
1372void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1373{
1374 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1375 {
1376 return error(GL_INVALID_VALUE);
1377 }
1378
1379 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1380
1381 if (!renderTarget)
1382 {
1383 ERR("Failed to retrieve the render target.");
1384 return error(GL_OUT_OF_MEMORY);
1385 }
1386
daniel@transgaming.com61208202011-03-21 16:38:50 +00001387 redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001388
daniel@transgaming.comf4e36032011-03-21 16:38:59 +00001389 if (!isRenderableFormat() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001390 {
1391 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1392 }
1393 else
1394 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001395 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001396 {
1397 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001398 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001399
1400 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001401
1402 if (level < levelCount())
1403 {
1404 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1405 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1406 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1407 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1408 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1409
1410 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1411
1412 IDirect3DSurface9 *dest;
1413 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1414
1415 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1416 dest->Release();
1417 }
1418 }
1419}
1420
1421// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1422bool Texture2D::isComplete() const
1423{
1424 GLsizei width = mImageArray[0].width;
1425 GLsizei height = mImageArray[0].height;
1426
1427 if (width <= 0 || height <= 0)
1428 {
1429 return false;
1430 }
1431
1432 bool mipmapping = false;
1433
1434 switch (mMinFilter)
1435 {
1436 case GL_NEAREST:
1437 case GL_LINEAR:
1438 mipmapping = false;
1439 break;
1440 case GL_NEAREST_MIPMAP_NEAREST:
1441 case GL_LINEAR_MIPMAP_NEAREST:
1442 case GL_NEAREST_MIPMAP_LINEAR:
1443 case GL_LINEAR_MIPMAP_LINEAR:
1444 mipmapping = true;
1445 break;
1446 default: UNREACHABLE();
1447 }
1448
1449 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1450 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1451 {
1452 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1453 {
1454 return false;
1455 }
1456 }
1457
1458
1459 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1460 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1461 {
1462 return false;
1463 }
1464
1465 if (mipmapping)
1466 {
1467 if (!isPow2(width) || !isPow2(height))
1468 {
1469 return false;
1470 }
1471
1472 int q = log2(std::max(width, height));
1473
1474 for (int level = 1; level <= q; level++)
1475 {
1476 if (mImageArray[level].format != mImageArray[0].format)
1477 {
1478 return false;
1479 }
1480
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001481 if (mImageArray[level].type != mImageArray[0].type)
1482 {
1483 return false;
1484 }
1485
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001486 if (mImageArray[level].width != std::max(1, width >> level))
1487 {
1488 return false;
1489 }
1490
1491 if (mImageArray[level].height != std::max(1, height >> level))
1492 {
1493 return false;
1494 }
1495 }
1496 }
1497
1498 return true;
1499}
1500
1501bool Texture2D::isCompressed() const
1502{
1503 return IsCompressed(getInternalFormat());
1504}
1505
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001506IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1507{
1508 return mTexture;
1509}
1510
1511// Constructs a Direct3D 9 texture resource from the texture images
1512void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001513{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001514 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001515 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1516 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001517
daniel@transgaming.com61208202011-03-21 16:38:50 +00001518 IDirect3DTexture9 *texture = NULL;
1519 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 +00001520
1521 if (FAILED(result))
1522 {
1523 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001524 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001525 }
1526
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001527 if (mTexture)
1528 {
1529 mTexture->Release();
1530 }
1531
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001532 mTexture = texture;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001533 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001534 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001535}
1536
1537void Texture2D::updateTexture()
1538{
1539 IDirect3DDevice9 *device = getDevice();
1540
1541 int levels = levelCount();
1542
1543 for (int level = 0; level < levels; level++)
1544 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001545 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001546 {
1547 IDirect3DSurface9 *levelSurface = NULL;
1548 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1549
1550 ASSERT(SUCCEEDED(result));
1551
1552 if (SUCCEEDED(result))
1553 {
1554 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1555 ASSERT(SUCCEEDED(result));
1556
1557 levelSurface->Release();
1558
1559 mImageArray[level].dirty = false;
1560 }
1561 }
1562 }
1563}
1564
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001565void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001566{
1567 IDirect3DTexture9 *texture = NULL;
1568
daniel@transgaming.com61208202011-03-21 16:38:50 +00001569 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001570 {
1571 egl::Display *display = getDisplay();
1572 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001573 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1574 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001575
daniel@transgaming.com61208202011-03-21 16:38:50 +00001576 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 +00001577
1578 if (FAILED(result))
1579 {
1580 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001581 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001582 }
1583
1584 if (mTexture != NULL)
1585 {
1586 int levels = levelCount();
1587 for (int i = 0; i < levels; i++)
1588 {
1589 IDirect3DSurface9 *source;
1590 result = mTexture->GetSurfaceLevel(i, &source);
1591
1592 if (FAILED(result))
1593 {
1594 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1595
1596 texture->Release();
1597
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001598 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001599 }
1600
1601 IDirect3DSurface9 *dest;
1602 result = texture->GetSurfaceLevel(i, &dest);
1603
1604 if (FAILED(result))
1605 {
1606 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1607
1608 texture->Release();
1609 source->Release();
1610
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001611 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001612 }
1613
1614 display->endScene();
1615 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1616
1617 if (FAILED(result))
1618 {
1619 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1620
1621 texture->Release();
1622 source->Release();
1623 dest->Release();
1624
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001625 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001626 }
1627
1628 source->Release();
1629 dest->Release();
1630 }
1631 }
1632 }
1633
1634 if (mTexture != NULL)
1635 {
1636 mTexture->Release();
1637 }
1638
1639 mTexture = texture;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001640 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001641 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001642}
1643
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001644void Texture2D::generateMipmaps()
1645{
1646 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1647 {
1648 return error(GL_INVALID_OPERATION);
1649 }
1650
1651 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001652 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001653 for (unsigned int i = 1; i <= q; i++)
1654 {
1655 if (mImageArray[i].surface != NULL)
1656 {
1657 mImageArray[i].surface->Release();
1658 mImageArray[i].surface = NULL;
1659 }
1660
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001661 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1662 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001663 mImageArray[i].format = mImageArray[0].format;
1664 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001665 }
1666
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001667 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001668 {
1669 if (mTexture == NULL)
1670 {
1671 ERR(" failed because mTexture was null.");
1672 return;
1673 }
1674
1675 for (unsigned int i = 1; i <= q; i++)
1676 {
1677 IDirect3DSurface9 *upper = NULL;
1678 IDirect3DSurface9 *lower = NULL;
1679
1680 mTexture->GetSurfaceLevel(i-1, &upper);
1681 mTexture->GetSurfaceLevel(i, &lower);
1682
1683 if (upper != NULL && lower != NULL)
1684 {
1685 getBlitter()->boxFilter(upper, lower);
1686 }
1687
1688 if (upper != NULL) upper->Release();
1689 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001690
1691 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001692 }
1693 }
1694 else
1695 {
1696 for (unsigned int i = 1; i <= q; i++)
1697 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001698 createSurface(&mImageArray[i]);
1699
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001700 if (mImageArray[i].surface == NULL)
1701 {
1702 return error(GL_OUT_OF_MEMORY);
1703 }
1704
1705 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1706 {
1707 ERR(" failed to load filter %d to %d.", i - 1, i);
1708 }
1709
1710 mImageArray[i].dirty = true;
1711 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001712 }
1713}
1714
1715Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1716{
1717 if (target != GL_TEXTURE_2D)
1718 {
1719 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1720 }
1721
1722 if (mColorbufferProxy.get() == NULL)
1723 {
1724 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1725 }
1726
1727 return mColorbufferProxy.get();
1728}
1729
1730IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1731{
1732 ASSERT(target == GL_TEXTURE_2D);
1733
daniel@transgaming.com61208202011-03-21 16:38:50 +00001734 if (!mIsRenderable)
1735 {
1736 convertToRenderTarget();
1737 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001738
1739 if (mTexture == NULL)
1740 {
1741 return NULL;
1742 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001743
1744 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001745
1746 IDirect3DSurface9 *renderTarget = NULL;
1747 mTexture->GetSurfaceLevel(0, &renderTarget);
1748
1749 return renderTarget;
1750}
1751
1752TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1753{
1754 mTexture = NULL;
1755}
1756
1757TextureCubeMap::~TextureCubeMap()
1758{
1759 for (int i = 0; i < 6; i++)
1760 {
1761 mFaceProxies[i].set(NULL);
1762 }
1763
1764 if (mTexture)
1765 {
1766 mTexture->Release();
1767 mTexture = NULL;
1768 }
1769}
1770
1771GLenum TextureCubeMap::getTarget() const
1772{
1773 return GL_TEXTURE_CUBE_MAP;
1774}
1775
daniel@transgaming.com61208202011-03-21 16:38:50 +00001776GLsizei TextureCubeMap::getWidth() const
1777{
1778 return mImageArray[0][0].width;
1779}
1780
1781GLsizei TextureCubeMap::getHeight() const
1782{
1783 return mImageArray[0][0].height;
1784}
1785
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001786GLenum TextureCubeMap::getInternalFormat() const
1787{
1788 return mImageArray[0][0].format;
1789}
1790
daniel@transgaming.com61208202011-03-21 16:38:50 +00001791GLenum TextureCubeMap::getType() const
1792{
1793 return mImageArray[0][0].type;
1794}
1795
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001796void 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 +00001797{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001798 setImage(0, 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::setImageNegX(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(1, 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::setImagePosY(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(2, 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::setImageNegY(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(3, 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::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001817{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001818 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001819}
1820
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001821void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001822{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001823 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001824}
1825
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001826void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001827{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001828 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001829
daniel@transgaming.com61208202011-03-21 16:38:50 +00001830 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001831}
1832
1833void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1834{
1835 int face = faceIndex(faceTarget);
1836 ASSERT(mImageArray[face][level].surface != NULL);
1837
1838 if (level < levelCount())
1839 {
1840 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1841 ASSERT(destLevel != NULL);
1842
1843 if (destLevel != NULL)
1844 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001845 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001846
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001847 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001848
1849 POINT destPoint;
1850 destPoint.x = sourceRect.left;
1851 destPoint.y = sourceRect.top;
1852
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001853 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001854 ASSERT(SUCCEEDED(result));
1855
1856 destLevel->Release();
1857
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001858 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001859 }
1860 }
1861}
1862
1863void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1864{
1865 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1866 {
1867 commitRect(target, level, xoffset, yoffset, width, height);
1868 }
1869}
1870
1871void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1872{
1873 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1874 {
1875 commitRect(target, level, xoffset, yoffset, width, height);
1876 }
1877}
1878
1879// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1880bool TextureCubeMap::isComplete() const
1881{
1882 int size = mImageArray[0][0].width;
1883
1884 if (size <= 0)
1885 {
1886 return false;
1887 }
1888
1889 bool mipmapping;
1890
1891 switch (mMinFilter)
1892 {
1893 case GL_NEAREST:
1894 case GL_LINEAR:
1895 mipmapping = false;
1896 break;
1897 case GL_NEAREST_MIPMAP_NEAREST:
1898 case GL_LINEAR_MIPMAP_NEAREST:
1899 case GL_NEAREST_MIPMAP_LINEAR:
1900 case GL_LINEAR_MIPMAP_LINEAR:
1901 mipmapping = true;
1902 break;
1903 default: UNREACHABLE();
1904 }
1905
1906 for (int face = 0; face < 6; face++)
1907 {
1908 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1909 {
1910 return false;
1911 }
1912 }
1913
1914 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1915 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1916 {
1917 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1918 {
1919 return false;
1920 }
1921 }
1922
1923 if (mipmapping)
1924 {
1925 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1926 {
1927 return false;
1928 }
1929
1930 int q = log2(size);
1931
1932 for (int face = 0; face < 6; face++)
1933 {
1934 for (int level = 1; level <= q; level++)
1935 {
1936 if (mImageArray[face][level].format != mImageArray[0][0].format)
1937 {
1938 return false;
1939 }
1940
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001941 if (mImageArray[face][level].type != mImageArray[0][0].type)
1942 {
1943 return false;
1944 }
1945
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001946 if (mImageArray[face][level].width != std::max(1, size >> level))
1947 {
1948 return false;
1949 }
1950
1951 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1952 }
1953 }
1954 }
1955
1956 return true;
1957}
1958
1959bool TextureCubeMap::isCompressed() const
1960{
1961 return IsCompressed(getInternalFormat());
1962}
1963
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001964IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1965{
1966 return mTexture;
1967}
1968
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001969// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001970void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001971{
1972 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001973 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
1974 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001975
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001976 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001977 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001978
1979 if (FAILED(result))
1980 {
1981 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001982 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001983 }
1984
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001985 if (mTexture)
1986 {
1987 mTexture->Release();
1988 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001989
1990 mTexture = texture;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001991 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001992 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001993}
1994
1995void TextureCubeMap::updateTexture()
1996{
1997 IDirect3DDevice9 *device = getDevice();
1998
1999 for (int face = 0; face < 6; face++)
2000 {
2001 int levels = levelCount();
2002 for (int level = 0; level < levels; level++)
2003 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002004 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002005
daniel@transgaming.com61208202011-03-21 16:38:50 +00002006 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002007 {
2008 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2009 ASSERT(levelSurface != NULL);
2010
2011 if (levelSurface != NULL)
2012 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002013 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002014 ASSERT(SUCCEEDED(result));
2015
2016 levelSurface->Release();
2017
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002018 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002019 }
2020 }
2021 }
2022 }
2023}
2024
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002025void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002026{
2027 IDirect3DCubeTexture9 *texture = NULL;
2028
daniel@transgaming.com61208202011-03-21 16:38:50 +00002029 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002030 {
2031 egl::Display *display = getDisplay();
2032 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002033 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
2034 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002035
daniel@transgaming.com61208202011-03-21 16:38:50 +00002036 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002037
2038 if (FAILED(result))
2039 {
2040 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002041 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002042 }
2043
2044 if (mTexture != NULL)
2045 {
2046 int levels = levelCount();
2047 for (int f = 0; f < 6; f++)
2048 {
2049 for (int i = 0; i < levels; i++)
2050 {
2051 IDirect3DSurface9 *source;
2052 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2053
2054 if (FAILED(result))
2055 {
2056 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2057
2058 texture->Release();
2059
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002060 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002061 }
2062
2063 IDirect3DSurface9 *dest;
2064 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2065
2066 if (FAILED(result))
2067 {
2068 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2069
2070 texture->Release();
2071 source->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 display->endScene();
2077 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2078
2079 if (FAILED(result))
2080 {
2081 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2082
2083 texture->Release();
2084 source->Release();
2085 dest->Release();
2086
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002087 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002088 }
2089 }
2090 }
2091 }
2092 }
2093
2094 if (mTexture != NULL)
2095 {
2096 mTexture->Release();
2097 }
2098
2099 mTexture = texture;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00002100 mDirty = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002101 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002102}
2103
daniel@transgaming.com61208202011-03-21 16:38:50 +00002104void 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 +00002105{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002106 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002107
daniel@transgaming.com61208202011-03-21 16:38:50 +00002108 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002109}
2110
2111unsigned int TextureCubeMap::faceIndex(GLenum face)
2112{
2113 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2114 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2115 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2116 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2117 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2118
2119 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2120}
2121
daniel@transgaming.com61208202011-03-21 16:38:50 +00002122void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002123{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002124 GLsizei textureWidth = mImageArray[0][0].width;
2125 GLsizei textureHeight = mImageArray[0][0].height;
2126 GLenum textureFormat = mImageArray[0][0].format;
2127 GLenum textureType = mImageArray[0][0].type;
2128
daniel@transgaming.com61208202011-03-21 16:38:50 +00002129 mImageArray[face][level].width = width;
2130 mImageArray[face][level].height = height;
2131 mImageArray[face][level].format = format;
2132 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002133
daniel@transgaming.com61208202011-03-21 16:38:50 +00002134 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002135 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002136 return;
2137 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002138
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002139 bool sizeOkay = (textureWidth >> level == width);
2140 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002141
2142 if (!textureOkay) // Purge all the levels and the texture.
2143 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002144 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2145 {
2146 for (int f = 0; f < 6; f++)
2147 {
2148 if (mImageArray[f][i].surface != NULL)
2149 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002150 mImageArray[f][i].surface->Release();
2151 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002152 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002153 }
2154 }
2155 }
2156
2157 if (mTexture != NULL)
2158 {
2159 mTexture->Release();
2160 mTexture = NULL;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00002161 mDirty = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002162 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002163 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002164 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002165}
2166
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002167void 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 +00002168{
2169 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2170
2171 if (!renderTarget)
2172 {
2173 ERR("Failed to retrieve the render target.");
2174 return error(GL_OUT_OF_MEMORY);
2175 }
2176
2177 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002178 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002179
daniel@transgaming.comf4e36032011-03-21 16:38:59 +00002180 if (!isRenderableFormat() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002181 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002182 copyNonRenderable(&mImageArray[faceindex][level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183 }
2184 else
2185 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002186 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002187 {
2188 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002189 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002190
2191 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002192
2193 ASSERT(width == height);
2194
2195 if (width > 0 && level < levelCount())
2196 {
2197 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2198 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2199 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2200 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2201 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2202
2203 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2204
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002205 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002206 dest->Release();
2207 }
2208 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002209}
2210
2211IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2212{
2213 if (mTexture == NULL)
2214 {
2215 UNREACHABLE();
2216 return NULL;
2217 }
2218
2219 IDirect3DSurface9 *surface = NULL;
2220
2221 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2222
2223 return (SUCCEEDED(hr)) ? surface : NULL;
2224}
2225
2226void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2227{
2228 GLsizei size = mImageArray[faceIndex(target)][level].width;
2229
2230 if (xoffset + width > size || yoffset + height > size)
2231 {
2232 return error(GL_INVALID_VALUE);
2233 }
2234
2235 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2236
2237 if (!renderTarget)
2238 {
2239 ERR("Failed to retrieve the render target.");
2240 return error(GL_OUT_OF_MEMORY);
2241 }
2242
2243 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002244 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 +00002245
2246 if (!isRenderableFormat())
2247 {
2248 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2249 }
2250 else
2251 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002252 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002253 {
2254 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002255 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002256
2257 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002258
2259 if (level < levelCount())
2260 {
2261 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2262 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2263 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2264 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2265 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2266
2267 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2268
2269 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2270
2271 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2272 dest->Release();
2273 }
2274 }
2275}
2276
2277bool TextureCubeMap::isCubeComplete() const
2278{
2279 if (mImageArray[0][0].width == 0)
2280 {
2281 return false;
2282 }
2283
2284 for (unsigned int f = 1; f < 6; f++)
2285 {
2286 if (mImageArray[f][0].width != mImageArray[0][0].width
2287 || mImageArray[f][0].format != mImageArray[0][0].format)
2288 {
2289 return false;
2290 }
2291 }
2292
2293 return true;
2294}
2295
2296void TextureCubeMap::generateMipmaps()
2297{
2298 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2299 {
2300 return error(GL_INVALID_OPERATION);
2301 }
2302
2303 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2304 unsigned int q = log2(mImageArray[0][0].width);
2305 for (unsigned int f = 0; f < 6; f++)
2306 {
2307 for (unsigned int i = 1; i <= q; i++)
2308 {
2309 if (mImageArray[f][i].surface != NULL)
2310 {
2311 mImageArray[f][i].surface->Release();
2312 mImageArray[f][i].surface = NULL;
2313 }
2314
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002315 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2316 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002317 mImageArray[f][i].format = mImageArray[f][0].format;
2318 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002319 }
2320 }
2321
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002322 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002323 {
2324 if (mTexture == NULL)
2325 {
2326 return;
2327 }
2328
2329 for (unsigned int f = 0; f < 6; f++)
2330 {
2331 for (unsigned int i = 1; i <= q; i++)
2332 {
2333 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2334 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2335
2336 if (upper != NULL && lower != NULL)
2337 {
2338 getBlitter()->boxFilter(upper, lower);
2339 }
2340
2341 if (upper != NULL) upper->Release();
2342 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002343
2344 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002345 }
2346 }
2347 }
2348 else
2349 {
2350 for (unsigned int f = 0; f < 6; f++)
2351 {
2352 for (unsigned int i = 1; i <= q; i++)
2353 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002354 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002355 if (mImageArray[f][i].surface == NULL)
2356 {
2357 return error(GL_OUT_OF_MEMORY);
2358 }
2359
2360 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2361 {
2362 ERR(" failed to load filter %d to %d.", i - 1, i);
2363 }
2364
2365 mImageArray[f][i].dirty = true;
2366 }
2367 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002368 }
2369}
2370
2371Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2372{
2373 if (!IsCubemapTextureTarget(target))
2374 {
2375 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2376 }
2377
2378 unsigned int face = faceIndex(target);
2379
2380 if (mFaceProxies[face].get() == NULL)
2381 {
2382 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2383 }
2384
2385 return mFaceProxies[face].get();
2386}
2387
2388IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2389{
2390 ASSERT(IsCubemapTextureTarget(target));
2391
daniel@transgaming.com61208202011-03-21 16:38:50 +00002392 if (!mIsRenderable)
2393 {
2394 convertToRenderTarget();
2395 }
2396
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002397 if (mTexture == NULL)
2398 {
2399 return NULL;
2400 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002401
2402 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002403
2404 IDirect3DSurface9 *renderTarget = NULL;
2405 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2406
2407 return renderTarget;
2408}
2409
2410}