blob: 9e3b404fc05788ba1861f7c38eabfa46f830aa1c [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
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +000013#include <d3dx9tex.h>
14
daniel@transgaming.com16973022010-03-11 19:22:19 +000015#include <algorithm>
16
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000017#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/mathutil.h"
21#include "libGLESv2/utilities.h"
22#include "libGLESv2/Blit.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023
24namespace gl
25{
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000026
27Texture::Image::Image()
daniel@transgaming.com01868132010-08-24 19:21:17 +000028 : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +000029{
30}
31
32Texture::Image::~Image()
33{
34 if (surface) surface->Release();
35}
36
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +000037Texture::Texture(GLuint id) : RefCountObject(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038{
39 mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
40 mMagFilter = GL_LINEAR;
41 mWrapS = GL_REPEAT;
42 mWrapT = GL_REPEAT;
daniel@transgaming.com29d27002010-03-11 19:41:22 +000043
daniel@transgaming.com31273552010-08-04 13:42:44 +000044 mWidth = 0;
45 mHeight = 0;
46
daniel@transgaming.com00c75962010-03-11 20:36:15 +000047 mDirtyMetaData = true;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000048 mDirty = true;
daniel@transgaming.com93a81472010-04-20 18:52:58 +000049 mIsRenderable = false;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +000050 mType = GL_UNSIGNED_BYTE;
daniel@transgaming.com0a311a42010-05-17 09:58:33 +000051 mBaseTexture = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000052}
53
54Texture::~Texture()
55{
56}
57
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000058Blit *Texture::getBlitter()
59{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000060 Context *context = getContext();
61 return context->getBlitter();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +000062}
63
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000064// Returns true on successful filter state update (valid enum parameter)
65bool Texture::setMinFilter(GLenum filter)
66{
67 switch (filter)
68 {
69 case GL_NEAREST:
70 case GL_LINEAR:
71 case GL_NEAREST_MIPMAP_NEAREST:
72 case GL_LINEAR_MIPMAP_NEAREST:
73 case GL_NEAREST_MIPMAP_LINEAR:
74 case GL_LINEAR_MIPMAP_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000075 {
76 if (mMinFilter != filter)
77 {
78 mMinFilter = filter;
79 mDirty = true;
80 }
81 return true;
82 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000083 default:
84 return false;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +000085 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000086}
87
88// Returns true on successful filter state update (valid enum parameter)
89bool Texture::setMagFilter(GLenum filter)
90{
91 switch (filter)
92 {
93 case GL_NEAREST:
94 case GL_LINEAR:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +000095 {
96 if (mMagFilter != filter)
97 {
98 mMagFilter = filter;
99 mDirty = true;
100 }
101 return true;
102 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000103 default:
104 return false;
105 }
106}
107
108// Returns true on successful wrap state update (valid enum parameter)
109bool Texture::setWrapS(GLenum wrap)
110{
111 switch (wrap)
112 {
113 case GL_REPEAT:
114 case GL_CLAMP_TO_EDGE:
115 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000116 {
117 if (mWrapS != wrap)
118 {
119 mWrapS = wrap;
120 mDirty = true;
121 }
122 return true;
123 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124 default:
125 return false;
126 }
127}
128
129// Returns true on successful wrap state update (valid enum parameter)
130bool Texture::setWrapT(GLenum wrap)
131{
132 switch (wrap)
133 {
134 case GL_REPEAT:
135 case GL_CLAMP_TO_EDGE:
136 case GL_MIRRORED_REPEAT:
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +0000137 {
138 if (mWrapT != wrap)
139 {
140 mWrapT = wrap;
141 mDirty = true;
142 }
143 return true;
144 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145 default:
146 return false;
147 }
148}
149
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000150GLenum Texture::getMinFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151{
152 return mMinFilter;
153}
154
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000155GLenum Texture::getMagFilter() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000156{
157 return mMagFilter;
158}
159
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000160GLenum Texture::getWrapS() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161{
162 return mWrapS;
163}
164
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000165GLenum Texture::getWrapT() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000166{
167 return mWrapT;
168}
169
daniel@transgaming.com93a81472010-04-20 18:52:58 +0000170GLuint Texture::getWidth() const
171{
172 return mWidth;
173}
174
175GLuint Texture::getHeight() const
176{
177 return mHeight;
178}
179
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000180bool Texture::isFloatingPoint() const
181{
182 return (mType == GL_FLOAT || mType == GL_HALF_FLOAT_OES);
183}
184
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000185bool Texture::isRenderableFormat() const
186{
187 D3DFORMAT format = getD3DFormat();
188
189 switch(format)
190 {
191 case D3DFMT_L8:
192 case D3DFMT_A8L8:
193 case D3DFMT_DXT1:
194 return false;
195 case D3DFMT_A8R8G8B8:
apatrick@chromium.org9c857952010-11-16 18:27:58 +0000196 case D3DFMT_X8R8G8B8:
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000197 case D3DFMT_A16B16G16R16F:
198 case D3DFMT_A32B32G32R32F:
199 return true;
200 default:
201 UNREACHABLE();
202 }
203
204 return false;
205}
206
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207// Selects an internal Direct3D 9 format for storing an Image
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000208D3DFORMAT Texture::selectFormat(GLenum format, GLenum type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209{
daniel@transgaming.com01868132010-08-24 19:21:17 +0000210 if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
211 format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
212 {
213 return D3DFMT_DXT1;
214 }
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000215 else if (type == GL_FLOAT)
216 {
217 return D3DFMT_A32B32G32R32F;
218 }
219 else if (type == GL_HALF_FLOAT_OES)
220 {
221 return D3DFMT_A16B16G16R16F;
222 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000223 else if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000224 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000225 if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
226 {
227 return D3DFMT_L8;
228 }
229 else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
230 {
231 return D3DFMT_A8L8;
232 }
apatrick@chromium.org9c857952010-11-16 18:27:58 +0000233 else if (format == GL_RGB)
234 {
235 return D3DFMT_X8R8G8B8;
236 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000237
daniel@transgaming.com01868132010-08-24 19:21:17 +0000238 return D3DFMT_A8R8G8B8;
239 }
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000240
241 return D3DFMT_A8R8G8B8;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242}
243
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000244// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000245// into the target pixel rectangle at output with outputPitch bytes in between each line.
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000246void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000247 GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000248{
daniel@transgaming.com713914b2010-05-04 03:35:17 +0000249 GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000250
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000251 switch (type)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000252 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000253 case GL_UNSIGNED_BYTE:
254 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000255 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000256 case GL_ALPHA:
257 loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
258 break;
259 case GL_LUMINANCE:
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000260 loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000261 break;
262 case GL_LUMINANCE_ALPHA:
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000263 loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000264 break;
265 case GL_RGB:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000266 loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
267 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000268 case GL_RGBA:
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000269 loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
270 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000271 case GL_BGRA_EXT:
272 loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000273 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000274 default: UNREACHABLE();
275 }
276 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000277 case GL_UNSIGNED_SHORT_5_6_5:
278 switch (format)
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000279 {
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000280 case GL_RGB:
281 loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000282 break;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000283 default: UNREACHABLE();
284 }
285 break;
286 case GL_UNSIGNED_SHORT_4_4_4_4:
287 switch (format)
288 {
289 case GL_RGBA:
290 loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
291 break;
292 default: UNREACHABLE();
293 }
294 break;
295 case GL_UNSIGNED_SHORT_5_5_5_1:
296 switch (format)
297 {
298 case GL_RGBA:
299 loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
300 break;
301 default: UNREACHABLE();
302 }
303 break;
304 case GL_FLOAT:
305 switch (format)
306 {
307 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
308 case GL_ALPHA:
309 loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
310 break;
311 case GL_LUMINANCE:
312 loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
313 break;
314 case GL_LUMINANCE_ALPHA:
315 loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
316 break;
317 case GL_RGB:
318 loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
319 break;
320 case GL_RGBA:
321 loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
322 break;
323 default: UNREACHABLE();
324 }
325 break;
326 case GL_HALF_FLOAT_OES:
327 switch (format)
328 {
329 // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
330 case GL_ALPHA:
331 loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
332 break;
333 case GL_LUMINANCE:
334 loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
335 break;
336 case GL_LUMINANCE_ALPHA:
337 loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
338 break;
339 case GL_RGB:
340 loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
341 break;
342 case GL_RGBA:
343 loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
344 break;
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000345 default: UNREACHABLE();
346 }
347 break;
348 default: UNREACHABLE();
349 }
350}
351
352void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
353 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
354{
355 const unsigned char *source = NULL;
356 unsigned char *dest = NULL;
357
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000358 for (int y = 0; y < height; y++)
359 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000360 source = static_cast<const unsigned char*>(input) + y * inputPitch;
361 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000362 for (int x = 0; x < width; x++)
363 {
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000364 dest[4 * x + 0] = 0;
365 dest[4 * x + 1] = 0;
366 dest[4 * x + 2] = 0;
367 dest[4 * x + 3] = source[x];
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000368 }
369 }
370}
371
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000372void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
373 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
374{
375 const float *source = NULL;
376 float *dest = NULL;
377
378 for (int y = 0; y < height; y++)
379 {
380 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
381 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
382 for (int x = 0; x < width; x++)
383 {
384 dest[4 * x + 0] = 0;
385 dest[4 * x + 1] = 0;
386 dest[4 * x + 2] = 0;
387 dest[4 * x + 3] = source[x];
388 }
389 }
390}
391
392void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
393 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
394{
395 const unsigned short *source = NULL;
396 unsigned short *dest = NULL;
397
398 for (int y = 0; y < height; y++)
399 {
400 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
401 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
402 for (int x = 0; x < width; x++)
403 {
404 dest[4 * x + 0] = 0;
405 dest[4 * x + 1] = 0;
406 dest[4 * x + 2] = 0;
407 dest[4 * x + 3] = source[x];
408 }
409 }
410}
411
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000412void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000413 size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000414{
415 const unsigned char *source = NULL;
416 unsigned char *dest = NULL;
417
418 for (int y = 0; y < height; y++)
419 {
420 source = static_cast<const unsigned char*>(input) + y * inputPitch;
421 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000422
423 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000424 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000425 for (int x = 0; x < width; x++)
426 {
427 dest[4 * x + 0] = source[x];
428 dest[4 * x + 1] = source[x];
429 dest[4 * x + 2] = source[x];
430 dest[4 * x + 3] = 0xFF;
431 }
432 }
433 else // L8 destination format
434 {
435 memcpy(dest, source, width);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000436 }
437 }
438}
439
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000440void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
441 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
442{
443 const float *source = NULL;
444 float *dest = NULL;
445
446 for (int y = 0; y < height; y++)
447 {
448 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
449 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
450 for (int x = 0; x < width; x++)
451 {
452 dest[4 * x + 0] = source[x];
453 dest[4 * x + 1] = source[x];
454 dest[4 * x + 2] = source[x];
455 dest[4 * x + 3] = 1.0f;
456 }
457 }
458}
459
460void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
461 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
462{
463 const unsigned short *source = NULL;
464 unsigned short *dest = NULL;
465
466 for (int y = 0; y < height; y++)
467 {
468 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
469 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
470 for (int x = 0; x < width; x++)
471 {
472 dest[4 * x + 0] = source[x];
473 dest[4 * x + 1] = source[x];
474 dest[4 * x + 2] = source[x];
475 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
476 }
477 }
478}
479
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000480void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000481 size_t inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000482{
483 const unsigned char *source = NULL;
484 unsigned char *dest = NULL;
485
486 for (int y = 0; y < height; y++)
487 {
488 source = static_cast<const unsigned char*>(input) + y * inputPitch;
489 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000490
491 if (!native) // BGRA8 destination format
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000492 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000493 for (int x = 0; x < width; x++)
494 {
495 dest[4 * x + 0] = source[2*x+0];
496 dest[4 * x + 1] = source[2*x+0];
497 dest[4 * x + 2] = source[2*x+0];
498 dest[4 * x + 3] = source[2*x+1];
499 }
500 }
501 else
502 {
503 memcpy(dest, source, width * 2);
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000504 }
505 }
506}
507
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000508void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
509 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
510{
511 const float *source = NULL;
512 float *dest = NULL;
513
514 for (int y = 0; y < height; y++)
515 {
516 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
517 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
518 for (int x = 0; x < width; x++)
519 {
520 dest[4 * x + 0] = source[2*x+0];
521 dest[4 * x + 1] = source[2*x+0];
522 dest[4 * x + 2] = source[2*x+0];
523 dest[4 * x + 3] = source[2*x+1];
524 }
525 }
526}
527
528void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
529 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
530{
531 const unsigned short *source = NULL;
532 unsigned short *dest = NULL;
533
534 for (int y = 0; y < height; y++)
535 {
536 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
537 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
538 for (int x = 0; x < width; x++)
539 {
540 dest[4 * x + 0] = source[2*x+0];
541 dest[4 * x + 1] = source[2*x+0];
542 dest[4 * x + 2] = source[2*x+0];
543 dest[4 * x + 3] = source[2*x+1];
544 }
545 }
546}
547
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000548void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
549 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
550{
551 const unsigned char *source = NULL;
552 unsigned char *dest = NULL;
553
554 for (int y = 0; y < height; y++)
555 {
556 source = static_cast<const unsigned char*>(input) + y * inputPitch;
557 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
558 for (int x = 0; x < width; x++)
559 {
560 dest[4 * x + 0] = source[x * 3 + 2];
561 dest[4 * x + 1] = source[x * 3 + 1];
562 dest[4 * x + 2] = source[x * 3 + 0];
563 dest[4 * x + 3] = 0xFF;
564 }
565 }
566}
567
568void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
569 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
570{
571 const unsigned short *source = NULL;
572 unsigned char *dest = NULL;
573
574 for (int y = 0; y < height; y++)
575 {
576 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
577 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
578 for (int x = 0; x < width; x++)
579 {
580 unsigned short rgba = source[x];
581 dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
582 dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
583 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
584 dest[4 * x + 3] = 0xFF;
585 }
586 }
587}
588
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000589void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
590 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
591{
592 const float *source = NULL;
593 float *dest = NULL;
594
595 for (int y = 0; y < height; y++)
596 {
597 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
598 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
599 for (int x = 0; x < width; x++)
600 {
601 dest[4 * x + 0] = source[x * 3 + 0];
602 dest[4 * x + 1] = source[x * 3 + 1];
603 dest[4 * x + 2] = source[x * 3 + 2];
604 dest[4 * x + 3] = 1.0f;
605 }
606 }
607}
608
609void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
610 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
611{
612 const unsigned short *source = NULL;
613 unsigned short *dest = NULL;
614
615 for (int y = 0; y < height; y++)
616 {
617 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
618 dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
619 for (int x = 0; x < width; x++)
620 {
621 dest[4 * x + 0] = source[x * 3 + 0];
622 dest[4 * x + 1] = source[x * 3 + 1];
623 dest[4 * x + 2] = source[x * 3 + 2];
624 dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
625 }
626 }
627}
628
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000629void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
630 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
631{
632 const unsigned char *source = NULL;
633 unsigned char *dest = NULL;
634
635 for (int y = 0; y < height; y++)
636 {
637 source = static_cast<const unsigned char*>(input) + y * inputPitch;
638 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
639 for (int x = 0; x < width; x++)
640 {
641 dest[4 * x + 0] = source[x * 4 + 2];
642 dest[4 * x + 1] = source[x * 4 + 1];
643 dest[4 * x + 2] = source[x * 4 + 0];
644 dest[4 * x + 3] = source[x * 4 + 3];
645 }
646 }
647}
648
649void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
650 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
651{
652 const unsigned short *source = NULL;
653 unsigned char *dest = NULL;
654
655 for (int y = 0; y < height; y++)
656 {
657 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
658 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
659 for (int x = 0; x < width; x++)
660 {
661 unsigned short rgba = source[x];
662 dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
663 dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
664 dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
665 dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
666 }
667 }
668}
669
670void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
671 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
672{
673 const unsigned short *source = NULL;
674 unsigned char *dest = NULL;
675
676 for (int y = 0; y < height; y++)
677 {
678 source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
679 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
680 for (int x = 0; x < width; x++)
681 {
682 unsigned short rgba = source[x];
683 dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
684 dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
685 dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
686 dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
687 }
688 }
689}
690
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000691void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
692 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
693{
694 const float *source = NULL;
695 float *dest = NULL;
696
697 for (int y = 0; y < height; y++)
698 {
699 source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
700 dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
701 memcpy(dest, source, width * 16);
702 }
703}
704
705void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
706 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
707{
708 const unsigned char *source = NULL;
709 unsigned char *dest = NULL;
710
711 for (int y = 0; y < height; y++)
712 {
713 source = static_cast<const unsigned char*>(input) + y * inputPitch;
714 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
715 memcpy(dest, source, width * 8);
716 }
717}
718
daniel@transgaming.com1ac37d82010-08-24 19:21:31 +0000719void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
720 size_t inputPitch, const void *input, size_t outputPitch, void *output) const
721{
722 const unsigned char *source = NULL;
723 unsigned char *dest = NULL;
724
725 for (int y = 0; y < height; y++)
726 {
727 source = static_cast<const unsigned char*>(input) + y * inputPitch;
728 dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
729 memcpy(dest, source, width*4);
730 }
731}
732
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000733void Texture::createSurface(GLsizei width, GLsizei height, GLenum format, GLenum type, Image *img)
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000734{
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000735 IDirect3DTexture9 *newTexture = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000736 IDirect3DSurface9 *newSurface = NULL;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000737
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000738 if (width != 0 && height != 0)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000739 {
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000740 int levelToFetch = 0;
741 GLsizei requestWidth = width;
742 GLsizei requestHeight = height;
743 if (IsCompressed(format) && (width % 4 != 0 || height % 4 != 0))
744 {
745 bool isMult4 = false;
746 int upsampleCount = 0;
747 while (!isMult4)
748 {
749 requestWidth <<= 1;
750 requestHeight <<= 1;
751 upsampleCount++;
752 if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
753 {
754 isMult4 = true;
755 }
756 }
757 levelToFetch = upsampleCount;
758 }
759
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000760 HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, selectFormat(format, type),
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000761 D3DPOOL_SYSTEMMEM, &newTexture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +0000762
763 if (FAILED(result))
764 {
765 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
766 return error(GL_OUT_OF_MEMORY);
767 }
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000768
daniel@transgaming.com1dcea9f2010-08-24 19:21:27 +0000769 newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
daniel@transgaming.comf5cde482010-08-24 19:21:11 +0000770 newTexture->Release();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000771 }
772
773 if (img->surface) img->surface->Release();
774 img->surface = newSurface;
775
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000776 img->width = width;
777 img->height = height;
778 img->format = format;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000779}
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000780
daniel@transgaming.com01868132010-08-24 19:21:17 +0000781void Texture::setImage(GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *img)
782{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000783 createSurface(width, height, format, type, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000784
785 if (pixels != NULL && img->surface != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000786 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000787 D3DSURFACE_DESC description;
788 img->surface->GetDesc(&description);
789
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000790 D3DLOCKED_RECT locked;
daniel@transgaming.com01868132010-08-24 19:21:17 +0000791 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000792
793 ASSERT(SUCCEEDED(result));
794
795 if (SUCCEEDED(result))
796 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000797 loadImageData(0, 0, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000798 img->surface->UnlockRect();
799 }
800
801 img->dirty = true;
802 }
803
804 mDirtyMetaData = true;
805}
806
807void Texture::setCompressedImage(GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
808{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +0000809 createSurface(width, height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000810
811 if (pixels != NULL && img->surface != NULL)
812 {
813 D3DLOCKED_RECT locked;
814 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
815
816 ASSERT(SUCCEEDED(result));
817
818 if (SUCCEEDED(result))
819 {
820 memcpy(locked.pBits, pixels, imageSize);
821 img->surface->UnlockRect();
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000822 }
823
824 img->dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000825 }
826
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000827 mDirtyMetaData = true;
828}
829
daniel@transgaming.com31273552010-08-04 13:42:44 +0000830bool 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 +0000831{
daniel@transgaming.com31273552010-08-04 13:42:44 +0000832 if (width + xoffset > img->width || height + yoffset > img->height)
833 {
834 error(GL_INVALID_VALUE);
835 return false;
836 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +0000837
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000838 if (!img->surface)
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000839 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000840 createSurface(img->width, img->height, format, type, img);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +0000841 }
842
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000843 if (pixels != NULL && img->surface != NULL)
844 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000845 D3DSURFACE_DESC description;
846 img->surface->GetDesc(&description);
847
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000848 D3DLOCKED_RECT locked;
849 HRESULT result = img->surface->LockRect(&locked, NULL, 0);
850
851 ASSERT(SUCCEEDED(result));
852
853 if (SUCCEEDED(result))
854 {
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +0000855 loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000856 img->surface->UnlockRect();
857 }
858
859 img->dirty = true;
860 }
861
daniel@transgaming.com31273552010-08-04 13:42:44 +0000862 return true;
daniel@transgaming.com29d27002010-03-11 19:41:22 +0000863}
864
daniel@transgaming.com01868132010-08-24 19:21:17 +0000865bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *img)
866{
867 if (width + xoffset > img->width || height + yoffset > img->height)
868 {
869 error(GL_INVALID_VALUE);
870 return false;
871 }
872
873 if (format != getFormat())
874 {
875 error(GL_INVALID_OPERATION);
876 return false;
877 }
878
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000879 if (!img->surface)
daniel@transgaming.com01868132010-08-24 19:21:17 +0000880 {
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000881 createSurface(img->width, img->height, format, GL_UNSIGNED_BYTE, img);
daniel@transgaming.com01868132010-08-24 19:21:17 +0000882 }
883
daniel@transgaming.comd3958d72010-09-22 17:13:54 +0000884 if (pixels != NULL && img->surface != NULL)
885 {
886 RECT updateRegion;
887 updateRegion.left = xoffset;
888 updateRegion.right = xoffset + width;
889 updateRegion.bottom = yoffset + height;
890 updateRegion.top = yoffset;
891
892 D3DLOCKED_RECT locked;
893 HRESULT result = img->surface->LockRect(&locked, &updateRegion, 0);
894
895 ASSERT(SUCCEEDED(result));
896
897 if (SUCCEEDED(result))
898 {
899 GLsizei inputPitch = ComputeCompressedPitch(width, format);
900 int rows = imageSize / inputPitch;
901 for (int i = 0; i < rows; ++i)
902 {
903 memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)pixels + i * inputPitch), inputPitch);
904 }
905 img->surface->UnlockRect();
906 }
907
908 img->dirty = true;
909 }
910
daniel@transgaming.com01868132010-08-24 19:21:17 +0000911 return true;
912}
913
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000914// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats
915void Texture::copyNonRenderable(Image *image, GLenum internalFormat, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
916{
917 IDirect3DDevice9 *device = getDevice();
918 IDirect3DSurface9 *surface = NULL;
919 D3DSURFACE_DESC description;
920 renderTarget->GetDesc(&description);
921
922 HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
923
924 if (!SUCCEEDED(result))
925 {
926 ERR("Could not create matching destination surface.");
927 return error(GL_OUT_OF_MEMORY);
928 }
929
930 result = device->GetRenderTargetData(renderTarget, surface);
931
932 if (!SUCCEEDED(result))
933 {
934 ERR("GetRenderTargetData unexpectedly failed.");
935 surface->Release();
936 return error(GL_OUT_OF_MEMORY);
937 }
938
939 D3DLOCKED_RECT sourceLock = {0};
940 RECT sourceRect = {x, y, x + width, y + height};
941 result = surface->LockRect(&sourceLock, &sourceRect, 0);
942
943 if (FAILED(result))
944 {
945 ERR("Failed to lock the source surface (rectangle might be invalid).");
946 surface->UnlockRect();
947 surface->Release();
948 return error(GL_OUT_OF_MEMORY);
949 }
950
951 if (!image->surface)
952 {
953 createSurface(width, height, internalFormat, mType, image);
954 }
955
956 if (image->surface == NULL)
957 {
958 ERR("Failed to create an image surface.");
959 surface->UnlockRect();
960 surface->Release();
961 return error(GL_OUT_OF_MEMORY);
962 }
963
964 D3DLOCKED_RECT destLock = {0};
965 RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
966 result = image->surface->LockRect(&destLock, &destRect, 0);
967
968 if (FAILED(result))
969 {
970 ERR("Failed to lock the destination surface (rectangle might be invalid).");
971 surface->UnlockRect();
972 surface->Release();
973 return error(GL_OUT_OF_MEMORY);
974 }
975
976 if (destLock.pBits && sourceLock.pBits)
977 {
978 unsigned char *source = (unsigned char*)sourceLock.pBits;
979 unsigned char *dest = (unsigned char*)destLock.pBits;
980
981 switch (description.Format)
982 {
983 case D3DFMT_X8R8G8B8:
984 case D3DFMT_A8R8G8B8:
985 switch(getD3DFormat())
986 {
987 case D3DFMT_L8:
988 for(int y = 0; y < height; y++)
989 {
daniel@transgaming.com17767ce2010-12-17 15:57:41 +0000990 for(int x = 0; x < width; x++)
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +0000991 {
992 dest[x] = source[x * 4 + 2];
993 }
994
995 source += sourceLock.Pitch;
996 dest += destLock.Pitch;
997 }
998 break;
999 case D3DFMT_A8L8:
1000 for(int y = 0; y < height; y++)
1001 {
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001002 for(int x = 0; x < width; x++)
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001003 {
1004 dest[x * 2 + 0] = source[x * 4 + 2];
1005 dest[x * 2 + 1] = source[x * 4 + 3];
1006 }
1007
1008 source += sourceLock.Pitch;
1009 dest += destLock.Pitch;
1010 }
1011 break;
1012 default:
1013 UNREACHABLE();
1014 }
1015 break;
daniel@transgaming.comfe5141e2010-10-18 12:18:12 +00001016 case D3DFMT_R5G6B5:
1017 switch(getD3DFormat())
1018 {
1019 case D3DFMT_L8:
1020 for(int y = 0; y < height; y++)
1021 {
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001022 for(int x = 0; x < width; x++)
daniel@transgaming.comfe5141e2010-10-18 12:18:12 +00001023 {
1024 unsigned char red = source[x * 2 + 1] & 0xF8;
1025 dest[x] = red | (red >> 5);
1026 }
1027
1028 source += sourceLock.Pitch;
1029 dest += destLock.Pitch;
1030 }
1031 break;
1032 default:
1033 UNREACHABLE();
1034 }
1035 break;
daniel@transgaming.com17767ce2010-12-17 15:57:41 +00001036 case D3DFMT_A1R5G5B5:
1037 switch(getD3DFormat())
1038 {
1039 case D3DFMT_L8:
1040 for(int y = 0; y < height; y++)
1041 {
1042 for(int x = 0; x < width; x++)
1043 {
1044 unsigned char red = source[x * 2 + 1] & 0x7C;
1045 dest[x] = (red << 1) | (red >> 4);
1046 }
1047
1048 source += sourceLock.Pitch;
1049 dest += destLock.Pitch;
1050 }
1051 break;
1052 case D3DFMT_A8L8:
1053 for(int y = 0; y < height; y++)
1054 {
1055 for(int x = 0; x < width; x++)
1056 {
1057 unsigned char red = source[x * 2 + 1] & 0x7C;
1058 dest[x * 2 + 0] = (red << 1) | (red >> 4);
1059 dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
1060 }
1061
1062 source += sourceLock.Pitch;
1063 dest += destLock.Pitch;
1064 }
1065 break;
1066 default:
1067 UNREACHABLE();
1068 }
1069 break;
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001070 default:
1071 UNREACHABLE();
1072 }
1073
1074 image->dirty = true;
1075 mDirtyMetaData = true;
1076 }
1077
1078 image->surface->UnlockRect();
1079 surface->UnlockRect();
1080 surface->Release();
1081}
1082
enne@chromium.org0fa74632010-09-21 16:18:52 +00001083D3DFORMAT Texture::getD3DFormat() const
1084{
1085 return selectFormat(getFormat(), mType);
1086}
1087
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001088IDirect3DBaseTexture9 *Texture::getTexture()
1089{
1090 if (!isComplete())
1091 {
1092 return NULL;
1093 }
1094
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001095 if (mDirtyMetaData)
1096 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001097 mBaseTexture = createTexture();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001098 mIsRenderable = false;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001099 }
1100
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001101 if (mDirtyMetaData || dirtyImageData())
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001102 {
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001103 updateTexture();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001104 }
1105
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001106 mDirtyMetaData = false;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001107 ASSERT(!dirtyImageData());
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001108
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001109 return mBaseTexture;
1110}
1111
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001112bool Texture::isDirty() const
1113{
1114 return (mDirty || mDirtyMetaData || dirtyImageData());
1115}
1116
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001117// Returns the top-level texture surface as a render target
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001118void Texture::needRenderTarget()
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001119{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001120 if (!mIsRenderable)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001121 {
1122 mBaseTexture = convertToRenderTarget();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001123 mIsRenderable = true;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001124 }
1125
1126 if (dirtyImageData())
1127 {
1128 updateTexture();
1129 }
1130
1131 mDirtyMetaData = false;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001132}
1133
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001134void Texture::dropTexture()
1135{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001136 if (mBaseTexture)
1137 {
1138 mBaseTexture = NULL;
1139 }
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001140
1141 mIsRenderable = false;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001142}
1143
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001144void Texture::pushTexture(IDirect3DBaseTexture9 *newTexture, bool renderable)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001145{
1146 mBaseTexture = newTexture;
1147 mDirtyMetaData = false;
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001148 mIsRenderable = renderable;
daniel@transgaming.com5a0b0a82010-05-12 03:45:07 +00001149 mDirty = true;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001150}
1151
1152
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001153GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
1154{
1155 if (isPow2(width) && isPow2(height))
1156 {
1157 return maxlevel;
1158 }
1159 else
1160 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001161 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
1162 return 1;
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001163 }
1164}
1165
1166GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
1167{
1168 return creationLevels(size, size, maxlevel);
1169}
1170
1171int Texture::levelCount() const
1172{
1173 return mBaseTexture ? mBaseTexture->GetLevelCount() : 0;
1174}
1175
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001176bool Texture::isRenderable() const
1177{
1178 return mIsRenderable;
1179}
1180
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001181Texture2D::Texture2D(GLuint id) : Texture(id)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001182{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001183 mTexture = NULL;
1184}
1185
1186Texture2D::~Texture2D()
1187{
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001188 mColorbufferProxy.set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001189
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001190 if (mTexture)
1191 {
1192 mTexture->Release();
1193 mTexture = NULL;
1194 }
1195}
1196
1197GLenum Texture2D::getTarget() const
1198{
1199 return GL_TEXTURE_2D;
1200}
1201
daniel@transgaming.com01868132010-08-24 19:21:17 +00001202GLenum Texture2D::getFormat() const
1203{
1204 return mImageArray[0].format;
1205}
1206
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001207// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
1208// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels.
1209// Call this when a particular level of the texture must be defined with a specific format, width and height.
1210//
daniel@transgaming.com11cb68c2010-10-15 17:57:40 +00001211// Returns true if the existing texture was unsuitable and had to be destroyed. If so, it will also set
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001212// 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 +00001213bool Texture2D::redefineTexture(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001214{
1215 bool widthOkay = (mWidth >> level == width);
1216 bool heightOkay = (mHeight >> level == height);
1217
1218 bool sizeOkay = ((widthOkay && heightOkay)
1219 || (widthOkay && mHeight >> level == 0 && height == 1)
1220 || (heightOkay && mWidth >> level == 0 && width == 1));
1221
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001222 bool typeOkay = (type == mType);
1223
1224 bool textureOkay = (sizeOkay && typeOkay && internalFormat == mImageArray[0].format);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001225
1226 if (!textureOkay)
1227 {
1228 TRACE("Redefining 2D texture (%d, 0x%04X, %d, %d => 0x%04X, %d, %d).", level,
1229 mImageArray[0].format, mWidth, mHeight,
1230 internalFormat, width, height);
1231
1232 // Purge all the levels and the texture.
1233
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00001234 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001235 {
1236 if (mImageArray[i].surface != NULL)
1237 {
1238 mImageArray[i].dirty = false;
1239
1240 mImageArray[i].surface->Release();
1241 mImageArray[i].surface = NULL;
1242 }
1243 }
1244
1245 if (mTexture != NULL)
1246 {
1247 mTexture->Release();
1248 mTexture = NULL;
1249 dropTexture();
1250 }
1251
1252 mWidth = width << level;
1253 mHeight = height << level;
1254 mImageArray[0].format = internalFormat;
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001255 mType = type;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001256 }
1257
1258 return !textureOkay;
1259}
1260
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001261void 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 +00001262{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001263 redefineTexture(level, internalFormat, width, height, type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001264
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001265 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001266}
1267
daniel@transgaming.com01868132010-08-24 19:21:17 +00001268void Texture2D::setCompressedImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1269{
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001270 redefineTexture(level, internalFormat, width, height, GL_UNSIGNED_BYTE);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001271
1272 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[level]);
1273}
1274
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001275void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1276{
1277 ASSERT(mImageArray[level].surface != NULL);
1278
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001279 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001280 {
1281 IDirect3DSurface9 *destLevel = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001282 HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001283
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001284 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001285
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001286 if (SUCCEEDED(result))
1287 {
1288 Image *img = &mImageArray[level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001289
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001290 RECT sourceRect;
1291 sourceRect.left = xoffset;
1292 sourceRect.top = yoffset;
1293 sourceRect.right = xoffset + width;
1294 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001295
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001296 POINT destPoint;
1297 destPoint.x = xoffset;
1298 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001299
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001300 result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
1301 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001302
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001303 destLevel->Release();
1304
1305 img->dirty = false;
1306 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001307 }
1308}
1309
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001310void 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 +00001311{
daniel@transgaming.com31273552010-08-04 13:42:44 +00001312 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
1313 {
1314 commitRect(level, xoffset, yoffset, width, height);
1315 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001316}
1317
daniel@transgaming.com01868132010-08-24 19:21:17 +00001318void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1319{
1320 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
1321 {
1322 commitRect(level, xoffset, yoffset, width, height);
1323 }
1324}
1325
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001326void Texture2D::copyImage(GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001327{
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001328 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1329
1330 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001331 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001332 ERR("Failed to retrieve the render target.");
1333 return error(GL_OUT_OF_MEMORY);
1334 }
1335
1336 bool redefined = redefineTexture(level, internalFormat, width, height, mType);
1337
1338 if (!isRenderableFormat())
1339 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001340 copyNonRenderable(&mImageArray[level], internalFormat, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001341 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00001342 else
1343 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001344 if (redefined)
1345 {
1346 convertToRenderTarget();
1347 pushTexture(mTexture, true);
1348 }
1349 else
1350 {
1351 needRenderTarget();
1352 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001353
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001354 if (width != 0 && height != 0 && level < levelCount())
1355 {
1356 RECT sourceRect;
1357 sourceRect.left = x;
1358 sourceRect.right = x + width;
1359 sourceRect.top = y;
1360 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001361
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001362 IDirect3DSurface9 *dest;
1363 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001364
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001365 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
1366 dest->Release();
1367 }
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001368 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001369
1370 mImageArray[level].width = width;
1371 mImageArray[level].height = height;
1372 mImageArray[level].format = internalFormat;
1373}
1374
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001375void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001376{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001377 if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
1378 {
1379 return error(GL_INVALID_VALUE);
1380 }
1381
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001382 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
1383
1384 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001385 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001386 ERR("Failed to retrieve the render target.");
1387 return error(GL_OUT_OF_MEMORY);
1388 }
1389
1390 bool redefined = redefineTexture(0, mImageArray[0].format, mImageArray[0].width, mImageArray[0].height, mType);
1391
1392 if (!isRenderableFormat())
1393 {
1394 copyNonRenderable(&mImageArray[level], getFormat(), xoffset, yoffset, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001395 }
1396 else
1397 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001398 if (redefined)
1399 {
1400 convertToRenderTarget();
1401 pushTexture(mTexture, true);
1402 }
1403 else
1404 {
1405 needRenderTarget();
1406 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001407
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001408 if (level < levelCount())
1409 {
1410 RECT sourceRect;
1411 sourceRect.left = x;
1412 sourceRect.right = x + width;
1413 sourceRect.top = y;
1414 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001415
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001416 IDirect3DSurface9 *dest;
1417 HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001418
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00001419 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, yoffset, dest);
1420 dest->Release();
1421 }
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001422 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001423}
1424
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001425// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1426bool Texture2D::isComplete() const
1427{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001428 GLsizei width = mImageArray[0].width;
1429 GLsizei height = mImageArray[0].height;
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001430
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001431 if (width <= 0 || height <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001432 {
1433 return false;
1434 }
1435
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001436 bool mipmapping = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001437
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001438 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001439 {
1440 case GL_NEAREST:
1441 case GL_LINEAR:
1442 mipmapping = false;
1443 break;
1444 case GL_NEAREST_MIPMAP_NEAREST:
1445 case GL_LINEAR_MIPMAP_NEAREST:
1446 case GL_NEAREST_MIPMAP_LINEAR:
1447 case GL_LINEAR_MIPMAP_LINEAR:
1448 mipmapping = true;
1449 break;
1450 default: UNREACHABLE();
1451 }
1452
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001453 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1454 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1455 {
1456 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1457 {
1458 return false;
1459 }
1460 }
1461
1462
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001463 if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width))
1464 || (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
1465 {
1466 return false;
1467 }
1468
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001469 if (mipmapping)
1470 {
daniel@transgaming.com4c03fa62010-06-24 13:02:16 +00001471 if (!isPow2(width) || !isPow2(height))
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001472 {
1473 return false;
1474 }
1475
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001476 int q = log2(std::max(width, height));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001477
1478 for (int level = 1; level <= q; level++)
1479 {
1480 if (mImageArray[level].format != mImageArray[0].format)
1481 {
1482 return false;
1483 }
1484
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001485 if (mImageArray[level].width != std::max(1, width >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001486 {
1487 return false;
1488 }
1489
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001490 if (mImageArray[level].height != std::max(1, height >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001491 {
1492 return false;
1493 }
1494 }
1495 }
1496
1497 return true;
1498}
1499
daniel@transgaming.com01868132010-08-24 19:21:17 +00001500bool Texture2D::isCompressed() const
1501{
1502 return IsCompressed(getFormat());
1503}
1504
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001505// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001506IDirect3DBaseTexture9 *Texture2D::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001507{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001508 IDirect3DTexture9 *texture;
1509
1510 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001511 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001512
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001513 HRESULT result = device->CreateTexture(mWidth, mHeight, creationLevels(mWidth, mHeight, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001514
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001515 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001516 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001517 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001518 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001519 }
1520
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001521 if (mTexture) mTexture->Release();
1522 mTexture = texture;
1523 return texture;
1524}
1525
1526void Texture2D::updateTexture()
1527{
1528 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001529
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001530 int levels = levelCount();
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001531
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001532 for (int level = 0; level < levels; level++)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001533 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001534 if (mImageArray[level].dirty)
1535 {
1536 IDirect3DSurface9 *levelSurface = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001537 HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001538
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001539 ASSERT(SUCCEEDED(result));
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001540
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001541 if (SUCCEEDED(result))
1542 {
1543 result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
1544 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001545
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001546 levelSurface->Release();
1547
1548 mImageArray[level].dirty = false;
1549 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001550 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001551 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001552}
1553
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001554IDirect3DBaseTexture9 *Texture2D::convertToRenderTarget()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001555{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001556 IDirect3DTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001557
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001558 if (mWidth != 0 && mHeight != 0)
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001559 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001560 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001561 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001562 D3DFORMAT format = selectFormat(mImageArray[0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001563
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001564 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 +00001565
1566 if (FAILED(result))
1567 {
1568 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1569 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1570 }
1571
1572 if (mTexture != NULL)
1573 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001574 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001575 for (int i = 0; i < levels; i++)
1576 {
1577 IDirect3DSurface9 *source;
1578 result = mTexture->GetSurfaceLevel(i, &source);
1579
1580 if (FAILED(result))
1581 {
1582 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1583
1584 texture->Release();
1585
1586 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1587 }
1588
1589 IDirect3DSurface9 *dest;
1590 result = texture->GetSurfaceLevel(i, &dest);
1591
1592 if (FAILED(result))
1593 {
1594 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1595
1596 texture->Release();
1597 source->Release();
1598
1599 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1600 }
1601
daniel@transgaming.comae072af2010-05-05 18:47:28 +00001602 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001603 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
1604
1605 if (FAILED(result))
1606 {
1607 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
1608
1609 texture->Release();
1610 source->Release();
1611 dest->Release();
1612
1613 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
1614 }
1615
1616 source->Release();
1617 dest->Release();
1618 }
1619 }
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001620 }
1621
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001622 if (mTexture != NULL)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001623 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001624 mTexture->Release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001625 }
1626
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001627 mTexture = texture;
1628 return mTexture;
1629}
1630
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001631bool Texture2D::dirtyImageData() const
1632{
1633 int q = log2(std::max(mWidth, mHeight));
1634
1635 for (int i = 0; i <= q; i++)
1636 {
1637 if (mImageArray[i].dirty) return true;
1638 }
1639
1640 return false;
1641}
1642
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001643void Texture2D::generateMipmaps()
1644{
1645 if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
1646 {
1647 return error(GL_INVALID_OPERATION);
1648 }
1649
1650 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1651 unsigned int q = log2(std::max(mWidth, mHeight));
1652 for (unsigned int i = 1; i <= q; i++)
1653 {
1654 if (mImageArray[i].surface != NULL)
1655 {
1656 mImageArray[i].surface->Release();
1657 mImageArray[i].surface = NULL;
1658 }
1659
1660 mImageArray[i].dirty = false;
1661
1662 mImageArray[i].format = mImageArray[0].format;
1663 mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
1664 mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
1665 }
1666
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001667 if (isRenderable())
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00001668 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001669 if (mTexture == NULL)
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001670 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001671 ERR(" failed because mTexture was null.");
1672 return;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001673 }
1674
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00001675 for (unsigned int i = 1; i <= q; i++)
1676 {
1677 IDirect3DSurface9 *upper = NULL;
1678 IDirect3DSurface9 *lower = NULL;
1679
1680 mTexture->GetSurfaceLevel(i-1, &upper);
1681 mTexture->GetSurfaceLevel(i, &lower);
1682
1683 if (upper != NULL && lower != NULL)
1684 {
1685 getBlitter()->boxFilter(upper, lower);
1686 }
1687
1688 if (upper != NULL) upper->Release();
1689 if (lower != NULL) lower->Release();
1690 }
1691 }
1692 else
1693 {
1694 for (unsigned int i = 1; i <= q; i++)
1695 {
1696 createSurface(mImageArray[i].width, mImageArray[i].height, mImageArray[i].format, mType, &mImageArray[i]);
1697 if (mImageArray[i].surface == NULL)
1698 {
1699 return error(GL_OUT_OF_MEMORY);
1700 }
1701
1702 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
1703 {
1704 ERR(" failed to load filter %d to %d.", i - 1, i);
1705 }
1706
1707 mImageArray[i].dirty = true;
1708 }
1709
1710 mDirtyMetaData = true;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00001711 }
1712}
1713
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001714Renderbuffer *Texture2D::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001715{
1716 if (target != GL_TEXTURE_2D)
1717 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001718 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001719 }
1720
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001721 if (mColorbufferProxy.get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001722 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001723 mColorbufferProxy.set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001724 }
1725
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001726 return mColorbufferProxy.get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001727}
1728
1729IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
1730{
1731 ASSERT(target == GL_TEXTURE_2D);
1732
1733 needRenderTarget();
1734
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00001735 if (mTexture == NULL)
1736 {
1737 return NULL;
1738 }
1739
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001740 IDirect3DSurface9 *renderTarget = NULL;
1741 mTexture->GetSurfaceLevel(0, &renderTarget);
1742
1743 return renderTarget;
1744}
1745
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00001746TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001747{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001748 mTexture = NULL;
1749}
1750
1751TextureCubeMap::~TextureCubeMap()
1752{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001753 for (int i = 0; i < 6; i++)
1754 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00001755 mFaceProxies[i].set(NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001756 }
1757
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001758 if (mTexture)
1759 {
1760 mTexture->Release();
1761 mTexture = NULL;
1762 }
1763}
1764
1765GLenum TextureCubeMap::getTarget() const
1766{
1767 return GL_TEXTURE_CUBE_MAP;
1768}
1769
daniel@transgaming.com01868132010-08-24 19:21:17 +00001770GLenum TextureCubeMap::getFormat() const
1771{
1772 return mImageArray[0][0].format;
1773}
1774
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001775void 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 +00001776{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001777 setImage(0, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001778}
1779
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001780void 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 +00001781{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001782 setImage(1, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001783}
1784
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001785void 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 +00001786{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001787 setImage(2, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001788}
1789
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001790void 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 +00001791{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001792 setImage(3, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001793}
1794
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001795void 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 +00001796{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001797 setImage(4, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001798}
1799
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001800void 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 +00001801{
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00001802 setImage(5, level, internalFormat, width, height, format, type, unpackAlignment, pixels);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001803}
1804
daniel@transgaming.com01868132010-08-24 19:21:17 +00001805void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1806{
1807 redefineTexture(level, internalFormat, width);
1808
1809 Texture::setCompressedImage(width, height, internalFormat, imageSize, pixels, &mImageArray[faceIndex(face)][level]);
1810}
1811
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001812void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1813{
1814 int face = faceIndex(faceTarget);
1815
1816 ASSERT(mImageArray[face][level].surface != NULL);
1817
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001818 if (level < levelCount())
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001819 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001820 IDirect3DSurface9 *destLevel = getCubeMapSurface(face, level);
1821 ASSERT(destLevel != NULL);
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001822
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001823 if (destLevel != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001824 {
1825 Image *img = &mImageArray[face][level];
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001826
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001827 RECT sourceRect;
1828 sourceRect.left = xoffset;
1829 sourceRect.top = yoffset;
1830 sourceRect.right = xoffset + width;
1831 sourceRect.bottom = yoffset + height;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001832
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001833 POINT destPoint;
1834 destPoint.x = xoffset;
1835 destPoint.y = yoffset;
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001836
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001837 HRESULT result = getDevice()->UpdateSurface(img->surface, &sourceRect, destLevel, &destPoint);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001838 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001839
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001840 destLevel->Release();
1841
1842 img->dirty = false;
1843 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001844 }
1845}
1846
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001847void TextureCubeMap::subImage(GLenum target, 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 +00001848{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001849 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
daniel@transgaming.com31273552010-08-04 13:42:44 +00001850 {
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001851 commitRect(target, level, xoffset, yoffset, width, height);
daniel@transgaming.com31273552010-08-04 13:42:44 +00001852 }
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001853}
1854
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001855void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
daniel@transgaming.com01868132010-08-24 19:21:17 +00001856{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001857 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
daniel@transgaming.com01868132010-08-24 19:21:17 +00001858 {
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00001859 commitRect(target, level, xoffset, yoffset, width, height);
daniel@transgaming.com01868132010-08-24 19:21:17 +00001860 }
1861}
1862
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001863// 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 +00001864bool TextureCubeMap::isComplete() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001865{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001866 int size = mImageArray[0][0].width;
1867
1868 if (size <= 0)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001869 {
1870 return false;
1871 }
1872
1873 bool mipmapping;
1874
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001875 switch (mMinFilter)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001876 {
1877 case GL_NEAREST:
1878 case GL_LINEAR:
1879 mipmapping = false;
1880 break;
1881 case GL_NEAREST_MIPMAP_NEAREST:
1882 case GL_LINEAR_MIPMAP_NEAREST:
1883 case GL_NEAREST_MIPMAP_LINEAR:
1884 case GL_LINEAR_MIPMAP_LINEAR:
1885 mipmapping = true;
1886 break;
1887 default: UNREACHABLE();
1888 }
1889
1890 for (int face = 0; face < 6; face++)
1891 {
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001892 if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001893 {
1894 return false;
1895 }
1896 }
1897
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001898 if ((getFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
1899 (getFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
1900 {
1901 if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
1902 {
1903 return false;
1904 }
1905 }
1906
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001907 if (mipmapping)
1908 {
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001909 if (!isPow2(size) && (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE))
1910 {
1911 return false;
1912 }
1913
daniel@transgaming.com93a81472010-04-20 18:52:58 +00001914 int q = log2(size);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001915
1916 for (int face = 0; face < 6; face++)
1917 {
1918 for (int level = 1; level <= q; level++)
1919 {
1920 if (mImageArray[face][level].format != mImageArray[0][0].format)
1921 {
1922 return false;
1923 }
1924
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001925 if (mImageArray[face][level].width != std::max(1, size >> level))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001926 {
1927 return false;
1928 }
1929
daniel@transgaming.comd99bd452010-04-22 13:35:25 +00001930 ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001931 }
1932 }
1933 }
1934
1935 return true;
1936}
1937
daniel@transgaming.com01868132010-08-24 19:21:17 +00001938bool TextureCubeMap::isCompressed() const
1939{
1940 return IsCompressed(getFormat());
1941}
1942
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001943// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001944IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001945{
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001946 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00001947 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001948
1949 IDirect3DCubeTexture9 *texture;
1950
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001951 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), 0, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001952
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001953 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001954 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001955 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001956 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001957 }
1958
daniel@transgaming.com00c75962010-03-11 20:36:15 +00001959 if (mTexture) mTexture->Release();
1960
1961 mTexture = texture;
1962 return mTexture;
1963}
1964
1965void TextureCubeMap::updateTexture()
1966{
1967 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001968
daniel@transgaming.com29d27002010-03-11 19:41:22 +00001969 for (int face = 0; face < 6; face++)
1970 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00001971 int levels = levelCount();
1972 for (int level = 0; level < levels; level++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001973 {
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001974 Image *img = &mImageArray[face][level];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001975
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001976 if (img->dirty)
1977 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001978 IDirect3DSurface9 *levelSurface = getCubeMapSurface(face, level);
1979 ASSERT(levelSurface != NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001980
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001981 if (levelSurface != NULL)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001982 {
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00001983 HRESULT result = device->UpdateSurface(img->surface, NULL, levelSurface, NULL);
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001984 ASSERT(SUCCEEDED(result));
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001985
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001986 levelSurface->Release();
1987
1988 img->dirty = false;
1989 }
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00001990 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001991 }
1992 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001993}
1994
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001995IDirect3DBaseTexture9 *TextureCubeMap::convertToRenderTarget()
1996{
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001997 IDirect3DCubeTexture9 *texture = NULL;
daniel@transgaming.com7051b972010-03-21 04:31:07 +00001998
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00001999 if (mWidth != 0)
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002000 {
daniel@transgaming.comae072af2010-05-05 18:47:28 +00002001 egl::Display *display = getDisplay();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002002 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com0a337e92010-08-28 17:38:27 +00002003 D3DFORMAT format = selectFormat(mImageArray[0][0].format, mType);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002004
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002005 HRESULT result = device->CreateCubeTexture(mWidth, creationLevels(mWidth, 0), D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002006
2007 if (FAILED(result))
2008 {
2009 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2010 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2011 }
2012
2013 if (mTexture != NULL)
2014 {
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002015 int levels = levelCount();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002016 for (int f = 0; f < 6; f++)
2017 {
2018 for (int i = 0; i < levels; i++)
2019 {
2020 IDirect3DSurface9 *source;
2021 result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
2022
2023 if (FAILED(result))
2024 {
2025 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2026
2027 texture->Release();
2028
2029 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2030 }
2031
2032 IDirect3DSurface9 *dest;
2033 result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
2034
2035 if (FAILED(result))
2036 {
2037 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2038
2039 texture->Release();
2040 source->Release();
2041
2042 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2043 }
2044
daniel@transgaming.comae072af2010-05-05 18:47:28 +00002045 display->endScene();
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002046 result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
2047
2048 if (FAILED(result))
2049 {
2050 ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
2051
2052 texture->Release();
2053 source->Release();
2054 dest->Release();
2055
2056 return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
2057 }
2058 }
2059 }
2060 }
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002061 }
2062
2063 if (mTexture != NULL)
2064 {
daniel@transgaming.com7051b972010-03-21 04:31:07 +00002065 mTexture->Release();
2066 }
2067
2068 mTexture = texture;
2069 return mTexture;
2070}
2071
daniel@transgaming.com3489e3a2010-03-21 04:31:11 +00002072void 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 +00002073{
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002074 redefineTexture(level, internalFormat, width);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002075
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002076 Texture::setImage(width, height, format, type, unpackAlignment, pixels, &mImageArray[face][level]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002077}
daniel@transgaming.com00c75962010-03-11 20:36:15 +00002078
2079unsigned int TextureCubeMap::faceIndex(GLenum face)
2080{
2081 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
2082 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
2083 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
2084 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
2085 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
2086
2087 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2088}
2089
daniel@transgaming.com842f7a42010-03-21 04:31:03 +00002090bool TextureCubeMap::dirtyImageData() const
2091{
2092 int q = log2(mWidth);
2093
2094 for (int f = 0; f < 6; f++)
2095 {
2096 for (int i = 0; i <= q; i++)
2097 {
2098 if (mImageArray[f][i].dirty) return true;
2099 }
2100 }
2101
2102 return false;
2103}
2104
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002105// While OpenGL doesn't check texture consistency until draw-time, D3D9 requires a complete texture
2106// for render-to-texture (such as CopyTexImage). We have no way of keeping individual inconsistent levels & faces.
2107// Call this when a particular level of the texture must be defined with a specific format, width and height.
2108//
2109// Returns true if the existing texture was unsuitable had to be destroyed. If so, it will also set
2110// a new size for the texture by working backwards from the given size.
2111bool TextureCubeMap::redefineTexture(GLint level, GLenum internalFormat, GLsizei width)
2112{
2113 // Are these settings compatible with level 0?
2114 bool sizeOkay = (mImageArray[0][0].width >> level == width);
2115
2116 bool textureOkay = (sizeOkay && internalFormat == mImageArray[0][0].format);
2117
2118 if (!textureOkay)
2119 {
2120 TRACE("Redefining cube texture (%d, 0x%04X, %d => 0x%04X, %d).", level,
2121 mImageArray[0][0].format, mImageArray[0][0].width,
2122 internalFormat, width);
2123
2124 // Purge all the levels and the texture.
daniel@transgaming.com5d752f22010-10-07 13:37:20 +00002125 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002126 {
2127 for (int f = 0; f < 6; f++)
2128 {
2129 if (mImageArray[f][i].surface != NULL)
2130 {
2131 mImageArray[f][i].dirty = false;
2132
2133 mImageArray[f][i].surface->Release();
2134 mImageArray[f][i].surface = NULL;
2135 }
2136 }
2137 }
2138
2139 if (mTexture != NULL)
2140 {
2141 mTexture->Release();
2142 mTexture = NULL;
2143 dropTexture();
2144 }
2145
2146 mWidth = width << level;
2147 mImageArray[0][0].width = width << level;
2148 mHeight = width << level;
2149 mImageArray[0][0].height = width << level;
2150
2151 mImageArray[0][0].format = internalFormat;
2152 }
2153
2154 return !textureOkay;
2155}
2156
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002157void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002158{
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002159 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002160
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002161 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002162 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002163 ERR("Failed to retrieve the render target.");
2164 return error(GL_OUT_OF_MEMORY);
2165 }
2166
2167 unsigned int faceindex = faceIndex(target);
2168 bool redefined = redefineTexture(level, internalFormat, width);
2169
2170 if (!isRenderableFormat())
2171 {
2172 copyNonRenderable(&mImageArray[faceindex][level], internalFormat, 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002173 }
daniel@transgaming.combc3699d2010-08-05 14:48:49 +00002174 else
2175 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002176 if (redefined)
2177 {
2178 convertToRenderTarget();
2179 pushTexture(mTexture, true);
2180 }
2181 else
2182 {
2183 needRenderTarget();
2184 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002185
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002186 ASSERT(width == height);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002187
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002188 if (width > 0 && level < levelCount())
2189 {
2190 RECT sourceRect;
2191 sourceRect.left = x;
2192 sourceRect.right = x + width;
2193 sourceRect.top = y;
2194 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002195
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002196 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002197
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002198 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, internalFormat, 0, 0, dest);
2199 dest->Release();
2200 }
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002201 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002202
2203 mImageArray[faceindex][level].width = width;
2204 mImageArray[faceindex][level].height = height;
2205 mImageArray[faceindex][level].format = internalFormat;
2206}
2207
2208IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(unsigned int faceIdentifier, unsigned int level)
2209{
2210 unsigned int faceIndex;
2211
2212 if (faceIdentifier < 6)
2213 {
2214 faceIndex = faceIdentifier;
2215 }
2216 else if (faceIdentifier >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && faceIdentifier <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
2217 {
2218 faceIndex = faceIdentifier - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
2219 }
2220 else
2221 {
2222 UNREACHABLE();
2223 faceIndex = 0;
2224 }
2225
2226 if (mTexture == NULL)
2227 {
2228 UNREACHABLE();
2229 return NULL;
2230 }
2231
2232 IDirect3DSurface9 *surface = NULL;
2233
2234 HRESULT hr = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex), level, &surface);
2235
2236 return (SUCCEEDED(hr)) ? surface : NULL;
2237}
2238
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002239void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, RenderbufferStorage *source)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002240{
daniel@transgaming.com3f85fbb2010-10-15 17:58:05 +00002241 GLsizei size = mImageArray[faceIndex(target)][level].width;
daniel@transgaming.com34dc3e82010-04-15 20:45:02 +00002242
2243 if (xoffset + width > size || yoffset + height > size)
2244 {
2245 return error(GL_INVALID_VALUE);
2246 }
2247
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002248 IDirect3DSurface9 *renderTarget = source->getRenderTarget();
2249
2250 if (!renderTarget)
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002251 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002252 ERR("Failed to retrieve the render target.");
2253 return error(GL_OUT_OF_MEMORY);
2254 }
2255
2256 unsigned int faceindex = faceIndex(target);
2257 bool redefined = redefineTexture(0, mImageArray[0][0].format, mImageArray[0][0].width);
2258
2259 if (!isRenderableFormat())
2260 {
2261 copyNonRenderable(&mImageArray[faceindex][level], getFormat(), 0, 0, x, y, width, height, renderTarget);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002262 }
2263 else
2264 {
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002265 if (redefined)
2266 {
2267 convertToRenderTarget();
2268 pushTexture(mTexture, true);
2269 }
2270 else
2271 {
2272 needRenderTarget();
2273 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002274
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002275 if (level < levelCount())
2276 {
2277 RECT sourceRect;
2278 sourceRect.left = x;
2279 sourceRect.right = x + width;
2280 sourceRect.top = y;
2281 sourceRect.bottom = y + height;
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002282
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002283 IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002284
daniel@transgaming.com4c5142c2010-10-15 17:58:27 +00002285 getBlitter()->formatConvert(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, yoffset, dest);
2286 dest->Release();
2287 }
daniel@transgaming.comc808c5a2010-05-14 17:31:01 +00002288 }
daniel@transgaming.comb8c28ed2010-04-13 03:26:32 +00002289}
2290
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002291bool TextureCubeMap::isCubeComplete() const
2292{
2293 if (mImageArray[0][0].width == 0)
2294 {
2295 return false;
2296 }
2297
2298 for (unsigned int f = 1; f < 6; f++)
2299 {
2300 if (mImageArray[f][0].width != mImageArray[0][0].width
2301 || mImageArray[f][0].format != mImageArray[0][0].format)
2302 {
2303 return false;
2304 }
2305 }
2306
2307 return true;
2308}
2309
2310void TextureCubeMap::generateMipmaps()
2311{
2312 if (!isPow2(mImageArray[0][0].width) || !isCubeComplete())
2313 {
2314 return error(GL_INVALID_OPERATION);
2315 }
2316
2317 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2318 unsigned int q = log2(mImageArray[0][0].width);
2319 for (unsigned int f = 0; f < 6; f++)
2320 {
2321 for (unsigned int i = 1; i <= q; i++)
2322 {
2323 if (mImageArray[f][i].surface != NULL)
2324 {
2325 mImageArray[f][i].surface->Release();
2326 mImageArray[f][i].surface = NULL;
2327 }
2328
2329 mImageArray[f][i].dirty = false;
2330
2331 mImageArray[f][i].format = mImageArray[f][0].format;
2332 mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
2333 mImageArray[f][i].height = mImageArray[f][i].width;
2334 }
2335 }
2336
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002337 if (isRenderable())
apatrick@chromium.org9398a6b2010-09-20 19:07:49 +00002338 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002339 if (mTexture == NULL)
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002340 {
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002341 return;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002342 }
apatrick@chromium.org9d1c9b42010-11-23 22:05:41 +00002343
2344 for (unsigned int f = 0; f < 6; f++)
2345 {
2346 for (unsigned int i = 1; i <= q; i++)
2347 {
2348 IDirect3DSurface9 *upper = getCubeMapSurface(f, i-1);
2349 IDirect3DSurface9 *lower = getCubeMapSurface(f, i);
2350
2351 if (upper != NULL && lower != NULL)
2352 {
2353 getBlitter()->boxFilter(upper, lower);
2354 }
2355
2356 if (upper != NULL) upper->Release();
2357 if (lower != NULL) lower->Release();
2358 }
2359 }
2360 }
2361 else
2362 {
2363 for (unsigned int f = 0; f < 6; f++)
2364 {
2365 for (unsigned int i = 1; i <= q; i++)
2366 {
2367 createSurface(mImageArray[f][i].width, mImageArray[f][i].height, mImageArray[f][i].format, mType, &mImageArray[f][i]);
2368 if (mImageArray[f][i].surface == NULL)
2369 {
2370 return error(GL_OUT_OF_MEMORY);
2371 }
2372
2373 if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
2374 {
2375 ERR(" failed to load filter %d to %d.", i - 1, i);
2376 }
2377
2378 mImageArray[f][i].dirty = true;
2379 }
2380 }
2381
2382 mDirtyMetaData = true;
daniel@transgaming.com8fd99e22010-04-20 18:52:00 +00002383 }
2384}
2385
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002386Renderbuffer *TextureCubeMap::getColorbuffer(GLenum target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002387{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002388 if (!IsCubemapTextureTarget(target))
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002389 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002390 return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002391 }
2392
2393 unsigned int face = faceIndex(target);
2394
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002395 if (mFaceProxies[face].get() == NULL)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002396 {
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002397 mFaceProxies[face].set(new Renderbuffer(id(), new TextureColorbufferProxy(this, target)));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002398 }
2399
apatrick@chromium.org4e3bad42010-09-15 17:31:48 +00002400 return mFaceProxies[face].get();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002401}
2402
2403IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
2404{
daniel@transgaming.com19ffc242010-05-04 03:35:21 +00002405 ASSERT(IsCubemapTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002406
2407 needRenderTarget();
daniel@transgaming.come979ead2010-09-23 18:03:14 +00002408
2409 if (mTexture == NULL)
2410 {
2411 return NULL;
apatrick@chromium.org4d5962c2010-09-20 19:02:30 +00002412 }
2413
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002414 IDirect3DSurface9 *renderTarget = NULL;
2415 mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(faceIndex(target)), 0, &renderTarget);
2416
2417 return renderTarget;
2418}
2419
2420Texture::TextureColorbufferProxy::TextureColorbufferProxy(Texture *texture, GLenum target)
enne@chromium.org0fa74632010-09-21 16:18:52 +00002421 : Colorbuffer(texture), mTexture(texture), mTarget(target)
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002422{
daniel@transgaming.comedc19182010-10-15 17:57:55 +00002423 ASSERT(IsTextureTarget(target));
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002424}
2425
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002426void Texture::TextureColorbufferProxy::addRef() const
2427{
2428 mTexture->addRef();
2429}
2430
2431void Texture::TextureColorbufferProxy::release() const
2432{
2433 mTexture->release();
2434}
2435
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002436IDirect3DSurface9 *Texture::TextureColorbufferProxy::getRenderTarget()
2437{
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002438 if (mRenderTarget) mRenderTarget->Release();
2439
2440 mRenderTarget = mTexture->getRenderTarget(mTarget);
2441
2442 return mRenderTarget;
2443}
2444
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002445int Texture::TextureColorbufferProxy::getWidth() const
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002446{
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002447 return mTexture->getWidth();
2448}
2449
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +00002450int Texture::TextureColorbufferProxy::getHeight() const
daniel@transgaming.com866f3182010-05-20 19:28:22 +00002451{
2452 return mTexture->getHeight();
daniel@transgaming.com93a81472010-04-20 18:52:58 +00002453}
2454
daniel@transgaming.com01868132010-08-24 19:21:17 +00002455GLenum Texture::TextureColorbufferProxy::getFormat() const
2456{
2457 return mTexture->getFormat();
2458}
2459
daniel@transgaming.com1297d922010-09-01 15:47:47 +00002460bool Texture::TextureColorbufferProxy::isFloatingPoint() const
2461{
2462 return mTexture->isFloatingPoint();
2463}
2464
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002465}