Support redefinition of textures through glTexImage2D.

TRAC #11316. Keep a dirty data flag, recreate the texture when it is set. Texture now owns getTexture() and calls a virtual createTexture method when the derived classes need to recreate. Signed-off-by: Daniel Koch Author: Andrew Lewycky <andrew.lewycky@transgaming.com> git-svn-id: https://angleproject.googlecode.com/svn/trunk@12 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent fab5a1ae
......@@ -24,6 +24,8 @@ Texture::Texture() : Colorbuffer(0)
mMagFilter = GL_LINEAR;
mWrapS = GL_REPEAT;
mWrapT = GL_REPEAT;
mDirtyImageData = true;
}
Texture::~Texture()
......@@ -113,24 +115,24 @@ GLenum Texture::getWrapT()
}
// Copies an Image into an already locked Direct3D 9 surface, performing format conversions as necessary
void Texture::copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image)
void Texture::copyImage(const D3DLOCKED_RECT &lock, D3DFORMAT format, Image *image)
{
if (lock.pBits && image.pixels)
if (lock.pBits && !image->pixels.empty())
{
for (int y = 0; y < image.height; y++)
for (int y = 0; y < image->height; y++)
{
unsigned char *source = (unsigned char*)image.pixels + y * image.width * pixelSize(image);
unsigned char *source = &image->pixels[0] + y * image->width * pixelSize(*image);
unsigned short *source16 = (unsigned short*)source;
unsigned char *dest = (unsigned char*)lock.pBits + y * lock.Pitch;
for (int x = 0; x < image.width; x++)
for (int x = 0; x < image->width; x++)
{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
switch (image.format)
switch (image->format)
{
case GL_ALPHA:
UNIMPLEMENTED();
......@@ -142,7 +144,7 @@ void Texture::copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image)
UNIMPLEMENTED();
break;
case GL_RGB:
switch (image.type)
switch (image->type)
{
case GL_UNSIGNED_BYTE: UNIMPLEMENTED(); break;
case GL_UNSIGNED_SHORT_5_6_5:
......@@ -159,7 +161,7 @@ void Texture::copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image)
}
break;
case GL_RGBA:
switch (image.type)
switch (image->type)
{
case GL_UNSIGNED_BYTE:
r = source[x * 4 + 0];
......@@ -262,23 +264,52 @@ int Texture::pixelSize(const Image &image)
return 0;
}
Texture2D::Texture2D()
void Texture::setImage(GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img)
{
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
mDirtyImageData = true;
img->internalFormat = internalFormat;
img->width = width;
img->height = height;
img->format = format;
img->type = type;
size_t imageSize = pixelSize(*img) * width * height;
std::vector<unsigned char> storage(imageSize);
if (pixels)
{
mImageArray[level].pixels = NULL;
memcpy(&storage[0], pixels, imageSize);
}
mTexture = NULL;
img->pixels.swap(storage);
}
Texture2D::~Texture2D()
IDirect3DBaseTexture9 *Texture::getTexture()
{
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
if (!isComplete())
{
delete[] mImageArray[level].pixels;
return NULL;
}
if (mDirtyImageData)
{
mBaseTexture = createTexture();
mDirtyImageData = false;
}
return mBaseTexture;
}
Texture2D::Texture2D()
{
mTexture = NULL;
}
Texture2D::~Texture2D()
{
if (mTexture)
{
mTexture->Release();
......@@ -298,22 +329,7 @@ void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsi
return;
}
mImageArray[level].internalFormat = internalFormat;
mImageArray[level].width = width;
mImageArray[level].height = height;
mImageArray[level].format = format;
mImageArray[level].type = type;
delete[] mImageArray[level].pixels;
mImageArray[level].pixels = NULL;
int imageSize = pixelSize(mImageArray[level]) * width * height;
mImageArray[level].pixels = new unsigned char[imageSize];
if (pixels)
{
memcpy(mImageArray[level].pixels, pixels, imageSize);
}
Texture::setImage(internalFormat, width, height, format, type, pixels, &mImageArray[level]);
if (level == 0)
{
......@@ -384,63 +400,63 @@ bool Texture2D::isComplete()
}
// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
IDirect3DBaseTexture9 *Texture2D::getTexture()
IDirect3DBaseTexture9 *Texture2D::createTexture()
{
if (!isComplete())
{
return NULL;
}
IDirect3DTexture9 *texture;
if (!mTexture) // FIXME: Recreate when changed (same for getRenderTarget)
{
IDirect3DDevice9 *device = getDevice();
D3DFORMAT format = selectFormat(mImageArray[0]);
HRESULT result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &mTexture, NULL);
IDirect3DDevice9 *device = getDevice();
D3DFORMAT format = selectFormat(mImageArray[0]);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
error(GL_OUT_OF_MEMORY, 0);
}
HRESULT result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
ASSERT(SUCCEEDED(result));
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
}
IDirect3DTexture9 *lockableTexture;
result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL);
ASSERT(SUCCEEDED(result));
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
error(GL_OUT_OF_MEMORY,(IDirect3DBaseTexture9*)NULL);
}
IDirect3DTexture9 *lockableTexture;
result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL);
ASSERT(SUCCEEDED(result));
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
texture->Release();
return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
}
if (mTexture) // FIXME: Handle failure
{
int levelCount = mTexture->GetLevelCount();
ASSERT(SUCCEEDED(result));
for (int level = 0; level < levelCount; level++)
{
D3DLOCKED_RECT lock = {0};
lockableTexture->LockRect(level, &lock, NULL, 0);
int levelCount = texture->GetLevelCount();
copyImage(lock, format, mImageArray[level]);
for (int level = 0; level < levelCount; level++)
{
D3DLOCKED_RECT lock = {0};
lockableTexture->LockRect(level, &lock, NULL, 0);
lockableTexture->UnlockRect(level);
}
copyImage(lock, format, &mImageArray[level]);
device->UpdateTexture(lockableTexture, mTexture);
lockableTexture->Release();
}
lockableTexture->UnlockRect(level);
}
return mTexture;
device->UpdateTexture(lockableTexture, texture);
lockableTexture->Release();
if (mTexture) mTexture->Release();
mTexture = texture;
return texture;
}
// Returns the top-level texture surface as a render target
IDirect3DSurface9 *Texture2D::getRenderTarget()
{
if (!mRenderTarget && getTexture())
if (mDirtyImageData && mRenderTarget)
{
mRenderTarget->Release();
mRenderTarget = NULL;
}
if (!mRenderTarget && getTexture()) // FIXME: getTexture fails for incomplete textures. Check spec.
{
mTexture->GetSurfaceLevel(0, &mRenderTarget);
}
......@@ -450,27 +466,11 @@ IDirect3DSurface9 *Texture2D::getRenderTarget()
TextureCubeMap::TextureCubeMap()
{
for (int face = 0; face < 6; face++)
{
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
{
mImageArray[face][level].pixels = NULL;
}
}
mTexture = NULL;
}
TextureCubeMap::~TextureCubeMap()
{
for (int face = 0; face < 6; face++)
{
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
{
delete[] mImageArray[face][level].pixels;
}
}
if (mTexture)
{
mTexture->Release();
......@@ -586,57 +586,52 @@ bool TextureCubeMap::isComplete()
}
// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
IDirect3DBaseTexture9 *TextureCubeMap::getTexture()
IDirect3DBaseTexture9 *TextureCubeMap::createTexture()
{
if (!isComplete())
{
return NULL;
}
IDirect3DDevice9 *device = getDevice();
D3DFORMAT format = selectFormat(mImageArray[0][0]);
if (!mTexture) // FIXME: Recreate when changed (same for getRenderTarget)
{
IDirect3DDevice9 *device = getDevice();
D3DFORMAT format = selectFormat(mImageArray[0][0]);
IDirect3DCubeTexture9 *texture;
HRESULT result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &mTexture, NULL);
HRESULT result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
}
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
}
ASSERT(SUCCEEDED(result));
ASSERT(SUCCEEDED(result));
IDirect3DCubeTexture9 *lockableTexture;
result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL);
IDirect3DCubeTexture9 *lockableTexture;
result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
}
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
{
texture->Release();
return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL);
}
ASSERT(SUCCEEDED(result));
ASSERT(SUCCEEDED(result));
if (mTexture)
for (int face = 0; face < 6; face++)
{
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
{
for (int face = 0; face < 6; face++)
{
for (int level = 0; level < MAX_TEXTURE_LEVELS; level++)
{
D3DLOCKED_RECT lock = {0};
lockableTexture->LockRect((D3DCUBEMAP_FACES)face, level, &lock, NULL, 0);
copyImage(lock, format, mImageArray[face][level]);
D3DLOCKED_RECT lock = {0};
lockableTexture->LockRect((D3DCUBEMAP_FACES)face, level, &lock, NULL, 0);
lockableTexture->UnlockRect((D3DCUBEMAP_FACES)face, level);
}
}
copyImage(lock, format, &mImageArray[face][level]);
device->UpdateTexture(lockableTexture, mTexture);
lockableTexture->Release();
lockableTexture->UnlockRect((D3DCUBEMAP_FACES)face, level);
}
}
device->UpdateTexture(lockableTexture, texture);
lockableTexture->Release();
if (mTexture) mTexture->Release();
mTexture = texture;
return mTexture;
}
......@@ -647,22 +642,7 @@ void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsi
return;
}
mImageArray[face][level].internalFormat = internalFormat;
mImageArray[face][level].width = width;
mImageArray[face][level].height = height;
mImageArray[face][level].format = format;
mImageArray[face][level].type = type;
delete[] mImageArray[face][level].pixels;
mImageArray[face][level].pixels = NULL;
int imageSize = pixelSize(mImageArray[face][level]) * width * height;
mImageArray[face][level].pixels = new unsigned char[imageSize];
if (pixels)
{
memcpy(mImageArray[face][level].pixels, pixels, imageSize);
}
Texture::setImage(internalFormat, width, height, format, type, pixels, &mImageArray[face][level]);
if (face == 0 && level == 0)
{
......
......@@ -17,6 +17,8 @@
#include <GLES2/gl2.h>
#include <d3d9.h>
#include <vector>
namespace gl
{
enum
......@@ -27,17 +29,6 @@ enum
MAX_TEXTURE_LEVELS = 11 // log2 of MAX_TEXTURE_SIZE
};
// Helper structure representing a single image layer
struct Image
{
GLenum internalFormat;
GLsizei width;
GLsizei height;
GLenum format;
GLenum type;
void *pixels;
};
class Texture : public Colorbuffer
{
public:
......@@ -58,10 +49,22 @@ class Texture : public Colorbuffer
GLenum getWrapT();
virtual bool isComplete() = 0;
virtual IDirect3DBaseTexture9 *getTexture() = 0;
IDirect3DBaseTexture9 *getTexture();
protected:
void copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image);
// Helper structure representing a single image layer
struct Image
{
GLenum internalFormat;
GLsizei width;
GLsizei height;
GLenum format;
GLenum type;
std::vector<unsigned char> pixels;
};
void copyImage(const D3DLOCKED_RECT &lock, D3DFORMAT format, Image *image);
static D3DFORMAT selectFormat(const Image &image);
static int pixelSize(const Image &image);
......@@ -71,8 +74,17 @@ class Texture : public Colorbuffer
GLenum mWrapS;
GLenum mWrapT;
void setImage(GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels, Image *img);
// The pointer returned is weak and it is assumed the derived class will keep a strong pointer until the next createTexture() call.
virtual IDirect3DBaseTexture9 *createTexture() = 0;
bool mDirtyImageData; // FIXME: would be private but getRenderTarget is still implemented through the derived classes and they need it.
private:
DISALLOW_COPY_AND_ASSIGN(Texture);
IDirect3DBaseTexture9 *mBaseTexture; // This is a weak pointer. The derived class is assumed to own a strong pointer.
};
class Texture2D : public Texture
......@@ -97,12 +109,13 @@ class Texture2D : public Texture
GLenum getWrapT();
bool isComplete();
IDirect3DBaseTexture9 *getTexture();
IDirect3DSurface9 *getRenderTarget();
private:
DISALLOW_COPY_AND_ASSIGN(Texture2D);
virtual IDirect3DBaseTexture9 *createTexture();
Image mImageArray[MAX_TEXTURE_LEVELS];
IDirect3DTexture9 *mTexture;
......@@ -125,11 +138,12 @@ class TextureCubeMap : public Texture
void setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
bool isComplete();
IDirect3DBaseTexture9 *getTexture();
private:
DISALLOW_COPY_AND_ASSIGN(TextureCubeMap);
virtual IDirect3DBaseTexture9 *createTexture();
void setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
Image mImageArray[6][MAX_TEXTURE_LEVELS];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment