blob: f08dbe88a822b71de00280ddfede7fc82f185147 [file] [log] [blame]
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Texture.cpp: Implements the gl::Texture class and its derived classes
8// Texture2D and TextureCubeMap. Implements GL texture objects and related
9// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
10
11#include "libGLESv2/Texture.h"
12
13#include <d3dx9tex.h>
14
15#include <algorithm>
16
17#include "common/debug.h"
18
19#include "libGLESv2/main.h"
20#include "libGLESv2/mathutil.h"
21#include "libGLESv2/utilities.h"
22#include "libGLESv2/Blit.h"
23#include "libGLESv2/Framebuffer.h"
24
25namespace gl
26{
27
28Texture::Image::Image()
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +000029 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000030{
31}
32
33Texture::Image::~Image()
34{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000035 if (surface)
36 {
37 surface->Release();
38 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000039}
40
41Texture::Texture(GLuint id) : RefCountObject(id)
42{
43 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
44 mMagFilter = GL_LINEAR;
45 mWrapS = GL_REPEAT;
46 mWrapT = GL_REPEAT;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000047 mDirtyParameters = true;
48
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000049 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000050}
51
52Texture::~Texture()
53{
54}
55
56Blit *Texture::getBlitter()
57{
58 Context *context = getContext();
59 return context->getBlitter();
60}
61
62// Returns true on successful filter state update (valid enum parameter)
63bool Texture::setMinFilter(GLenum filter)
64{
65 switch (filter)
66 {
67 case GL_NEAREST:
68 case GL_LINEAR:
69 case GL_NEAREST_MIPMAP_NEAREST:
70 case GL_LINEAR_MIPMAP_NEAREST:
71 case GL_NEAREST_MIPMAP_LINEAR:
72 case GL_LINEAR_MIPMAP_LINEAR:
73 {
74 if (mMinFilter != filter)
75 {
76 mMinFilter = filter;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000077 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000078 }
79 return true;
80 }
81 default:
82 return false;
83 }
84}
85
86// Returns true on successful filter state update (valid enum parameter)
87bool Texture::setMagFilter(GLenum filter)
88{
89 switch (filter)
90 {
91 case GL_NEAREST:
92 case GL_LINEAR:
93 {
94 if (mMagFilter != filter)
95 {
96 mMagFilter = filter;
daniel@transgaming.comaed18322011-03-21 16:38:13 +000097 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000098 }
99 return true;
100 }
101 default:
102 return false;
103 }
104}
105
106// Returns true on successful wrap state update (valid enum parameter)
107bool Texture::setWrapS(GLenum wrap)
108{
109 switch (wrap)
110 {
111 case GL_REPEAT:
112 case GL_CLAMP_TO_EDGE:
113 case GL_MIRRORED_REPEAT:
114 {
115 if (mWrapS != wrap)
116 {
117 mWrapS = wrap;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000118 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000119 }
120 return true;
121 }
122 default:
123 return false;
124 }
125}
126
127// Returns true on successful wrap state update (valid enum parameter)
128bool Texture::setWrapT(GLenum wrap)
129{
130 switch (wrap)
131 {
132 case GL_REPEAT:
133 case GL_CLAMP_TO_EDGE:
134 case GL_MIRRORED_REPEAT:
135 {
136 if (mWrapT != wrap)
137 {
138 mWrapT = wrap;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000139 mDirtyParameters = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000140 }
141 return true;
142 }
143 default:
144 return false;
145 }
146}
147
148GLenum Texture::getMinFilter() const
149{
150 return mMinFilter;
151}
152
153GLenum Texture::getMagFilter() const
154{
155 return mMagFilter;
156}
157
158GLenum Texture::getWrapS() const
159{
160 return mWrapS;
161}
162
163GLenum Texture::getWrapT() const
164{
165 return mWrapT;
166}
167
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000168bool Texture::isFloatingPoint() const
169{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000170 return (getType() == GL_FLOAT || getType() == GL_HALF_FLOAT_OES);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000171}
172
173bool Texture::isRenderableFormat() const
174{
175 D3DFORMAT format = getD3DFormat();
176
177 switch(format)
178 {
179 case D3DFMT_L8:
180 case D3DFMT_A8L8:
181 case D3DFMT_DXT1:
182 return false;
183 case D3DFMT_A8R8G8B8:
184 case D3DFMT_X8R8G8B8:
185 case D3DFMT_A16B16G16R16F:
186 case D3DFMT_A32B32G32R32F:
187 return true;
188 default:
189 UNREACHABLE();
190 }
191
192 return false;
193}
194
195// Selects an internal Direct3D 9 format for storing an Image
196D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
197{
198 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
199 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
200 {
201 return D3DFMT_DXT1;
202 }
203 else if (type == GL_FLOAT)
204 {
205 return D3DFMT_A32B32G32R32F;
206 }
207 else if (type == GL_HALF_FLOAT_OES)
208 {
209 return D3DFMT_A16B16G16R16F;
210 }
211 else if (type == GL_UNSIGNED_BYTE)
212 {
213 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
214 {
215 return D3DFMT_L8;
216 }
217 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
218 {
219 return D3DFMT_A8L8;
220 }
221 else if (format == GL_RGB)
222 {
223 return D3DFMT_X8R8G8B8;
224 }
225
226 return D3DFMT_A8R8G8B8;
227 }
228
229 return D3DFMT_A8R8G8B8;
230}
231
232// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
233// into the target pixel rectangle at output with outputPitch bytes in between each line.
234void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
235 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
236{
237 GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
238 input = ((char*)input) - inputPitch * (height - 1);
239
240 switch (type)
241 {
242 case GL_UNSIGNED_BYTE:
243 switch (format)
244 {
245 case GL_ALPHA:
246 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
247 break;
248 case GL_LUMINANCE:
249 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
250 break;
251 case GL_LUMINANCE_ALPHA:
252 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
253 break;
254 case GL_RGB:
255 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
256 break;
257 case GL_RGBA:
258 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
259 break;
260 case GL_BGRA_EXT:
261 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
262 break;
263 default: UNREACHABLE();
264 }
265 break;
266 case GL_UNSIGNED_SHORT_5_6_5:
267 switch (format)
268 {
269 case GL_RGB:
270 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
271 break;
272 default: UNREACHABLE();
273 }
274 break;
275 case GL_UNSIGNED_SHORT_4_4_4_4:
276 switch (format)
277 {
278 case GL_RGBA:
279 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
280 break;
281 default: UNREACHABLE();
282 }
283 break;
284 case GL_UNSIGNED_SHORT_5_5_5_1:
285 switch (format)
286 {
287 case GL_RGBA:
288 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
289 break;
290 default: UNREACHABLE();
291 }
292 break;
293 case GL_FLOAT:
294 switch (format)
295 {
296 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
297 case GL_ALPHA:
298 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
299 break;
300 case GL_LUMINANCE:
301 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
302 break;
303 case GL_LUMINANCE_ALPHA:
304 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
305 break;
306 case GL_RGB:
307 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
308 break;
309 case GL_RGBA:
310 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
311 break;
312 default: UNREACHABLE();
313 }
314 break;
315 case GL_HALF_FLOAT_OES:
316 switch (format)
317 {
318 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
319 case GL_ALPHA:
320 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
321 break;
322 case GL_LUMINANCE:
323 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
324 break;
325 case GL_LUMINANCE_ALPHA:
326 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
327 break;
328 case GL_RGB:
329 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
330 break;
331 case GL_RGBA:
332 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
333 break;
334 default: UNREACHABLE();
335 }
336 break;
337 default: UNREACHABLE();
338 }
339}
340
341void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
342 int inputPitch, const void *input, size_t outputPitch, void *output) const
343{
344 const unsigned char *source = NULL;
345 unsigned char *dest = NULL;
346
347 for (int y = 0; y < height; y++)
348 {
349 source = static_cast<const unsigned char*>(input) + y * inputPitch;
350 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
351 for (int x = 0; x < width; x++)
352 {
353 dest[4 * x + 0] = 0;
354 dest[4 * x + 1] = 0;
355 dest[4 * x + 2] = 0;
356 dest[4 * x + 3] = source[x];
357 }
358 }
359}
360
361void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
362 int inputPitch, const void *input, size_t outputPitch, void *output) const
363{
364 const float *source = NULL;
365 float *dest = NULL;
366
367 for (int y = 0; y < height; y++)
368 {
369 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
370 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
371 for (int x = 0; x < width; x++)
372 {
373 dest[4 * x + 0] = 0;
374 dest[4 * x + 1] = 0;
375 dest[4 * x + 2] = 0;
376 dest[4 * x + 3] = source[x];
377 }
378 }
379}
380
381void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
382 int inputPitch, const void *input, size_t outputPitch, void *output) const
383{
384 const unsigned short *source = NULL;
385 unsigned short *dest = NULL;
386
387 for (int y = 0; y < height; y++)
388 {
389 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
390 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
391 for (int x = 0; x < width; x++)
392 {
393 dest[4 * x + 0] = 0;
394 dest[4 * x + 1] = 0;
395 dest[4 * x + 2] = 0;
396 dest[4 * x + 3] = source[x];
397 }
398 }
399}
400
401void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
402 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
403{
404 const int destBytesPerPixel = native? 1: 4;
405 const unsigned char *source = NULL;
406 unsigned char *dest = NULL;
407
408 for (int y = 0; y < height; y++)
409 {
410 source = static_cast<const unsigned char*>(input) + y * inputPitch;
411 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
412
413 if (!native) // BGRA8 destination format
414 {
415 for (int x = 0; x < width; x++)
416 {
417 dest[4 * x + 0] = source[x];
418 dest[4 * x + 1] = source[x];
419 dest[4 * x + 2] = source[x];
420 dest[4 * x + 3] = 0xFF;
421 }
422 }
423 else // L8 destination format
424 {
425 memcpy(dest, source, width);
426 }
427 }
428}
429
430void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
431 int inputPitch, const void *input, size_t outputPitch, void *output) const
432{
433 const float *source = NULL;
434 float *dest = NULL;
435
436 for (int y = 0; y < height; y++)
437 {
438 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
439 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
440 for (int x = 0; x < width; x++)
441 {
442 dest[4 * x + 0] = source[x];
443 dest[4 * x + 1] = source[x];
444 dest[4 * x + 2] = source[x];
445 dest[4 * x + 3] = 1.0f;
446 }
447 }
448}
449
450void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
451 int inputPitch, const void *input, size_t outputPitch, void *output) const
452{
453 const unsigned short *source = NULL;
454 unsigned short *dest = NULL;
455
456 for (int y = 0; y < height; y++)
457 {
458 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
459 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
460 for (int x = 0; x < width; x++)
461 {
462 dest[4 * x + 0] = source[x];
463 dest[4 * x + 1] = source[x];
464 dest[4 * x + 2] = source[x];
465 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
466 }
467 }
468}
469
470void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
471 int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
472{
473 const int destBytesPerPixel = native? 2: 4;
474 const unsigned char *source = NULL;
475 unsigned char *dest = NULL;
476
477 for (int y = 0; y < height; y++)
478 {
479 source = static_cast<const unsigned char*>(input) + y * inputPitch;
480 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
481
482 if (!native) // BGRA8 destination format
483 {
484 for (int x = 0; x < width; x++)
485 {
486 dest[4 * x + 0] = source[2*x+0];
487 dest[4 * x + 1] = source[2*x+0];
488 dest[4 * x + 2] = source[2*x+0];
489 dest[4 * x + 3] = source[2*x+1];
490 }
491 }
492 else
493 {
494 memcpy(dest, source, width * 2);
495 }
496 }
497}
498
499void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
500 int inputPitch, const void *input, size_t outputPitch, void *output) const
501{
502 const float *source = NULL;
503 float *dest = NULL;
504
505 for (int y = 0; y < height; y++)
506 {
507 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
508 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
509 for (int x = 0; x < width; x++)
510 {
511 dest[4 * x + 0] = source[2*x+0];
512 dest[4 * x + 1] = source[2*x+0];
513 dest[4 * x + 2] = source[2*x+0];
514 dest[4 * x + 3] = source[2*x+1];
515 }
516 }
517}
518
519void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
520 int inputPitch, const void *input, size_t outputPitch, void *output) const
521{
522 const unsigned short *source = NULL;
523 unsigned short *dest = NULL;
524
525 for (int y = 0; y < height; y++)
526 {
527 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
528 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
529 for (int x = 0; x < width; x++)
530 {
531 dest[4 * x + 0] = source[2*x+0];
532 dest[4 * x + 1] = source[2*x+0];
533 dest[4 * x + 2] = source[2*x+0];
534 dest[4 * x + 3] = source[2*x+1];
535 }
536 }
537}
538
539void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
540 int inputPitch, const void *input, size_t outputPitch, void *output) const
541{
542 const unsigned char *source = NULL;
543 unsigned char *dest = NULL;
544
545 for (int y = 0; y < height; y++)
546 {
547 source = static_cast<const unsigned char*>(input) + y * inputPitch;
548 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
549 for (int x = 0; x < width; x++)
550 {
551 dest[4 * x + 0] = source[x * 3 + 2];
552 dest[4 * x + 1] = source[x * 3 + 1];
553 dest[4 * x + 2] = source[x * 3 + 0];
554 dest[4 * x + 3] = 0xFF;
555 }
556 }
557}
558
559void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
560 int inputPitch, const void *input, size_t outputPitch, void *output) const
561{
562 const unsigned short *source = NULL;
563 unsigned char *dest = NULL;
564
565 for (int y = 0; y < height; y++)
566 {
567 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
568 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
569 for (int x = 0; x < width; x++)
570 {
571 unsigned short rgba = source[x];
572 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
573 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
574 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
575 dest[4 * x + 3] = 0xFF;
576 }
577 }
578}
579
580void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
581 int inputPitch, const void *input, size_t outputPitch, void *output) const
582{
583 const float *source = NULL;
584 float *dest = NULL;
585
586 for (int y = 0; y < height; y++)
587 {
588 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
589 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
590 for (int x = 0; x < width; x++)
591 {
592 dest[4 * x + 0] = source[x * 3 + 0];
593 dest[4 * x + 1] = source[x * 3 + 1];
594 dest[4 * x + 2] = source[x * 3 + 2];
595 dest[4 * x + 3] = 1.0f;
596 }
597 }
598}
599
600void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
601 int inputPitch, const void *input, size_t outputPitch, void *output) const
602{
603 const unsigned short *source = NULL;
604 unsigned short *dest = NULL;
605
606 for (int y = 0; y < height; y++)
607 {
608 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
609 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
610 for (int x = 0; x < width; x++)
611 {
612 dest[4 * x + 0] = source[x * 3 + 0];
613 dest[4 * x + 1] = source[x * 3 + 1];
614 dest[4 * x + 2] = source[x * 3 + 2];
615 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
616 }
617 }
618}
619
620void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
621 int inputPitch, const void *input, size_t outputPitch, void *output) const
622{
623 const unsigned char *source = NULL;
624 unsigned char *dest = NULL;
625
626 for (int y = 0; y < height; y++)
627 {
628 source = static_cast<const unsigned char*>(input) + y * inputPitch;
629 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
630 for (int x = 0; x < width; x++)
631 {
632 dest[4 * x + 0] = source[x * 4 + 2];
633 dest[4 * x + 1] = source[x * 4 + 1];
634 dest[4 * x + 2] = source[x * 4 + 0];
635 dest[4 * x + 3] = source[x * 4 + 3];
636 }
637 }
638}
639
640void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
641 int inputPitch, const void *input, size_t outputPitch, void *output) const
642{
643 const unsigned short *source = NULL;
644 unsigned char *dest = NULL;
645
646 for (int y = 0; y < height; y++)
647 {
648 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
649 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
650 for (int x = 0; x < width; x++)
651 {
652 unsigned short rgba = source[x];
653 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
654 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
655 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
656 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
657 }
658 }
659}
660
661void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
662 int inputPitch, const void *input, size_t outputPitch, void *output) const
663{
664 const unsigned short *source = NULL;
665 unsigned char *dest = NULL;
666
667 for (int y = 0; y < height; y++)
668 {
669 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
670 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
671 for (int x = 0; x < width; x++)
672 {
673 unsigned short rgba = source[x];
674 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
675 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
676 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
677 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
678 }
679 }
680}
681
682void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
683 int inputPitch, const void *input, size_t outputPitch, void *output) const
684{
685 const float *source = NULL;
686 float *dest = NULL;
687
688 for (int y = 0; y < height; y++)
689 {
690 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
691 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
692 memcpy(dest, source, width * 16);
693 }
694}
695
696void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
697 int inputPitch, const void *input, size_t outputPitch, void *output) const
698{
699 const unsigned char *source = NULL;
700 unsigned char *dest = NULL;
701
702 for (int y = 0; y < height; y++)
703 {
704 source = static_cast<const unsigned char*>(input) + y * inputPitch;
705 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
706 memcpy(dest, source, width * 8);
707 }
708}
709
710void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
711 int inputPitch, const void *input, size_t outputPitch, void *output) const
712{
713 const unsigned char *source = NULL;
714 unsigned char *dest = NULL;
715
716 for (int y = 0; y < height; y++)
717 {
718 source = static_cast<const unsigned char*>(input) + y * inputPitch;
719 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
720 memcpy(dest, source, width*4);
721 }
722}
723
724void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
725 int inputPitch, const void *input, size_t outputPitch, void *output) const
726{
727 ASSERT(xoffset % 4 == 0);
728 ASSERT(yoffset % 4 == 0);
729 ASSERT(width % 4 == 0 || width == 2 || width == 1);
730 ASSERT(inputPitch % 8 == 0);
731 ASSERT(outputPitch % 8 == 0);
732
733 const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
734 unsigned int *dest = reinterpret_cast<unsigned int*>(output);
735
736 switch (height)
737 {
738 case 1:
739 // Round width up in case it is 1.
740 for (int x = 0; x < (width + 1) / 2; x += 2)
741 {
742 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
743 dest[x] = source[x];
744
745 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
746 dest[x + 1] = source[x + 1];
747 }
748 break;
749 case 2:
750 // Round width up in case it is 1.
751 for (int x = 0; x < (width + 1) / 2; x += 2)
752 {
753 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
754 dest[x] = source[x];
755
756 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 2 rows being unused. Only the top 2 rows should be flipped.
757 dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
758 ((source[x + 1] >> 8) & 0x000000FF);
759 }
760 break;
761 default:
762 ASSERT(height % 4 == 0);
763 for (int y = 0; y < height / 4; ++y)
764 {
765 const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
766 unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
767
768 // Round width up in case it is 1.
769 for (int x = 0; x < (width + 1) / 2; x += 2)
770 {
771 // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
772 dest[x] = source[x];
773
774 // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
775 dest[x + 1] = (source[x + 1] >> 24) |
776 ((source[x + 1] << 8) & 0x00FF0000) |
777 ((source[x + 1] >> 8) & 0x0000FF00) |
778 (source[x + 1] << 24);
779 }
780 }
781 break;
782 }
783}
784
daniel@transgaming.com61208202011-03-21 16:38:50 +0000785void Texture::createSurface(Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000786{
787 IDirect3DTexture9 *newTexture = NULL;
788 IDirect3DSurface9 *newSurface = NULL;
789
daniel@transgaming.com61208202011-03-21 16:38:50 +0000790 if (image->width != 0 && image->height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000791 {
792 int levelToFetch = 0;
daniel@transgaming.com61208202011-03-21 16:38:50 +0000793 GLsizei requestWidth = image->width;
794 GLsizei requestHeight = image->height;
795 if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000796 {
797 bool isMult4 = false;
798 int upsampleCount = 0;
799 while (!isMult4)
800 {
801 requestWidth <<= 1;
802 requestHeight <<= 1;
803 upsampleCount++;
804 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
805 {
806 isMult4 = true;
807 }
808 }
809 levelToFetch = upsampleCount;
810 }
811
daniel@transgaming.com61208202011-03-21 16:38:50 +0000812 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(image->format, image->type),
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000813 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
814
815 if (FAILED(result))
816 {
817 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
818 return error(GL_OUT_OF_MEMORY);
819 }
820
821 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
822 newTexture->Release();
823 }
824
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000825 if (image->surface)
826 {
827 image->surface->Release();
828 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000829
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +0000830 image->surface = newSurface;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000831}
832
daniel@transgaming.com61208202011-03-21 16:38:50 +0000833void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000834{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000835 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000836
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000837 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000838 {
839 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000840 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000841
842 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000843 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000844
845 ASSERT(SUCCEEDED(result));
846
847 if (SUCCEEDED(result))
848 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000849 loadImageData(0, 0, image->width, image->height, image->format, image->type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000850 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000851 }
852
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000853 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000854 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000855}
856
daniel@transgaming.com61208202011-03-21 16:38:50 +0000857void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000858{
daniel@transgaming.com61208202011-03-21 16:38:50 +0000859 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000860
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000861 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000862 {
863 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000864 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000865
866 ASSERT(SUCCEEDED(result));
867
868 if (SUCCEEDED(result))
869 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000870 int inputPitch = ComputeCompressedPitch(image->width, image->format);
871 int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
872 loadCompressedImageData(0, 0, image->width, image->height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000873 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000874 }
875
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000876 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000877 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000878}
879
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000880bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000881{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000882 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000883 {
884 error(GL_INVALID_VALUE);
885 return false;
886 }
887
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000888 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000889 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000890 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000891 }
892
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000893 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000894 {
895 D3DSURFACE_DESC description;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000896 image->surface->GetDesc(&description);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000897
898 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000899 HRESULT result = image->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000900
901 ASSERT(SUCCEEDED(result));
902
903 if (SUCCEEDED(result))
904 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000905 loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
906 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000907 }
908
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000909 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000910 }
911
912 return true;
913}
914
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000915bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000916{
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000917 if (width + xoffset > image->width || height + yoffset > image->height)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000918 {
919 error(GL_INVALID_VALUE);
920 return false;
921 }
922
923 if (format != getInternalFormat())
924 {
925 error(GL_INVALID_OPERATION);
926 return false;
927 }
928
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000929 if (!image->surface)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000930 {
daniel@transgaming.com61208202011-03-21 16:38:50 +0000931 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000932 }
933
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000934 if (pixels != NULL && image->surface != NULL)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000935 {
936 RECT updateRegion;
937 updateRegion.left = xoffset;
938 updateRegion.right = xoffset + width;
939 updateRegion.bottom = yoffset + height;
940 updateRegion.top = yoffset;
941
942 D3DLOCKED_RECT locked;
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000943 HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000944
945 ASSERT(SUCCEEDED(result));
946
947 if (SUCCEEDED(result))
948 {
949 int inputPitch = ComputeCompressedPitch(width, format);
950 int inputSize = ComputeCompressedSize(width, height, format);
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000951 loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
952 image->surface->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000953 }
954
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +0000955 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000956 }
957
958 return true;
959}
960
961// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +0000962void Texture::copyNonRenderable(Image *image, GLenum format, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000963{
964 IDirect3DDevice9 *device = getDevice();
965 IDirect3DSurface9 *surface = NULL;
966 D3DSURFACE_DESC description;
967 renderTarget->GetDesc(&description);
968
969 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
970
971 if (!SUCCEEDED(result))
972 {
973 ERR("Could not create matching destination surface.");
974 return error(GL_OUT_OF_MEMORY);
975 }
976
977 result = device->GetRenderTargetData(renderTarget, surface);
978
979 if (!SUCCEEDED(result))
980 {
981 ERR("GetRenderTargetData unexpectedly failed.");
982 surface->Release();
983 return error(GL_OUT_OF_MEMORY);
984 }
985
986 D3DLOCKED_RECT sourceLock = {0};
987 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
988 result = surface->LockRect(&sourceLock, &sourceRect, 0);
989
990 if (FAILED(result))
991 {
992 ERR("Failed to lock the source surface (rectangle might be invalid).");
993 surface->UnlockRect();
994 surface->Release();
995 return error(GL_OUT_OF_MEMORY);
996 }
997
998 if (!image->surface)
999 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001000 createSurface(image);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001001 }
1002
1003 if (image->surface == NULL)
1004 {
1005 ERR("Failed to create an image surface.");
1006 surface->UnlockRect();
1007 surface->Release();
1008 return error(GL_OUT_OF_MEMORY);
1009 }
1010
1011 D3DLOCKED_RECT destLock = {0};
1012 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
1013 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
1014 result = image->surface->LockRect(&destLock, &destRect, 0);
1015
1016 if (FAILED(result))
1017 {
1018 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1019 surface->UnlockRect();
1020 surface->Release();
1021 return error(GL_OUT_OF_MEMORY);
1022 }
1023
1024 if (destLock.pBits && sourceLock.pBits)
1025 {
1026 unsigned char *source = (unsigned char*)sourceLock.pBits;
1027 unsigned char *dest = (unsigned char*)destLock.pBits;
1028
1029 switch (description.Format)
1030 {
1031 case D3DFMT_X8R8G8B8:
1032 case D3DFMT_A8R8G8B8:
1033 switch(getD3DFormat())
1034 {
1035 case D3DFMT_L8:
1036 for(int y = 0; y < height; y++)
1037 {
1038 for(int x = 0; x < width; x++)
1039 {
1040 dest[x] = source[x * 4 + 2];
1041 }
1042
1043 source += sourceLock.Pitch;
1044 dest += destLock.Pitch;
1045 }
1046 break;
1047 case D3DFMT_A8L8:
1048 for(int y = 0; y < height; y++)
1049 {
1050 for(int x = 0; x < width; x++)
1051 {
1052 dest[x * 2 + 0] = source[x * 4 + 2];
1053 dest[x * 2 + 1] = source[x * 4 + 3];
1054 }
1055
1056 source += sourceLock.Pitch;
1057 dest += destLock.Pitch;
1058 }
1059 break;
1060 default:
1061 UNREACHABLE();
1062 }
1063 break;
1064 case D3DFMT_R5G6B5:
1065 switch(getD3DFormat())
1066 {
1067 case D3DFMT_L8:
1068 for(int y = 0; y < height; y++)
1069 {
1070 for(int x = 0; x < width; x++)
1071 {
1072 unsigned char red = source[x * 2 + 1] & 0xF8;
1073 dest[x] = red | (red >> 5);
1074 }
1075
1076 source += sourceLock.Pitch;
1077 dest += destLock.Pitch;
1078 }
1079 break;
1080 default:
1081 UNREACHABLE();
1082 }
1083 break;
1084 case D3DFMT_A1R5G5B5:
1085 switch(getD3DFormat())
1086 {
1087 case D3DFMT_L8:
1088 for(int y = 0; y < height; y++)
1089 {
1090 for(int x = 0; x < width; x++)
1091 {
1092 unsigned char red = source[x * 2 + 1] & 0x7C;
1093 dest[x] = (red << 1) | (red >> 4);
1094 }
1095
1096 source += sourceLock.Pitch;
1097 dest += destLock.Pitch;
1098 }
1099 break;
1100 case D3DFMT_A8L8:
1101 for(int y = 0; y < height; y++)
1102 {
1103 for(int x = 0; x < width; x++)
1104 {
1105 unsigned char red = source[x * 2 + 1] & 0x7C;
1106 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1107 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1108 }
1109
1110 source += sourceLock.Pitch;
1111 dest += destLock.Pitch;
1112 }
1113 break;
1114 default:
1115 UNREACHABLE();
1116 }
1117 break;
1118 default:
1119 UNREACHABLE();
1120 }
1121
1122 image->dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001123 }
1124
1125 image->surface->UnlockRect();
1126 surface->UnlockRect();
1127 surface->Release();
1128}
1129
1130D3DFORMAT Texture::getD3DFormat() const
1131{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001132 return selectFormat(getInternalFormat(), getType());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001133}
1134
1135IDirect3DBaseTexture9 *Texture::getTexture()
1136{
1137 if (!isComplete())
1138 {
1139 return NULL;
1140 }
1141
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001142 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001143 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001144 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001145 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001146
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001147 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001148
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001149 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001150}
1151
1152bool Texture::isDirty() const
1153{
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001154 return true;//(mDirty || mDirtyMetaData || dirtyImageData());
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001155}
1156
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001157GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1158{
1159 if (isPow2(width) && isPow2(height))
1160 {
1161 return maxlevel;
1162 }
1163 else
1164 {
1165 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1166 return 1;
1167 }
1168}
1169
1170GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1171{
1172 return creationLevels(size, size, maxlevel);
1173}
1174
1175int Texture::levelCount() const
1176{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001177 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001178}
1179
1180Texture2D::Texture2D(GLuint id) : Texture(id)
1181{
1182 mTexture = NULL;
1183}
1184
1185Texture2D::~Texture2D()
1186{
1187 mColorbufferProxy.set(NULL);
1188
1189 if (mTexture)
1190 {
1191 mTexture->Release();
1192 mTexture = NULL;
1193 }
1194}
1195
1196GLenum Texture2D::getTarget() const
1197{
1198 return GL_TEXTURE_2D;
1199}
1200
daniel@transgaming.com61208202011-03-21 16:38:50 +00001201GLsizei Texture2D::getWidth() const
1202{
1203 return mImageArray[0].width;
1204}
1205
1206GLsizei Texture2D::getHeight() const
1207{
1208 return mImageArray[0].height;
1209}
1210
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001211GLenum Texture2D::getInternalFormat() const
1212{
1213 return mImageArray[0].format;
1214}
1215
daniel@transgaming.com61208202011-03-21 16:38:50 +00001216GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001217{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001218 return mImageArray[0].type;
1219}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001220
daniel@transgaming.com61208202011-03-21 16:38:50 +00001221void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1222{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001223 GLsizei textureWidth = mImageArray[0].width;
1224 GLsizei textureHeight = mImageArray[0].height;
1225 GLenum textureFormat = mImageArray[0].format;
1226 GLenum textureType = mImageArray[0].type;
1227
daniel@transgaming.com61208202011-03-21 16:38:50 +00001228 mImageArray[level].width = width;
1229 mImageArray[level].height = height;
1230 mImageArray[level].format = format;
1231 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001232
daniel@transgaming.com61208202011-03-21 16:38:50 +00001233 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001234 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001235 return;
1236 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001237
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001238 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1239 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1240 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001241
1242 if (!textureOkay) // Purge all the levels and the texture.
1243 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001244 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1245 {
1246 if (mImageArray[i].surface != NULL)
1247 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001248 mImageArray[i].surface->Release();
1249 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001250 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001251 }
1252 }
1253
1254 if (mTexture != NULL)
1255 {
1256 mTexture->Release();
1257 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001258 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001259 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001260 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001261}
1262
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001263void 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 +00001264{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001265 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001266
daniel@transgaming.com61208202011-03-21 16:38:50 +00001267 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001268}
1269
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001270void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001271{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001272 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001273
daniel@transgaming.com61208202011-03-21 16:38:50 +00001274 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001275}
1276
1277void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1278{
1279 ASSERT(mImageArray[level].surface != NULL);
1280
1281 if (level < levelCount())
1282 {
1283 IDirect3DSurface9 *destLevel = NULL;
1284 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1285
1286 ASSERT(SUCCEEDED(result));
1287
1288 if (SUCCEEDED(result))
1289 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001290 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001291
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001292 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001293
1294 POINT destPoint;
1295 destPoint.x = sourceRect.left;
1296 destPoint.y = sourceRect.top;
1297
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001298 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001299 ASSERT(SUCCEEDED(result));
1300
1301 destLevel->Release();
1302
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001303 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001304 }
1305 }
1306}
1307
1308void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1309{
1310 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1311 {
1312 commitRect(level, xoffset, yoffset, width, height);
1313 }
1314}
1315
1316void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1317{
1318 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1319 {
1320 commitRect(level, xoffset, yoffset, width, height);
1321 }
1322}
1323
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001324void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001325{
1326 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1327
1328 if (!renderTarget)
1329 {
1330 ERR("Failed to retrieve the render target.");
1331 return error(GL_OUT_OF_MEMORY);
1332 }
1333
daniel@transgaming.com61208202011-03-21 16:38:50 +00001334 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001335
1336 if (!isRenderableFormat())
1337 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001338 copyNonRenderable(&mImageArray[level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001339 }
1340 else
1341 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001342 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001343 {
1344 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001345 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001346
1347 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001348
1349 if (width != 0 && height != 0 && level < levelCount())
1350 {
1351 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1352 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1353 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1354 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1355 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1356
1357 IDirect3DSurface9 *dest;
1358 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1359
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001360 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001361 dest->Release();
1362 }
1363 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001364}
1365
1366void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1367{
1368 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1369 {
1370 return error(GL_INVALID_VALUE);
1371 }
1372
1373 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1374
1375 if (!renderTarget)
1376 {
1377 ERR("Failed to retrieve the render target.");
1378 return error(GL_OUT_OF_MEMORY);
1379 }
1380
daniel@transgaming.com61208202011-03-21 16:38:50 +00001381 redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001382
1383 if (!isRenderableFormat())
1384 {
1385 copyNonRenderable(&mImageArray[level], getInternalFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
1386 }
1387 else
1388 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001389 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001390 {
1391 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001392 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001393
1394 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001395
1396 if (level < levelCount())
1397 {
1398 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1399 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1400 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1401 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1402 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1403
1404 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1405
1406 IDirect3DSurface9 *dest;
1407 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1408
1409 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1410 dest->Release();
1411 }
1412 }
1413}
1414
1415// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1416bool Texture2D::isComplete() const
1417{
1418 GLsizei width = mImageArray[0].width;
1419 GLsizei height = mImageArray[0].height;
1420
1421 if (width <= 0 || height <= 0)
1422 {
1423 return false;
1424 }
1425
1426 bool mipmapping = false;
1427
1428 switch (mMinFilter)
1429 {
1430 case GL_NEAREST:
1431 case GL_LINEAR:
1432 mipmapping = false;
1433 break;
1434 case GL_NEAREST_MIPMAP_NEAREST:
1435 case GL_LINEAR_MIPMAP_NEAREST:
1436 case GL_NEAREST_MIPMAP_LINEAR:
1437 case GL_LINEAR_MIPMAP_LINEAR:
1438 mipmapping = true;
1439 break;
1440 default: UNREACHABLE();
1441 }
1442
1443 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1444 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1445 {
1446 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1447 {
1448 return false;
1449 }
1450 }
1451
1452
1453 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1454 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1455 {
1456 return false;
1457 }
1458
1459 if (mipmapping)
1460 {
1461 if (!isPow2(width) || !isPow2(height))
1462 {
1463 return false;
1464 }
1465
1466 int q = log2(std::max(width, height));
1467
1468 for (int level = 1; level <= q; level++)
1469 {
1470 if (mImageArray[level].format != mImageArray[0].format)
1471 {
1472 return false;
1473 }
1474
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001475 if (mImageArray[level].type != mImageArray[0].type)
1476 {
1477 return false;
1478 }
1479
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001480 if (mImageArray[level].width != std::max(1, width >> level))
1481 {
1482 return false;
1483 }
1484
1485 if (mImageArray[level].height != std::max(1, height >> level))
1486 {
1487 return false;
1488 }
1489 }
1490 }
1491
1492 return true;
1493}
1494
1495bool Texture2D::isCompressed() const
1496{
1497 return IsCompressed(getInternalFormat());
1498}
1499
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001500IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1501{
1502 return mTexture;
1503}
1504
1505// Constructs a Direct3D 9 texture resource from the texture images
1506void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001507{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001508 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001509 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1510 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001511
daniel@transgaming.com61208202011-03-21 16:38:50 +00001512 IDirect3DTexture9 *texture = NULL;
1513 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 +00001514
1515 if (FAILED(result))
1516 {
1517 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001518 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001519 }
1520
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001521 if (mTexture)
1522 {
1523 mTexture->Release();
1524 }
1525
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001526 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001527 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001528}
1529
1530void Texture2D::updateTexture()
1531{
1532 IDirect3DDevice9 *device = getDevice();
1533
1534 int levels = levelCount();
1535
1536 for (int level = 0; level < levels; level++)
1537 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001538 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001539 {
1540 IDirect3DSurface9 *levelSurface = NULL;
1541 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1542
1543 ASSERT(SUCCEEDED(result));
1544
1545 if (SUCCEEDED(result))
1546 {
1547 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1548 ASSERT(SUCCEEDED(result));
1549
1550 levelSurface->Release();
1551
1552 mImageArray[level].dirty = false;
1553 }
1554 }
1555 }
1556}
1557
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001558void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001559{
1560 IDirect3DTexture9 *texture = NULL;
1561
daniel@transgaming.com61208202011-03-21 16:38:50 +00001562 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001563 {
1564 egl::Display *display = getDisplay();
1565 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001566 D3DFORMAT format = selectFormat(mImageArray[0].format, mImageArray[0].type);
1567 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001568
daniel@transgaming.com61208202011-03-21 16:38:50 +00001569 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 +00001570
1571 if (FAILED(result))
1572 {
1573 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001574 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001575 }
1576
1577 if (mTexture != NULL)
1578 {
1579 int levels = levelCount();
1580 for (int i = 0; i < levels; i++)
1581 {
1582 IDirect3DSurface9 *source;
1583 result = mTexture->GetSurfaceLevel(i, &source);
1584
1585 if (FAILED(result))
1586 {
1587 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1588
1589 texture->Release();
1590
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001591 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001592 }
1593
1594 IDirect3DSurface9 *dest;
1595 result = texture->GetSurfaceLevel(i, &dest);
1596
1597 if (FAILED(result))
1598 {
1599 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1600
1601 texture->Release();
1602 source->Release();
1603
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001604 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001605 }
1606
1607 display->endScene();
1608 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1609
1610 if (FAILED(result))
1611 {
1612 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1613
1614 texture->Release();
1615 source->Release();
1616 dest->Release();
1617
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001618 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001619 }
1620
1621 source->Release();
1622 dest->Release();
1623 }
1624 }
1625 }
1626
1627 if (mTexture != NULL)
1628 {
1629 mTexture->Release();
1630 }
1631
1632 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001633 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001634}
1635
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001636void Texture2D::generateMipmaps()
1637{
1638 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1639 {
1640 return error(GL_INVALID_OPERATION);
1641 }
1642
1643 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001644 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001645 for (unsigned int i = 1; i <= q; i++)
1646 {
1647 if (mImageArray[i].surface != NULL)
1648 {
1649 mImageArray[i].surface->Release();
1650 mImageArray[i].surface = NULL;
1651 }
1652
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001653 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1654 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001655 mImageArray[i].format = mImageArray[0].format;
1656 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001657 }
1658
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001659 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001660 {
1661 if (mTexture == NULL)
1662 {
1663 ERR(" failed because mTexture was null.");
1664 return;
1665 }
1666
1667 for (unsigned int i = 1; i <= q; i++)
1668 {
1669 IDirect3DSurface9 *upper = NULL;
1670 IDirect3DSurface9 *lower = NULL;
1671
1672 mTexture->GetSurfaceLevel(i-1, &upper);
1673 mTexture->GetSurfaceLevel(i, &lower);
1674
1675 if (upper != NULL && lower != NULL)
1676 {
1677 getBlitter()->boxFilter(upper, lower);
1678 }
1679
1680 if (upper != NULL) upper->Release();
1681 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001682
1683 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001684 }
1685 }
1686 else
1687 {
1688 for (unsigned int i = 1; i <= q; i++)
1689 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001690 createSurface(&mImageArray[i]);
1691
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001692 if (mImageArray[i].surface == NULL)
1693 {
1694 return error(GL_OUT_OF_MEMORY);
1695 }
1696
1697 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1698 {
1699 ERR(" failed to load filter %d to %d.", i - 1, i);
1700 }
1701
1702 mImageArray[i].dirty = true;
1703 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001704 }
1705}
1706
1707Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1708{
1709 if (target != GL_TEXTURE_2D)
1710 {
1711 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1712 }
1713
1714 if (mColorbufferProxy.get() == NULL)
1715 {
1716 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1717 }
1718
1719 return mColorbufferProxy.get();
1720}
1721
1722IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1723{
1724 ASSERT(target == GL_TEXTURE_2D);
1725
daniel@transgaming.com61208202011-03-21 16:38:50 +00001726 if (!mIsRenderable)
1727 {
1728 convertToRenderTarget();
1729 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001730
1731 if (mTexture == NULL)
1732 {
1733 return NULL;
1734 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001735
1736 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001737
1738 IDirect3DSurface9 *renderTarget = NULL;
1739 mTexture->GetSurfaceLevel(0, &renderTarget);
1740
1741 return renderTarget;
1742}
1743
1744TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1745{
1746 mTexture = NULL;
1747}
1748
1749TextureCubeMap::~TextureCubeMap()
1750{
1751 for (int i = 0; i < 6; i++)
1752 {
1753 mFaceProxies[i].set(NULL);
1754 }
1755
1756 if (mTexture)
1757 {
1758 mTexture->Release();
1759 mTexture = NULL;
1760 }
1761}
1762
1763GLenum TextureCubeMap::getTarget() const
1764{
1765 return GL_TEXTURE_CUBE_MAP;
1766}
1767
daniel@transgaming.com61208202011-03-21 16:38:50 +00001768GLsizei TextureCubeMap::getWidth() const
1769{
1770 return mImageArray[0][0].width;
1771}
1772
1773GLsizei TextureCubeMap::getHeight() const
1774{
1775 return mImageArray[0][0].height;
1776}
1777
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001778GLenum TextureCubeMap::getInternalFormat() const
1779{
1780 return mImageArray[0][0].format;
1781}
1782
daniel@transgaming.com61208202011-03-21 16:38:50 +00001783GLenum TextureCubeMap::getType() const
1784{
1785 return mImageArray[0][0].type;
1786}
1787
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001788void 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 +00001789{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001790 setImage(0, 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::setImageNegX(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(1, 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::setImagePosY(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(2, 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::setImageNegY(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(3, 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::setImagePosZ(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(4, 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::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001814{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001815 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001816}
1817
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001818void 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 +00001819{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001820 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001821
daniel@transgaming.com61208202011-03-21 16:38:50 +00001822 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001823}
1824
1825void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1826{
1827 int face = faceIndex(faceTarget);
1828 ASSERT(mImageArray[face][level].surface != NULL);
1829
1830 if (level < levelCount())
1831 {
1832 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1833 ASSERT(destLevel != NULL);
1834
1835 if (destLevel != NULL)
1836 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001837 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001838
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001839 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001840
1841 POINT destPoint;
1842 destPoint.x = sourceRect.left;
1843 destPoint.y = sourceRect.top;
1844
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001845 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001846 ASSERT(SUCCEEDED(result));
1847
1848 destLevel->Release();
1849
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001850 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001851 }
1852 }
1853}
1854
1855void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1856{
1857 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1858 {
1859 commitRect(target, level, xoffset, yoffset, width, height);
1860 }
1861}
1862
1863void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1864{
1865 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1866 {
1867 commitRect(target, level, xoffset, yoffset, width, height);
1868 }
1869}
1870
1871// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1872bool TextureCubeMap::isComplete() const
1873{
1874 int size = mImageArray[0][0].width;
1875
1876 if (size <= 0)
1877 {
1878 return false;
1879 }
1880
1881 bool mipmapping;
1882
1883 switch (mMinFilter)
1884 {
1885 case GL_NEAREST:
1886 case GL_LINEAR:
1887 mipmapping = false;
1888 break;
1889 case GL_NEAREST_MIPMAP_NEAREST:
1890 case GL_LINEAR_MIPMAP_NEAREST:
1891 case GL_NEAREST_MIPMAP_LINEAR:
1892 case GL_LINEAR_MIPMAP_LINEAR:
1893 mipmapping = true;
1894 break;
1895 default: UNREACHABLE();
1896 }
1897
1898 for (int face = 0; face < 6; face++)
1899 {
1900 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1901 {
1902 return false;
1903 }
1904 }
1905
1906 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1907 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1908 {
1909 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1910 {
1911 return false;
1912 }
1913 }
1914
1915 if (mipmapping)
1916 {
1917 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1918 {
1919 return false;
1920 }
1921
1922 int q = log2(size);
1923
1924 for (int face = 0; face < 6; face++)
1925 {
1926 for (int level = 1; level <= q; level++)
1927 {
1928 if (mImageArray[face][level].format != mImageArray[0][0].format)
1929 {
1930 return false;
1931 }
1932
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001933 if (mImageArray[face][level].type != mImageArray[0][0].type)
1934 {
1935 return false;
1936 }
1937
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001938 if (mImageArray[face][level].width != std::max(1, size >> level))
1939 {
1940 return false;
1941 }
1942
1943 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1944 }
1945 }
1946 }
1947
1948 return true;
1949}
1950
1951bool TextureCubeMap::isCompressed() const
1952{
1953 return IsCompressed(getInternalFormat());
1954}
1955
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001956IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1957{
1958 return mTexture;
1959}
1960
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001961// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001962void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001963{
1964 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001965 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
1966 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001967
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001968 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001969 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001970
1971 if (FAILED(result))
1972 {
1973 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001974 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001975 }
1976
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001977 if (mTexture)
1978 {
1979 mTexture->Release();
1980 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001981
1982 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001983 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001984}
1985
1986void TextureCubeMap::updateTexture()
1987{
1988 IDirect3DDevice9 *device = getDevice();
1989
1990 for (int face = 0; face < 6; face++)
1991 {
1992 int levels = levelCount();
1993 for (int level = 0; level < levels; level++)
1994 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001995 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001996
daniel@transgaming.com61208202011-03-21 16:38:50 +00001997 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001998 {
1999 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2000 ASSERT(levelSurface != NULL);
2001
2002 if (levelSurface != NULL)
2003 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002004 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002005 ASSERT(SUCCEEDED(result));
2006
2007 levelSurface->Release();
2008
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002009 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002010 }
2011 }
2012 }
2013 }
2014}
2015
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002016void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002017{
2018 IDirect3DCubeTexture9 *texture = NULL;
2019
daniel@transgaming.com61208202011-03-21 16:38:50 +00002020 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002021 {
2022 egl::Display *display = getDisplay();
2023 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002024 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mImageArray[0][0].type);
2025 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002026
daniel@transgaming.com61208202011-03-21 16:38:50 +00002027 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002028
2029 if (FAILED(result))
2030 {
2031 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002032 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002033 }
2034
2035 if (mTexture != NULL)
2036 {
2037 int levels = levelCount();
2038 for (int f = 0; f < 6; f++)
2039 {
2040 for (int i = 0; i < levels; i++)
2041 {
2042 IDirect3DSurface9 *source;
2043 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2044
2045 if (FAILED(result))
2046 {
2047 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2048
2049 texture->Release();
2050
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002051 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002052 }
2053
2054 IDirect3DSurface9 *dest;
2055 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2056
2057 if (FAILED(result))
2058 {
2059 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2060
2061 texture->Release();
2062 source->Release();
2063
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002064 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002065 }
2066
2067 display->endScene();
2068 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2069
2070 if (FAILED(result))
2071 {
2072 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2073
2074 texture->Release();
2075 source->Release();
2076 dest->Release();
2077
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002078 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002079 }
2080 }
2081 }
2082 }
2083 }
2084
2085 if (mTexture != NULL)
2086 {
2087 mTexture->Release();
2088 }
2089
2090 mTexture = texture;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002091 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002092}
2093
daniel@transgaming.com61208202011-03-21 16:38:50 +00002094void 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 +00002095{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002096 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002097
daniel@transgaming.com61208202011-03-21 16:38:50 +00002098 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002099}
2100
2101unsigned int TextureCubeMap::faceIndex(GLenum face)
2102{
2103 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2104 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2105 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2106 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2107 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2108
2109 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2110}
2111
daniel@transgaming.com61208202011-03-21 16:38:50 +00002112void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002113{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002114 GLsizei textureWidth = mImageArray[0][0].width;
2115 GLsizei textureHeight = mImageArray[0][0].height;
2116 GLenum textureFormat = mImageArray[0][0].format;
2117 GLenum textureType = mImageArray[0][0].type;
2118
daniel@transgaming.com61208202011-03-21 16:38:50 +00002119 mImageArray[face][level].width = width;
2120 mImageArray[face][level].height = height;
2121 mImageArray[face][level].format = format;
2122 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002123
daniel@transgaming.com61208202011-03-21 16:38:50 +00002124 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002125 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002126 return;
2127 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002128
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002129 bool sizeOkay = (textureWidth >> level == width);
2130 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002131
2132 if (!textureOkay) // Purge all the levels and the texture.
2133 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002134 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2135 {
2136 for (int f = 0; f < 6; f++)
2137 {
2138 if (mImageArray[f][i].surface != NULL)
2139 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002140 mImageArray[f][i].surface->Release();
2141 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002142 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002143 }
2144 }
2145 }
2146
2147 if (mTexture != NULL)
2148 {
2149 mTexture->Release();
2150 mTexture = NULL;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002151 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002152 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002153 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002154}
2155
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002156void 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 +00002157{
2158 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2159
2160 if (!renderTarget)
2161 {
2162 ERR("Failed to retrieve the render target.");
2163 return error(GL_OUT_OF_MEMORY);
2164 }
2165
2166 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002167 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002168
2169 if (!isRenderableFormat())
2170 {
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002171 copyNonRenderable(&mImageArray[faceindex][level], format, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002172 }
2173 else
2174 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002175 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002176 {
2177 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002178 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002179
2180 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002181
2182 ASSERT(width == height);
2183
2184 if (width > 0 && level < levelCount())
2185 {
2186 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2187 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2188 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2189 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2190 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2191
2192 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2193
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002194 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002195 dest->Release();
2196 }
2197 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002198}
2199
2200IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2201{
2202 if (mTexture == NULL)
2203 {
2204 UNREACHABLE();
2205 return NULL;
2206 }
2207
2208 IDirect3DSurface9 *surface = NULL;
2209
2210 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2211
2212 return (SUCCEEDED(hr)) ? surface : NULL;
2213}
2214
2215void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2216{
2217 GLsizei size = mImageArray[faceIndex(target)][level].width;
2218
2219 if (xoffset + width > size || yoffset + height > size)
2220 {
2221 return error(GL_INVALID_VALUE);
2222 }
2223
2224 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2225
2226 if (!renderTarget)
2227 {
2228 ERR("Failed to retrieve the render target.");
2229 return error(GL_OUT_OF_MEMORY);
2230 }
2231
2232 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002233 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 +00002234
2235 if (!isRenderableFormat())
2236 {
2237 copyNonRenderable(&mImageArray[faceindex][level], getInternalFormat(), 0, 0, x, y, width, height, renderTarget);
2238 }
2239 else
2240 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002241 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002242 {
2243 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002244 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002245
2246 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002247
2248 if (level < levelCount())
2249 {
2250 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2251 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2252 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2253 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2254 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2255
2256 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2257
2258 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2259
2260 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2261 dest->Release();
2262 }
2263 }
2264}
2265
2266bool TextureCubeMap::isCubeComplete() const
2267{
2268 if (mImageArray[0][0].width == 0)
2269 {
2270 return false;
2271 }
2272
2273 for (unsigned int f = 1; f < 6; f++)
2274 {
2275 if (mImageArray[f][0].width != mImageArray[0][0].width
2276 || mImageArray[f][0].format != mImageArray[0][0].format)
2277 {
2278 return false;
2279 }
2280 }
2281
2282 return true;
2283}
2284
2285void TextureCubeMap::generateMipmaps()
2286{
2287 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2288 {
2289 return error(GL_INVALID_OPERATION);
2290 }
2291
2292 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2293 unsigned int q = log2(mImageArray[0][0].width);
2294 for (unsigned int f = 0; f < 6; f++)
2295 {
2296 for (unsigned int i = 1; i <= q; i++)
2297 {
2298 if (mImageArray[f][i].surface != NULL)
2299 {
2300 mImageArray[f][i].surface->Release();
2301 mImageArray[f][i].surface = NULL;
2302 }
2303
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002304 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2305 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002306 mImageArray[f][i].format = mImageArray[f][0].format;
2307 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002308 }
2309 }
2310
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002311 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002312 {
2313 if (mTexture == NULL)
2314 {
2315 return;
2316 }
2317
2318 for (unsigned int f = 0; f < 6; f++)
2319 {
2320 for (unsigned int i = 1; i <= q; i++)
2321 {
2322 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2323 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2324
2325 if (upper != NULL && lower != NULL)
2326 {
2327 getBlitter()->boxFilter(upper, lower);
2328 }
2329
2330 if (upper != NULL) upper->Release();
2331 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002332
2333 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002334 }
2335 }
2336 }
2337 else
2338 {
2339 for (unsigned int f = 0; f < 6; f++)
2340 {
2341 for (unsigned int i = 1; i <= q; i++)
2342 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002343 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002344 if (mImageArray[f][i].surface == NULL)
2345 {
2346 return error(GL_OUT_OF_MEMORY);
2347 }
2348
2349 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2350 {
2351 ERR(" failed to load filter %d to %d.", i - 1, i);
2352 }
2353
2354 mImageArray[f][i].dirty = true;
2355 }
2356 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002357 }
2358}
2359
2360Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2361{
2362 if (!IsCubemapTextureTarget(target))
2363 {
2364 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2365 }
2366
2367 unsigned int face = faceIndex(target);
2368
2369 if (mFaceProxies[face].get() == NULL)
2370 {
2371 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2372 }
2373
2374 return mFaceProxies[face].get();
2375}
2376
2377IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2378{
2379 ASSERT(IsCubemapTextureTarget(target));
2380
daniel@transgaming.com61208202011-03-21 16:38:50 +00002381 if (!mIsRenderable)
2382 {
2383 convertToRenderTarget();
2384 }
2385
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002386 if (mTexture == NULL)
2387 {
2388 return NULL;
2389 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002390
2391 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002392
2393 IDirect3DSurface9 *renderTarget = NULL;
2394 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2395
2396 return renderTarget;
2397}
2398
2399}