Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorMitchell Stokes <mogurijin@gmail.com>2012-06-30 08:34:34 +0400
committerMitchell Stokes <mogurijin@gmail.com>2012-06-30 08:34:34 +0400
commit436f02ab9cdf58d8b68f124be0d974a5de0d9308 (patch)
tree55394116b8e2a7c84899e389acda1e725c61a744 /source
parent2d7efed014539e5b7193f9a73ccfa61ea3ed0838 (diff)
Finally committing support for compressed textures on the GPU (DDS+DXT). This patch started out as a patch by me, then cleaned up by Kupoman during his work on Cucumber.
One important thing to keep in mind when using this feature is that you'll need to flip your textures vertically (both the GIMP and Photoshop DDS tools I've seen have support for this on export). This is a quirk in using a texture format originally made for DirectX/DirectDraw, and flipping the compressed data is a real headache. Another quick fix for this issue is to change the Y value for the Size in the Mapping panel in the Texture properties to -1 (default is 1).
Diffstat (limited to 'source')
-rw-r--r--source/blender/gpu/CMakeLists.txt5
-rw-r--r--source/blender/gpu/GPU_draw.h3
-rw-r--r--source/blender/gpu/SConscript3
-rw-r--r--source/blender/gpu/intern/gpu_draw.c120
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h32
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c2
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp27
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.h2
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp12
-rw-r--r--source/gameengine/Ketsji/BL_Texture.cpp28
-rw-r--r--source/gameengine/Ketsji/BL_Texture.h1
-rw-r--r--source/gameengine/Ketsji/CMakeLists.txt4
12 files changed, 222 insertions, 17 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 59e384cbd4b..d80e756f0b6 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -71,5 +71,10 @@ endif()
add_definitions(-DGLEW_STATIC)
+if(WITH_IMAGE_DDS)
+ add_definitions(-DWITH_DDS)
+endif()
+
+
blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 438cfd6b741..59140b2be80 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -122,6 +122,9 @@ void GPU_paint_update_image(struct Image *ima, int x, int y, int w, int h, int m
void GPU_update_images_framechange(void);
int GPU_update_image_time(struct Image *ima, double time);
int GPU_verify_image(struct Image *ima, struct ImageUser *iuser, int tftile, int compare, int mipmap);
+void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float *frect, int rectw, int recth, int mipmap, int use_hight_bit_depth, struct Image *ima);
+void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x, int y, int mipmap, struct Image *ima, struct ImBuf *ibuf);
+int GPU_upload_dxt_texture(struct ImBuf *ibuf);
void GPU_free_image(struct Image *ima);
void GPU_free_images(void);
void GPU_free_images_anim(void);
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
index cf1c91f25fe..7ab0c6cce46 100644
--- a/source/blender/gpu/SConscript
+++ b/source/blender/gpu/SConscript
@@ -17,4 +17,7 @@ incs += ' ' + env['BF_OPENGL_INC']
if env['WITH_BF_SMOKE']:
defs.append('WITH_SMOKE')
+if env['WITH_BF_DDS']:
+ defs.append('WITH_DDS')
+
env.BlenderLib ( 'bf_gpu', sources, Split(incs), defines = defs, libtype=['core','player'], priority=[160,110] )
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 4197e1a3edb..1e261e10ed6 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -427,8 +427,8 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
ImBuf *ibuf = NULL;
unsigned int *bind = NULL;
int rectw, recth, tpx=0, tpy=0, y;
- unsigned int *tilerect= NULL, *scalerect= NULL, *rect= NULL;
- float *ftilerect= NULL, *fscalerect = NULL, *frect = NULL;
+ unsigned int *tilerect= NULL, *rect= NULL;
+ float *ftilerect= NULL, *frect = NULL;
float *srgb_frect = NULL;
short texwindx, texwindy, texwinsx, texwinsy;
/* flag to determine whether high resolution format is used */
@@ -611,7 +611,32 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
rect= tilerect;
}
}
+#ifdef WITH_DDS
+ if (ibuf->ftype & DDS)
+ GPU_create_gl_tex_compressed(bind, rect, rectw, recth, mipmap, ima, ibuf);
+ else
+#endif
+ GPU_create_gl_tex(bind, rect, frect, rectw, recth, mipmap, use_high_bit_depth, ima);
+
+ /* clean up */
+ if (tilerect)
+ MEM_freeN(tilerect);
+ if (ftilerect)
+ MEM_freeN(ftilerect);
+ if (srgb_frect)
+ MEM_freeN(srgb_frect);
+ return *bind;
+}
+
+void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float * frect, int rectw, int recth, int mipmap, int use_high_bit_depth, Image *ima)
+{
+ unsigned int *scalerect = NULL;
+ float *fscalerect = NULL;
+
+ int tpx = rectw;
+ int tpy = recth;
+
/* scale if not a power of two. this is not strictly necessary for newer
* GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures */
if (!is_pow2_limit(rectw) || !is_pow2_limit(recth)) {
@@ -626,9 +651,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
}
else {
scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
- gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
+ gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, pix, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
- rect= scalerect;
+ pix= scalerect;
}
}
@@ -640,7 +665,7 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
if (use_high_bit_depth)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
}
@@ -649,14 +674,14 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
if (use_high_bit_depth)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix);
glGenerateMipmapEXT(GL_TEXTURE_2D);
} else {
if (use_high_bit_depth)
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA16, rectw, recth, GL_RGBA, GL_FLOAT, frect);
else
- gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, pix);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
@@ -668,21 +693,84 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
/* set to modulate with vertex color */
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
- /* clean up */
- if (tilerect)
- MEM_freeN(tilerect);
- if (ftilerect)
- MEM_freeN(ftilerect);
+
if (scalerect)
MEM_freeN(scalerect);
if (fscalerect)
MEM_freeN(fscalerect);
- if (srgb_frect)
- MEM_freeN(srgb_frect);
- return *bind;
}
+/**
+ * GPU_upload_dxt_texture() assumes that the texture is already bound and ready to go.
+ * This is so the viewport and the BGE can share some code.
+ * Returns 0 if the provided ImBuf doesn't have a supported DXT compression format
+ */
+int GPU_upload_dxt_texture(ImBuf *ibuf)
+{
+ GLint format, err;
+ int blocksize, height, width, i, size, offset = 0;
+
+ height = ibuf->x;
+ width = ibuf->y;
+
+ if (ibuf->dds_data.fourcc == FOURCC_DXT1)
+ format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ else if (ibuf->dds_data.fourcc == FOURCC_DXT3)
+ format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ else if (ibuf->dds_data.fourcc == FOURCC_DXT5)
+ format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ else {
+ printf("Unable to find a suitable DXT compression, falling back to uncompressed\n");
+ return 0;
+ }
+
+ blocksize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
+ for (i=0; i<ibuf->dds_data.nummipmaps && (width||height); ++i) {
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ size = ((width+3)/4)*((height+3)/4)*blocksize;
+
+ glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height,
+ 0, size, ibuf->dds_data.data + offset);
+
+ err = glGetError();
+
+ if (err != GL_NO_ERROR)
+ printf("OpenGL error: %s\nFormat: %x\n", gluErrorString(err), format);
+
+ offset += size;
+ width >>= 1;
+ height >>= 1;
+ }
+
+ return 1;
+}
+
+void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x, int y, int mipmap, Image *ima, ImBuf *ibuf)
+{
+#ifndef WITH_DDS
+ // Fall back to uncompressed if DDS isn't enabled
+ GPU_create_gl_tex(bind, pix, NULL, x, y, mipmap, 0, ima);
+#else
+
+
+ glGenTextures(1, (GLuint *)bind);
+ glBindTexture(GL_TEXTURE_2D, *bind);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ if (GPU_upload_dxt_texture(ibuf) == 0) {
+ glDeleteTextures(1, (GLuint*)bind);
+ GPU_create_gl_tex(bind, pix, NULL, x, y, mipmap, 0, ima);
+ }
+#endif
+}
static void gpu_verify_repeat(Image *ima)
{
/* set either clamp or repeat in X/Y */
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 2cb1dfe149a..dcb5cdd7d32 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -50,6 +50,13 @@ struct ImMetaData;
#define IB_MIPMAP_LEVELS 20
#define IB_FILENAME_SIZE 1024
+typedef struct DDSData {
+ unsigned int fourcc; /* DDS fourcc info */
+ unsigned int nummipmaps; /* The number of mipmaps in the dds file */
+ unsigned char *data; /* The compressed image data */
+ unsigned int size; /* The size of the compressed data */
+} DDSData;
+
/**
* \ingroup imbuf
* This is the abstraction of an image. ImBuf is the basic type used for all
@@ -119,6 +126,9 @@ typedef struct ImBuf {
unsigned char *encodedbuffer; /* Compressed image only used with png currently */
unsigned int encodedsize; /* Size of data written to encodedbuffer */
unsigned int encodedbuffersize; /* Size of encodedbuffer */
+
+ /* information for compressed textures */
+ struct DDSData dds_data;
} ImBuf;
/* Moved from BKE_bmfont_types.h because it is a userflag bit mask. */
@@ -215,6 +225,28 @@ typedef struct ImBuf {
#define IB_PROFILE_SRGB 2
#define IB_PROFILE_CUSTOM 3
+/* dds */
+#ifdef WITH_DDS
+#ifndef MAKEFOURCC
+#define MAKEFOURCC(ch0, ch1, ch2, ch3)\
+ ((unsigned long)(unsigned char)(ch0) | \
+ ((unsigned long)(unsigned char)(ch1) << 8) | \
+ ((unsigned long)(unsigned char)(ch2) << 16) | \
+ ((unsigned long)(unsigned char)(ch3) << 24))
+#endif //MAKEFOURCC
+
+/*
+ * FOURCC codes for DX compressed-texture pixel formats
+ */
+
+#define FOURCC_DDS (MAKEFOURCC('D','D','S',' '))
+#define FOURCC_DXT1 (MAKEFOURCC('D','X','T','1'))
+#define FOURCC_DXT2 (MAKEFOURCC('D','X','T','2'))
+#define FOURCC_DXT3 (MAKEFOURCC('D','X','T','3'))
+#define FOURCC_DXT4 (MAKEFOURCC('D','X','T','4'))
+#define FOURCC_DXT5 (MAKEFOURCC('D','X','T','5'))
+
+#endif // DDS
extern const char *imb_ext_image[];
extern const char *imb_ext_image_qt[];
extern const char *imb_ext_movie[];
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 5dff3e1aea0..68a094c26d0 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -162,6 +162,8 @@ void IMB_freeImBuf(ImBuf *ibuf)
IMB_freezbuffloatImBuf(ibuf);
freeencodedbufferImBuf(ibuf);
IMB_metadata_free(ibuf);
+ if (ibuf->dds_data.data != NULL)
+ free(ibuf->dds_data.data); /* dds_data.data is allocated by DirectDrawSurface::readData(), so don't use MEM_freeN! */
MEM_freeN(ibuf);
}
}
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index 438988fbe48..82f355e1bb2 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -1016,6 +1016,10 @@ uint DirectDrawSurface::mipmapCount() const
else return 1;
}
+uint DirectDrawSurface::fourCC() const
+{
+ return header.pf.fourcc;
+}
uint DirectDrawSurface::width() const
{
@@ -1131,6 +1135,29 @@ void DirectDrawSurface::mipmap(Image * img, uint face, uint mipmap)
}
}
+// It was easier to copy this function from upstream than to resync.
+// This should be removed if a resync ever occurs.
+void* DirectDrawSurface::readData(uint &rsize)
+{
+ uint header_size = 128; // sizeof(DDSHeader);
+ if (header.hasDX10Header())
+ {
+ header_size += 20; // sizeof(DDSHeader10);
+ }
+
+ uint size = stream.size - header_size;
+ rsize = size;
+
+ unsigned char *data = new unsigned char[size];
+
+ stream.seek(header_size);
+ mem_read(stream, data, size);
+
+ // Maybe check if size == rsize? assert() isn't in this scope...
+
+ return data;
+}
+
void DirectDrawSurface::readLinearImage(Image * img)
{
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
index ddae8826620..a851533b1f3 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.h
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
@@ -158,6 +158,7 @@ public:
bool hasAlpha() const;
uint mipmapCount() const;
+ uint fourCC() const;
uint width() const;
uint height() const;
uint depth() const;
@@ -171,6 +172,7 @@ public:
void setUserVersion(int version);
void mipmap(Image * img, uint f, uint m);
+ void* readData(uint &size);
// void mipmap(FloatImage * img, uint f, uint m);
void printInfo() const;
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index 071d94c2076..fba326f7865 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -123,6 +123,8 @@ struct ImBuf *imb_load_dds(unsigned char *mem, size_t size, int flags)
ibuf->ftype = DDS;
ibuf->profile = IB_PROFILE_SRGB;
+ ibuf->dds_data.fourcc = dds.fourCC();
+ ibuf->dds_data.nummipmaps = dds.mipmapCount();
if ((flags & IB_test) == 0) {
if (!imb_addrectImBuf(ibuf)) return(ibuf);
@@ -136,10 +138,18 @@ struct ImBuf *imb_load_dds(unsigned char *mem, size_t size, int flags)
cp[0] = pixel.r; /* set R component of col */
cp[1] = pixel.g; /* set G component of col */
cp[2] = pixel.b; /* set B component of col */
- if (bits_per_pixel == 32)
+ if (dds.hasAlpha())
cp[3] = pixel.a; /* set A component of col */
rect[i] = col;
}
+
+ if (ibuf->dds_data.fourcc != FOURCC_DDS)
+ ibuf->dds_data.data = (unsigned char*)dds.readData(ibuf->dds_data.size);
+ else {
+ ibuf->dds_data.data = NULL;
+ ibuf->dds_data.size = 0;
+ }
+
IMB_flipy(ibuf);
}
diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp
index 576da0d3f40..19247664dfa 100644
--- a/source/gameengine/Ketsji/BL_Texture.cpp
+++ b/source/gameengine/Ketsji/BL_Texture.cpp
@@ -144,7 +144,15 @@ bool BL_Texture::InitFromImage(int unit, Image *img, bool mipmap)
mNeedsDeleted = 1;
glGenTextures(1, (GLuint*)&mTexture);
+
+#ifdef WITH_DDS
+ if (ibuf->ftype & DDS)
+ InitGLCompressedTex(ibuf, mipmap);
+ else
+ InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap);
+#else
InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap);
+#endif
// track created units
BL_TextureObject obj;
@@ -183,6 +191,26 @@ void BL_Texture::InitGLTex(unsigned int *pix,int x,int y,bool mipmap)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
+void BL_Texture::InitGLCompressedTex(ImBuf* ibuf, bool mipmap)
+{
+#ifndef WITH_DDS
+ // Fall back to uncompressed if DDS isn't enabled
+ InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap);
+ return;
+#else
+ glBindTexture(GL_TEXTURE_2D, mTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+
+ if (GPU_upload_dxt_texture(ibuf) == 0) {
+ InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap);
+ return;
+ }
+#endif
+}
void BL_Texture::InitNonPow2Tex(unsigned int *pix,int x,int y,bool mipmap)
{
diff --git a/source/gameengine/Ketsji/BL_Texture.h b/source/gameengine/Ketsji/BL_Texture.h
index 2673be2bc42..a6bd354d260 100644
--- a/source/gameengine/Ketsji/BL_Texture.h
+++ b/source/gameengine/Ketsji/BL_Texture.h
@@ -35,6 +35,7 @@ private:
void InitNonPow2Tex(unsigned int *p,int x,int y,bool mipmap );
void InitGLTex(unsigned int *p,int x,int y,bool mipmap );
+ void InitGLCompressedTex(struct ImBuf *p, bool mipmap);
public:
BL_Texture();
~BL_Texture( );
diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt
index c7f54838c10..4b3426e0784 100644
--- a/source/gameengine/Ketsji/CMakeLists.txt
+++ b/source/gameengine/Ketsji/CMakeLists.txt
@@ -221,6 +221,10 @@ set(SRC
add_definitions(-DGLEW_STATIC)
+if(WITH_IMAGE_DDS)
+ add_definitions(-DWITH_DDS)
+endif()
+
if(WITH_SDL)
list(APPEND INC_SYS
${SDL_INCLUDE_DIR}