blob: 3b60ae384e9fb0fa5fa1c71003f7bb0696b5577e [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{
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000027unsigned int Texture::mCurrentSerial = 1;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000028
29Texture::Image::Image()
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +000030 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000031{
32}
33
34Texture::Image::~Image()
35{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +000036 if (surface)
37 {
38 surface->Release();
39 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000040}
41
daniel@transgaming.com549bdef2011-03-29 00:57:01 +000042bool Texture::Image::isRenderable() const
43{
44 switch(getD3DFormat())
45 {
46 case D3DFMT_L8:
47 case D3DFMT_A8L8:
48 case D3DFMT_DXT1:
49 return false;
50 case D3DFMT_A8R8G8B8:
51 case D3DFMT_X8R8G8B8:
52 case D3DFMT_A16B16G16R16F:
53 case D3DFMT_A32B32G32R32F:
54 return true;
55 default:
56 UNREACHABLE();
57 }
58
59 return false;
60}
61
62D3DFORMAT Texture::Image::getD3DFormat() const
63{
64 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
65 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
66 {
67 return D3DFMT_DXT1;
68 }
69 else if (type == GL_FLOAT)
70 {
71 return D3DFMT_A32B32G32R32F;
72 }
73 else if (type == GL_HALF_FLOAT_OES)
74 {
75 return D3DFMT_A16B16G16R16F;
76 }
77 else if (type == GL_UNSIGNED_BYTE)
78 {
79 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
80 {
81 return D3DFMT_L8;
82 }
83 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
84 {
85 return D3DFMT_A8L8;
86 }
87 else if (format == GL_RGB)
88 {
89 return D3DFMT_X8R8G8B8;
90 }
91
92 return D3DFMT_A8R8G8B8;
93 }
94
95 return D3DFMT_A8R8G8B8;
96}
97
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +000098Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +000099{
100 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
101 mMagFilter = GL_LINEAR;
102 mWrapS = GL_REPEAT;
103 mWrapT = GL_REPEAT;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000104 mDirtyParameter = true;
105
106 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +0000107
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000108 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000109}
110
111Texture::~Texture()
112{
113}
114
115Blit *Texture::getBlitter()
116{
117 Context *context = getContext();
118 return context->getBlitter();
119}
120
121// Returns true on successful filter state update (valid enum parameter)
122bool Texture::setMinFilter(GLenum filter)
123{
124 switch (filter)
125 {
126 case GL_NEAREST:
127 case GL_LINEAR:
128 case GL_NEAREST_MIPMAP_NEAREST:
129 case GL_LINEAR_MIPMAP_NEAREST:
130 case GL_NEAREST_MIPMAP_LINEAR:
131 case GL_LINEAR_MIPMAP_LINEAR:
132 {
133 if (mMinFilter != filter)
134 {
135 mMinFilter = filter;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000136 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000137 }
138 return true;
139 }
140 default:
141 return false;
142 }
143}
144
145// Returns true on successful filter state update (valid enum parameter)
146bool Texture::setMagFilter(GLenum filter)
147{
148 switch (filter)
149 {
150 case GL_NEAREST:
151 case GL_LINEAR:
152 {
153 if (mMagFilter != filter)
154 {
155 mMagFilter = filter;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000156 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000157 }
158 return true;
159 }
160 default:
161 return false;
162 }
163}
164
165// Returns true on successful wrap state update (valid enum parameter)
166bool Texture::setWrapS(GLenum wrap)
167{
168 switch (wrap)
169 {
170 case GL_REPEAT:
171 case GL_CLAMP_TO_EDGE:
172 case GL_MIRRORED_REPEAT:
173 {
174 if (mWrapS != wrap)
175 {
176 mWrapS = wrap;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000177 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000178 }
179 return true;
180 }
181 default:
182 return false;
183 }
184}
185
186// Returns true on successful wrap state update (valid enum parameter)
187bool Texture::setWrapT(GLenum wrap)
188{
189 switch (wrap)
190 {
191 case GL_REPEAT:
192 case GL_CLAMP_TO_EDGE:
193 case GL_MIRRORED_REPEAT:
194 {
195 if (mWrapT != wrap)
196 {
197 mWrapT = wrap;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +0000198 mDirtyParameter = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000199 }
200 return true;
201 }
202 default:
203 return false;
204 }
205}
206
207GLenum Texture::getMinFilter() const
208{
209 return mMinFilter;
210}
211
212GLenum Texture::getMagFilter() const
213{
214 return mMagFilter;
215}
216
217GLenum Texture::getWrapS() const
218{
219 return mWrapS;
220}
221
222GLenum Texture::getWrapT() const
223{
224 return mWrapT;
225}
226
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000227// 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.com549bdef2011-03-29 00:57:01 +0000807 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, image->getD3DFormat(),
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.coma06aa872011-03-21 17:22:21 +0000849 mDirtyImage = 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.coma06aa872011-03-21 17:22:21 +0000873 mDirtyImage = 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.coma06aa872011-03-21 17:22:21 +0000907 mDirtyImage = 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.coma06aa872011-03-21 17:22:21 +0000954 mDirtyImage = 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.com549bdef2011-03-29 00:57:01 +0000961void Texture::copyNonRenderable(Image *image, 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:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001032 switch(image->getD3DFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001033 {
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:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001064 switch(image->getD3DFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001065 {
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:
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001084 switch(image->getD3DFormat())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001085 {
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.coma06aa872011-03-21 17:22:21 +00001122 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001123 }
1124
1125 image->surface->UnlockRect();
1126 surface->UnlockRect();
1127 surface->Release();
1128}
1129
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001130IDirect3DBaseTexture9 *Texture::getTexture()
1131{
1132 if (!isComplete())
1133 {
1134 return NULL;
1135 }
1136
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001137 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001138 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001139 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001140 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001141
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001142 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001143
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001144 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001145}
1146
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001147bool Texture::isDirtyParameter() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001148{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001149 return mDirtyParameter;
1150}
1151
1152bool Texture::isDirtyImage() const
1153{
1154 return mDirtyImage;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001155}
1156
1157void Texture::resetDirty()
1158{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001159 mDirtyParameter = false;
1160 mDirtyImage = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001161}
1162
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001163unsigned int Texture::getSerial() const
1164{
1165 return mSerial;
1166}
1167
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001168GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1169{
1170 if (isPow2(width) && isPow2(height))
1171 {
1172 return maxlevel;
1173 }
1174 else
1175 {
1176 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1177 return 1;
1178 }
1179}
1180
1181GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1182{
1183 return creationLevels(size, size, maxlevel);
1184}
1185
1186int Texture::levelCount() const
1187{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001188 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001189}
1190
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001191unsigned int Texture::issueSerial()
1192{
1193 return mCurrentSerial++;
1194}
1195
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001196Texture2D::Texture2D(GLuint id) : Texture(id)
1197{
1198 mTexture = NULL;
1199}
1200
1201Texture2D::~Texture2D()
1202{
1203 mColorbufferProxy.set(NULL);
1204
1205 if (mTexture)
1206 {
1207 mTexture->Release();
1208 mTexture = NULL;
1209 }
1210}
1211
1212GLenum Texture2D::getTarget() const
1213{
1214 return GL_TEXTURE_2D;
1215}
1216
daniel@transgaming.com61208202011-03-21 16:38:50 +00001217GLsizei Texture2D::getWidth() const
1218{
1219 return mImageArray[0].width;
1220}
1221
1222GLsizei Texture2D::getHeight() const
1223{
1224 return mImageArray[0].height;
1225}
1226
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001227GLenum Texture2D::getInternalFormat() const
1228{
1229 return mImageArray[0].format;
1230}
1231
daniel@transgaming.com61208202011-03-21 16:38:50 +00001232GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001233{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001234 return mImageArray[0].type;
1235}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001236
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001237D3DFORMAT Texture2D::getD3DFormat() const
1238{
1239 return mImageArray[0].getD3DFormat();
1240}
1241
daniel@transgaming.com61208202011-03-21 16:38:50 +00001242void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1243{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001244 GLsizei textureWidth = mImageArray[0].width;
1245 GLsizei textureHeight = mImageArray[0].height;
1246 GLenum textureFormat = mImageArray[0].format;
1247 GLenum textureType = mImageArray[0].type;
1248
daniel@transgaming.com61208202011-03-21 16:38:50 +00001249 mImageArray[level].width = width;
1250 mImageArray[level].height = height;
1251 mImageArray[level].format = format;
1252 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001253
daniel@transgaming.com61208202011-03-21 16:38:50 +00001254 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001255 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001256 return;
1257 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001258
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001259 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1260 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1261 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001262
1263 if (!textureOkay) // Purge all the levels and the texture.
1264 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001265 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1266 {
1267 if (mImageArray[i].surface != NULL)
1268 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001269 mImageArray[i].surface->Release();
1270 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001271 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001272 }
1273 }
1274
1275 if (mTexture != NULL)
1276 {
1277 mTexture->Release();
1278 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001279 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001280 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001281 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001282 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001283}
1284
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001285void 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 +00001286{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001287 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001288
daniel@transgaming.com61208202011-03-21 16:38:50 +00001289 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001290}
1291
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001292void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001293{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001294 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001295
daniel@transgaming.com61208202011-03-21 16:38:50 +00001296 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001297}
1298
1299void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1300{
1301 ASSERT(mImageArray[level].surface != NULL);
1302
1303 if (level < levelCount())
1304 {
1305 IDirect3DSurface9 *destLevel = NULL;
1306 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1307
1308 ASSERT(SUCCEEDED(result));
1309
1310 if (SUCCEEDED(result))
1311 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001312 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001313
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001314 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001315
1316 POINT destPoint;
1317 destPoint.x = sourceRect.left;
1318 destPoint.y = sourceRect.top;
1319
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001320 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001321 ASSERT(SUCCEEDED(result));
1322
1323 destLevel->Release();
1324
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001325 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001326 }
1327 }
1328}
1329
1330void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1331{
1332 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1333 {
1334 commitRect(level, xoffset, yoffset, width, height);
1335 }
1336}
1337
1338void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1339{
1340 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1341 {
1342 commitRect(level, xoffset, yoffset, width, height);
1343 }
1344}
1345
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001346void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001347{
1348 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1349
1350 if (!renderTarget)
1351 {
1352 ERR("Failed to retrieve the render target.");
1353 return error(GL_OUT_OF_MEMORY);
1354 }
1355
daniel@transgaming.com61208202011-03-21 16:38:50 +00001356 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001357
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001358 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001359 {
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001360 copyNonRenderable(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001361 }
1362 else
1363 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001364 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001365 {
1366 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001367 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001368
1369 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001370
1371 if (width != 0 && height != 0 && level < levelCount())
1372 {
1373 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1374 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1375 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1376 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1377 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1378
1379 IDirect3DSurface9 *dest;
1380 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1381
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001382 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001383 dest->Release();
1384 }
1385 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001386}
1387
1388void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1389{
1390 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1391 {
1392 return error(GL_INVALID_VALUE);
1393 }
1394
1395 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1396
1397 if (!renderTarget)
1398 {
1399 ERR("Failed to retrieve the render target.");
1400 return error(GL_OUT_OF_MEMORY);
1401 }
1402
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001403 redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001404
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001405 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001406 {
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001407 copyNonRenderable(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001408 }
1409 else
1410 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001411 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001412 {
1413 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001414 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001415
1416 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001417
1418 if (level < levelCount())
1419 {
1420 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1421 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1422 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1423 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1424 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1425
1426 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1427
1428 IDirect3DSurface9 *dest;
1429 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1430
1431 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1432 dest->Release();
1433 }
1434 }
1435}
1436
1437// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1438bool Texture2D::isComplete() const
1439{
1440 GLsizei width = mImageArray[0].width;
1441 GLsizei height = mImageArray[0].height;
1442
1443 if (width <= 0 || height <= 0)
1444 {
1445 return false;
1446 }
1447
1448 bool mipmapping = false;
1449
1450 switch (mMinFilter)
1451 {
1452 case GL_NEAREST:
1453 case GL_LINEAR:
1454 mipmapping = false;
1455 break;
1456 case GL_NEAREST_MIPMAP_NEAREST:
1457 case GL_LINEAR_MIPMAP_NEAREST:
1458 case GL_NEAREST_MIPMAP_LINEAR:
1459 case GL_LINEAR_MIPMAP_LINEAR:
1460 mipmapping = true;
1461 break;
1462 default: UNREACHABLE();
1463 }
1464
1465 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1466 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1467 {
1468 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1469 {
1470 return false;
1471 }
1472 }
1473
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001474 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1475 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1476 {
1477 return false;
1478 }
1479
1480 if (mipmapping)
1481 {
1482 if (!isPow2(width) || !isPow2(height))
1483 {
1484 return false;
1485 }
1486
1487 int q = log2(std::max(width, height));
1488
1489 for (int level = 1; level <= q; level++)
1490 {
1491 if (mImageArray[level].format != mImageArray[0].format)
1492 {
1493 return false;
1494 }
1495
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001496 if (mImageArray[level].type != mImageArray[0].type)
1497 {
1498 return false;
1499 }
1500
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001501 if (mImageArray[level].width != std::max(1, width >> level))
1502 {
1503 return false;
1504 }
1505
1506 if (mImageArray[level].height != std::max(1, height >> level))
1507 {
1508 return false;
1509 }
1510 }
1511 }
1512
1513 return true;
1514}
1515
1516bool Texture2D::isCompressed() const
1517{
1518 return IsCompressed(getInternalFormat());
1519}
1520
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001521IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1522{
1523 return mTexture;
1524}
1525
1526// Constructs a Direct3D 9 texture resource from the texture images
1527void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001528{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001529 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001530 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001531 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001532
daniel@transgaming.com61208202011-03-21 16:38:50 +00001533 IDirect3DTexture9 *texture = NULL;
1534 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 +00001535
1536 if (FAILED(result))
1537 {
1538 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001539 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001540 }
1541
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001542 if (mTexture)
1543 {
1544 mTexture->Release();
1545 }
1546
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001547 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001548 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001549 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001550}
1551
1552void Texture2D::updateTexture()
1553{
1554 IDirect3DDevice9 *device = getDevice();
1555
1556 int levels = levelCount();
1557
1558 for (int level = 0; level < levels; level++)
1559 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001560 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001561 {
1562 IDirect3DSurface9 *levelSurface = NULL;
1563 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1564
1565 ASSERT(SUCCEEDED(result));
1566
1567 if (SUCCEEDED(result))
1568 {
1569 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1570 ASSERT(SUCCEEDED(result));
1571
1572 levelSurface->Release();
1573
1574 mImageArray[level].dirty = false;
1575 }
1576 }
1577 }
1578}
1579
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001580void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001581{
1582 IDirect3DTexture9 *texture = NULL;
1583
daniel@transgaming.com61208202011-03-21 16:38:50 +00001584 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001585 {
1586 egl::Display *display = getDisplay();
1587 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001588 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001589 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001590
daniel@transgaming.com61208202011-03-21 16:38:50 +00001591 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 +00001592
1593 if (FAILED(result))
1594 {
1595 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001596 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001597 }
1598
1599 if (mTexture != NULL)
1600 {
1601 int levels = levelCount();
1602 for (int i = 0; i < levels; i++)
1603 {
1604 IDirect3DSurface9 *source;
1605 result = mTexture->GetSurfaceLevel(i, &source);
1606
1607 if (FAILED(result))
1608 {
1609 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1610
1611 texture->Release();
1612
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001613 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001614 }
1615
1616 IDirect3DSurface9 *dest;
1617 result = texture->GetSurfaceLevel(i, &dest);
1618
1619 if (FAILED(result))
1620 {
1621 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1622
1623 texture->Release();
1624 source->Release();
1625
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001626 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001627 }
1628
1629 display->endScene();
1630 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1631
1632 if (FAILED(result))
1633 {
1634 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1635
1636 texture->Release();
1637 source->Release();
1638 dest->Release();
1639
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001640 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001641 }
1642
1643 source->Release();
1644 dest->Release();
1645 }
1646 }
1647 }
1648
1649 if (mTexture != NULL)
1650 {
1651 mTexture->Release();
1652 }
1653
1654 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001655 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001656 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001657}
1658
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001659void Texture2D::generateMipmaps()
1660{
1661 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1662 {
1663 return error(GL_INVALID_OPERATION);
1664 }
1665
1666 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001667 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001668 for (unsigned int i = 1; i <= q; i++)
1669 {
1670 if (mImageArray[i].surface != NULL)
1671 {
1672 mImageArray[i].surface->Release();
1673 mImageArray[i].surface = NULL;
1674 }
1675
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001676 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1677 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001678 mImageArray[i].format = mImageArray[0].format;
1679 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001680 }
1681
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001682 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001683 {
1684 if (mTexture == NULL)
1685 {
1686 ERR(" failed because mTexture was null.");
1687 return;
1688 }
1689
1690 for (unsigned int i = 1; i <= q; i++)
1691 {
1692 IDirect3DSurface9 *upper = NULL;
1693 IDirect3DSurface9 *lower = NULL;
1694
1695 mTexture->GetSurfaceLevel(i-1, &upper);
1696 mTexture->GetSurfaceLevel(i, &lower);
1697
1698 if (upper != NULL && lower != NULL)
1699 {
1700 getBlitter()->boxFilter(upper, lower);
1701 }
1702
1703 if (upper != NULL) upper->Release();
1704 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001705
1706 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001707 }
1708 }
1709 else
1710 {
1711 for (unsigned int i = 1; i <= q; i++)
1712 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001713 createSurface(&mImageArray[i]);
1714
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001715 if (mImageArray[i].surface == NULL)
1716 {
1717 return error(GL_OUT_OF_MEMORY);
1718 }
1719
1720 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1721 {
1722 ERR(" failed to load filter %d to %d.", i - 1, i);
1723 }
1724
1725 mImageArray[i].dirty = true;
1726 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001727 }
1728}
1729
1730Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1731{
1732 if (target != GL_TEXTURE_2D)
1733 {
1734 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1735 }
1736
1737 if (mColorbufferProxy.get() == NULL)
1738 {
1739 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1740 }
1741
1742 return mColorbufferProxy.get();
1743}
1744
1745IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1746{
1747 ASSERT(target == GL_TEXTURE_2D);
1748
daniel@transgaming.com61208202011-03-21 16:38:50 +00001749 if (!mIsRenderable)
1750 {
1751 convertToRenderTarget();
1752 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001753
1754 if (mTexture == NULL)
1755 {
1756 return NULL;
1757 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001758
1759 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001760
1761 IDirect3DSurface9 *renderTarget = NULL;
1762 mTexture->GetSurfaceLevel(0, &renderTarget);
1763
1764 return renderTarget;
1765}
1766
1767TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1768{
1769 mTexture = NULL;
1770}
1771
1772TextureCubeMap::~TextureCubeMap()
1773{
1774 for (int i = 0; i < 6; i++)
1775 {
1776 mFaceProxies[i].set(NULL);
1777 }
1778
1779 if (mTexture)
1780 {
1781 mTexture->Release();
1782 mTexture = NULL;
1783 }
1784}
1785
1786GLenum TextureCubeMap::getTarget() const
1787{
1788 return GL_TEXTURE_CUBE_MAP;
1789}
1790
daniel@transgaming.com61208202011-03-21 16:38:50 +00001791GLsizei TextureCubeMap::getWidth() const
1792{
1793 return mImageArray[0][0].width;
1794}
1795
1796GLsizei TextureCubeMap::getHeight() const
1797{
1798 return mImageArray[0][0].height;
1799}
1800
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001801GLenum TextureCubeMap::getInternalFormat() const
1802{
1803 return mImageArray[0][0].format;
1804}
1805
daniel@transgaming.com61208202011-03-21 16:38:50 +00001806GLenum TextureCubeMap::getType() const
1807{
1808 return mImageArray[0][0].type;
1809}
1810
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001811D3DFORMAT TextureCubeMap::getD3DFormat() const
1812{
1813 return mImageArray[0][0].getD3DFormat();
1814}
1815
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001816void 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 +00001817{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001818 setImage(0, 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::setImageNegX(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(1, 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::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001827{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001828 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001829}
1830
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001831void 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 +00001832{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001833 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001834}
1835
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001836void 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 +00001837{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001838 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001839}
1840
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001841void 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 +00001842{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001843 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001844}
1845
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001846void 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 +00001847{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001848 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001849
daniel@transgaming.com61208202011-03-21 16:38:50 +00001850 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001851}
1852
1853void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1854{
1855 int face = faceIndex(faceTarget);
1856 ASSERT(mImageArray[face][level].surface != NULL);
1857
1858 if (level < levelCount())
1859 {
1860 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1861 ASSERT(destLevel != NULL);
1862
1863 if (destLevel != NULL)
1864 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001865 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001866
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001867 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001868
1869 POINT destPoint;
1870 destPoint.x = sourceRect.left;
1871 destPoint.y = sourceRect.top;
1872
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001873 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001874 ASSERT(SUCCEEDED(result));
1875
1876 destLevel->Release();
1877
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001878 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001879 }
1880 }
1881}
1882
1883void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1884{
1885 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1886 {
1887 commitRect(target, level, xoffset, yoffset, width, height);
1888 }
1889}
1890
1891void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1892{
1893 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1894 {
1895 commitRect(target, level, xoffset, yoffset, width, height);
1896 }
1897}
1898
1899// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1900bool TextureCubeMap::isComplete() const
1901{
1902 int size = mImageArray[0][0].width;
1903
1904 if (size <= 0)
1905 {
1906 return false;
1907 }
1908
1909 bool mipmapping;
1910
1911 switch (mMinFilter)
1912 {
1913 case GL_NEAREST:
1914 case GL_LINEAR:
1915 mipmapping = false;
1916 break;
1917 case GL_NEAREST_MIPMAP_NEAREST:
1918 case GL_LINEAR_MIPMAP_NEAREST:
1919 case GL_NEAREST_MIPMAP_LINEAR:
1920 case GL_LINEAR_MIPMAP_LINEAR:
1921 mipmapping = true;
1922 break;
1923 default: UNREACHABLE();
1924 }
1925
1926 for (int face = 0; face < 6; face++)
1927 {
1928 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1929 {
1930 return false;
1931 }
1932 }
1933
1934 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1935 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1936 {
1937 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1938 {
1939 return false;
1940 }
1941 }
1942
1943 if (mipmapping)
1944 {
1945 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1946 {
1947 return false;
1948 }
1949
1950 int q = log2(size);
1951
1952 for (int face = 0; face < 6; face++)
1953 {
1954 for (int level = 1; level <= q; level++)
1955 {
1956 if (mImageArray[face][level].format != mImageArray[0][0].format)
1957 {
1958 return false;
1959 }
1960
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001961 if (mImageArray[face][level].type != mImageArray[0][0].type)
1962 {
1963 return false;
1964 }
1965
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001966 if (mImageArray[face][level].width != std::max(1, size >> level))
1967 {
1968 return false;
1969 }
1970
1971 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1972 }
1973 }
1974 }
1975
1976 return true;
1977}
1978
1979bool TextureCubeMap::isCompressed() const
1980{
1981 return IsCompressed(getInternalFormat());
1982}
1983
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001984IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1985{
1986 return mTexture;
1987}
1988
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001989// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001990void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001991{
1992 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001993 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001994 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001995
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001996 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001997 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001998
1999 if (FAILED(result))
2000 {
2001 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002002 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002003 }
2004
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002005 if (mTexture)
2006 {
2007 mTexture->Release();
2008 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002009
2010 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002011 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002012 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002013}
2014
2015void TextureCubeMap::updateTexture()
2016{
2017 IDirect3DDevice9 *device = getDevice();
2018
2019 for (int face = 0; face < 6; face++)
2020 {
2021 int levels = levelCount();
2022 for (int level = 0; level < levels; level++)
2023 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002024 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002025
daniel@transgaming.com61208202011-03-21 16:38:50 +00002026 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002027 {
2028 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2029 ASSERT(levelSurface != NULL);
2030
2031 if (levelSurface != NULL)
2032 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002033 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002034 ASSERT(SUCCEEDED(result));
2035
2036 levelSurface->Release();
2037
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002038 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002039 }
2040 }
2041 }
2042 }
2043}
2044
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002045void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002046{
2047 IDirect3DCubeTexture9 *texture = NULL;
2048
daniel@transgaming.com61208202011-03-21 16:38:50 +00002049 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002050 {
2051 egl::Display *display = getDisplay();
2052 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002053 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002054 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002055
daniel@transgaming.com61208202011-03-21 16:38:50 +00002056 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002057
2058 if (FAILED(result))
2059 {
2060 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002061 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002062 }
2063
2064 if (mTexture != NULL)
2065 {
2066 int levels = levelCount();
2067 for (int f = 0; f < 6; f++)
2068 {
2069 for (int i = 0; i < levels; i++)
2070 {
2071 IDirect3DSurface9 *source;
2072 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2073
2074 if (FAILED(result))
2075 {
2076 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2077
2078 texture->Release();
2079
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002080 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002081 }
2082
2083 IDirect3DSurface9 *dest;
2084 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2085
2086 if (FAILED(result))
2087 {
2088 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2089
2090 texture->Release();
2091 source->Release();
2092
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002093 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002094 }
2095
2096 display->endScene();
2097 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2098
2099 if (FAILED(result))
2100 {
2101 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2102
2103 texture->Release();
2104 source->Release();
2105 dest->Release();
2106
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002107 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002108 }
2109 }
2110 }
2111 }
2112 }
2113
2114 if (mTexture != NULL)
2115 {
2116 mTexture->Release();
2117 }
2118
2119 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002120 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002121 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002122}
2123
daniel@transgaming.com61208202011-03-21 16:38:50 +00002124void 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 +00002125{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002126 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002127
daniel@transgaming.com61208202011-03-21 16:38:50 +00002128 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002129}
2130
2131unsigned int TextureCubeMap::faceIndex(GLenum face)
2132{
2133 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2134 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2135 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2136 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2137 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2138
2139 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2140}
2141
daniel@transgaming.com61208202011-03-21 16:38:50 +00002142void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002143{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002144 GLsizei textureWidth = mImageArray[0][0].width;
2145 GLsizei textureHeight = mImageArray[0][0].height;
2146 GLenum textureFormat = mImageArray[0][0].format;
2147 GLenum textureType = mImageArray[0][0].type;
2148
daniel@transgaming.com61208202011-03-21 16:38:50 +00002149 mImageArray[face][level].width = width;
2150 mImageArray[face][level].height = height;
2151 mImageArray[face][level].format = format;
2152 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002153
daniel@transgaming.com61208202011-03-21 16:38:50 +00002154 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002155 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002156 return;
2157 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002158
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002159 bool sizeOkay = (textureWidth >> level == width);
2160 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002161
2162 if (!textureOkay) // Purge all the levels and the texture.
2163 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002164 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2165 {
2166 for (int f = 0; f < 6; f++)
2167 {
2168 if (mImageArray[f][i].surface != NULL)
2169 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002170 mImageArray[f][i].surface->Release();
2171 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002172 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002173 }
2174 }
2175 }
2176
2177 if (mTexture != NULL)
2178 {
2179 mTexture->Release();
2180 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002181 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002182 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002184 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002185}
2186
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002187void 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 +00002188{
2189 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2190
2191 if (!renderTarget)
2192 {
2193 ERR("Failed to retrieve the render target.");
2194 return error(GL_OUT_OF_MEMORY);
2195 }
2196
2197 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002198 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002199
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002200 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002201 {
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002202 copyNonRenderable(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002203 }
2204 else
2205 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002206 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002207 {
2208 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002209 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002210
2211 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002212
2213 ASSERT(width == height);
2214
2215 if (width > 0 && level < levelCount())
2216 {
2217 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2218 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2219 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2220 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2221 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2222
2223 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2224
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002225 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002226 dest->Release();
2227 }
2228 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002229}
2230
2231IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2232{
2233 if (mTexture == NULL)
2234 {
2235 UNREACHABLE();
2236 return NULL;
2237 }
2238
2239 IDirect3DSurface9 *surface = NULL;
2240
2241 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2242
2243 return (SUCCEEDED(hr)) ? surface : NULL;
2244}
2245
2246void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2247{
2248 GLsizei size = mImageArray[faceIndex(target)][level].width;
2249
2250 if (xoffset + width > size || yoffset + height > size)
2251 {
2252 return error(GL_INVALID_VALUE);
2253 }
2254
2255 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2256
2257 if (!renderTarget)
2258 {
2259 ERR("Failed to retrieve the render target.");
2260 return error(GL_OUT_OF_MEMORY);
2261 }
2262
2263 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002264 redefineTexture(faceindex, level, mImageArray[faceindex][level].format, mImageArray[faceindex][level].width, mImageArray[faceindex][level].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002265
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002266 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002267 {
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002268 copyNonRenderable(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002269 }
2270 else
2271 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002272 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002273 {
2274 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002275 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002276
2277 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002278
2279 if (level < levelCount())
2280 {
2281 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2282 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2283 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2284 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2285 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2286
2287 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2288
2289 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2290
2291 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2292 dest->Release();
2293 }
2294 }
2295}
2296
2297bool TextureCubeMap::isCubeComplete() const
2298{
2299 if (mImageArray[0][0].width == 0)
2300 {
2301 return false;
2302 }
2303
2304 for (unsigned int f = 1; f < 6; f++)
2305 {
2306 if (mImageArray[f][0].width != mImageArray[0][0].width
2307 || mImageArray[f][0].format != mImageArray[0][0].format)
2308 {
2309 return false;
2310 }
2311 }
2312
2313 return true;
2314}
2315
2316void TextureCubeMap::generateMipmaps()
2317{
2318 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2319 {
2320 return error(GL_INVALID_OPERATION);
2321 }
2322
2323 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2324 unsigned int q = log2(mImageArray[0][0].width);
2325 for (unsigned int f = 0; f < 6; f++)
2326 {
2327 for (unsigned int i = 1; i <= q; i++)
2328 {
2329 if (mImageArray[f][i].surface != NULL)
2330 {
2331 mImageArray[f][i].surface->Release();
2332 mImageArray[f][i].surface = NULL;
2333 }
2334
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002335 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2336 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002337 mImageArray[f][i].format = mImageArray[f][0].format;
2338 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002339 }
2340 }
2341
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002342 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002343 {
2344 if (mTexture == NULL)
2345 {
2346 return;
2347 }
2348
2349 for (unsigned int f = 0; f < 6; f++)
2350 {
2351 for (unsigned int i = 1; i <= q; i++)
2352 {
2353 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2354 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2355
2356 if (upper != NULL && lower != NULL)
2357 {
2358 getBlitter()->boxFilter(upper, lower);
2359 }
2360
2361 if (upper != NULL) upper->Release();
2362 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002363
2364 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002365 }
2366 }
2367 }
2368 else
2369 {
2370 for (unsigned int f = 0; f < 6; f++)
2371 {
2372 for (unsigned int i = 1; i <= q; i++)
2373 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002374 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002375 if (mImageArray[f][i].surface == NULL)
2376 {
2377 return error(GL_OUT_OF_MEMORY);
2378 }
2379
2380 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2381 {
2382 ERR(" failed to load filter %d to %d.", i - 1, i);
2383 }
2384
2385 mImageArray[f][i].dirty = true;
2386 }
2387 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002388 }
2389}
2390
2391Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2392{
2393 if (!IsCubemapTextureTarget(target))
2394 {
2395 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2396 }
2397
2398 unsigned int face = faceIndex(target);
2399
2400 if (mFaceProxies[face].get() == NULL)
2401 {
2402 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2403 }
2404
2405 return mFaceProxies[face].get();
2406}
2407
2408IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2409{
2410 ASSERT(IsCubemapTextureTarget(target));
2411
daniel@transgaming.com61208202011-03-21 16:38:50 +00002412 if (!mIsRenderable)
2413 {
2414 convertToRenderTarget();
2415 }
2416
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002417 if (mTexture == NULL)
2418 {
2419 return NULL;
2420 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002421
2422 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002423
2424 IDirect3DSurface9 *renderTarget = NULL;
2425 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2426
2427 return renderTarget;
2428}
2429
2430}