blob: d5825cf0ba3343071d664928ed85d3d4b52b9bdc [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;
926}
927
928Texture2D::~Texture2D()
929{
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +0000930 mColorbufferProxy.set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000931
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000932 if (mTexture)
933 {
934 mTexture->Release();
935 mTexture = NULL;
936 }
937}
938
939GLenum Texture2D::getTarget() const
940{
941 return GL_TEXTURE_2D;
942}
943
daniel@transgaming.com01868132010-08-24 19:21:17 +0000944GLenum Texture2D::getFormat() const
945{
946 return mImageArray[0].format;
947}
948
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000949// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
950// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
951// Call this when a particular level of the texture must be defined with a specific format, width and height.
952//
953// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
954// 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 +0000955bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000956{
957 bool widthOkay = (mWidth >> level == width);
958 bool heightOkay = (mHeight >> level == height);
959
960 bool sizeOkay = ((widthOkay && heightOkay)
961 || (widthOkay && mHeight >> level == 0 && height == 1)
962 || (heightOkay && mWidth >> level == 0 && width == 1));
963
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000964 bool typeOkay = (type == mType);
965
966 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000967
968 if (!textureOkay)
969 {
970 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
971 mImageArray[0].format, mWidth, mHeight,
972 internalFormat, width, height);
973
974 // Purge all the levels and the texture.
975
976 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
977 {
978 if (mImageArray[i].surface != NULL)
979 {
980 mImageArray[i].dirty = false;
981
982 mImageArray[i].surface->Release();
983 mImageArray[i].surface = NULL;
984 }
985 }
986
987 if (mTexture != NULL)
988 {
989 mTexture->Release();
990 mTexture = NULL;
991 dropTexture();
992 }
993
994 mWidth = width << level;
995 mHeight = height << level;
996 mImageArray[0].format = internalFormat;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000997 mType = type;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +0000998 }
999
1000 return !textureOkay;
1001}
1002
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001003void 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 +00001004{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001005 redefineTexture(level, internalFormat, width, height, type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001006
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001007 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001008}
1009
daniel@transgaming.com01868132010-08-24 19:21:17 +00001010void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1011{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001012 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001013
1014 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1015}
1016
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001017void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1018{
1019 ASSERT(mImageArray[level].surface != NULL);
1020
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001021 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001022 {
1023 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001024 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001025
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001026 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001027
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001028 if (SUCCEEDED(result))
1029 {
1030 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001031
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001032 RECT sourceRect;
1033 sourceRect.left = xoffset;
1034 sourceRect.top = yoffset;
1035 sourceRect.right = xoffset + width;
1036 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001037
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001038 POINT destPoint;
1039 destPoint.x = xoffset;
1040 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001041
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001042 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1043 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001044
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001045 destLevel->Release();
1046
1047 img->dirty = false;
1048 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001049 }
1050}
1051
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001052void 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 +00001053{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001054 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1055 {
1056 commitRect(level, xoffset, yoffset, width, height);
1057 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001058}
1059
daniel@transgaming.com01868132010-08-24 19:21:17 +00001060void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1061{
1062 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1063 {
1064 commitRect(level, xoffset, yoffset, width, height);
1065 }
1066}
1067
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001068void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001069{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001070 if (redefineTexture(level, internalFormat, width, height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001071 {
1072 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001073 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001074 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001075 else
1076 {
1077 needRenderTarget();
1078 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001079
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001080 if (width != 0 && height != 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001081 {
1082 RECT sourceRect;
1083 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001084 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001085 sourceRect.top = y;
1086 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001087
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001088 IDirect3DSurface9 *dest;
1089 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001090
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001091 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1092 dest->Release();
1093 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001094
1095 mImageArray[level].width = width;
1096 mImageArray[level].height = height;
1097 mImageArray[level].format = internalFormat;
1098}
1099
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001100void 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 +00001101{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001102 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1103 {
1104 return error(GL_INVALID_VALUE);
1105 }
1106
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001107 if (redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType))
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001108 {
1109 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001110 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001111 }
1112 else
1113 {
daniel@transgaming.comfc23fe22010-05-05 18:48:17 +00001114 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001115 }
1116
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001117 if (level < levelCount())
1118 {
1119 RECT sourceRect;
1120 sourceRect.left = x;
1121 sourceRect.right = x + width;
1122 sourceRect.top = y;
1123 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001124
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001125 IDirect3DSurface9 *dest;
1126 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001127
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001128 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
1129 dest->Release();
1130 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001131}
1132
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001133// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1134bool Texture2D::isComplete() const
1135{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001136 GLsizei width = mImageArray[0].width;
1137 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001138
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001139 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001140 {
1141 return false;
1142 }
1143
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001144 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001146 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001147 {
1148 case GL_NEAREST:
1149 case GL_LINEAR:
1150 mipmapping = false;
1151 break;
1152 case GL_NEAREST_MIPMAP_NEAREST:
1153 case GL_LINEAR_MIPMAP_NEAREST:
1154 case GL_NEAREST_MIPMAP_LINEAR:
1155 case GL_LINEAR_MIPMAP_LINEAR:
1156 mipmapping = true;
1157 break;
1158 default: UNREACHABLE();
1159 }
1160
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001161 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1162 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1163 {
1164 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1165 {
1166 return false;
1167 }
1168 }
1169
1170
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001171 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1172 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1173 {
1174 return false;
1175 }
1176
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001177 if (mipmapping)
1178 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001179 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001180 {
1181 return false;
1182 }
1183
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001184 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001185
1186 for (int level = 1; level <= q; level++)
1187 {
1188 if (mImageArray[level].format != mImageArray[0].format)
1189 {
1190 return false;
1191 }
1192
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001193 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001194 {
1195 return false;
1196 }
1197
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001198 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001199 {
1200 return false;
1201 }
1202 }
1203 }
1204
1205 return true;
1206}
1207
daniel@transgaming.com01868132010-08-24 19:21:17 +00001208bool Texture2D::isCompressed() const
1209{
1210 return IsCompressed(getFormat());
1211}
1212
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001213// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001214IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001215{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001216 IDirect3DTexture9 *texture;
1217
1218 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001219 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001220
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001221 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001222
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001223 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001224 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001225 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001226 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001227 }
1228
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001229 if (mTexture) mTexture->Release();
1230 mTexture = texture;
1231 return texture;
1232}
1233
1234void Texture2D::updateTexture()
1235{
1236 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001237
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001238 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001239
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001240 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001241 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001242 if (mImageArray[level].dirty)
1243 {
1244 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001245 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001246
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001247 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001248
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001249 if (SUCCEEDED(result))
1250 {
1251 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1252 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001253
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001254 levelSurface->Release();
1255
1256 mImageArray[level].dirty = false;
1257 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001258 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001259 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001260}
1261
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001262IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001263{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001264 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001265
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001266 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001267 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001268 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001269 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001270 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001271
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001272 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 +00001273
1274 if (FAILED(result))
1275 {
1276 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1277 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1278 }
1279
1280 if (mTexture != NULL)
1281 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001282 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001283 for (int i = 0; i < levels; i++)
1284 {
1285 IDirect3DSurface9 *source;
1286 result = mTexture->GetSurfaceLevel(i, &source);
1287
1288 if (FAILED(result))
1289 {
1290 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1291
1292 texture->Release();
1293
1294 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1295 }
1296
1297 IDirect3DSurface9 *dest;
1298 result = texture->GetSurfaceLevel(i, &dest);
1299
1300 if (FAILED(result))
1301 {
1302 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1303
1304 texture->Release();
1305 source->Release();
1306
1307 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1308 }
1309
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001310 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001311 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1312
1313 if (FAILED(result))
1314 {
1315 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1316
1317 texture->Release();
1318 source->Release();
1319 dest->Release();
1320
1321 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1322 }
1323
1324 source->Release();
1325 dest->Release();
1326 }
1327 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001328 }
1329
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001330 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001331 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001332 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001333 }
1334
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001335 mTexture = texture;
1336 return mTexture;
1337}
1338
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001339bool Texture2D::dirtyImageData() const
1340{
1341 int q = log2(std::max(mWidth, mHeight));
1342
1343 for (int i = 0; i <= q; i++)
1344 {
1345 if (mImageArray[i].dirty) return true;
1346 }
1347
1348 return false;
1349}
1350
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001351void Texture2D::generateMipmaps()
1352{
1353 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1354 {
1355 return error(GL_INVALID_OPERATION);
1356 }
1357
1358 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1359 unsigned int q = log2(std::max(mWidth, mHeight));
1360 for (unsigned int i = 1; i <= q; i++)
1361 {
1362 if (mImageArray[i].surface != NULL)
1363 {
1364 mImageArray[i].surface->Release();
1365 mImageArray[i].surface = NULL;
1366 }
1367
1368 mImageArray[i].dirty = false;
1369
1370 mImageArray[i].format = mImageArray[0].format;
1371 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1372 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1373 }
1374
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001375 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001376
1377 for (unsigned int i = 1; i <= q; i++)
1378 {
1379 IDirect3DSurface9 *upper = NULL;
1380 IDirect3DSurface9 *lower = NULL;
1381
1382 mTexture->GetSurfaceLevel(i-1, &upper);
1383 mTexture->GetSurfaceLevel(i, &lower);
1384
1385 if (upper != NULL && lower != NULL)
1386 {
1387 getBlitter()->boxFilter(upper, lower);
1388 }
1389
1390 if (upper != NULL) upper->Release();
1391 if (lower != NULL) lower->Release();
1392 }
1393}
1394
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001395Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001396{
1397 if (target != GL_TEXTURE_2D)
1398 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001399 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001400 }
1401
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001402 if (mColorbufferProxy.get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001403 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001404 mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001405 }
1406
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001407 return mColorbufferProxy.get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001408}
1409
1410IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1411{
1412 ASSERT(target == GL_TEXTURE_2D);
1413
1414 needRenderTarget();
1415
1416 IDirect3DSurface9 *renderTarget = NULL;
1417 mTexture->GetSurfaceLevel(0, &renderTarget);
1418
1419 return renderTarget;
1420}
1421
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001422TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001423{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001424 mTexture = NULL;
1425}
1426
1427TextureCubeMap::~TextureCubeMap()
1428{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001429 for (int i = 0; i < 6; i++)
1430 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001431 mFaceProxies[i].set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001432 }
1433
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001434 if (mTexture)
1435 {
1436 mTexture->Release();
1437 mTexture = NULL;
1438 }
1439}
1440
1441GLenum TextureCubeMap::getTarget() const
1442{
1443 return GL_TEXTURE_CUBE_MAP;
1444}
1445
daniel@transgaming.com01868132010-08-24 19:21:17 +00001446GLenum TextureCubeMap::getFormat() const
1447{
1448 return mImageArray[0][0].format;
1449}
1450
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001451void 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 +00001452{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001453 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001454}
1455
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001456void 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 +00001457{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001458 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001459}
1460
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001461void 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 +00001462{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001463 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001464}
1465
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001466void 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 +00001467{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001468 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001469}
1470
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001471void 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 +00001472{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001473 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001474}
1475
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001476void 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 +00001477{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001478 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001479}
1480
daniel@transgaming.com01868132010-08-24 19:21:17 +00001481void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1482{
1483 redefineTexture(level, internalFormat, width);
1484
1485 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1486}
1487
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001488void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1489{
1490 int face = faceIndex(faceTarget);
1491
1492 ASSERT(mImageArray[face][level].surface != NULL);
1493
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001494 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001495 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001496 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1497 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001498
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001499 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001500 {
1501 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001502
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001503 RECT sourceRect;
1504 sourceRect.left = xoffset;
1505 sourceRect.top = yoffset;
1506 sourceRect.right = xoffset + width;
1507 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001508
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001509 POINT destPoint;
1510 destPoint.x = xoffset;
1511 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001512
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001513 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001514 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001515
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001516 destLevel->Release();
1517
1518 img->dirty = false;
1519 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001520 }
1521}
1522
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001523void 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 +00001524{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001525 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1526 {
1527 commitRect(face, level, xoffset, yoffset, width, height);
1528 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001529}
1530
daniel@transgaming.com01868132010-08-24 19:21:17 +00001531void TextureCubeMap::subImageCompressed(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1532{
1533 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]))
1534 {
1535 commitRect(face, level, xoffset, yoffset, width, height);
1536 }
1537}
1538
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001539// 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 +00001540bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001541{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001542 int size = mImageArray[0][0].width;
1543
1544 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001545 {
1546 return false;
1547 }
1548
1549 bool mipmapping;
1550
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001551 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001552 {
1553 case GL_NEAREST:
1554 case GL_LINEAR:
1555 mipmapping = false;
1556 break;
1557 case GL_NEAREST_MIPMAP_NEAREST:
1558 case GL_LINEAR_MIPMAP_NEAREST:
1559 case GL_NEAREST_MIPMAP_LINEAR:
1560 case GL_LINEAR_MIPMAP_LINEAR:
1561 mipmapping = true;
1562 break;
1563 default: UNREACHABLE();
1564 }
1565
1566 for (int face = 0; face < 6; face++)
1567 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001568 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001569 {
1570 return false;
1571 }
1572 }
1573
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001574 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1575 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1576 {
1577 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1578 {
1579 return false;
1580 }
1581 }
1582
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001583 if (mipmapping)
1584 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001585 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1586 {
1587 return false;
1588 }
1589
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001590 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001591
1592 for (int face = 0; face < 6; face++)
1593 {
1594 for (int level = 1; level <= q; level++)
1595 {
1596 if (mImageArray[face][level].format != mImageArray[0][0].format)
1597 {
1598 return false;
1599 }
1600
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001601 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001602 {
1603 return false;
1604 }
1605
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001606 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001607 }
1608 }
1609 }
1610
1611 return true;
1612}
1613
daniel@transgaming.com01868132010-08-24 19:21:17 +00001614bool TextureCubeMap::isCompressed() const
1615{
1616 return IsCompressed(getFormat());
1617}
1618
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001619// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001620IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001621{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001622 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001623 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001624
1625 IDirect3DCubeTexture9 *texture;
1626
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001627 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001628
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001629 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001630 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001631 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001632 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001633 }
1634
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001635 if (mTexture) mTexture->Release();
1636
1637 mTexture = texture;
1638 return mTexture;
1639}
1640
1641void TextureCubeMap::updateTexture()
1642{
1643 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001644
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001645 for (int face = 0; face < 6; face++)
1646 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001647 int levels = levelCount();
1648 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001649 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001650 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001651
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001652 if (img->dirty)
1653 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001654 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1655 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001656
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001657 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001658 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001659 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001660 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001661
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001662 levelSurface->Release();
1663
1664 img->dirty = false;
1665 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001666 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001667 }
1668 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001669}
1670
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001671IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1672{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001673 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001674
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001675 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001676 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001677 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001678 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001679 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001680
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001681 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001682
1683 if (FAILED(result))
1684 {
1685 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1686 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1687 }
1688
1689 if (mTexture != NULL)
1690 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001691 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001692 for (int f = 0; f < 6; f++)
1693 {
1694 for (int i = 0; i < levels; i++)
1695 {
1696 IDirect3DSurface9 *source;
1697 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1698
1699 if (FAILED(result))
1700 {
1701 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1702
1703 texture->Release();
1704
1705 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1706 }
1707
1708 IDirect3DSurface9 *dest;
1709 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1710
1711 if (FAILED(result))
1712 {
1713 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1714
1715 texture->Release();
1716 source->Release();
1717
1718 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1719 }
1720
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001721 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001722 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1723
1724 if (FAILED(result))
1725 {
1726 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1727
1728 texture->Release();
1729 source->Release();
1730 dest->Release();
1731
1732 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1733 }
1734 }
1735 }
1736 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001737 }
1738
1739 if (mTexture != NULL)
1740 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001741 mTexture->Release();
1742 }
1743
1744 mTexture = texture;
1745 return mTexture;
1746}
1747
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001748void 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 +00001749{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001750 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001751
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001752 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001753}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001754
1755unsigned int TextureCubeMap::faceIndex(GLenum face)
1756{
1757 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1758 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1759 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1760 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1761 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1762
1763 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1764}
1765
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001766bool TextureCubeMap::dirtyImageData() const
1767{
1768 int q = log2(mWidth);
1769
1770 for (int f = 0; f < 6; f++)
1771 {
1772 for (int i = 0; i <= q; i++)
1773 {
1774 if (mImageArray[f][i].dirty) return true;
1775 }
1776 }
1777
1778 return false;
1779}
1780
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001781// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1782// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1783// Call this when a particular level of the texture must be defined with a specific format, width and height.
1784//
1785// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1786// a new size for the texture by working backwards from the given size.
1787bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1788{
1789 // Are these settings compatible with level 0?
1790 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1791
1792 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1793
1794 if (!textureOkay)
1795 {
1796 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1797 mImageArray[0][0].format, mImageArray[0][0].width,
1798 internalFormat, width);
1799
1800 // Purge all the levels and the texture.
1801 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1802 {
1803 for (int f = 0; f < 6; f++)
1804 {
1805 if (mImageArray[f][i].surface != NULL)
1806 {
1807 mImageArray[f][i].dirty = false;
1808
1809 mImageArray[f][i].surface->Release();
1810 mImageArray[f][i].surface = NULL;
1811 }
1812 }
1813 }
1814
1815 if (mTexture != NULL)
1816 {
1817 mTexture->Release();
1818 mTexture = NULL;
1819 dropTexture();
1820 }
1821
1822 mWidth = width << level;
1823 mImageArray[0][0].width = width << level;
1824 mHeight = width << level;
1825 mImageArray[0][0].height = width << level;
1826
1827 mImageArray[0][0].format = internalFormat;
1828 }
1829
1830 return !textureOkay;
1831}
1832
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001833void 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 +00001834{
1835 unsigned int faceindex = faceIndex(face);
1836
1837 if (redefineTexture(level, internalFormat, width))
1838 {
1839 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001840 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001841 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001842 else
1843 {
1844 needRenderTarget();
1845 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001846
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001847 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001848
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001849 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001850 {
1851 RECT sourceRect;
1852 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001853 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001854 sourceRect.top = y;
1855 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001856
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001857 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1858
1859 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1860 dest->Release();
1861 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001862
1863 mImageArray[faceindex][level].width = width;
1864 mImageArray[faceindex][level].height = height;
1865 mImageArray[faceindex][level].format = internalFormat;
1866}
1867
1868IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1869{
1870 unsigned int faceIndex;
1871
1872 if (faceIdentifier < 6)
1873 {
1874 faceIndex = faceIdentifier;
1875 }
1876 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1877 {
1878 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1879 }
1880 else
1881 {
1882 UNREACHABLE();
1883 faceIndex = 0;
1884 }
1885
1886 if (mTexture == NULL)
1887 {
1888 UNREACHABLE();
1889 return NULL;
1890 }
1891
1892 IDirect3DSurface9 *surface = NULL;
1893
1894 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1895
1896 return (SUCCEEDED(hr)) ? surface : NULL;
1897}
1898
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001899void 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 +00001900{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001901 GLsizei size = mImageArray[faceIndex(face)][level].width;
1902
1903 if (xoffset + width > size || yoffset + height > size)
1904 {
1905 return error(GL_INVALID_VALUE);
1906 }
1907
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001908 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1909 {
1910 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001911 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001912 }
1913 else
1914 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001915 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001916 }
1917
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001918 if (level < levelCount())
1919 {
1920 RECT sourceRect;
1921 sourceRect.left = x;
1922 sourceRect.right = x + width;
1923 sourceRect.top = y;
1924 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001925
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001926 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001927
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001928 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1929 dest->Release();
1930 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001931}
1932
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001933bool TextureCubeMap::isCubeComplete() const
1934{
1935 if (mImageArray[0][0].width == 0)
1936 {
1937 return false;
1938 }
1939
1940 for (unsigned int f = 1; f < 6; f++)
1941 {
1942 if (mImageArray[f][0].width != mImageArray[0][0].width
1943 || mImageArray[f][0].format != mImageArray[0][0].format)
1944 {
1945 return false;
1946 }
1947 }
1948
1949 return true;
1950}
1951
1952void TextureCubeMap::generateMipmaps()
1953{
1954 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1955 {
1956 return error(GL_INVALID_OPERATION);
1957 }
1958
1959 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1960 unsigned int q = log2(mImageArray[0][0].width);
1961 for (unsigned int f = 0; f < 6; f++)
1962 {
1963 for (unsigned int i = 1; i <= q; i++)
1964 {
1965 if (mImageArray[f][i].surface != NULL)
1966 {
1967 mImageArray[f][i].surface->Release();
1968 mImageArray[f][i].surface = NULL;
1969 }
1970
1971 mImageArray[f][i].dirty = false;
1972
1973 mImageArray[f][i].format = mImageArray[f][0].format;
1974 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1975 mImageArray[f][i].height = mImageArray[f][i].width;
1976 }
1977 }
1978
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001979 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001980
1981 for (unsigned int f = 0; f < 6; f++)
1982 {
1983 for (unsigned int i = 1; i <= q; i++)
1984 {
1985 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1986 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1987
1988 if (upper != NULL && lower != NULL)
1989 {
1990 getBlitter()->boxFilter(upper, lower);
1991 }
1992
1993 if (upper != NULL) upper->Release();
1994 if (lower != NULL) lower->Release();
1995 }
1996 }
1997}
1998
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001999Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002000{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002001 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002002 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002003 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002004 }
2005
2006 unsigned int face = faceIndex(target);
2007
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002008 if (mFaceProxies[face].get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002009 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002010 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002011 }
2012
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002013 return mFaceProxies[face].get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002014}
2015
2016IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2017{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002018 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002019
2020 needRenderTarget();
2021
2022 IDirect3DSurface9 *renderTarget = NULL;
2023 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
2024
2025 return renderTarget;
2026}
2027
2028Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
2029 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
2030{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002031 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002032}
2033
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002034void Texture::TextureColorbufferProxy::addRef() const
2035{
2036 mTexture->addRef();
2037}
2038
2039void Texture::TextureColorbufferProxy::release() const
2040{
2041 mTexture->release();
2042}
2043
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002044IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2045{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002046 if (mRenderTarget) mRenderTarget->Release();
2047
2048 mRenderTarget = mTexture->getRenderTarget(mTarget);
2049
2050 return mRenderTarget;
2051}
2052
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002053int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002054{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002055 return mTexture->getWidth();
2056}
2057
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002058int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002059{
2060 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002061}
2062
daniel@transgaming.com01868132010-08-24 19:21:17 +00002063GLenum Texture::TextureColorbufferProxy::getFormat() const
2064{
2065 return mTexture->getFormat();
2066}
2067
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002068bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2069{
2070 return mTexture->isFloatingPoint();
2071}
2072
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002073}