blob: 4b7db678426fd4e516edf8349cf8e0ccb2981197 [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
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00001416 if (mTexture == NULL)
1417 {
1418 return NULL;
1419 }
1420
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001421 IDirect3DSurface9 *renderTarget = NULL;
1422 mTexture->GetSurfaceLevel(0, &renderTarget);
1423
1424 return renderTarget;
1425}
1426
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001427TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001428{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001429 mTexture = NULL;
1430}
1431
1432TextureCubeMap::~TextureCubeMap()
1433{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001434 for (int i = 0; i < 6; i++)
1435 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001436 mFaceProxies[i].set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001437 }
1438
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001439 if (mTexture)
1440 {
1441 mTexture->Release();
1442 mTexture = NULL;
1443 }
1444}
1445
1446GLenum TextureCubeMap::getTarget() const
1447{
1448 return GL_TEXTURE_CUBE_MAP;
1449}
1450
daniel@transgaming.com01868132010-08-24 19:21:17 +00001451GLenum TextureCubeMap::getFormat() const
1452{
1453 return mImageArray[0][0].format;
1454}
1455
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001456void 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 +00001457{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001458 setImage(0, 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::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 +00001462{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001463 setImage(1, 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::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 +00001467{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001468 setImage(2, 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::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 +00001472{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001473 setImage(3, 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::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 +00001477{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001478 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001479}
1480
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001481void 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 +00001482{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001483 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001484}
1485
daniel@transgaming.com01868132010-08-24 19:21:17 +00001486void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1487{
1488 redefineTexture(level, internalFormat, width);
1489
1490 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1491}
1492
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001493void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1494{
1495 int face = faceIndex(faceTarget);
1496
1497 ASSERT(mImageArray[face][level].surface != NULL);
1498
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001499 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001500 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001501 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1502 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001503
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001504 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001505 {
1506 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001507
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001508 RECT sourceRect;
1509 sourceRect.left = xoffset;
1510 sourceRect.top = yoffset;
1511 sourceRect.right = xoffset + width;
1512 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001513
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001514 POINT destPoint;
1515 destPoint.x = xoffset;
1516 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001517
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001518 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001519 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001520
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001521 destLevel->Release();
1522
1523 img->dirty = false;
1524 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001525 }
1526}
1527
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001528void 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 +00001529{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001530 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(face)][level]))
1531 {
1532 commitRect(face, level, xoffset, yoffset, width, height);
1533 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001534}
1535
daniel@transgaming.com01868132010-08-24 19:21:17 +00001536void TextureCubeMap::subImageCompressed(GLenum face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1537{
1538 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(face)][level]))
1539 {
1540 commitRect(face, level, xoffset, yoffset, width, height);
1541 }
1542}
1543
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001544// 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 +00001545bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001546{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001547 int size = mImageArray[0][0].width;
1548
1549 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001550 {
1551 return false;
1552 }
1553
1554 bool mipmapping;
1555
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001556 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001557 {
1558 case GL_NEAREST:
1559 case GL_LINEAR:
1560 mipmapping = false;
1561 break;
1562 case GL_NEAREST_MIPMAP_NEAREST:
1563 case GL_LINEAR_MIPMAP_NEAREST:
1564 case GL_NEAREST_MIPMAP_LINEAR:
1565 case GL_LINEAR_MIPMAP_LINEAR:
1566 mipmapping = true;
1567 break;
1568 default: UNREACHABLE();
1569 }
1570
1571 for (int face = 0; face < 6; face++)
1572 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001573 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001574 {
1575 return false;
1576 }
1577 }
1578
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001579 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1580 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1581 {
1582 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1583 {
1584 return false;
1585 }
1586 }
1587
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001588 if (mipmapping)
1589 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001590 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1591 {
1592 return false;
1593 }
1594
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001595 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001596
1597 for (int face = 0; face < 6; face++)
1598 {
1599 for (int level = 1; level <= q; level++)
1600 {
1601 if (mImageArray[face][level].format != mImageArray[0][0].format)
1602 {
1603 return false;
1604 }
1605
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001606 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001607 {
1608 return false;
1609 }
1610
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001611 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001612 }
1613 }
1614 }
1615
1616 return true;
1617}
1618
daniel@transgaming.com01868132010-08-24 19:21:17 +00001619bool TextureCubeMap::isCompressed() const
1620{
1621 return IsCompressed(getFormat());
1622}
1623
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001624// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001625IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001626{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001627 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001628 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001629
1630 IDirect3DCubeTexture9 *texture;
1631
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001632 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001633
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001634 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001635 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001636 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001637 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001638 }
1639
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001640 if (mTexture) mTexture->Release();
1641
1642 mTexture = texture;
1643 return mTexture;
1644}
1645
1646void TextureCubeMap::updateTexture()
1647{
1648 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001649
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001650 for (int face = 0; face < 6; face++)
1651 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001652 int levels = levelCount();
1653 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001654 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001655 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001656
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001657 if (img->dirty)
1658 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001659 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1660 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001661
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001662 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001663 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001664 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001665 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001666
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001667 levelSurface->Release();
1668
1669 img->dirty = false;
1670 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001671 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001672 }
1673 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001674}
1675
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001676IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1677{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001678 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001679
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001680 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001681 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001682 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001683 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001684 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001685
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001686 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001687
1688 if (FAILED(result))
1689 {
1690 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1691 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1692 }
1693
1694 if (mTexture != NULL)
1695 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001696 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001697 for (int f = 0; f < 6; f++)
1698 {
1699 for (int i = 0; i < levels; i++)
1700 {
1701 IDirect3DSurface9 *source;
1702 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
1703
1704 if (FAILED(result))
1705 {
1706 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1707
1708 texture->Release();
1709
1710 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1711 }
1712
1713 IDirect3DSurface9 *dest;
1714 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
1715
1716 if (FAILED(result))
1717 {
1718 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1719
1720 texture->Release();
1721 source->Release();
1722
1723 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1724 }
1725
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001726 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001727 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1728
1729 if (FAILED(result))
1730 {
1731 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1732
1733 texture->Release();
1734 source->Release();
1735 dest->Release();
1736
1737 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1738 }
1739 }
1740 }
1741 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001742 }
1743
1744 if (mTexture != NULL)
1745 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001746 mTexture->Release();
1747 }
1748
1749 mTexture = texture;
1750 return mTexture;
1751}
1752
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001753void 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 +00001754{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001755 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001756
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001757 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001758}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001759
1760unsigned int TextureCubeMap::faceIndex(GLenum face)
1761{
1762 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1763 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1764 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1765 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1766 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1767
1768 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1769}
1770
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001771bool TextureCubeMap::dirtyImageData() const
1772{
1773 int q = log2(mWidth);
1774
1775 for (int f = 0; f < 6; f++)
1776 {
1777 for (int i = 0; i <= q; i++)
1778 {
1779 if (mImageArray[f][i].dirty) return true;
1780 }
1781 }
1782
1783 return false;
1784}
1785
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001786// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1787// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
1788// Call this when a particular level of the texture must be defined with a specific format, width and height.
1789//
1790// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
1791// a new size for the texture by working backwards from the given size.
1792bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
1793{
1794 // Are these settings compatible with level 0?
1795 bool sizeOkay = (mImageArray[0][0].width >> level == width);
1796
1797 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
1798
1799 if (!textureOkay)
1800 {
1801 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
1802 mImageArray[0][0].format, mImageArray[0][0].width,
1803 internalFormat, width);
1804
1805 // Purge all the levels and the texture.
1806 for (int i = 0; i < MAX_TEXTURE_LEVELS; i++)
1807 {
1808 for (int f = 0; f < 6; f++)
1809 {
1810 if (mImageArray[f][i].surface != NULL)
1811 {
1812 mImageArray[f][i].dirty = false;
1813
1814 mImageArray[f][i].surface->Release();
1815 mImageArray[f][i].surface = NULL;
1816 }
1817 }
1818 }
1819
1820 if (mTexture != NULL)
1821 {
1822 mTexture->Release();
1823 mTexture = NULL;
1824 dropTexture();
1825 }
1826
1827 mWidth = width << level;
1828 mImageArray[0][0].width = width << level;
1829 mHeight = width << level;
1830 mImageArray[0][0].height = width << level;
1831
1832 mImageArray[0][0].format = internalFormat;
1833 }
1834
1835 return !textureOkay;
1836}
1837
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001838void 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 +00001839{
1840 unsigned int faceindex = faceIndex(face);
1841
1842 if (redefineTexture(level, internalFormat, width))
1843 {
1844 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001845 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001846 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001847 else
1848 {
1849 needRenderTarget();
1850 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001851
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001852 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001853
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001854 if (width > 0 && level < levelCount())
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001855 {
1856 RECT sourceRect;
1857 sourceRect.left = x;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001858 sourceRect.right = x + width;
daniel@transgaming.com18b426b2010-04-20 18:52:44 +00001859 sourceRect.top = y;
1860 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001861
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001862 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
1863
1864 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1865 dest->Release();
1866 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001867
1868 mImageArray[faceindex][level].width = width;
1869 mImageArray[faceindex][level].height = height;
1870 mImageArray[faceindex][level].format = internalFormat;
1871}
1872
1873IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
1874{
1875 unsigned int faceIndex;
1876
1877 if (faceIdentifier < 6)
1878 {
1879 faceIndex = faceIdentifier;
1880 }
1881 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
1882 {
1883 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1884 }
1885 else
1886 {
1887 UNREACHABLE();
1888 faceIndex = 0;
1889 }
1890
1891 if (mTexture == NULL)
1892 {
1893 UNREACHABLE();
1894 return NULL;
1895 }
1896
1897 IDirect3DSurface9 *surface = NULL;
1898
1899 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
1900
1901 return (SUCCEEDED(hr)) ? surface : NULL;
1902}
1903
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001904void 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 +00001905{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001906 GLsizei size = mImageArray[faceIndex(face)][level].width;
1907
1908 if (xoffset + width > size || yoffset + height > size)
1909 {
1910 return error(GL_INVALID_VALUE);
1911 }
1912
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001913 if (redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width))
1914 {
1915 convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001916 pushTexture(mTexture, true);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001917 }
1918 else
1919 {
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001920 needRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001921 }
1922
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001923 if (level < levelCount())
1924 {
1925 RECT sourceRect;
1926 sourceRect.left = x;
1927 sourceRect.right = x + width;
1928 sourceRect.top = y;
1929 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001930
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001931 IDirect3DSurface9 *dest = getCubeMapSurface(face, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001932
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001933 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
1934 dest->Release();
1935 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001936}
1937
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001938bool TextureCubeMap::isCubeComplete() const
1939{
1940 if (mImageArray[0][0].width == 0)
1941 {
1942 return false;
1943 }
1944
1945 for (unsigned int f = 1; f < 6; f++)
1946 {
1947 if (mImageArray[f][0].width != mImageArray[0][0].width
1948 || mImageArray[f][0].format != mImageArray[0][0].format)
1949 {
1950 return false;
1951 }
1952 }
1953
1954 return true;
1955}
1956
1957void TextureCubeMap::generateMipmaps()
1958{
1959 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
1960 {
1961 return error(GL_INVALID_OPERATION);
1962 }
1963
1964 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1965 unsigned int q = log2(mImageArray[0][0].width);
1966 for (unsigned int f = 0; f < 6; f++)
1967 {
1968 for (unsigned int i = 1; i <= q; i++)
1969 {
1970 if (mImageArray[f][i].surface != NULL)
1971 {
1972 mImageArray[f][i].surface->Release();
1973 mImageArray[f][i].surface = NULL;
1974 }
1975
1976 mImageArray[f][i].dirty = false;
1977
1978 mImageArray[f][i].format = mImageArray[f][0].format;
1979 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
1980 mImageArray[f][i].height = mImageArray[f][i].width;
1981 }
1982 }
1983
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001984 needRenderTarget();
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001985
1986 for (unsigned int f = 0; f < 6; f++)
1987 {
1988 for (unsigned int i = 1; i <= q; i++)
1989 {
1990 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
1991 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
1992
1993 if (upper != NULL && lower != NULL)
1994 {
1995 getBlitter()->boxFilter(upper, lower);
1996 }
1997
1998 if (upper != NULL) upper->Release();
1999 if (lower != NULL) lower->Release();
2000 }
2001 }
2002}
2003
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002004Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002005{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002006 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002007 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002008 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002009 }
2010
2011 unsigned int face = faceIndex(target);
2012
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002013 if (mFaceProxies[face].get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002014 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002015 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002016 }
2017
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002018 return mFaceProxies[face].get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002019}
2020
2021IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2022{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002023 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002024
2025 needRenderTarget();
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00002026
2027 if (mTexture == NULL)
2028 {
2029 return NULL;
2030 }
2031
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002032 IDirect3DSurface9 *renderTarget = NULL;
2033 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
2034
2035 return renderTarget;
2036}
2037
2038Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
2039 : Colorbuffer(NULL), mTexture(texture), mTarget(target)
2040{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002041 ASSERT(target == GL_TEXTURE_2D || IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002042}
2043
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002044void Texture::TextureColorbufferProxy::addRef() const
2045{
2046 mTexture->addRef();
2047}
2048
2049void Texture::TextureColorbufferProxy::release() const
2050{
2051 mTexture->release();
2052}
2053
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002054IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2055{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002056 if (mRenderTarget) mRenderTarget->Release();
2057
2058 mRenderTarget = mTexture->getRenderTarget(mTarget);
2059
2060 return mRenderTarget;
2061}
2062
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002063int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002064{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002065 return mTexture->getWidth();
2066}
2067
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002068int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002069{
2070 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002071}
2072
daniel@transgaming.com01868132010-08-24 19:21:17 +00002073GLenum Texture::TextureColorbufferProxy::getFormat() const
2074{
2075 return mTexture->getFormat();
2076}
2077
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002078bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2079{
2080 return mTexture->isFloatingPoint();
2081}
2082
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002083}