diff options
-rw-r--r-- | source/blender/gpu/CMakeLists.txt | 5 | ||||
-rw-r--r-- | source/blender/gpu/GPU_draw.h | 3 | ||||
-rw-r--r-- | source/blender/gpu/SConscript | 3 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_draw.c | 120 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_imbuf_types.h | 32 | ||||
-rw-r--r-- | source/blender/imbuf/intern/allocimbuf.c | 2 | ||||
-rw-r--r-- | source/blender/imbuf/intern/dds/DirectDrawSurface.cpp | 27 | ||||
-rw-r--r-- | source/blender/imbuf/intern/dds/DirectDrawSurface.h | 2 | ||||
-rw-r--r-- | source/blender/imbuf/intern/dds/dds_api.cpp | 12 | ||||
-rw-r--r-- | source/gameengine/Ketsji/BL_Texture.cpp | 28 | ||||
-rw-r--r-- | source/gameengine/Ketsji/BL_Texture.h | 1 | ||||
-rw-r--r-- | source/gameengine/Ketsji/CMakeLists.txt | 4 |
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} |