blob: 10c1e2c5fb5df5935ba97c1d690f9ad918eebd9c [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
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000960// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
961void Texture::copyToImage(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{
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000963 if (!image->surface)
964 {
965 createSurface(image);
966
967 if (!image->surface)
968 {
969 ERR("Failed to create an image surface.");
970 return error(GL_OUT_OF_MEMORY);
971 }
972 }
973
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000974 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000975 IDirect3DSurface9 *renderTargetData = NULL;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000976 D3DSURFACE_DESC description;
977 renderTarget->GetDesc(&description);
978
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000979 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000980
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000981 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000982 {
983 ERR("Could not create matching destination surface.");
984 return error(GL_OUT_OF_MEMORY);
985 }
986
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000987 result = device->GetRenderTargetData(renderTarget, renderTargetData);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000988
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000989 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000990 {
991 ERR("GetRenderTargetData unexpectedly failed.");
daniel@transgaming.comb6276992011-03-29 00:58:18 +0000992 renderTargetData->Release();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000993 return error(GL_OUT_OF_MEMORY);
994 }
995
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000996 RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000997 int destYOffset = transformPixelYOffset(yoffset, height, image->height);
998 RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +0000999
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001000 if (image->isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001001 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001002 result = D3DXLoadSurfaceFromSurface(image->surface, NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
1003
1004 if (FAILED(result))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001005 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001006 ERR("Copying surfaces unexpectedly failed.");
1007 renderTargetData->Release();
1008 return error(GL_OUT_OF_MEMORY);
1009 }
1010 }
1011 else
1012 {
1013 D3DLOCKED_RECT sourceLock = {0};
1014 result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001015
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001016 if (FAILED(result))
1017 {
1018 ERR("Failed to lock the source surface (rectangle might be invalid).");
1019 renderTargetData->Release();
1020 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001021 }
1022
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001023 D3DLOCKED_RECT destLock = {0};
1024 result = image->surface->LockRect(&destLock, &destRect, 0);
1025
1026 if (FAILED(result))
1027 {
1028 ERR("Failed to lock the destination surface (rectangle might be invalid).");
1029 renderTargetData->UnlockRect();
1030 renderTargetData->Release();
1031 return error(GL_OUT_OF_MEMORY);
1032 }
1033
1034 if (destLock.pBits && sourceLock.pBits)
1035 {
1036 unsigned char *source = (unsigned char*)sourceLock.pBits;
1037 unsigned char *dest = (unsigned char*)destLock.pBits;
1038
1039 switch (description.Format)
1040 {
1041 case D3DFMT_X8R8G8B8:
1042 case D3DFMT_A8R8G8B8:
1043 switch(image->getD3DFormat())
1044 {
1045 case D3DFMT_L8:
1046 for(int y = 0; y < height; y++)
1047 {
1048 for(int x = 0; x < width; x++)
1049 {
1050 dest[x] = source[x * 4 + 2];
1051 }
1052
1053 source += sourceLock.Pitch;
1054 dest += destLock.Pitch;
1055 }
1056 break;
1057 case D3DFMT_A8L8:
1058 for(int y = 0; y < height; y++)
1059 {
1060 for(int x = 0; x < width; x++)
1061 {
1062 dest[x * 2 + 0] = source[x * 4 + 2];
1063 dest[x * 2 + 1] = source[x * 4 + 3];
1064 }
1065
1066 source += sourceLock.Pitch;
1067 dest += destLock.Pitch;
1068 }
1069 break;
1070 default:
1071 UNREACHABLE();
1072 }
1073 break;
1074 case D3DFMT_R5G6B5:
1075 switch(image->getD3DFormat())
1076 {
1077 case D3DFMT_L8:
1078 for(int y = 0; y < height; y++)
1079 {
1080 for(int x = 0; x < width; x++)
1081 {
1082 unsigned char red = source[x * 2 + 1] & 0xF8;
1083 dest[x] = red | (red >> 5);
1084 }
1085
1086 source += sourceLock.Pitch;
1087 dest += destLock.Pitch;
1088 }
1089 break;
1090 default:
1091 UNREACHABLE();
1092 }
1093 break;
1094 case D3DFMT_A1R5G5B5:
1095 switch(image->getD3DFormat())
1096 {
1097 case D3DFMT_L8:
1098 for(int y = 0; y < height; y++)
1099 {
1100 for(int x = 0; x < width; x++)
1101 {
1102 unsigned char red = source[x * 2 + 1] & 0x7C;
1103 dest[x] = (red << 1) | (red >> 4);
1104 }
1105
1106 source += sourceLock.Pitch;
1107 dest += destLock.Pitch;
1108 }
1109 break;
1110 case D3DFMT_A8L8:
1111 for(int y = 0; y < height; y++)
1112 {
1113 for(int x = 0; x < width; x++)
1114 {
1115 unsigned char red = source[x * 2 + 1] & 0x7C;
1116 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1117 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1118 }
1119
1120 source += sourceLock.Pitch;
1121 dest += destLock.Pitch;
1122 }
1123 break;
1124 default:
1125 UNREACHABLE();
1126 }
1127 break;
1128 default:
1129 UNREACHABLE();
1130 }
1131 }
1132
1133 image->surface->UnlockRect();
1134 renderTargetData->UnlockRect();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001135 }
1136
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001137 renderTargetData->Release();
1138
1139 image->dirty = true;
1140 mDirtyImage = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001141}
1142
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001143IDirect3DBaseTexture9 *Texture::getTexture()
1144{
1145 if (!isComplete())
1146 {
1147 return NULL;
1148 }
1149
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001150 if (!getBaseTexture())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001151 {
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001152 createTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001153 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001154
daniel@transgaming.comc50edcb2011-03-21 16:38:40 +00001155 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001156
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001157 return getBaseTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001158}
1159
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001160bool Texture::isDirtyParameter() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001161{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001162 return mDirtyParameter;
1163}
1164
1165bool Texture::isDirtyImage() const
1166{
1167 return mDirtyImage;
daniel@transgaming.com38e76e52011-03-21 16:39:10 +00001168}
1169
1170void Texture::resetDirty()
1171{
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001172 mDirtyParameter = false;
1173 mDirtyImage = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001174}
1175
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001176unsigned int Texture::getSerial() const
1177{
1178 return mSerial;
1179}
1180
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001181GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1182{
1183 if (isPow2(width) && isPow2(height))
1184 {
1185 return maxlevel;
1186 }
1187 else
1188 {
1189 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1190 return 1;
1191 }
1192}
1193
1194GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1195{
1196 return creationLevels(size, size, maxlevel);
1197}
1198
1199int Texture::levelCount() const
1200{
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001201 return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001202}
1203
daniel@transgaming.coma9eb5da2011-03-21 16:39:16 +00001204unsigned int Texture::issueSerial()
1205{
1206 return mCurrentSerial++;
1207}
1208
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001209Texture2D::Texture2D(GLuint id) : Texture(id)
1210{
1211 mTexture = NULL;
1212}
1213
1214Texture2D::~Texture2D()
1215{
1216 mColorbufferProxy.set(NULL);
1217
1218 if (mTexture)
1219 {
1220 mTexture->Release();
1221 mTexture = NULL;
1222 }
1223}
1224
1225GLenum Texture2D::getTarget() const
1226{
1227 return GL_TEXTURE_2D;
1228}
1229
daniel@transgaming.com61208202011-03-21 16:38:50 +00001230GLsizei Texture2D::getWidth() const
1231{
1232 return mImageArray[0].width;
1233}
1234
1235GLsizei Texture2D::getHeight() const
1236{
1237 return mImageArray[0].height;
1238}
1239
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001240GLenum Texture2D::getInternalFormat() const
1241{
1242 return mImageArray[0].format;
1243}
1244
daniel@transgaming.com61208202011-03-21 16:38:50 +00001245GLenum Texture2D::getType() const
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001246{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001247 return mImageArray[0].type;
1248}
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001249
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001250D3DFORMAT Texture2D::getD3DFormat() const
1251{
1252 return mImageArray[0].getD3DFormat();
1253}
1254
daniel@transgaming.com61208202011-03-21 16:38:50 +00001255void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
1256{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001257 GLsizei textureWidth = mImageArray[0].width;
1258 GLsizei textureHeight = mImageArray[0].height;
1259 GLenum textureFormat = mImageArray[0].format;
1260 GLenum textureType = mImageArray[0].type;
1261
daniel@transgaming.com61208202011-03-21 16:38:50 +00001262 mImageArray[level].width = width;
1263 mImageArray[level].height = height;
1264 mImageArray[level].format = format;
1265 mImageArray[level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001266
daniel@transgaming.com61208202011-03-21 16:38:50 +00001267 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001268 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001269 return;
1270 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001271
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00001272 bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
1273 bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
1274 bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00001275
1276 if (!textureOkay) // Purge all the levels and the texture.
1277 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001278 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1279 {
1280 if (mImageArray[i].surface != NULL)
1281 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001282 mImageArray[i].surface->Release();
1283 mImageArray[i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00001284 mImageArray[i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001285 }
1286 }
1287
1288 if (mTexture != NULL)
1289 {
1290 mTexture->Release();
1291 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001292 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001293 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001294 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001295 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001296}
1297
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001298void 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 +00001299{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001300 redefineTexture(level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001301
daniel@transgaming.com61208202011-03-21 16:38:50 +00001302 Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001303}
1304
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001305void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001306{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001307 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001308
daniel@transgaming.com61208202011-03-21 16:38:50 +00001309 Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001310}
1311
1312void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1313{
1314 ASSERT(mImageArray[level].surface != NULL);
1315
1316 if (level < levelCount())
1317 {
1318 IDirect3DSurface9 *destLevel = NULL;
1319 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
1320
1321 ASSERT(SUCCEEDED(result));
1322
1323 if (SUCCEEDED(result))
1324 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001325 Image *image = &mImageArray[level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001326
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001327 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001328
1329 POINT destPoint;
1330 destPoint.x = sourceRect.left;
1331 destPoint.y = sourceRect.top;
1332
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001333 result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001334 ASSERT(SUCCEEDED(result));
1335
1336 destLevel->Release();
1337
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001338 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001339 }
1340 }
1341}
1342
1343void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1344{
1345 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1346 {
1347 commitRect(level, xoffset, yoffset, width, height);
1348 }
1349}
1350
1351void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1352{
1353 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1354 {
1355 commitRect(level, xoffset, yoffset, width, height);
1356 }
1357}
1358
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001359void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001360{
1361 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1362
1363 if (!renderTarget)
1364 {
1365 ERR("Failed to retrieve the render target.");
1366 return error(GL_OUT_OF_MEMORY);
1367 }
1368
daniel@transgaming.com61208202011-03-21 16:38:50 +00001369 redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001370
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001371 if (!mImageArray[level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001372 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001373 copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001374 }
1375 else
1376 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001377 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001378 {
1379 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001380 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001381
1382 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001383
1384 if (width != 0 && height != 0 && level < levelCount())
1385 {
1386 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1387 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1388 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1389 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1390 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1391
1392 IDirect3DSurface9 *dest;
1393 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1394
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001395 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001396 dest->Release();
1397 }
1398 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001399}
1400
1401void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1402{
1403 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1404 {
1405 return error(GL_INVALID_VALUE);
1406 }
1407
1408 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1409
1410 if (!renderTarget)
1411 {
1412 ERR("Failed to retrieve the render target.");
1413 return error(GL_OUT_OF_MEMORY);
1414 }
1415
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001416 redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001417
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001418 if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001419 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00001420 copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001421 }
1422 else
1423 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001424 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001425 {
1426 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001427 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001428
1429 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001430
1431 if (level < levelCount())
1432 {
1433 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
1434 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
1435 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
1436 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
1437 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
1438
1439 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
1440
1441 IDirect3DSurface9 *dest;
1442 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
1443
1444 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
1445 dest->Release();
1446 }
1447 }
1448}
1449
1450// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1451bool Texture2D::isComplete() const
1452{
1453 GLsizei width = mImageArray[0].width;
1454 GLsizei height = mImageArray[0].height;
1455
1456 if (width <= 0 || height <= 0)
1457 {
1458 return false;
1459 }
1460
1461 bool mipmapping = false;
1462
1463 switch (mMinFilter)
1464 {
1465 case GL_NEAREST:
1466 case GL_LINEAR:
1467 mipmapping = false;
1468 break;
1469 case GL_NEAREST_MIPMAP_NEAREST:
1470 case GL_LINEAR_MIPMAP_NEAREST:
1471 case GL_NEAREST_MIPMAP_LINEAR:
1472 case GL_LINEAR_MIPMAP_LINEAR:
1473 mipmapping = true;
1474 break;
1475 default: UNREACHABLE();
1476 }
1477
1478 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1479 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1480 {
1481 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1482 {
1483 return false;
1484 }
1485 }
1486
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001487 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1488 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1489 {
1490 return false;
1491 }
1492
1493 if (mipmapping)
1494 {
1495 if (!isPow2(width) || !isPow2(height))
1496 {
1497 return false;
1498 }
1499
1500 int q = log2(std::max(width, height));
1501
1502 for (int level = 1; level <= q; level++)
1503 {
1504 if (mImageArray[level].format != mImageArray[0].format)
1505 {
1506 return false;
1507 }
1508
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001509 if (mImageArray[level].type != mImageArray[0].type)
1510 {
1511 return false;
1512 }
1513
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001514 if (mImageArray[level].width != std::max(1, width >> level))
1515 {
1516 return false;
1517 }
1518
1519 if (mImageArray[level].height != std::max(1, height >> level))
1520 {
1521 return false;
1522 }
1523 }
1524 }
1525
1526 return true;
1527}
1528
1529bool Texture2D::isCompressed() const
1530{
1531 return IsCompressed(getInternalFormat());
1532}
1533
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001534IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
1535{
1536 return mTexture;
1537}
1538
1539// Constructs a Direct3D 9 texture resource from the texture images
1540void Texture2D::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001541{
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001542 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001543 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001544 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001545
daniel@transgaming.com61208202011-03-21 16:38:50 +00001546 IDirect3DTexture9 *texture = NULL;
1547 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 +00001548
1549 if (FAILED(result))
1550 {
1551 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001552 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001553 }
1554
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001555 if (mTexture)
1556 {
1557 mTexture->Release();
1558 }
1559
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001560 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001561 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001562 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001563}
1564
1565void Texture2D::updateTexture()
1566{
1567 IDirect3DDevice9 *device = getDevice();
1568
1569 int levels = levelCount();
1570
1571 for (int level = 0; level < levels; level++)
1572 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001573 if (mImageArray[level].surface && mImageArray[level].dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001574 {
1575 IDirect3DSurface9 *levelSurface = NULL;
1576 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
1577
1578 ASSERT(SUCCEEDED(result));
1579
1580 if (SUCCEEDED(result))
1581 {
1582 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1583 ASSERT(SUCCEEDED(result));
1584
1585 levelSurface->Release();
1586
1587 mImageArray[level].dirty = false;
1588 }
1589 }
1590 }
1591}
1592
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001593void Texture2D::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001594{
1595 IDirect3DTexture9 *texture = NULL;
1596
daniel@transgaming.com61208202011-03-21 16:38:50 +00001597 if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001598 {
1599 egl::Display *display = getDisplay();
1600 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001601 D3DFORMAT format = mImageArray[0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001602 GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001603
daniel@transgaming.com61208202011-03-21 16:38:50 +00001604 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 +00001605
1606 if (FAILED(result))
1607 {
1608 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001609 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001610 }
1611
1612 if (mTexture != NULL)
1613 {
1614 int levels = levelCount();
1615 for (int i = 0; i < levels; i++)
1616 {
1617 IDirect3DSurface9 *source;
1618 result = mTexture->GetSurfaceLevel(i, &source);
1619
1620 if (FAILED(result))
1621 {
1622 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1623
1624 texture->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 IDirect3DSurface9 *dest;
1630 result = texture->GetSurfaceLevel(i, &dest);
1631
1632 if (FAILED(result))
1633 {
1634 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1635
1636 texture->Release();
1637 source->Release();
1638
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001639 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001640 }
1641
1642 display->endScene();
1643 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1644
1645 if (FAILED(result))
1646 {
1647 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1648
1649 texture->Release();
1650 source->Release();
1651 dest->Release();
1652
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001653 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001654 }
1655
1656 source->Release();
1657 dest->Release();
1658 }
1659 }
1660 }
1661
1662 if (mTexture != NULL)
1663 {
1664 mTexture->Release();
1665 }
1666
1667 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00001668 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00001669 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001670}
1671
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001672void Texture2D::generateMipmaps()
1673{
1674 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1675 {
1676 return error(GL_INVALID_OPERATION);
1677 }
1678
1679 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
daniel@transgaming.com61208202011-03-21 16:38:50 +00001680 unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001681 for (unsigned int i = 1; i <= q; i++)
1682 {
1683 if (mImageArray[i].surface != NULL)
1684 {
1685 mImageArray[i].surface->Release();
1686 mImageArray[i].surface = NULL;
1687 }
1688
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001689 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1690 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001691 mImageArray[i].format = mImageArray[0].format;
1692 mImageArray[i].type = mImageArray[0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001693 }
1694
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001695 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001696 {
1697 if (mTexture == NULL)
1698 {
1699 ERR(" failed because mTexture was null.");
1700 return;
1701 }
1702
1703 for (unsigned int i = 1; i <= q; i++)
1704 {
1705 IDirect3DSurface9 *upper = NULL;
1706 IDirect3DSurface9 *lower = NULL;
1707
1708 mTexture->GetSurfaceLevel(i-1, &upper);
1709 mTexture->GetSurfaceLevel(i, &lower);
1710
1711 if (upper != NULL && lower != NULL)
1712 {
1713 getBlitter()->boxFilter(upper, lower);
1714 }
1715
1716 if (upper != NULL) upper->Release();
1717 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00001718
1719 mImageArray[i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001720 }
1721 }
1722 else
1723 {
1724 for (unsigned int i = 1; i <= q; i++)
1725 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00001726 createSurface(&mImageArray[i]);
1727
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001728 if (mImageArray[i].surface == NULL)
1729 {
1730 return error(GL_OUT_OF_MEMORY);
1731 }
1732
1733 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1734 {
1735 ERR(" failed to load filter %d to %d.", i - 1, i);
1736 }
1737
1738 mImageArray[i].dirty = true;
1739 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001740 }
1741}
1742
1743Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
1744{
1745 if (target != GL_TEXTURE_2D)
1746 {
1747 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
1748 }
1749
1750 if (mColorbufferProxy.get() == NULL)
1751 {
1752 mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
1753 }
1754
1755 return mColorbufferProxy.get();
1756}
1757
1758IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1759{
1760 ASSERT(target == GL_TEXTURE_2D);
1761
daniel@transgaming.com61208202011-03-21 16:38:50 +00001762 if (!mIsRenderable)
1763 {
1764 convertToRenderTarget();
1765 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001766
1767 if (mTexture == NULL)
1768 {
1769 return NULL;
1770 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00001771
1772 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001773
1774 IDirect3DSurface9 *renderTarget = NULL;
1775 mTexture->GetSurfaceLevel(0, &renderTarget);
1776
1777 return renderTarget;
1778}
1779
1780TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
1781{
1782 mTexture = NULL;
1783}
1784
1785TextureCubeMap::~TextureCubeMap()
1786{
1787 for (int i = 0; i < 6; i++)
1788 {
1789 mFaceProxies[i].set(NULL);
1790 }
1791
1792 if (mTexture)
1793 {
1794 mTexture->Release();
1795 mTexture = NULL;
1796 }
1797}
1798
1799GLenum TextureCubeMap::getTarget() const
1800{
1801 return GL_TEXTURE_CUBE_MAP;
1802}
1803
daniel@transgaming.com61208202011-03-21 16:38:50 +00001804GLsizei TextureCubeMap::getWidth() const
1805{
1806 return mImageArray[0][0].width;
1807}
1808
1809GLsizei TextureCubeMap::getHeight() const
1810{
1811 return mImageArray[0][0].height;
1812}
1813
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001814GLenum TextureCubeMap::getInternalFormat() const
1815{
1816 return mImageArray[0][0].format;
1817}
1818
daniel@transgaming.com61208202011-03-21 16:38:50 +00001819GLenum TextureCubeMap::getType() const
1820{
1821 return mImageArray[0][0].type;
1822}
1823
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00001824D3DFORMAT TextureCubeMap::getD3DFormat() const
1825{
1826 return mImageArray[0][0].getD3DFormat();
1827}
1828
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001829void 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 +00001830{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001831 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001832}
1833
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001834void 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 +00001835{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001836 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001837}
1838
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001839void 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 +00001840{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001841 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001842}
1843
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001844void 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 +00001845{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001846 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001847}
1848
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001849void 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 +00001850{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001851 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001852}
1853
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001854void 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 +00001855{
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001856 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001857}
1858
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00001859void 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 +00001860{
daniel@transgaming.com61208202011-03-21 16:38:50 +00001861 redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001862
daniel@transgaming.com61208202011-03-21 16:38:50 +00001863 Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001864}
1865
1866void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1867{
1868 int face = faceIndex(faceTarget);
1869 ASSERT(mImageArray[face][level].surface != NULL);
1870
1871 if (level < levelCount())
1872 {
1873 IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
1874 ASSERT(destLevel != NULL);
1875
1876 if (destLevel != NULL)
1877 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001878 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001879
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001880 RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001881
1882 POINT destPoint;
1883 destPoint.x = sourceRect.left;
1884 destPoint.y = sourceRect.top;
1885
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001886 HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001887 ASSERT(SUCCEEDED(result));
1888
1889 destLevel->Release();
1890
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00001891 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001892 }
1893 }
1894}
1895
1896void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
1897{
1898 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
1899 {
1900 commitRect(target, level, xoffset, yoffset, width, height);
1901 }
1902}
1903
1904void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1905{
1906 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
1907 {
1908 commitRect(target, level, xoffset, yoffset, width, height);
1909 }
1910}
1911
1912// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1913bool TextureCubeMap::isComplete() const
1914{
1915 int size = mImageArray[0][0].width;
1916
1917 if (size <= 0)
1918 {
1919 return false;
1920 }
1921
1922 bool mipmapping;
1923
1924 switch (mMinFilter)
1925 {
1926 case GL_NEAREST:
1927 case GL_LINEAR:
1928 mipmapping = false;
1929 break;
1930 case GL_NEAREST_MIPMAP_NEAREST:
1931 case GL_LINEAR_MIPMAP_NEAREST:
1932 case GL_NEAREST_MIPMAP_LINEAR:
1933 case GL_LINEAR_MIPMAP_LINEAR:
1934 mipmapping = true;
1935 break;
1936 default: UNREACHABLE();
1937 }
1938
1939 for (int face = 0; face < 6; face++)
1940 {
1941 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
1942 {
1943 return false;
1944 }
1945 }
1946
1947 if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1948 (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1949 {
1950 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1951 {
1952 return false;
1953 }
1954 }
1955
1956 if (mipmapping)
1957 {
1958 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1959 {
1960 return false;
1961 }
1962
1963 int q = log2(size);
1964
1965 for (int face = 0; face < 6; face++)
1966 {
1967 for (int level = 1; level <= q; level++)
1968 {
1969 if (mImageArray[face][level].format != mImageArray[0][0].format)
1970 {
1971 return false;
1972 }
1973
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00001974 if (mImageArray[face][level].type != mImageArray[0][0].type)
1975 {
1976 return false;
1977 }
1978
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00001979 if (mImageArray[face][level].width != std::max(1, size >> level))
1980 {
1981 return false;
1982 }
1983
1984 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
1985 }
1986 }
1987 }
1988
1989 return true;
1990}
1991
1992bool TextureCubeMap::isCompressed() const
1993{
1994 return IsCompressed(getInternalFormat());
1995}
1996
daniel@transgaming.com68076a02011-03-21 16:38:09 +00001997IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
1998{
1999 return mTexture;
2000}
2001
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002002// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002003void TextureCubeMap::createTexture()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002004{
2005 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002006 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002007 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002008
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002009 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002010 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002011
2012 if (FAILED(result))
2013 {
2014 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002015 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002016 }
2017
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002018 if (mTexture)
2019 {
2020 mTexture->Release();
2021 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002022
2023 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002024 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002025 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002026}
2027
2028void TextureCubeMap::updateTexture()
2029{
2030 IDirect3DDevice9 *device = getDevice();
2031
2032 for (int face = 0; face < 6; face++)
2033 {
2034 int levels = levelCount();
2035 for (int level = 0; level < levels; level++)
2036 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002037 Image *image = &mImageArray[face][level];
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002038
daniel@transgaming.com61208202011-03-21 16:38:50 +00002039 if (image->surface && image->dirty)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002040 {
2041 IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
2042 ASSERT(levelSurface != NULL);
2043
2044 if (levelSurface != NULL)
2045 {
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002046 HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002047 ASSERT(SUCCEEDED(result));
2048
2049 levelSurface->Release();
2050
daniel@transgaming.comb5a3a6b2011-03-21 16:38:46 +00002051 image->dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002052 }
2053 }
2054 }
2055 }
2056}
2057
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002058void TextureCubeMap::convertToRenderTarget()
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002059{
2060 IDirect3DCubeTexture9 *texture = NULL;
2061
daniel@transgaming.com61208202011-03-21 16:38:50 +00002062 if (mImageArray[0][0].width != 0)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002063 {
2064 egl::Display *display = getDisplay();
2065 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002066 D3DFORMAT format = mImageArray[0][0].getD3DFormat();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002067 GLint levels = creationLevels(mImageArray[0][0].width, 0);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002068
daniel@transgaming.com61208202011-03-21 16:38:50 +00002069 HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002070
2071 if (FAILED(result))
2072 {
2073 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002074 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002075 }
2076
2077 if (mTexture != NULL)
2078 {
2079 int levels = levelCount();
2080 for (int f = 0; f < 6; f++)
2081 {
2082 for (int i = 0; i < levels; i++)
2083 {
2084 IDirect3DSurface9 *source;
2085 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2086
2087 if (FAILED(result))
2088 {
2089 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2090
2091 texture->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 IDirect3DSurface9 *dest;
2097 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2098
2099 if (FAILED(result))
2100 {
2101 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2102
2103 texture->Release();
2104 source->Release();
2105
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002106 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002107 }
2108
2109 display->endScene();
2110 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2111
2112 if (FAILED(result))
2113 {
2114 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2115
2116 texture->Release();
2117 source->Release();
2118 dest->Release();
2119
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002120 return error(GL_OUT_OF_MEMORY);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002121 }
2122 }
2123 }
2124 }
2125 }
2126
2127 if (mTexture != NULL)
2128 {
2129 mTexture->Release();
2130 }
2131
2132 mTexture = texture;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002133 mDirtyImage = true;
daniel@transgaming.comaed18322011-03-21 16:38:13 +00002134 mIsRenderable = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002135}
2136
daniel@transgaming.com61208202011-03-21 16:38:50 +00002137void 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 +00002138{
daniel@transgaming.com61208202011-03-21 16:38:50 +00002139 redefineTexture(faceIndex, level, format, width, height, type);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002140
daniel@transgaming.com61208202011-03-21 16:38:50 +00002141 Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002142}
2143
2144unsigned int TextureCubeMap::faceIndex(GLenum face)
2145{
2146 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2147 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2148 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2149 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2150 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2151
2152 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2153}
2154
daniel@transgaming.com61208202011-03-21 16:38:50 +00002155void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002156{
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002157 GLsizei textureWidth = mImageArray[0][0].width;
2158 GLsizei textureHeight = mImageArray[0][0].height;
2159 GLenum textureFormat = mImageArray[0][0].format;
2160 GLenum textureType = mImageArray[0][0].type;
2161
daniel@transgaming.com61208202011-03-21 16:38:50 +00002162 mImageArray[face][level].width = width;
2163 mImageArray[face][level].height = height;
2164 mImageArray[face][level].format = format;
2165 mImageArray[face][level].type = type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002166
daniel@transgaming.com61208202011-03-21 16:38:50 +00002167 if (!mTexture)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002168 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002169 return;
2170 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002171
daniel@transgaming.com94a4f032011-03-21 16:38:55 +00002172 bool sizeOkay = (textureWidth >> level == width);
2173 bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002174
2175 if (!textureOkay) // Purge all the levels and the texture.
2176 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002177 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2178 {
2179 for (int f = 0; f < 6; f++)
2180 {
2181 if (mImageArray[f][i].surface != NULL)
2182 {
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002183 mImageArray[f][i].surface->Release();
2184 mImageArray[f][i].surface = NULL;
daniel@transgaming.com61208202011-03-21 16:38:50 +00002185 mImageArray[f][i].dirty = true;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002186 }
2187 }
2188 }
2189
2190 if (mTexture != NULL)
2191 {
2192 mTexture->Release();
2193 mTexture = NULL;
daniel@transgaming.coma06aa872011-03-21 17:22:21 +00002194 mDirtyImage = true;
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002195 mIsRenderable = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002196 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002197 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002198}
2199
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002200void 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 +00002201{
2202 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2203
2204 if (!renderTarget)
2205 {
2206 ERR("Failed to retrieve the render target.");
2207 return error(GL_OUT_OF_MEMORY);
2208 }
2209
2210 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com61208202011-03-21 16:38:50 +00002211 redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002212
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002213 if (!mImageArray[faceindex][level].isRenderable())
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002214 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002215 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002216 }
2217 else
2218 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002219 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002220 {
2221 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002222 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002223
2224 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002225
2226 ASSERT(width == height);
2227
2228 if (width > 0 && level < levelCount())
2229 {
2230 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2231 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2232 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2233 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2234 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2235
2236 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2237
daniel@transgaming.com8a0a2db2011-03-21 16:38:20 +00002238 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, format, 0, 0, dest);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002239 dest->Release();
2240 }
2241 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002242}
2243
2244IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
2245{
2246 if (mTexture == NULL)
2247 {
2248 UNREACHABLE();
2249 return NULL;
2250 }
2251
2252 IDirect3DSurface9 *surface = NULL;
2253
2254 HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
2255
2256 return (SUCCEEDED(hr)) ? surface : NULL;
2257}
2258
2259void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2260{
2261 GLsizei size = mImageArray[faceIndex(target)][level].width;
2262
2263 if (xoffset + width > size || yoffset + height > size)
2264 {
2265 return error(GL_INVALID_VALUE);
2266 }
2267
2268 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2269
2270 if (!renderTarget)
2271 {
2272 ERR("Failed to retrieve the render target.");
2273 return error(GL_OUT_OF_MEMORY);
2274 }
2275
2276 unsigned int faceindex = faceIndex(target);
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002277 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 +00002278
daniel@transgaming.com549bdef2011-03-29 00:57:01 +00002279 if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002280 {
daniel@transgaming.comb6276992011-03-29 00:58:18 +00002281 copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002282 }
2283 else
2284 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002285 if (!mTexture || !mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002286 {
2287 convertToRenderTarget();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002288 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002289
2290 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002291
2292 if (level < levelCount())
2293 {
2294 RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
2295 sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
2296 sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
2297 sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
2298 sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
2299
2300 GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
2301
2302 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
2303
2304 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
2305 dest->Release();
2306 }
2307 }
2308}
2309
2310bool TextureCubeMap::isCubeComplete() const
2311{
2312 if (mImageArray[0][0].width == 0)
2313 {
2314 return false;
2315 }
2316
2317 for (unsigned int f = 1; f < 6; f++)
2318 {
2319 if (mImageArray[f][0].width != mImageArray[0][0].width
2320 || mImageArray[f][0].format != mImageArray[0][0].format)
2321 {
2322 return false;
2323 }
2324 }
2325
2326 return true;
2327}
2328
2329void TextureCubeMap::generateMipmaps()
2330{
2331 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2332 {
2333 return error(GL_INVALID_OPERATION);
2334 }
2335
2336 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2337 unsigned int q = log2(mImageArray[0][0].width);
2338 for (unsigned int f = 0; f < 6; f++)
2339 {
2340 for (unsigned int i = 1; i <= q; i++)
2341 {
2342 if (mImageArray[f][i].surface != NULL)
2343 {
2344 mImageArray[f][i].surface->Release();
2345 mImageArray[f][i].surface = NULL;
2346 }
2347
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002348 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2349 mImageArray[f][i].height = mImageArray[f][i].width;
daniel@transgaming.com0bd22bc2011-03-21 16:38:26 +00002350 mImageArray[f][i].format = mImageArray[f][0].format;
2351 mImageArray[f][i].type = mImageArray[f][0].type;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002352 }
2353 }
2354
daniel@transgaming.com68076a02011-03-21 16:38:09 +00002355 if (mIsRenderable)
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002356 {
2357 if (mTexture == NULL)
2358 {
2359 return;
2360 }
2361
2362 for (unsigned int f = 0; f < 6; f++)
2363 {
2364 for (unsigned int i = 1; i <= q; i++)
2365 {
2366 IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
2367 IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
2368
2369 if (upper != NULL && lower != NULL)
2370 {
2371 getBlitter()->boxFilter(upper, lower);
2372 }
2373
2374 if (upper != NULL) upper->Release();
2375 if (lower != NULL) lower->Release();
daniel@transgaming.com61208202011-03-21 16:38:50 +00002376
2377 mImageArray[f][i].dirty = false;
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002378 }
2379 }
2380 }
2381 else
2382 {
2383 for (unsigned int f = 0; f < 6; f++)
2384 {
2385 for (unsigned int i = 1; i <= q; i++)
2386 {
daniel@transgaming.com61208202011-03-21 16:38:50 +00002387 createSurface(&mImageArray[f][i]);
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002388 if (mImageArray[f][i].surface == NULL)
2389 {
2390 return error(GL_OUT_OF_MEMORY);
2391 }
2392
2393 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2394 {
2395 ERR(" failed to load filter %d to %d.", i - 1, i);
2396 }
2397
2398 mImageArray[f][i].dirty = true;
2399 }
2400 }
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002401 }
2402}
2403
2404Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
2405{
2406 if (!IsCubemapTextureTarget(target))
2407 {
2408 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
2409 }
2410
2411 unsigned int face = faceIndex(target);
2412
2413 if (mFaceProxies[face].get() == NULL)
2414 {
2415 mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
2416 }
2417
2418 return mFaceProxies[face].get();
2419}
2420
2421IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2422{
2423 ASSERT(IsCubemapTextureTarget(target));
2424
daniel@transgaming.com61208202011-03-21 16:38:50 +00002425 if (!mIsRenderable)
2426 {
2427 convertToRenderTarget();
2428 }
2429
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002430 if (mTexture == NULL)
2431 {
2432 return NULL;
2433 }
daniel@transgaming.com61208202011-03-21 16:38:50 +00002434
2435 updateTexture();
daniel@transgaming.comd2fd4f22011-02-01 18:49:11 +00002436
2437 IDirect3DSurface9 *renderTarget = NULL;
2438 mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
2439
2440 return renderTarget;
2441}
2442
2443}