blob: 2feb7e45c81147d27cf97d93cceb3939f4f6e860 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +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
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000011#include "libGLESv2/Texture.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
daniel@transgaming.com16973022010-03-11 19:22:19 +000013#include <algorithm>
14
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000015#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000016
17#include "libGLESv2/main.h"
18#include "libGLESv2/mathutil.h"
19#include "libGLESv2/utilities.h"
20#include "libGLESv2/Blit.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021
22namespace gl
23{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000024
25Texture::Image::Image()
daniel@transgaming.com01868132010-08-24 19:21:17 +000026 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000027{
28}
29
30Texture::Image::~Image()
31{
32 if (surface) surface->Release();
33}
34
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000035Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036{
37 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
38 mMagFilter = GL_LINEAR;
39 mWrapS = GL_REPEAT;
40 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000041
daniel@transgaming.com31273552010-08-04 13:42:44 +000042 mWidth = 0;
43 mHeight = 0;
44
daniel@transgaming.com00c75962010-03-11 20:36:15 +000045 mDirtyMetaData = true;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000046 mDirty = true;
daniel@transgaming.com93a81472010-04-20 18:52:58 +000047 mIsRenderable = false;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +000048 mType = GL_UNSIGNED_BYTE;
daniel@transgaming.com0a311a42010-05-17 09:58:33 +000049 mBaseTexture = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000050}
51
52Texture::~Texture()
53{
54}
55
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000056Blit *Texture::getBlitter()
57{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000058 Context *context = getContext();
59 return context->getBlitter();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000060}
61
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000062// Returns true on successful filter state update (valid enum parameter)
63bool Texture::setMinFilter(GLenum filter)
64{
65 switch (filter)
66 {
67 case GL_NEAREST:
68 case GL_LINEAR:
69 case GL_NEAREST_MIPMAP_NEAREST:
70 case GL_LINEAR_MIPMAP_NEAREST:
71 case GL_NEAREST_MIPMAP_LINEAR:
72 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000073 {
74 if (mMinFilter != filter)
75 {
76 mMinFilter = filter;
77 mDirty = true;
78 }
79 return true;
80 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000081 default:
82 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000083 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000084}
85
86// Returns true on successful filter state update (valid enum parameter)
87bool Texture::setMagFilter(GLenum filter)
88{
89 switch (filter)
90 {
91 case GL_NEAREST:
92 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000093 {
94 if (mMagFilter != filter)
95 {
96 mMagFilter = filter;
97 mDirty = true;
98 }
99 return true;
100 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000101 default:
102 return false;
103 }
104}
105
106// Returns true on successful wrap state update (valid enum parameter)
107bool Texture::setWrapS(GLenum wrap)
108{
109 switch (wrap)
110 {
111 case GL_REPEAT:
112 case GL_CLAMP_TO_EDGE:
113 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000114 {
115 if (mWrapS != wrap)
116 {
117 mWrapS = wrap;
118 mDirty = true;
119 }
120 return true;
121 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122 default:
123 return false;
124 }
125}
126
127// Returns true on successful wrap state update (valid enum parameter)
128bool Texture::setWrapT(GLenum wrap)
129{
130 switch (wrap)
131 {
132 case GL_REPEAT:
133 case GL_CLAMP_TO_EDGE:
134 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000135 {
136 if (mWrapT != wrap)
137 {
138 mWrapT = wrap;
139 mDirty = true;
140 }
141 return true;
142 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143 default:
144 return false;
145 }
146}
147
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000148GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149{
150 return mMinFilter;
151}
152
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000153GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154{
155 return mMagFilter;
156}
157
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000158GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159{
160 return mWrapS;
161}
162
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000163GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164{
165 return mWrapT;
166}
167
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000168GLuint Texture::getWidth() const
169{
170 return mWidth;
171}
172
173GLuint Texture::getHeight() const
174{
175 return mHeight;
176}
177
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000178bool Texture::isFloatingPoint() const
179{
180 return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
181}
182
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000184D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000185{
daniel@transgaming.com01868132010-08-24 19:21:17 +0000186 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
187 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
188 {
189 return D3DFMT_DXT1;
190 }
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000191 else if (type == GL_FLOAT)
192 {
193 return D3DFMT_A32B32G32R32F;
194 }
195 else if (type == GL_HALF_FLOAT_OES)
196 {
197 return D3DFMT_A16B16G16R16F;
198 }
daniel@transgaming.com01868132010-08-24 19:21:17 +0000199 else
200 {
201 return D3DFMT_A8R8G8B8;
202 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203}
204
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000205// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
206// into the BGRA8 pixel rectangle at output with outputPitch bytes in between each line.
207void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000208 GLint unpackAlignment, const void *input, size_t outputPitch, void *output) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000209{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000210 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000211
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000212 switch (type)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000213 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000214 case GL_UNSIGNED_BYTE:
215 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000216 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000217 case GL_ALPHA:
218 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
219 break;
220 case GL_LUMINANCE:
221 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
222 break;
223 case GL_LUMINANCE_ALPHA:
224 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
225 break;
226 case GL_RGB:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000227 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
228 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000229 case GL_RGBA:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000230 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
231 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000232 case GL_BGRA_EXT:
233 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000234 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000235 default: UNREACHABLE();
236 }
237 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000238 case GL_UNSIGNED_SHORT_5_6_5:
239 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000240 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000241 case GL_RGB:
242 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000243 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000244 default: UNREACHABLE();
245 }
246 break;
247 case GL_UNSIGNED_SHORT_4_4_4_4:
248 switch (format)
249 {
250 case GL_RGBA:
251 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
252 break;
253 default: UNREACHABLE();
254 }
255 break;
256 case GL_UNSIGNED_SHORT_5_5_5_1:
257 switch (format)
258 {
259 case GL_RGBA:
260 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
261 break;
262 default: UNREACHABLE();
263 }
264 break;
265 case GL_FLOAT:
266 switch (format)
267 {
268 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
269 case GL_ALPHA:
270 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
271 break;
272 case GL_LUMINANCE:
273 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
274 break;
275 case GL_LUMINANCE_ALPHA:
276 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
277 break;
278 case GL_RGB:
279 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
280 break;
281 case GL_RGBA:
282 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
283 break;
284 default: UNREACHABLE();
285 }
286 break;
287 case GL_HALF_FLOAT_OES:
288 switch (format)
289 {
290 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
291 case GL_ALPHA:
292 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
293 break;
294 case GL_LUMINANCE:
295 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
296 break;
297 case GL_LUMINANCE_ALPHA:
298 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
299 break;
300 case GL_RGB:
301 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
302 break;
303 case GL_RGBA:
304 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
305 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000306 default: UNREACHABLE();
307 }
308 break;
309 default: UNREACHABLE();
310 }
311}
312
313void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
314 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
315{
316 const unsigned char *source = NULL;
317 unsigned char *dest = NULL;
318
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000319 for (int y = 0; y < height; y++)
320 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000321 source = static_cast<const unsigned char*>(input) + y * inputPitch;
322 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000323 for (int x = 0; x < width; x++)
324 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000325 dest[4 * x + 0] = 0;
326 dest[4 * x + 1] = 0;
327 dest[4 * x + 2] = 0;
328 dest[4 * x + 3] = source[x];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000329 }
330 }
331}
332
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000333void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
334 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
335{
336 const float *source = NULL;
337 float *dest = NULL;
338
339 for (int y = 0; y < height; y++)
340 {
341 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
342 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
343 for (int x = 0; x < width; x++)
344 {
345 dest[4 * x + 0] = 0;
346 dest[4 * x + 1] = 0;
347 dest[4 * x + 2] = 0;
348 dest[4 * x + 3] = source[x];
349 }
350 }
351}
352
353void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
354 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
355{
356 const unsigned short *source = NULL;
357 unsigned short *dest = NULL;
358
359 for (int y = 0; y < height; y++)
360 {
361 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
362 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
363 for (int x = 0; x < width; x++)
364 {
365 dest[4 * x + 0] = 0;
366 dest[4 * x + 1] = 0;
367 dest[4 * x + 2] = 0;
368 dest[4 * x + 3] = source[x];
369 }
370 }
371}
372
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000373void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
374 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
375{
376 const unsigned char *source = NULL;
377 unsigned char *dest = NULL;
378
379 for (int y = 0; y < height; y++)
380 {
381 source = static_cast<const unsigned char*>(input) + y * inputPitch;
382 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
383 for (int x = 0; x < width; x++)
384 {
385 dest[4 * x + 0] = source[x];
386 dest[4 * x + 1] = source[x];
387 dest[4 * x + 2] = source[x];
388 dest[4 * x + 3] = 0xFF;
389 }
390 }
391}
392
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000393void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
394 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
395{
396 const float *source = NULL;
397 float *dest = NULL;
398
399 for (int y = 0; y < height; y++)
400 {
401 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
402 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
403 for (int x = 0; x < width; x++)
404 {
405 dest[4 * x + 0] = source[x];
406 dest[4 * x + 1] = source[x];
407 dest[4 * x + 2] = source[x];
408 dest[4 * x + 3] = 1.0f;
409 }
410 }
411}
412
413void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
414 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
415{
416 const unsigned short *source = NULL;
417 unsigned short *dest = NULL;
418
419 for (int y = 0; y < height; y++)
420 {
421 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
422 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
423 for (int x = 0; x < width; x++)
424 {
425 dest[4 * x + 0] = source[x];
426 dest[4 * x + 1] = source[x];
427 dest[4 * x + 2] = source[x];
428 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
429 }
430 }
431}
432
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000433void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
434 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
435{
436 const unsigned char *source = NULL;
437 unsigned char *dest = NULL;
438
439 for (int y = 0; y < height; y++)
440 {
441 source = static_cast<const unsigned char*>(input) + y * inputPitch;
442 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
443 for (int x = 0; x < width; x++)
444 {
445 dest[4 * x + 0] = source[2*x+0];
446 dest[4 * x + 1] = source[2*x+0];
447 dest[4 * x + 2] = source[2*x+0];
448 dest[4 * x + 3] = source[2*x+1];
449 }
450 }
451}
452
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000453void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
454 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
455{
456 const float *source = NULL;
457 float *dest = NULL;
458
459 for (int y = 0; y < height; y++)
460 {
461 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
462 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
463 for (int x = 0; x < width; x++)
464 {
465 dest[4 * x + 0] = source[2*x+0];
466 dest[4 * x + 1] = source[2*x+0];
467 dest[4 * x + 2] = source[2*x+0];
468 dest[4 * x + 3] = source[2*x+1];
469 }
470 }
471}
472
473void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
474 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
475{
476 const unsigned short *source = NULL;
477 unsigned short *dest = NULL;
478
479 for (int y = 0; y < height; y++)
480 {
481 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
482 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
483 for (int x = 0; x < width; x++)
484 {
485 dest[4 * x + 0] = source[2*x+0];
486 dest[4 * x + 1] = source[2*x+0];
487 dest[4 * x + 2] = source[2*x+0];
488 dest[4 * x + 3] = source[2*x+1];
489 }
490 }
491}
492
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000493void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
494 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
495{
496 const unsigned char *source = NULL;
497 unsigned char *dest = NULL;
498
499 for (int y = 0; y < height; y++)
500 {
501 source = static_cast<const unsigned char*>(input) + y * inputPitch;
502 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
503 for (int x = 0; x < width; x++)
504 {
505 dest[4 * x + 0] = source[x * 3 + 2];
506 dest[4 * x + 1] = source[x * 3 + 1];
507 dest[4 * x + 2] = source[x * 3 + 0];
508 dest[4 * x + 3] = 0xFF;
509 }
510 }
511}
512
513void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
514 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
515{
516 const unsigned short *source = NULL;
517 unsigned char *dest = NULL;
518
519 for (int y = 0; y < height; y++)
520 {
521 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
522 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
523 for (int x = 0; x < width; x++)
524 {
525 unsigned short rgba = source[x];
526 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
527 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
528 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
529 dest[4 * x + 3] = 0xFF;
530 }
531 }
532}
533
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000534void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
535 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
536{
537 const float *source = NULL;
538 float *dest = NULL;
539
540 for (int y = 0; y < height; y++)
541 {
542 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
543 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
544 for (int x = 0; x < width; x++)
545 {
546 dest[4 * x + 0] = source[x * 3 + 0];
547 dest[4 * x + 1] = source[x * 3 + 1];
548 dest[4 * x + 2] = source[x * 3 + 2];
549 dest[4 * x + 3] = 1.0f;
550 }
551 }
552}
553
554void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
555 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
556{
557 const unsigned short *source = NULL;
558 unsigned short *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 = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
564 for (int x = 0; x < width; x++)
565 {
566 dest[4 * x + 0] = source[x * 3 + 0];
567 dest[4 * x + 1] = source[x * 3 + 1];
568 dest[4 * x + 2] = source[x * 3 + 2];
569 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
570 }
571 }
572}
573
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000574void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
575 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
576{
577 const unsigned char *source = NULL;
578 unsigned char *dest = NULL;
579
580 for (int y = 0; y < height; y++)
581 {
582 source = static_cast<const unsigned char*>(input) + y * inputPitch;
583 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
584 for (int x = 0; x < width; x++)
585 {
586 dest[4 * x + 0] = source[x * 4 + 2];
587 dest[4 * x + 1] = source[x * 4 + 1];
588 dest[4 * x + 2] = source[x * 4 + 0];
589 dest[4 * x + 3] = source[x * 4 + 3];
590 }
591 }
592}
593
594void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
595 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
596{
597 const unsigned short *source = NULL;
598 unsigned char *dest = NULL;
599
600 for (int y = 0; y < height; y++)
601 {
602 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
603 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
604 for (int x = 0; x < width; x++)
605 {
606 unsigned short rgba = source[x];
607 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
608 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
609 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
610 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
611 }
612 }
613}
614
615void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
616 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
617{
618 const unsigned short *source = NULL;
619 unsigned char *dest = NULL;
620
621 for (int y = 0; y < height; y++)
622 {
623 source = reinterpret_cast<const unsigned short*>(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 unsigned short rgba = source[x];
628 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
629 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
630 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
631 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
632 }
633 }
634}
635
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000636void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
637 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
638{
639 const float *source = NULL;
640 float *dest = NULL;
641
642 for (int y = 0; y < height; y++)
643 {
644 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
645 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
646 memcpy(dest, source, width * 16);
647 }
648}
649
650void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
651 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
652{
653 const unsigned char *source = NULL;
654 unsigned char *dest = NULL;
655
656 for (int y = 0; y < height; y++)
657 {
658 source = static_cast<const unsigned char*>(input) + y * inputPitch;
659 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
660 memcpy(dest, source, width * 8);
661 }
662}
663
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000664void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
665 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
666{
667 const unsigned char *source = NULL;
668 unsigned char *dest = NULL;
669
670 for (int y = 0; y < height; y++)
671 {
672 source = static_cast<const unsigned char*>(input) + y * inputPitch;
673 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
674 memcpy(dest, source, width*4);
675 }
676}
677
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000678void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000679{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000680 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000681 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000682
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000683 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000684 {
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000685 int levelToFetch = 0;
686 GLsizei requestWidth = width;
687 GLsizei requestHeight = height;
688 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
689 {
690 bool isMult4 = false;
691 int upsampleCount = 0;
692 while (!isMult4)
693 {
694 requestWidth <<= 1;
695 requestHeight <<= 1;
696 upsampleCount++;
697 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
698 {
699 isMult4 = true;
700 }
701 }
702 levelToFetch = upsampleCount;
703 }
704
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000705 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000706 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000707
708 if (FAILED(result))
709 {
710 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
711 return error(GL_OUT_OF_MEMORY);
712 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000713
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000714 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000715 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000716 }
717
718 if (img->surface) img->surface->Release();
719 img->surface = newSurface;
720
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000721 img->width = width;
722 img->height = height;
723 img->format = format;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000724}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000725
daniel@transgaming.com01868132010-08-24 19:21:17 +0000726void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
727{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000728 createSurface(width, height, format, type, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000729
730 if (pixels != NULL && img->surface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000731 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000732 D3DLOCKED_RECT locked;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000733 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000734
735 ASSERT(SUCCEEDED(result));
736
737 if (SUCCEEDED(result))
738 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000739 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000740 img->surface->UnlockRect();
741 }
742
743 img->dirty = true;
744 }
745
746 mDirtyMetaData = true;
747}
748
749void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
750{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000751 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000752
753 if (pixels != NULL && img->surface != NULL)
754 {
755 D3DLOCKED_RECT locked;
756 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
757
758 ASSERT(SUCCEEDED(result));
759
760 if (SUCCEEDED(result))
761 {
762 memcpy(locked.pBits, pixels, imageSize);
763 img->surface->UnlockRect();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000764 }
765
766 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000767 }
768
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000769 mDirtyMetaData = true;
770}
771
daniel@transgaming.com31273552010-08-04 13:42:44 +0000772bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000773{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000774 if (width + xoffset > img->width || height + yoffset > img->height)
775 {
776 error(GL_INVALID_VALUE);
777 return false;
778 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000779
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000780 D3DLOCKED_RECT locked;
781 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000782
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000783 ASSERT(SUCCEEDED(result));
784
785 if (SUCCEEDED(result))
786 {
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +0000787 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000788 img->surface->UnlockRect();
789 }
790
791 img->dirty = true;
daniel@transgaming.com31273552010-08-04 13:42:44 +0000792 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000793}
794
daniel@transgaming.com01868132010-08-24 19:21:17 +0000795bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
796{
797 if (width + xoffset > img->width || height + yoffset > img->height)
798 {
799 error(GL_INVALID_VALUE);
800 return false;
801 }
802
803 if (format != getFormat())
804 {
805 error(GL_INVALID_OPERATION);
806 return false;
807 }
808
809 RECT updateRegion;
810 updateRegion.left = xoffset;
811 updateRegion.right = xoffset + width;
812 updateRegion.bottom = yoffset + height;
813 updateRegion.top = yoffset;
814
815 D3DLOCKED_RECT locked;
816 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
817
818 ASSERT(SUCCEEDED(result));
819
820 if (SUCCEEDED(result))
821 {
822 GLsizei inputPitch = ComputeCompressedPitch(width, format);
823 int rows = imageSize / inputPitch;
824 for (int i = 0; i < rows; ++i)
825 {
826 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch);
827 }
828 img->surface->UnlockRect();
829 }
830
831 img->dirty = true;
832 return true;
833}
834
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000835IDirect3DBaseTexture9 *Texture::getTexture()
836{
837 if (!isComplete())
838 {
839 return NULL;
840 }
841
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000842 if (mDirtyMetaData)
843 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000844 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000845 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000846 }
847
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000848 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000849 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000850 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000851 }
852
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000853 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000854 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000855
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000856 return mBaseTexture;
857}
858
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000859bool Texture::isDirty() const
860{
861 return (mDirty || mDirtyMetaData || dirtyImageData());
862}
863
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000864// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000865void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000866{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000867 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000868 {
869 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000870 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000871 }
872
873 if (dirtyImageData())
874 {
875 updateTexture();
876 }
877
878 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +0000879}
880
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000881void Texture::dropTexture()
882{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000883 if (mBaseTexture)
884 {
885 mBaseTexture = NULL;
886 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000887
888 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000889}
890
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000891void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000892{
893 mBaseTexture = newTexture;
894 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000895 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000896 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000897}
898
899
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000900GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
901{
902 if (isPow2(width) && isPow2(height))
903 {
904 return maxlevel;
905 }
906 else
907 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +0000908 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
909 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +0000910 }
911}
912
913GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
914{
915 return creationLevels(size, size, maxlevel);
916}
917
918int Texture::levelCount() const
919{
920 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
921}
922
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000923Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000924{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000925 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000926 mColorbufferProxy = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000927}
928
929Texture2D::~Texture2D()
930{
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000931 delete mColorbufferProxy;
932
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000933 if (mTexture)
934 {
935 mTexture->Release();
936 mTexture = NULL;
937 }
938}
939
940GLenum Texture2D::getTarget() const
941{
942 return GL_TEXTURE_2D;
943}
944
daniel@transgaming.com01868132010-08-24 19:21:17 +0000945GLenum Texture2D::getFormat() const
946{
947 return mImageArray[0].format;
948}
949
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000950// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
951// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
952// Call this when a particular level of the texture must be defined with a specific format, width and height.
953//
954// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
955// a new height and width for the texture by working backwards from the given width and height.
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000956bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000957{
958 bool widthOkay = (mWidth >> level == width);
959 bool heightOkay = (mHeight >> level == height);
960
961 bool sizeOkay = ((widthOkay && heightOkay)
962 || (widthOkay && mHeight >> level == 0 && height == 1)
963 || (heightOkay && mWidth >> level == 0 && width == 1));
964
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000965 bool typeOkay = (type == mType);
966
967 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000968
969 if (!textureOkay)
970 {
971 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
972 mImageArray[0].format, mWidth, mHeight,
973 internalFormat, width, height);
974
975 // Purge all the levels and the texture.
976
977 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
978 {
979 if (mImageArray[i].surface != NULL)
980 {
981 mImageArray[i].dirty = false;
982
983 mImageArray[i].surface->Release();
984 mImageArray[i].surface = NULL;
985 }
986 }
987
988 if (mTexture != NULL)
989 {
990 mTexture->Release();
991 mTexture = NULL;
992 dropTexture();
993 }
994
995 mWidth = width << level;
996 mHeight = height << level;
997 mImageArray[0].format = internalFormat;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000998 mType = type;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000999 }
1000
1001 return !textureOkay;
1002}
1003
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001004void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001005{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001006 redefineTexture(level, internalFormat, width, height, type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001007
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001008 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001009}
1010
daniel@transgaming.com01868132010-08-24 19:21:17 +00001011void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1012{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001013 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001014
1015 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1016}
1017
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001018void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1019{
1020 ASSERT(mImageArray[level].surface != NULL);
1021
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001022 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001023 {
1024 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001025 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001026
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001027 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001028
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001029 if (SUCCEEDED(result))
1030 {
1031 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001032
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001033 RECT sourceRect;
1034 sourceRect.left = xoffset;
1035 sourceRect.top = yoffset;
1036 sourceRect.right = xoffset + width;
1037 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001038
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001039 POINT destPoint;
1040 destPoint.x = xoffset;
1041 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001042
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001043 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1044 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001045
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001046 destLevel->Release();
1047
1048 img->dirty = false;
1049 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001050 }
1051}
1052
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001053void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001054{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001055 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1056 {
1057 commitRect(level, xoffset, yoffset, width, height);
1058 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001059}
1060
daniel@transgaming.com01868132010-08-24 19:21:17 +00001061void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1062{
1063 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1064 {
1065 commitRect(level, xoffset, yoffset, width, height);
1066 }
1067}
1068
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001069void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001070{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001071 if (redefineTexture(level, internalFormat, width, height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001072 {
1073 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001074 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001075 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001076 else
1077 {
1078 needRenderTarget();
1079 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001080
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001081 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001082 {
1083 RECT sourceRect;
1084 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001085 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001086 sourceRect.top = y;
1087 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001088
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001089 IDirect3DSurface9 *dest;
1090 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001091
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001092 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1093 dest->Release();
1094 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001095
1096 mImageArray[level].width = width;
1097 mImageArray[level].height = height;
1098 mImageArray[level].format = internalFormat;
1099}
1100
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001101void Texture2D::copySubImage(GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001102{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001103 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1104 {
1105 return error(GL_INVALID_VALUE);
1106 }
1107
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001108 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001109 {
1110 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001111 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001112 }
1113 else
1114 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +00001115 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001116 }
1117
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001118 if (level < levelCount())
1119 {
1120 RECT sourceRect;
1121 sourceRect.left = x;
1122 sourceRect.right = x + width;
1123 sourceRect.top = y;
1124 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001125
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001126 IDirect3DSurface9 *dest;
1127 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001128
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001129 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
1130 dest->Release();
1131 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001132}
1133
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001134// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1135bool Texture2D::isComplete() const
1136{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001137 GLsizei width = mImageArray[0].width;
1138 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001139
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001140 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001141 {
1142 return false;
1143 }
1144
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001145 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001146
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001147 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001148 {
1149 case GL_NEAREST:
1150 case GL_LINEAR:
1151 mipmapping = false;
1152 break;
1153 case GL_NEAREST_MIPMAP_NEAREST:
1154 case GL_LINEAR_MIPMAP_NEAREST:
1155 case GL_NEAREST_MIPMAP_LINEAR:
1156 case GL_LINEAR_MIPMAP_LINEAR:
1157 mipmapping = true;
1158 break;
1159 default: UNREACHABLE();
1160 }
1161
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001162 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1163 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1164 {
1165 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1166 {
1167 return false;
1168 }
1169 }
1170
1171
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001172 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1173 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1174 {
1175 return false;
1176 }
1177
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001178 if (mipmapping)
1179 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001180 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001181 {
1182 return false;
1183 }
1184
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001185 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001186
1187 for (int level = 1; level <= q; level++)
1188 {
1189 if (mImageArray[level].format != mImageArray[0].format)
1190 {
1191 return false;
1192 }
1193
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001194 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001195 {
1196 return false;
1197 }
1198
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001199 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001200 {
1201 return false;
1202 }
1203 }
1204 }
1205
1206 return true;
1207}
1208
daniel@transgaming.com01868132010-08-24 19:21:17 +00001209bool Texture2D::isCompressed() const
1210{
1211 return IsCompressed(getFormat());
1212}
1213
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001214// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001215IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001216{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001217 IDirect3DTexture9 *texture;
1218
1219 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001220 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001221
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001222 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001223
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001224 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001225 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001226 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001227 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001228 }
1229
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001230 if (mTexture) mTexture->Release();
1231 mTexture = texture;
1232 return texture;
1233}
1234
1235void Texture2D::updateTexture()
1236{
1237 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001238
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001239 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001240
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001241 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001242 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001243 if (mImageArray[level].dirty)
1244 {
1245 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001246 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001247
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001248 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001249
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001250 if (SUCCEEDED(result))
1251 {
1252 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1253 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001254
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001255 levelSurface->Release();
1256
1257 mImageArray[level].dirty = false;
1258 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001259 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001260 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001261}
1262
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001263IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001264{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001265 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001266
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001267 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001268 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001269 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001270 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001271 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001272
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001273 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001274
1275 if (FAILED(result))
1276 {
1277 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1278 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1279 }
1280
1281 if (mTexture != NULL)
1282 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001283 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001284 for (int i = 0; i < levels; i++)
1285 {
1286 IDirect3DSurface9 *source;
1287 result = mTexture->GetSurfaceLevel(i, &source);
1288
1289 if (FAILED(result))
1290 {
1291 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1292
1293 texture->Release();
1294
1295 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1296 }
1297
1298 IDirect3DSurface9 *dest;
1299 result = texture->GetSurfaceLevel(i, &dest);
1300
1301 if (FAILED(result))
1302 {
1303 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1304
1305 texture->Release();
1306 source->Release();
1307
1308 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1309 }
1310
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001311 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001312 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1313
1314 if (FAILED(result))
1315 {
1316 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1317
1318 texture->Release();
1319 source->Release();
1320 dest->Release();
1321
1322 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1323 }
1324
1325 source->Release();
1326 dest->Release();
1327 }
1328 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001329 }
1330
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001331 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001332 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001333 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001334 }
1335
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001336 mTexture = texture;
1337 return mTexture;
1338}
1339
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001340bool Texture2D::dirtyImageData() const
1341{
1342 int q = log2(std::max(mWidth, mHeight));
1343
1344 for (int i = 0; i <= q; i++)
1345 {
1346 if (mImageArray[i].dirty) return true;
1347 }
1348
1349 return false;
1350}
1351
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001352void Texture2D::generateMipmaps()
1353{
1354 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1355 {
1356 return error(GL_INVALID_OPERATION);
1357 }
1358
1359 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1360 unsigned int q = log2(std::max(mWidth, mHeight));
1361 for (unsigned int i = 1; i <= q; i++)
1362 {
1363 if (mImageArray[i].surface != NULL)
1364 {
1365 mImageArray[i].surface->Release();
1366 mImageArray[i].surface = NULL;
1367 }
1368
1369 mImageArray[i].dirty = false;
1370
1371 mImageArray[i].format = mImageArray[0].format;
1372 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1373 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1374 }
1375
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001376 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001377
1378 for (unsigned int i = 1; i <= q; i++)
1379 {
1380 IDirect3DSurface9 *upper = NULL;
1381 IDirect3DSurface9 *lower = NULL;
1382
1383 mTexture->GetSurfaceLevel(i-1, &upper);
1384 mTexture->GetSurfaceLevel(i, &lower);
1385
1386 if (upper != NULL && lower != NULL)
1387 {
1388 getBlitter()->boxFilter(upper, lower);
1389 }
1390
1391 if (upper != NULL) upper->Release();
1392 if (lower != NULL) lower->Release();
1393 }
1394}
1395
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001396Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001397{
1398 if (target != GL_TEXTURE_2D)
1399 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001400 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001401 }
1402
1403 if (mColorbufferProxy == NULL)
1404 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001405 mColorbufferProxy = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
1406 mColorbufferProxy->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001407 }
1408
1409 return mColorbufferProxy;
1410}
1411
1412IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1413{
1414 ASSERT(target == GL_TEXTURE_2D);
1415
1416 needRenderTarget();
1417
1418 IDirect3DSurface9 *renderTarget = NULL;
1419 mTexture->GetSurfaceLevel(0, &renderTarget);
1420
1421 return renderTarget;
1422}
1423
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001424TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001425{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001426 mTexture = NULL;
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001427
1428 for (int i = 0; i < 6; i++)
1429 {
1430 mFaceProxies[i] = NULL;
1431 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001432}
1433
1434TextureCubeMap::~TextureCubeMap()
1435{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001436 for (int i = 0; i < 6; i++)
1437 {
1438 delete mFaceProxies[i];
1439 }
1440
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001441 if (mTexture)
1442 {
1443 mTexture->Release();
1444 mTexture = NULL;
1445 }
1446}
1447
1448GLenum TextureCubeMap::getTarget() const
1449{
1450 return GL_TEXTURE_CUBE_MAP;
1451}
1452
daniel@transgaming.com01868132010-08-24 19:21:17 +00001453GLenum TextureCubeMap::getFormat() const
1454{
1455 return mImageArray[0][0].format;
1456}
1457
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001458void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001459{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001460 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001461}
1462
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001463void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001464{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001465 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001466}
1467
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001468void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001469{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001470 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001471}
1472
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001473void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001474{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001475 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001476}
1477
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001478void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001479{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001480 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001481}
1482
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001483void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001484{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001485 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001486}
1487
daniel@transgaming.com01868132010-08-24 19:21:17 +00001488void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1489{
1490 redefineTexture(level, internalFormat, width);
1491
1492 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1493}
1494
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001495void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1496{
1497 int face = faceIndex(faceTarget);
1498
1499 ASSERT(mImageArray[face][level].surface != NULL);
1500
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001501 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001502 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001503 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1504 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001505
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001506 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001507 {
1508 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001509
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001510 RECT sourceRect;
1511 sourceRect.left = xoffset;
1512 sourceRect.top = yoffset;
1513 sourceRect.right = xoffset + width;
1514 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001515
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001516 POINT destPoint;
1517 destPoint.x = xoffset;
1518 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001519
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001520 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001521 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001522
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001523 destLevel->Release();
1524
1525 img->dirty = false;
1526 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001527 }
1528}
1529
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001530void TextureCubeMap::subImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001531{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001532 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1533 {
1534 commitRect(face, level, xoffset, yoffset, width, height);
1535 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001536}
1537
daniel@transgaming.com01868132010-08-24 19:21:17 +00001538void TextureCubeMap::subImageCompressed(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1539{
1540 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]))
1541 {
1542 commitRect(face, level, xoffset, yoffset, width, height);
1543 }
1544}
1545
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001546// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001547bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001548{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001549 int size = mImageArray[0][0].width;
1550
1551 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001552 {
1553 return false;
1554 }
1555
1556 bool mipmapping;
1557
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001558 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001559 {
1560 case GL_NEAREST:
1561 case GL_LINEAR:
1562 mipmapping = false;
1563 break;
1564 case GL_NEAREST_MIPMAP_NEAREST:
1565 case GL_LINEAR_MIPMAP_NEAREST:
1566 case GL_NEAREST_MIPMAP_LINEAR:
1567 case GL_LINEAR_MIPMAP_LINEAR:
1568 mipmapping = true;
1569 break;
1570 default: UNREACHABLE();
1571 }
1572
1573 for (int face = 0; face < 6; face++)
1574 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001575 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001576 {
1577 return false;
1578 }
1579 }
1580
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001581 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1582 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1583 {
1584 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1585 {
1586 return false;
1587 }
1588 }
1589
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001590 if (mipmapping)
1591 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001592 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1593 {
1594 return false;
1595 }
1596
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001597 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001598
1599 for (int face = 0; face < 6; face++)
1600 {
1601 for (int level = 1; level <= q; level++)
1602 {
1603 if (mImageArray[face][level].format != mImageArray[0][0].format)
1604 {
1605 return false;
1606 }
1607
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001608 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001609 {
1610 return false;
1611 }
1612
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001613 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001614 }
1615 }
1616 }
1617
1618 return true;
1619}
1620
daniel@transgaming.com01868132010-08-24 19:21:17 +00001621bool TextureCubeMap::isCompressed() const
1622{
1623 return IsCompressed(getFormat());
1624}
1625
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001626// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001627IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001628{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001629 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001630 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001631
1632 IDirect3DCubeTexture9 *texture;
1633
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001634 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001635
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001636 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001637 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001638 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001639 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001640 }
1641
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001642 if (mTexture) mTexture->Release();
1643
1644 mTexture = texture;
1645 return mTexture;
1646}
1647
1648void TextureCubeMap::updateTexture()
1649{
1650 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001651
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001652 for (int face = 0; face < 6; face++)
1653 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001654 int levels = levelCount();
1655 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001656 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001657 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001658
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001659 if (img->dirty)
1660 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001661 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1662 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001663
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001664 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001665 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001666 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001667 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001668
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001669 levelSurface->Release();
1670
1671 img->dirty = false;
1672 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001673 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001674 }
1675 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001676}
1677
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001678IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1679{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001680 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001681
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001682 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001683 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001684 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001685 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001686 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001687
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001688 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001689
1690 if (FAILED(result))
1691 {
1692 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1693 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1694 }
1695
1696 if (mTexture != NULL)
1697 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001698 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001699 for (int f = 0; f < 6; f++)
1700 {
1701 for (int i = 0; i < levels; i++)
1702 {
1703 IDirect3DSurface9 *source;
1704 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1705
1706 if (FAILED(result))
1707 {
1708 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1709
1710 texture->Release();
1711
1712 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1713 }
1714
1715 IDirect3DSurface9 *dest;
1716 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1717
1718 if (FAILED(result))
1719 {
1720 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1721
1722 texture->Release();
1723 source->Release();
1724
1725 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1726 }
1727
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001728 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001729 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1730
1731 if (FAILED(result))
1732 {
1733 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1734
1735 texture->Release();
1736 source->Release();
1737 dest->Release();
1738
1739 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1740 }
1741 }
1742 }
1743 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001744 }
1745
1746 if (mTexture != NULL)
1747 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001748 mTexture->Release();
1749 }
1750
1751 mTexture = texture;
1752 return mTexture;
1753}
1754
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001755void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001756{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001757 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001758
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001759 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001760}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001761
1762unsigned int TextureCubeMap::faceIndex(GLenum face)
1763{
1764 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1765 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1766 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1767 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1768 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1769
1770 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1771}
1772
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001773bool TextureCubeMap::dirtyImageData() const
1774{
1775 int q = log2(mWidth);
1776
1777 for (int f = 0; f < 6; f++)
1778 {
1779 for (int i = 0; i <= q; i++)
1780 {
1781 if (mImageArray[f][i].dirty) return true;
1782 }
1783 }
1784
1785 return false;
1786}
1787
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001788// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1789// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1790// Call this when a particular level of the texture must be defined with a specific format, width and height.
1791//
1792// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1793// a new size for the texture by working backwards from the given size.
1794bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1795{
1796 // Are these settings compatible with level 0?
1797 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1798
1799 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1800
1801 if (!textureOkay)
1802 {
1803 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1804 mImageArray[0][0].format, mImageArray[0][0].width,
1805 internalFormat, width);
1806
1807 // Purge all the levels and the texture.
1808 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1809 {
1810 for (int f = 0; f < 6; f++)
1811 {
1812 if (mImageArray[f][i].surface != NULL)
1813 {
1814 mImageArray[f][i].dirty = false;
1815
1816 mImageArray[f][i].surface->Release();
1817 mImageArray[f][i].surface = NULL;
1818 }
1819 }
1820 }
1821
1822 if (mTexture != NULL)
1823 {
1824 mTexture->Release();
1825 mTexture = NULL;
1826 dropTexture();
1827 }
1828
1829 mWidth = width << level;
1830 mImageArray[0][0].width = width << level;
1831 mHeight = width << level;
1832 mImageArray[0][0].height = width << level;
1833
1834 mImageArray[0][0].format = internalFormat;
1835 }
1836
1837 return !textureOkay;
1838}
1839
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001840void TextureCubeMap::copyImage(GLenum face, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001841{
1842 unsigned int faceindex = faceIndex(face);
1843
1844 if (redefineTexture(level, internalFormat, width))
1845 {
1846 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001847 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001848 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001849 else
1850 {
1851 needRenderTarget();
1852 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001853
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001854 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001855
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001856 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001857 {
1858 RECT sourceRect;
1859 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001860 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001861 sourceRect.top = y;
1862 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001863
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001864 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1865
1866 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1867 dest->Release();
1868 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001869
1870 mImageArray[faceindex][level].width = width;
1871 mImageArray[faceindex][level].height = height;
1872 mImageArray[faceindex][level].format = internalFormat;
1873}
1874
1875IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1876{
1877 unsigned int faceIndex;
1878
1879 if (faceIdentifier < 6)
1880 {
1881 faceIndex = faceIdentifier;
1882 }
1883 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1884 {
1885 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1886 }
1887 else
1888 {
1889 UNREACHABLE();
1890 faceIndex = 0;
1891 }
1892
1893 if (mTexture == NULL)
1894 {
1895 UNREACHABLE();
1896 return NULL;
1897 }
1898
1899 IDirect3DSurface9 *surface = NULL;
1900
1901 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1902
1903 return (SUCCEEDED(hr)) ? surface : NULL;
1904}
1905
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001906void TextureCubeMap::copySubImage(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001907{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001908 GLsizei size = mImageArray[faceIndex(face)][level].width;
1909
1910 if (xoffset + width > size || yoffset + height > size)
1911 {
1912 return error(GL_INVALID_VALUE);
1913 }
1914
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001915 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1916 {
1917 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001918 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001919 }
1920 else
1921 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001922 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001923 }
1924
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001925 if (level < levelCount())
1926 {
1927 RECT sourceRect;
1928 sourceRect.left = x;
1929 sourceRect.right = x + width;
1930 sourceRect.top = y;
1931 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001932
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001933 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001934
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001935 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1936 dest->Release();
1937 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001938}
1939
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001940bool TextureCubeMap::isCubeComplete() const
1941{
1942 if (mImageArray[0][0].width == 0)
1943 {
1944 return false;
1945 }
1946
1947 for (unsigned int f = 1; f < 6; f++)
1948 {
1949 if (mImageArray[f][0].width != mImageArray[0][0].width
1950 || mImageArray[f][0].format != mImageArray[0][0].format)
1951 {
1952 return false;
1953 }
1954 }
1955
1956 return true;
1957}
1958
1959void TextureCubeMap::generateMipmaps()
1960{
1961 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1962 {
1963 return error(GL_INVALID_OPERATION);
1964 }
1965
1966 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1967 unsigned int q = log2(mImageArray[0][0].width);
1968 for (unsigned int f = 0; f < 6; f++)
1969 {
1970 for (unsigned int i = 1; i <= q; i++)
1971 {
1972 if (mImageArray[f][i].surface != NULL)
1973 {
1974 mImageArray[f][i].surface->Release();
1975 mImageArray[f][i].surface = NULL;
1976 }
1977
1978 mImageArray[f][i].dirty = false;
1979
1980 mImageArray[f][i].format = mImageArray[f][0].format;
1981 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1982 mImageArray[f][i].height = mImageArray[f][i].width;
1983 }
1984 }
1985
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001986 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001987
1988 for (unsigned int f = 0; f < 6; f++)
1989 {
1990 for (unsigned int i = 1; i <= q; i++)
1991 {
1992 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1993 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1994
1995 if (upper != NULL && lower != NULL)
1996 {
1997 getBlitter()->boxFilter(upper, lower);
1998 }
1999
2000 if (upper != NULL) upper->Release();
2001 if (lower != NULL) lower->Release();
2002 }
2003 }
2004}
2005
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002006Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002007{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002008 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002009 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002010 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002011 }
2012
2013 unsigned int face = faceIndex(target);
2014
2015 if (mFaceProxies[face] == NULL)
2016 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002017 mFaceProxies[face] = new Renderbuffer(id(), new TextureColorbufferProxy(this, target));
2018 mFaceProxies[face]->addRef();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002019 }
2020
2021 return mFaceProxies[face];
2022}
2023
2024IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2025{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002026 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002027
2028 needRenderTarget();
2029
2030 IDirect3DSurface9 *renderTarget = NULL;
2031 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
2032
2033 return renderTarget;
2034}
2035
2036Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
2037 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
2038{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002039 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002040}
2041
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002042void Texture::TextureColorbufferProxy::addRef() const
2043{
2044 mTexture->addRef();
2045}
2046
2047void Texture::TextureColorbufferProxy::release() const
2048{
2049 mTexture->release();
2050}
2051
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002052IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2053{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002054 if (mRenderTarget) mRenderTarget->Release();
2055
2056 mRenderTarget = mTexture->getRenderTarget(mTarget);
2057
2058 return mRenderTarget;
2059}
2060
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002061int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002062{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002063 return mTexture->getWidth();
2064}
2065
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002066int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002067{
2068 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002069}
2070
daniel@transgaming.com01868132010-08-24 19:21:17 +00002071GLenum Texture::TextureColorbufferProxy::getFormat() const
2072{
2073 return mTexture->getFormat();
2074}
2075
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002076bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2077{
2078 return mTexture->isFloatingPoint();
2079}
2080
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002081}