├── img_test.bmp ├── img_test.dds ├── img_test.png ├── img_test.tga ├── testSOIL.exe ├── test_rect.png ├── img_cheryl.jpg ├── field_128_cube.dds ├── img_test_indexed.tga ├── README.md ├── projects ├── VC6 │ ├── SOIL.dsw │ └── SOIL.dsp ├── VC8 │ ├── SOIL.sln │ └── SOIL.vcproj ├── VC7.1 │ ├── SOIL.sln │ └── SOIL.vcproj ├── VC9 │ ├── SOIL.sln │ └── SOIL.vcproj ├── VC14 │ ├── SOIL.sln │ └── SOIL.vcxproj ├── VC12 │ ├── SOIL.sln │ └── SOIL.vcxproj ├── makefile │ ├── alternate Makefile.txt │ ├── makefile │ ├── makefile-pdk-host │ └── makefile-pdk-device └── codeblocks │ └── SOIL.cbp ├── src ├── stbi_DDS_aug.h ├── image_helper.h ├── image_DXT.h ├── image_helper.c ├── test_SOIL.cpp ├── SOIL.h ├── stbi_DDS_aug_c.h ├── stb_image_aug.h └── image_DXT.c ├── support └── FreeBasic │ └── SOIL.bi └── soil.html /img_test.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epatel/SOIL/HEAD/img_test.bmp -------------------------------------------------------------------------------- /img_test.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epatel/SOIL/HEAD/img_test.dds -------------------------------------------------------------------------------- /img_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epatel/SOIL/HEAD/img_test.png -------------------------------------------------------------------------------- /img_test.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epatel/SOIL/HEAD/img_test.tga -------------------------------------------------------------------------------- /testSOIL.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epatel/SOIL/HEAD/testSOIL.exe -------------------------------------------------------------------------------- /test_rect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epatel/SOIL/HEAD/test_rect.png -------------------------------------------------------------------------------- /img_cheryl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epatel/SOIL/HEAD/img_cheryl.jpg -------------------------------------------------------------------------------- /field_128_cube.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epatel/SOIL/HEAD/field_128_cube.dds -------------------------------------------------------------------------------- /img_test_indexed.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epatel/SOIL/HEAD/img_test_indexed.tga -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Simple OpenGL Image Library 2 | 3 | Made some small changes to SOIL so it compiles for PalmPDK. 4 | 5 | See the two makefile 6 | 7 | * projects/makefile/makefile-pdk-host 8 | * projects/makefile/makefile-pdk-device 9 | 10 | Please note that it compiles for Pixi and that I'm using a Mac. 11 | 12 | Feel free to add/fix other platforms. 13 | -------------------------------------------------------------------------------- /projects/VC6/SOIL.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "SOIL"=".\SOIL.dsp" - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Global: 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<3> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | -------------------------------------------------------------------------------- /src/stbi_DDS_aug.h: -------------------------------------------------------------------------------- 1 | /* 2 | adding DDS loading support to stbi 3 | */ 4 | 5 | #ifndef HEADER_STB_IMAGE_DDS_AUGMENTATION 6 | #define HEADER_STB_IMAGE_DDS_AUGMENTATION 7 | 8 | // is it a DDS file? 9 | extern int stbi_dds_test_memory (stbi_uc const *buffer, int len); 10 | 11 | extern stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp); 12 | extern stbi_uc *stbi_dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 13 | #ifndef STBI_NO_STDIO 14 | extern int stbi_dds_test_file (FILE *f); 15 | extern stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); 16 | #endif 17 | 18 | // 19 | // 20 | //// end header file ///////////////////////////////////////////////////// 21 | #endif // HEADER_STB_IMAGE_DDS_AUGMENTATION 22 | -------------------------------------------------------------------------------- /projects/VC8/SOIL.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual Studio 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SOIL", "SOIL.vcproj", "{C32FB2B4-500C-43CD-A099-EECCE079D3F1}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|Win32.Build.0 = Debug|Win32 14 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|Win32.ActiveCfg = Release|Win32 15 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /projects/VC7.1/SOIL.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 8.00 2 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SOIL", "SOIL.vcproj", "{35D9B7E3-EE73-4C06-9B98-FCB7F7644C99}" 3 | ProjectSection(ProjectDependencies) = postProject 4 | EndProjectSection 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfiguration) = preSolution 8 | Debug = Debug 9 | Release = Release 10 | EndGlobalSection 11 | GlobalSection(ProjectConfiguration) = postSolution 12 | {35D9B7E3-EE73-4C06-9B98-FCB7F7644C99}.Debug.ActiveCfg = Debug|Win32 13 | {35D9B7E3-EE73-4C06-9B98-FCB7F7644C99}.Debug.Build.0 = Debug|Win32 14 | {35D9B7E3-EE73-4C06-9B98-FCB7F7644C99}.Release.ActiveCfg = Release|Win32 15 | {35D9B7E3-EE73-4C06-9B98-FCB7F7644C99}.Release.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(ExtensibilityGlobals) = postSolution 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityAddIns) = postSolution 20 | EndGlobalSection 21 | EndGlobal 22 | -------------------------------------------------------------------------------- /projects/VC9/SOIL.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SOIL", "SOIL.vcproj", "{C32FB2B4-500C-43CD-A099-EECCE079D3F1}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|Win32.Build.0 = Debug|Win32 16 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|x64.ActiveCfg = Debug|x64 17 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|x64.Build.0 = Debug|x64 18 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|Win32.ActiveCfg = Release|Win32 19 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|Win32.Build.0 = Release|Win32 20 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|x64.ActiveCfg = Release|x64 21 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /projects/VC14/SOIL.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SOIL", "SOIL.vcxproj", "{C32FB2B4-500C-43CD-A099-EECCE079D3F1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|x64.ActiveCfg = Debug|x64 17 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|x64.Build.0 = Debug|x64 18 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|x86.ActiveCfg = Debug|Win32 19 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|x86.Build.0 = Debug|Win32 20 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|x64.ActiveCfg = Release|x64 21 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|x64.Build.0 = Release|x64 22 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|x86.ActiveCfg = Release|Win32 23 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /projects/VC12/SOIL.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SOIL", "SOIL.vcxproj", "{C32FB2B4-500C-43CD-A099-EECCE079D3F1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|Win32.Build.0 = Debug|Win32 18 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|x64.ActiveCfg = Debug|x64 19 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Debug|x64.Build.0 = Debug|x64 20 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|Win32.ActiveCfg = Release|Win32 21 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|Win32.Build.0 = Release|Win32 22 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|x64.ActiveCfg = Release|x64 23 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /projects/makefile/alternate Makefile.txt: -------------------------------------------------------------------------------- 1 | MAKE = make 2 | CC = gcc 3 | INSTALL_FILE = install -p -o root -g root -m 644 4 | INSTALL_DIR = install -p -o root -g root -d 5 | LN = ln -s 6 | RM = rm -fv 7 | CFLAGS += -c -O2 -Wall 8 | LDFLAGS += 9 | 10 | CFILES = image_DXT.c image_helper.c SOIL.c stb_image_aug.c 11 | OFILES = $(CFILES:.c=.o) 12 | LIBNAME = libSOIL 13 | VERSION = 1.07-20071110 14 | MAJOR = 1 15 | 16 | HFILES = SOIL.h image_DXT.h image_helper.h \ 17 | stbi_DDS_aug.h stbi_DDS_aug_c.h stb_image_aug.h 18 | AFILE = libSOIL.a 19 | SOFILE = libSOIL.so.$(VERSION) 20 | INCLUDEDIR = /usr/include/SOIL 21 | LIBDIR = /usr/lib 22 | 23 | all: $(OFILES) lib 24 | 25 | %.o: %.c 26 | $(CC) $(CFLAGS) $< -o $@ 27 | 28 | lib: $(OFILES) 29 | # create static library 30 | ar -cvq $(LIBNAME).a $(OFILES) 31 | # create shared library 32 | gcc -shared -Wl,-soname,$(LIBNAME).so.$(MAJOR) -o $(LIBNAME).so.$(VERSION) $(OFILES) 33 | 34 | install: 35 | $(INSTALL_DIR) $(DESTDIR)/$(INCLUDEDIR) 36 | $(INSTALL_FILE) $(HFILES) $(DESTDIR)/$(INCLUDEDIR) 37 | $(INSTALL_DIR) $(DESTDIR)/$(LIBDIR) 38 | $(INSTALL_FILE) $(AFILE) $(DESTDIR)/$(LIBDIR) 39 | $(INSTALL_FILE) $(SOFILE) $(DESTDIR)/$(LIBDIR) 40 | ( cd $(DESTDIR)/$(LIBDIR) && $(LN) $(SOFILE) $(LIBNAME).so.$(MAJOR) \ 41 | && $(LN) $(SOFILE) $(LIBNAME).so ) 42 | 43 | clean: 44 | $(RM) *.o 45 | $(RM) *~ 46 | 47 | distclean: 48 | $(RM) $(AFILE) $(SOFILE) 49 | 50 | .PHONY: all lib clean distclean 51 | -------------------------------------------------------------------------------- /projects/makefile/makefile: -------------------------------------------------------------------------------- 1 | # SOIL makefile for linux (based on the AngelScript makefile) 2 | # Type 'make' then 'make install' to complete the installation of the library 3 | 4 | # For 'make install' to work, set LOCAL according to your system configuration 5 | LOCAL = /usr/local 6 | 7 | LIB = libSOIL.a 8 | INC = SOIL.h 9 | 10 | SRCDIR = ../../src 11 | LIBDIR = ../../lib 12 | INCDIR = ../../src 13 | OBJDIR = obj 14 | 15 | CXX = gcc 16 | CXXFLAGS = -O2 -s -Wall 17 | DELETER = rm -f 18 | COPIER = cp 19 | 20 | SRCNAMES = \ 21 | image_helper.c \ 22 | stb_image_aug.c \ 23 | image_DXT.c \ 24 | SOIL.c \ 25 | 26 | OBJ = $(addprefix $(OBJDIR)/, $(notdir $(SRCNAMES:.c=.o))) 27 | BIN = $(LIBDIR)/$(LIB) 28 | 29 | all: $(BIN) 30 | 31 | $(BIN): $(OBJ) 32 | ar r $(BIN) $(OBJ) 33 | ranlib $(BIN) 34 | @echo ------------------------------------------------------------------- 35 | @echo Done. As root, type 'make install' to install the library. 36 | 37 | $(OBJDIR)/%.o: $(SRCDIR)/%.c 38 | $(CXX) $(CXXFLAGS) -o $@ -c $< 39 | 40 | 41 | clean: 42 | $(DELETER) $(OBJ) $(BIN) 43 | 44 | install: $(BIN) 45 | @echo Installing to: $(LOCAL)/lib and $(LOCAL)/include... 46 | @echo ------------------------------------------------------------------- 47 | $(COPIER) $(BIN) $(LOCAL)/lib 48 | $(COPIER) $(INCDIR)/$(INC) $(LOCAL)/include 49 | @echo ------------------------------------------------------------------- 50 | @echo SOIL library installed. Enjoy! 51 | 52 | uninstall: 53 | $(DELETER) $(LOCAL)/include/$(INC) $(LOCAL)/lib/$(LIB) 54 | @echo ------------------------------------------------------------------- 55 | @echo SOIL library uninstalled. 56 | 57 | .PHONY: all clean install uninstall 58 | -------------------------------------------------------------------------------- /projects/makefile/makefile-pdk-host: -------------------------------------------------------------------------------- 1 | # SOIL makefile for Palm PDK (based on the Linux makefile) 2 | # Type 'make -f makefile-pdk-host' to build the SOIL lib 3 | # Type 'make -f makefile-pdk-host install' to install SOIL into PalmPDK 4 | 5 | PalmPDK = /opt/PalmPDK 6 | 7 | LOCAL_LIB = $(PalmPDK)/host 8 | LOCAL_INC = $(PalmPDK) 9 | 10 | LIB = libSOIL-host.a 11 | LIB_INSTALL = libSOIL.a 12 | INC = SOIL.h 13 | 14 | SRCDIR = ../../src 15 | INCDIR = ../../src 16 | 17 | CXX = g++ 18 | AR = ar 19 | RANLIB = ranlib 20 | CXXFLAGS = -arch i386 -I/opt/PalmPDK/include -I/opt/PalmPDK/include/SDL -D__PALMPDK__ 21 | DELETER = rm -f 22 | COPIER = cp 23 | 24 | SRCNAMES = \ 25 | image_helper.c \ 26 | stb_image_aug.c \ 27 | image_DXT.c \ 28 | SOIL.c 29 | 30 | OBJ = $(SRCNAMES:.c=-host.o) 31 | BIN = $(LIB) 32 | 33 | all: $(BIN) 34 | 35 | $(BIN): $(OBJ) 36 | $(AR) r $(BIN) $(OBJ) 37 | $(RANLIB) $(BIN) 38 | @echo ------------------------------------------------------------------------- 39 | @echo 'Done. Type "make -f makefile-pdk-host install" to install the library.' 40 | 41 | %-host.o: $(SRCDIR)/%.c 42 | $(CXX) $(CXXFLAGS) -o $@ -c $< 43 | 44 | clean: 45 | $(DELETER) $(OBJ) $(BIN) 46 | 47 | install: $(BIN) 48 | @echo Installing to: $(LOCAL_LIB)/lib and $(LOCAL_INC)/include... 49 | @echo ------------------------------------------------------------------- 50 | $(COPIER) $(BIN) $(LOCAL_LIB)/lib/$(LIB_INSTALL) 51 | $(COPIER) $(INCDIR)/$(INC) $(LOCAL_INC)/include 52 | @echo ------------------------------------------------------------------- 53 | @echo SOIL library installed. Enjoy! 54 | 55 | uninstall: 56 | $(DELETER) $(LOCAL_INC)/include/$(INC) $(LOCAL_LIB)/lib/$(LIB_INSTALL) 57 | @echo ------------------------------------------------------------------- 58 | @echo SOIL library uninstalled. 59 | 60 | .PHONY: all clean install uninstall 61 | -------------------------------------------------------------------------------- /projects/makefile/makefile-pdk-device: -------------------------------------------------------------------------------- 1 | # SOIL makefile for Palm PDK (based on the Linux makefile) 2 | # Type 'make -f makefile-pdk-device' to build the SOIL lib 3 | # Type 'make -f makefile-pdk-device install' to install SOIL into PalmPDK 4 | 5 | PalmPDK = /opt/PalmPDK 6 | 7 | LOCAL_LIB = $(PalmPDK)/device 8 | LOCAL_INC = $(PalmPDK) 9 | 10 | LIB = libSOIL-device.a 11 | LIB_INSTALL = libSOIL.a 12 | INC = SOIL.h 13 | 14 | SRCDIR = ../../src 15 | INCDIR = ../../src 16 | 17 | CXX = $(PalmPDK)/arm-gcc/bin/arm-none-linux-gnueabi-gcc 18 | AR = $(PalmPDK)/arm-gcc/bin/arm-none-linux-gnueabi-ar 19 | RANLIB = $(PalmPDK)/arm-gcc/bin/arm-none-linux-gnueabi-ranlib 20 | CXXFLAGS = -mcpu=arm1136jf-s -mfpu=vfp -mfloat-abi=softfp --sysroot=/opt/PalmPDK/arm-gcc/sysroot -I/opt/PalmPDK/include -I/opt/PalmPDK/include/SDL -D__PALMPDK__ 21 | DELETER = rm -f 22 | COPIER = cp 23 | 24 | SRCNAMES = \ 25 | image_helper.c \ 26 | stb_image_aug.c \ 27 | image_DXT.c \ 28 | SOIL.c 29 | 30 | OBJ = $(SRCNAMES:.c=-device.o) 31 | BIN = $(LIB) 32 | 33 | all: $(BIN) 34 | 35 | $(BIN): $(OBJ) 36 | $(AR) r $(BIN) $(OBJ) 37 | $(RANLIB) $(BIN) 38 | @echo ------------------------------------------------------------------------- 39 | @echo 'Done. Type "make -f makefile-pdk-device install" to install the library.' 40 | 41 | %-device.o: $(SRCDIR)/%.c 42 | $(CXX) $(CXXFLAGS) -o $@ -c $< 43 | 44 | clean: 45 | $(DELETER) $(OBJ) $(BIN) 46 | 47 | install: $(BIN) 48 | @echo Installing to: $(LOCAL_LIB)/lib and $(LOCAL_INC)/include... 49 | @echo ------------------------------------------------------------------- 50 | $(COPIER) $(BIN) $(LOCAL_LIB)/lib/$(LIB_INSTALL) 51 | $(COPIER) $(INCDIR)/$(INC) $(LOCAL_INC)/include 52 | @echo ------------------------------------------------------------------- 53 | @echo SOIL library installed. Enjoy! 54 | 55 | uninstall: 56 | $(DELETER) $(LOCAL_INC)/include/$(INC) $(LOCAL_LIB)/lib/$(LIB_INSTALL) 57 | @echo ------------------------------------------------------------------- 58 | @echo SOIL library uninstalled. 59 | 60 | .PHONY: all clean install uninstall 61 | -------------------------------------------------------------------------------- /projects/codeblocks/SOIL.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 89 | 90 | -------------------------------------------------------------------------------- /src/image_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | Jonathan Dummer 3 | 4 | Image helper functions 5 | 6 | MIT license 7 | */ 8 | 9 | #ifndef HEADER_IMAGE_HELPER 10 | #define HEADER_IMAGE_HELPER 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | /** 17 | This function upscales an image. 18 | Not to be used to create MIPmaps, 19 | but to make it square, 20 | or to make it a power-of-two sized. 21 | **/ 22 | int 23 | up_scale_image 24 | ( 25 | const unsigned char* const orig, 26 | int width, int height, int channels, 27 | unsigned char* resampled, 28 | int resampled_width, int resampled_height 29 | ); 30 | 31 | /** 32 | This function downscales an image. 33 | Used for creating MIPmaps, 34 | the incoming image should be a 35 | power-of-two sized. 36 | **/ 37 | int 38 | mipmap_image 39 | ( 40 | const unsigned char* const orig, 41 | int width, int height, int channels, 42 | unsigned char* resampled, 43 | int block_size_x, int block_size_y 44 | ); 45 | 46 | /** 47 | This function takes the RGB components of the image 48 | and scales each channel from [0,255] to [16,235]. 49 | This makes the colors "Safe" for display on NTSC 50 | displays. Note that this is _NOT_ a good idea for 51 | loading images like normal- or height-maps! 52 | **/ 53 | int 54 | scale_image_RGB_to_NTSC_safe 55 | ( 56 | unsigned char* orig, 57 | int width, int height, int channels 58 | ); 59 | 60 | /** 61 | This function takes the RGB components of the image 62 | and converts them into YCoCg. 3 components will be 63 | re-ordered to CoYCg (for optimum DXT1 compression), 64 | while 4 components will be ordered CoCgAY (for DXT5 65 | compression). 66 | **/ 67 | int 68 | convert_RGB_to_YCoCg 69 | ( 70 | unsigned char* orig, 71 | int width, int height, int channels 72 | ); 73 | 74 | /** 75 | This function takes the YCoCg components of the image 76 | and converts them into RGB. See above. 77 | **/ 78 | int 79 | convert_YCoCg_to_RGB 80 | ( 81 | unsigned char* orig, 82 | int width, int height, int channels 83 | ); 84 | 85 | /** 86 | Converts an HDR image from an array 87 | of unsigned chars (RGBE) to RGBdivA 88 | \return 0 if failed, otherwise returns 1 89 | **/ 90 | int 91 | RGBE_to_RGBdivA 92 | ( 93 | unsigned char *image, 94 | int width, int height, 95 | int rescale_to_max 96 | ); 97 | 98 | /** 99 | Converts an HDR image from an array 100 | of unsigned chars (RGBE) to RGBdivA2 101 | \return 0 if failed, otherwise returns 1 102 | **/ 103 | int 104 | RGBE_to_RGBdivA2 105 | ( 106 | unsigned char *image, 107 | int width, int height, 108 | int rescale_to_max 109 | ); 110 | 111 | #ifdef __cplusplus 112 | } 113 | #endif 114 | 115 | #endif /* HEADER_IMAGE_HELPER */ 116 | -------------------------------------------------------------------------------- /src/image_DXT.h: -------------------------------------------------------------------------------- 1 | /* 2 | Jonathan Dummer 3 | 2007-07-31-10.32 4 | 5 | simple DXT compression / decompression code 6 | 7 | public domain 8 | */ 9 | 10 | #ifndef HEADER_IMAGE_DXT 11 | #define HEADER_IMAGE_DXT 12 | 13 | /** 14 | Converts an image from an array of unsigned chars (RGB or RGBA) to 15 | DXT1 or DXT5, then saves the converted image to disk. 16 | \return 0 if failed, otherwise returns 1 17 | **/ 18 | int 19 | save_image_as_DDS 20 | ( 21 | const char *filename, 22 | int width, int height, int channels, 23 | const unsigned char *const data 24 | ); 25 | 26 | /** 27 | take an image and convert it to DXT1 (no alpha) 28 | **/ 29 | unsigned char* 30 | convert_image_to_DXT1 31 | ( 32 | const unsigned char *const uncompressed, 33 | int width, int height, int channels, 34 | int *out_size 35 | ); 36 | 37 | /** 38 | take an image and convert it to DXT5 (with alpha) 39 | **/ 40 | unsigned char* 41 | convert_image_to_DXT5 42 | ( 43 | const unsigned char *const uncompressed, 44 | int width, int height, int channels, 45 | int *out_size 46 | ); 47 | 48 | /** A bunch of DirectDraw Surface structures and flags **/ 49 | typedef struct 50 | { 51 | unsigned int dwMagic; 52 | unsigned int dwSize; 53 | unsigned int dwFlags; 54 | unsigned int dwHeight; 55 | unsigned int dwWidth; 56 | unsigned int dwPitchOrLinearSize; 57 | unsigned int dwDepth; 58 | unsigned int dwMipMapCount; 59 | unsigned int dwReserved1[ 11 ]; 60 | 61 | /* DDPIXELFORMAT */ 62 | struct 63 | { 64 | unsigned int dwSize; 65 | unsigned int dwFlags; 66 | unsigned int dwFourCC; 67 | unsigned int dwRGBBitCount; 68 | unsigned int dwRBitMask; 69 | unsigned int dwGBitMask; 70 | unsigned int dwBBitMask; 71 | unsigned int dwAlphaBitMask; 72 | } 73 | sPixelFormat; 74 | 75 | /* DDCAPS2 */ 76 | struct 77 | { 78 | unsigned int dwCaps1; 79 | unsigned int dwCaps2; 80 | unsigned int dwDDSX; 81 | unsigned int dwReserved; 82 | } 83 | sCaps; 84 | unsigned int dwReserved2; 85 | } 86 | DDS_header ; 87 | 88 | /* the following constants were copied directly off the MSDN website */ 89 | 90 | /* The dwFlags member of the original DDSURFACEDESC2 structure 91 | can be set to one or more of the following values. */ 92 | #define DDSD_CAPS 0x00000001 93 | #define DDSD_HEIGHT 0x00000002 94 | #define DDSD_WIDTH 0x00000004 95 | #define DDSD_PITCH 0x00000008 96 | #define DDSD_PIXELFORMAT 0x00001000 97 | #define DDSD_MIPMAPCOUNT 0x00020000 98 | #define DDSD_LINEARSIZE 0x00080000 99 | #define DDSD_DEPTH 0x00800000 100 | 101 | /* DirectDraw Pixel Format */ 102 | #define DDPF_ALPHAPIXELS 0x00000001 103 | #define DDPF_FOURCC 0x00000004 104 | #define DDPF_RGB 0x00000040 105 | 106 | /* The dwCaps1 member of the DDSCAPS2 structure can be 107 | set to one or more of the following values. */ 108 | #define DDSCAPS_COMPLEX 0x00000008 109 | #define DDSCAPS_TEXTURE 0x00001000 110 | #define DDSCAPS_MIPMAP 0x00400000 111 | 112 | /* The dwCaps2 member of the DDSCAPS2 structure can be 113 | set to one or more of the following values. */ 114 | #define DDSCAPS2_CUBEMAP 0x00000200 115 | #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 116 | #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 117 | #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 118 | #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 119 | #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 120 | #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 121 | #define DDSCAPS2_VOLUME 0x00200000 122 | 123 | #endif /* HEADER_IMAGE_DXT */ 124 | -------------------------------------------------------------------------------- /projects/VC6/SOIL.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="SOIL" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Static Library" 0x0104 6 | 7 | CFG=SOIL - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "SOIL.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "SOIL.mak" CFG="SOIL - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "SOIL - Win32 Release" (based on "Win32 (x86) Static Library") 21 | !MESSAGE "SOIL - Win32 Debug" (based on "Win32 (x86) Static Library") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "SOIL - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Target_Dir "" 43 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c 44 | # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c 45 | # ADD BASE RSC /l 0x409 /d "NDEBUG" 46 | # ADD RSC /l 0x409 /d "NDEBUG" 47 | BSC32=bscmake.exe 48 | # ADD BASE BSC32 /nologo 49 | # ADD BSC32 /nologo 50 | LIB32=link.exe -lib 51 | # ADD BASE LIB32 /nologo 52 | # ADD LIB32 /nologo 53 | 54 | !ELSEIF "$(CFG)" == "SOIL - Win32 Debug" 55 | 56 | # PROP BASE Use_MFC 0 57 | # PROP BASE Use_Debug_Libraries 1 58 | # PROP BASE Output_Dir "Debug" 59 | # PROP BASE Intermediate_Dir "Debug" 60 | # PROP BASE Target_Dir "" 61 | # PROP Use_MFC 0 62 | # PROP Use_Debug_Libraries 1 63 | # PROP Output_Dir "Debug" 64 | # PROP Intermediate_Dir "Debug" 65 | # PROP Target_Dir "" 66 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 67 | # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c 68 | # ADD BASE RSC /l 0x409 /d "_DEBUG" 69 | # ADD RSC /l 0x409 /d "_DEBUG" 70 | BSC32=bscmake.exe 71 | # ADD BASE BSC32 /nologo 72 | # ADD BSC32 /nologo 73 | LIB32=link.exe -lib 74 | # ADD BASE LIB32 /nologo 75 | # ADD LIB32 /nologo 76 | 77 | !ENDIF 78 | 79 | # Begin Target 80 | 81 | # Name "SOIL - Win32 Release" 82 | # Name "SOIL - Win32 Debug" 83 | # Begin Group "Source Files" 84 | 85 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 86 | # Begin Source File 87 | 88 | SOURCE=..\..\src\image_DXT.c 89 | # End Source File 90 | # Begin Source File 91 | 92 | SOURCE=..\..\src\image_helper.c 93 | # End Source File 94 | # Begin Source File 95 | 96 | SOURCE=..\..\src\SOIL.c 97 | # End Source File 98 | # Begin Source File 99 | 100 | SOURCE=..\..\src\stb_image_aug.c 101 | # End Source File 102 | # End Group 103 | # Begin Group "Header Files" 104 | 105 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 106 | # Begin Source File 107 | 108 | SOURCE=..\..\src\image_DXT.h 109 | # End Source File 110 | # Begin Source File 111 | 112 | SOURCE=..\..\src\image_helper.h 113 | # End Source File 114 | # Begin Source File 115 | 116 | SOURCE=..\..\src\SOIL.h 117 | # End Source File 118 | # Begin Source File 119 | 120 | SOURCE=..\..\src\stb_image_aug.h 121 | # End Source File 122 | # Begin Source File 123 | 124 | SOURCE=..\..\src\stbi_DDS_aug.h 125 | # End Source File 126 | # Begin Source File 127 | 128 | SOURCE=..\..\src\stbi_DDS_aug_c.h 129 | # End Source File 130 | # End Group 131 | # End Target 132 | # End Project 133 | -------------------------------------------------------------------------------- /projects/VC7.1/SOIL.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 11 | 12 | 13 | 19 | 30 | 32 | 35 | 37 | 39 | 41 | 43 | 45 | 47 | 49 | 51 | 53 | 54 | 60 | 68 | 70 | 73 | 75 | 77 | 79 | 81 | 83 | 85 | 87 | 89 | 91 | 92 | 93 | 94 | 95 | 96 | 100 | 102 | 103 | 105 | 106 | 108 | 109 | 111 | 112 | 113 | 117 | 119 | 120 | 122 | 123 | 125 | 126 | 128 | 129 | 131 | 132 | 134 | 135 | 136 | 140 | 141 | 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /support/FreeBasic/SOIL.bi: -------------------------------------------------------------------------------- 1 | '' 2 | '' 3 | '' Jonathan Dummer 4 | '' Simple OpenGL Image Library 5 | '' MIT License 6 | '' 7 | '' I'm using Sean's Tool Box image loader as a base: 8 | '' http://www.nothings.org/ 9 | '' 10 | '' Note: header translated with help of SWIG FB wrapper 11 | '' Check the SOIL.h file for more information 12 | '' 13 | #ifndef __SOIL_bi__ 14 | #define __SOIL_bi__ 15 | 16 | #inclib "SOIL" 17 | 18 | enum 19 | SOIL_LOAD_AUTO = 0 20 | SOIL_LOAD_L = 1 21 | SOIL_LOAD_LA = 2 22 | SOIL_LOAD_RGB = 3 23 | SOIL_LOAD_RGBA = 4 24 | end enum 25 | 26 | enum 27 | SOIL_CREATE_NEW_ID = 0 28 | end enum 29 | 30 | enum 31 | SOIL_FLAG_POWER_OF_TWO = 1 32 | SOIL_FLAG_MIPMAPS = 2 33 | SOIL_FLAG_TEXTURE_REPEATS = 4 34 | SOIL_FLAG_MULTIPLY_ALPHA = 8 35 | SOIL_FLAG_INVERT_Y = 16 36 | SOIL_FLAG_COMPRESS_TO_DXT = 32 37 | SOIL_FLAG_DDS_LOAD_DIRECT = 64 38 | SOIL_FLAG_NTSC_SAFE_RGB = 128 39 | SOIL_FLAG_CoCg_Y = 256 40 | SOIL_FLAG_TEXTURE_RECTANGLE = 512 41 | end enum 42 | 43 | enum 44 | SOIL_SAVE_TYPE_TGA = 0 45 | SOIL_SAVE_TYPE_BMP = 1 46 | SOIL_SAVE_TYPE_DDS = 2 47 | end enum 48 | 49 | const SOIL_DDS_CUBEMAP_FACE_ORDER = "EWUDNS" 50 | 51 | declare function SOIL_load_OGL_texture cdecl alias "SOIL_load_OGL_texture" (byval filename as zstring ptr, byval force_channels as integer, byval reuse_texture_ID as uinteger, byval flags as uinteger) as uinteger 52 | declare function SOIL_load_OGL_cubemap cdecl alias "SOIL_load_OGL_cubemap" (byval x_pos_file as zstring ptr, byval x_neg_file as zstring ptr, byval y_pos_file as zstring ptr, byval y_neg_file as zstring ptr, byval z_pos_file as zstring ptr, byval z_neg_file as zstring ptr, byval force_channels as integer, byval reuse_texture_ID as uinteger, byval flags as uinteger) as uinteger 53 | declare function SOIL_load_OGL_single_cubemap cdecl alias "SOIL_load_OGL_single_cubemap" (byval filename as zstring ptr, byval face_order as zstring ptr, byval force_channels as integer, byval reuse_texture_ID as uinteger, byval flags as uinteger) as uinteger 54 | declare function SOIL_load_OGL_texture_from_memory cdecl alias "SOIL_load_OGL_texture_from_memory" (byval buffer as ubyte ptr, byval buffer_length as integer, byval force_channels as integer, byval reuse_texture_ID as uinteger, byval flags as uinteger) as uinteger 55 | declare function SOIL_load_OGL_cubemap_from_memory cdecl alias "SOIL_load_OGL_cubemap_from_memory" (byval x_pos_buffer as ubyte ptr, byval x_pos_buffer_length as integer, byval x_neg_buffer as ubyte ptr, byval x_neg_buffer_length as integer, byval y_pos_buffer as ubyte ptr, byval y_pos_buffer_length as integer, byval y_neg_buffer as ubyte ptr, byval y_neg_buffer_length as integer, byval z_pos_buffer as ubyte ptr, byval z_pos_buffer_length as integer, byval z_neg_buffer as ubyte ptr, byval z_neg_buffer_length as integer, byval force_channels as integer, byval reuse_texture_ID as uinteger, byval flags as uinteger) as uinteger 56 | declare function SOIL_load_OGL_single_cubemap_from_memory cdecl alias "SOIL_load_OGL_single_cubemap_from_memory" (byval buffer as ubyte ptr, byval buffer_length as integer, byval face_order as zstring ptr, byval force_channels as integer, byval reuse_texture_ID as uinteger, byval flags as uinteger) as uinteger 57 | declare function SOIL_create_OGL_texture cdecl alias "SOIL_create_OGL_texture" (byval data as ubyte ptr, byval width as integer, byval height as integer, byval channels as integer, byval reuse_texture_ID as uinteger, byval flags as uinteger) as uinteger 58 | declare function SOIL_create_OGL_single_cubemap cdecl alias "SOIL_create_OGL_single_cubemap" (byval data as ubyte ptr, byval width as integer, byval height as integer, byval channels as integer, byval face_order as zstring ptr, byval reuse_texture_ID as uinteger, byval flags as uinteger) as uinteger 59 | declare function SOIL_save_screenshot cdecl alias "SOIL_save_screenshot" (byval filename as zstring ptr, byval image_type as integer, byval x as integer, byval y as integer, byval width as integer, byval height as integer) as integer 60 | declare function SOIL_load_image cdecl alias "SOIL_load_image" (byval filename as zstring ptr, byval width as integer ptr, byval height as integer ptr, byval channels as integer ptr, byval force_channels as integer) as ubyte ptr 61 | declare function SOIL_load_image_from_memory cdecl alias "SOIL_load_image_from_memory" (byval buffer as ubyte ptr, byval buffer_length as integer, byval width as integer ptr, byval height as integer ptr, byval channels as integer ptr, byval force_channels as integer) as ubyte ptr 62 | declare function SOIL_save_image cdecl alias "SOIL_save_image" (byval filename as zstring ptr, byval image_type as integer, byval width as integer, byval height as integer, byval channels as integer, byval data as ubyte ptr) as integer 63 | declare sub SOIL_free_image_data cdecl alias "SOIL_free_image_data" (byval img_data as ubyte ptr) 64 | declare function SOIL_last_result cdecl alias "SOIL_last_result" () as zstring ptr 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /projects/VC8/SOIL.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 25 | 28 | 31 | 34 | 37 | 40 | 52 | 55 | 58 | 61 | 64 | 67 | 70 | 73 | 76 | 79 | 80 | 88 | 91 | 94 | 97 | 100 | 103 | 112 | 115 | 118 | 121 | 124 | 127 | 130 | 133 | 136 | 139 | 140 | 141 | 142 | 143 | 144 | 149 | 152 | 153 | 156 | 157 | 160 | 161 | 164 | 165 | 166 | 171 | 174 | 175 | 178 | 179 | 182 | 183 | 186 | 187 | 190 | 191 | 194 | 195 | 196 | 201 | 202 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /projects/VC12/SOIL.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1} 23 | SOIL 24 | Win32Proj 25 | 26 | 27 | 28 | StaticLibrary 29 | v120 30 | Unicode 31 | true 32 | 33 | 34 | StaticLibrary 35 | v120 36 | Unicode 37 | 38 | 39 | StaticLibrary 40 | v120 41 | Unicode 42 | true 43 | 44 | 45 | StaticLibrary 46 | v120 47 | Unicode 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | <_ProjectFileVersion>12.0.30501.0 67 | 68 | 69 | $(SolutionDir)$(Configuration)\ 70 | $(Configuration)\ 71 | 72 | 73 | $(SolutionDir)$(Configuration)\ 74 | $(Configuration)\ 75 | 76 | 77 | $(SolutionDir)$(Platform)\$(Configuration)\ 78 | $(Platform)\$(Configuration)\ 79 | 80 | 81 | $(SolutionDir)$(Platform)\$(Configuration)\ 82 | $(Platform)\$(Configuration)\ 83 | 84 | 85 | 86 | Disabled 87 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 88 | true 89 | EnableFastChecks 90 | MultiThreadedDebugDLL 91 | 92 | Level3 93 | EditAndContinue 94 | 95 | 96 | 97 | 98 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 99 | MultiThreadedDLL 100 | 101 | Level3 102 | ProgramDatabase 103 | 104 | 105 | 106 | 107 | X64 108 | 109 | 110 | Disabled 111 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 112 | true 113 | EnableFastChecks 114 | MultiThreadedDebugDLL 115 | 116 | Level3 117 | ProgramDatabase 118 | 119 | 120 | 121 | 122 | X64 123 | 124 | 125 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 126 | MultiThreadedDLL 127 | 128 | Level3 129 | ProgramDatabase 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /projects/VC14/SOIL.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {C32FB2B4-500C-43CD-A099-EECCE079D3F1} 23 | SOIL 24 | Win32Proj 25 | 26 | 27 | 28 | StaticLibrary 29 | v140 30 | Unicode 31 | true 32 | 33 | 34 | StaticLibrary 35 | v140 36 | Unicode 37 | 38 | 39 | StaticLibrary 40 | v140 41 | Unicode 42 | true 43 | 44 | 45 | StaticLibrary 46 | v140 47 | Unicode 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | <_ProjectFileVersion>14.0.25123.0 67 | 68 | 69 | $(SolutionDir)$(Configuration)\ 70 | $(Configuration)\ 71 | 72 | 73 | $(SolutionDir)$(Configuration)\ 74 | $(Configuration)\ 75 | 76 | 77 | $(SolutionDir)$(Platform)\$(Configuration)\ 78 | $(Platform)\$(Configuration)\ 79 | 80 | 81 | $(SolutionDir)$(Platform)\$(Configuration)\ 82 | $(Platform)\$(Configuration)\ 83 | 84 | 85 | 86 | Disabled 87 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 88 | true 89 | EnableFastChecks 90 | MultiThreadedDebugDLL 91 | 92 | Level3 93 | EditAndContinue 94 | 95 | 96 | 97 | 98 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 99 | MultiThreadedDLL 100 | 101 | Level3 102 | ProgramDatabase 103 | 104 | 105 | 106 | 107 | X64 108 | 109 | 110 | Disabled 111 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 112 | true 113 | EnableFastChecks 114 | MultiThreadedDebugDLL 115 | 116 | Level3 117 | ProgramDatabase 118 | 119 | 120 | 121 | 122 | X64 123 | 124 | 125 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 126 | MultiThreadedDLL 127 | 128 | Level3 129 | ProgramDatabase 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /projects/VC9/SOIL.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 56 | 59 | 62 | 65 | 68 | 71 | 74 | 77 | 80 | 83 | 84 | 92 | 95 | 98 | 101 | 104 | 107 | 116 | 119 | 122 | 125 | 128 | 131 | 134 | 137 | 140 | 143 | 144 | 151 | 154 | 157 | 160 | 163 | 167 | 179 | 182 | 185 | 188 | 191 | 194 | 197 | 200 | 203 | 206 | 207 | 215 | 218 | 221 | 224 | 227 | 231 | 240 | 243 | 246 | 249 | 252 | 255 | 258 | 261 | 264 | 267 | 268 | 269 | 270 | 271 | 272 | 277 | 280 | 281 | 284 | 285 | 288 | 289 | 292 | 293 | 294 | 299 | 302 | 303 | 306 | 307 | 310 | 311 | 314 | 315 | 318 | 319 | 322 | 323 | 324 | 329 | 330 | 333 | 334 | 335 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /src/image_helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | Jonathan Dummer 3 | 4 | image helper functions 5 | 6 | MIT license 7 | */ 8 | 9 | #include "image_helper.h" 10 | #include 11 | #include 12 | 13 | /* Upscaling the image uses simple bilinear interpolation */ 14 | int 15 | up_scale_image 16 | ( 17 | const unsigned char* const orig, 18 | int width, int height, int channels, 19 | unsigned char* resampled, 20 | int resampled_width, int resampled_height 21 | ) 22 | { 23 | float dx, dy; 24 | int x, y, c; 25 | 26 | /* error(s) check */ 27 | if ( (width < 1) || (height < 1) || 28 | (resampled_width < 2) || (resampled_height < 2) || 29 | (channels < 1) || 30 | (NULL == orig) || (NULL == resampled) ) 31 | { 32 | /* signify badness */ 33 | return 0; 34 | } 35 | /* 36 | for each given pixel in the new map, find the exact location 37 | from the original map which would contribute to this guy 38 | */ 39 | dx = (width - 1.0f) / (resampled_width - 1.0f); 40 | dy = (height - 1.0f) / (resampled_height - 1.0f); 41 | for ( y = 0; y < resampled_height; ++y ) 42 | { 43 | /* find the base y index and fractional offset from that */ 44 | float sampley = y * dy; 45 | int inty = (int)sampley; 46 | /* if( inty < 0 ) { inty = 0; } else */ 47 | if( inty > height - 2 ) { inty = height - 2; } 48 | sampley -= inty; 49 | for ( x = 0; x < resampled_width; ++x ) 50 | { 51 | float samplex = x * dx; 52 | int intx = (int)samplex; 53 | int base_index; 54 | /* find the base x index and fractional offset from that */ 55 | /* if( intx < 0 ) { intx = 0; } else */ 56 | if( intx > width - 2 ) { intx = width - 2; } 57 | samplex -= intx; 58 | /* base index into the original image */ 59 | base_index = (inty * width + intx) * channels; 60 | for ( c = 0; c < channels; ++c ) 61 | { 62 | /* do the sampling */ 63 | float value = 0.5f; 64 | value += orig[base_index] 65 | *(1.0f-samplex)*(1.0f-sampley); 66 | value += orig[base_index+channels] 67 | *(samplex)*(1.0f-sampley); 68 | value += orig[base_index+width*channels] 69 | *(1.0f-samplex)*(sampley); 70 | value += orig[base_index+width*channels+channels] 71 | *(samplex)*(sampley); 72 | /* move to the next channel */ 73 | ++base_index; 74 | /* save the new value */ 75 | resampled[y*resampled_width*channels+x*channels+c] = 76 | (unsigned char)(value); 77 | } 78 | } 79 | } 80 | /* done */ 81 | return 1; 82 | } 83 | 84 | int 85 | mipmap_image 86 | ( 87 | const unsigned char* const orig, 88 | int width, int height, int channels, 89 | unsigned char* resampled, 90 | int block_size_x, int block_size_y 91 | ) 92 | { 93 | int mip_width, mip_height; 94 | int i, j, c; 95 | 96 | /* error check */ 97 | if( (width < 1) || (height < 1) || 98 | (channels < 1) || (orig == NULL) || 99 | (resampled == NULL) || 100 | (block_size_x < 1) || (block_size_y < 1) ) 101 | { 102 | /* nothing to do */ 103 | return 0; 104 | } 105 | mip_width = width / block_size_x; 106 | mip_height = height / block_size_y; 107 | if( mip_width < 1 ) 108 | { 109 | mip_width = 1; 110 | } 111 | if( mip_height < 1 ) 112 | { 113 | mip_height = 1; 114 | } 115 | for( j = 0; j < mip_height; ++j ) 116 | { 117 | for( i = 0; i < mip_width; ++i ) 118 | { 119 | for( c = 0; c < channels; ++c ) 120 | { 121 | const int index = (j*block_size_y)*width*channels + (i*block_size_x)*channels + c; 122 | int sum_value; 123 | int u,v; 124 | int u_block = block_size_x; 125 | int v_block = block_size_y; 126 | int block_area; 127 | /* do a bit of checking so we don't over-run the boundaries 128 | (necessary for non-square textures!) */ 129 | if( block_size_x * (i+1) > width ) 130 | { 131 | u_block = width - i*block_size_y; 132 | } 133 | if( block_size_y * (j+1) > height ) 134 | { 135 | v_block = height - j*block_size_y; 136 | } 137 | block_area = u_block*v_block; 138 | /* for this pixel, see what the average 139 | of all the values in the block are. 140 | note: start the sum at the rounding value, not at 0 */ 141 | sum_value = block_area >> 1; 142 | for( v = 0; v < v_block; ++v ) 143 | for( u = 0; u < u_block; ++u ) 144 | { 145 | sum_value += orig[index + v*width*channels + u*channels]; 146 | } 147 | resampled[j*mip_width*channels + i*channels + c] = sum_value / block_area; 148 | } 149 | } 150 | } 151 | return 1; 152 | } 153 | 154 | int 155 | scale_image_RGB_to_NTSC_safe 156 | ( 157 | unsigned char* orig, 158 | int width, int height, int channels 159 | ) 160 | { 161 | const float scale_lo = 16.0f - 0.499f; 162 | const float scale_hi = 235.0f + 0.499f; 163 | int i, j; 164 | int nc = channels; 165 | unsigned char scale_LUT[256]; 166 | /* error check */ 167 | if( (width < 1) || (height < 1) || 168 | (channels < 1) || (orig == NULL) ) 169 | { 170 | /* nothing to do */ 171 | return 0; 172 | } 173 | /* set up the scaling Look Up Table */ 174 | for( i = 0; i < 256; ++i ) 175 | { 176 | scale_LUT[i] = (unsigned char)((scale_hi - scale_lo) * i / 255.0f + scale_lo); 177 | } 178 | /* for channels = 2 or 4, ignore the alpha component */ 179 | nc -= 1 - (channels & 1); 180 | /* OK, go through the image and scale any non-alpha components */ 181 | for( i = 0; i < width*height*channels; i += channels ) 182 | { 183 | for( j = 0; j < nc; ++j ) 184 | { 185 | orig[i+j] = scale_LUT[orig[i+j]]; 186 | } 187 | } 188 | return 1; 189 | } 190 | 191 | unsigned char clamp_byte( int x ) { return ( (x) < 0 ? (0) : ( (x) > 255 ? 255 : (x) ) ); } 192 | 193 | /* 194 | This function takes the RGB components of the image 195 | and converts them into YCoCg. 3 components will be 196 | re-ordered to CoYCg (for optimum DXT1 compression), 197 | while 4 components will be ordered CoCgAY (for DXT5 198 | compression). 199 | */ 200 | int 201 | convert_RGB_to_YCoCg 202 | ( 203 | unsigned char* orig, 204 | int width, int height, int channels 205 | ) 206 | { 207 | int i; 208 | /* error check */ 209 | if( (width < 1) || (height < 1) || 210 | (channels < 3) || (channels > 4) || 211 | (orig == NULL) ) 212 | { 213 | /* nothing to do */ 214 | return -1; 215 | } 216 | /* do the conversion */ 217 | if( channels == 3 ) 218 | { 219 | for( i = 0; i < width*height*3; i += 3 ) 220 | { 221 | int r = orig[i+0]; 222 | int g = (orig[i+1] + 1) >> 1; 223 | int b = orig[i+2]; 224 | int tmp = (2 + r + b) >> 2; 225 | /* Co */ 226 | orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) ); 227 | /* Y */ 228 | orig[i+1] = clamp_byte( g + tmp ); 229 | /* Cg */ 230 | orig[i+2] = clamp_byte( 128 + g - tmp ); 231 | } 232 | } else 233 | { 234 | for( i = 0; i < width*height*4; i += 4 ) 235 | { 236 | int r = orig[i+0]; 237 | int g = (orig[i+1] + 1) >> 1; 238 | int b = orig[i+2]; 239 | unsigned char a = orig[i+3]; 240 | int tmp = (2 + r + b) >> 2; 241 | /* Co */ 242 | orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) ); 243 | /* Cg */ 244 | orig[i+1] = clamp_byte( 128 + g - tmp ); 245 | /* Alpha */ 246 | orig[i+2] = a; 247 | /* Y */ 248 | orig[i+3] = clamp_byte( g + tmp ); 249 | } 250 | } 251 | /* done */ 252 | return 0; 253 | } 254 | 255 | /* 256 | This function takes the YCoCg components of the image 257 | and converts them into RGB. See above. 258 | */ 259 | int 260 | convert_YCoCg_to_RGB 261 | ( 262 | unsigned char* orig, 263 | int width, int height, int channels 264 | ) 265 | { 266 | int i; 267 | /* error check */ 268 | if( (width < 1) || (height < 1) || 269 | (channels < 3) || (channels > 4) || 270 | (orig == NULL) ) 271 | { 272 | /* nothing to do */ 273 | return -1; 274 | } 275 | /* do the conversion */ 276 | if( channels == 3 ) 277 | { 278 | for( i = 0; i < width*height*3; i += 3 ) 279 | { 280 | int co = orig[i+0] - 128; 281 | int y = orig[i+1]; 282 | int cg = orig[i+2] - 128; 283 | /* R */ 284 | orig[i+0] = clamp_byte( y + co - cg ); 285 | /* G */ 286 | orig[i+1] = clamp_byte( y + cg ); 287 | /* B */ 288 | orig[i+2] = clamp_byte( y - co - cg ); 289 | } 290 | } else 291 | { 292 | for( i = 0; i < width*height*4; i += 4 ) 293 | { 294 | int co = orig[i+0] - 128; 295 | int cg = orig[i+1] - 128; 296 | unsigned char a = orig[i+2]; 297 | int y = orig[i+3]; 298 | /* R */ 299 | orig[i+0] = clamp_byte( y + co - cg ); 300 | /* G */ 301 | orig[i+1] = clamp_byte( y + cg ); 302 | /* B */ 303 | orig[i+2] = clamp_byte( y - co - cg ); 304 | /* A */ 305 | orig[i+3] = a; 306 | } 307 | } 308 | /* done */ 309 | return 0; 310 | } 311 | 312 | float 313 | find_max_RGBE 314 | ( 315 | unsigned char *image, 316 | int width, int height 317 | ) 318 | { 319 | float max_val = 0.0f; 320 | unsigned char *img = image; 321 | int i, j; 322 | for( i = width * height; i > 0; --i ) 323 | { 324 | /* float scale = powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ 325 | float scale = ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); 326 | for( j = 0; j < 3; ++j ) 327 | { 328 | if( img[j] * scale > max_val ) 329 | { 330 | max_val = img[j] * scale; 331 | } 332 | } 333 | /* next pixel */ 334 | img += 4; 335 | } 336 | return max_val; 337 | } 338 | 339 | int 340 | RGBE_to_RGBdivA 341 | ( 342 | unsigned char *image, 343 | int width, int height, 344 | int rescale_to_max 345 | ) 346 | { 347 | /* local variables */ 348 | int i, iv; 349 | unsigned char *img = image; 350 | float scale = 1.0f; 351 | /* error check */ 352 | if( (!image) || (width < 1) || (height < 1) ) 353 | { 354 | return 0; 355 | } 356 | /* convert (note: no negative numbers, but 0.0 is possible) */ 357 | if( rescale_to_max ) 358 | { 359 | scale = 255.0f / find_max_RGBE( image, width, height ); 360 | } 361 | for( i = width * height; i > 0; --i ) 362 | { 363 | /* decode this pixel, and find the max */ 364 | float r,g,b,e, m; 365 | /* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ 366 | e = scale * ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); 367 | r = e * img[0]; 368 | g = e * img[1]; 369 | b = e * img[2]; 370 | m = (r > g) ? r : g; 371 | m = (b > m) ? b : m; 372 | /* and encode it into RGBdivA */ 373 | iv = (m != 0.0f) ? (int)(255.0f / m) : 1.0f; 374 | iv = (iv < 1) ? 1 : iv; 375 | img[3] = (iv > 255) ? 255 : iv; 376 | iv = (int)(img[3] * r + 0.5f); 377 | img[0] = (iv > 255) ? 255 : iv; 378 | iv = (int)(img[3] * g + 0.5f); 379 | img[1] = (iv > 255) ? 255 : iv; 380 | iv = (int)(img[3] * b + 0.5f); 381 | img[2] = (iv > 255) ? 255 : iv; 382 | /* and on to the next pixel */ 383 | img += 4; 384 | } 385 | return 1; 386 | } 387 | 388 | int 389 | RGBE_to_RGBdivA2 390 | ( 391 | unsigned char *image, 392 | int width, int height, 393 | int rescale_to_max 394 | ) 395 | { 396 | /* local variables */ 397 | int i, iv; 398 | unsigned char *img = image; 399 | float scale = 1.0f; 400 | /* error check */ 401 | if( (!image) || (width < 1) || (height < 1) ) 402 | { 403 | return 0; 404 | } 405 | /* convert (note: no negative numbers, but 0.0 is possible) */ 406 | if( rescale_to_max ) 407 | { 408 | scale = 255.0f * 255.0f / find_max_RGBE( image, width, height ); 409 | } 410 | for( i = width * height; i > 0; --i ) 411 | { 412 | /* decode this pixel, and find the max */ 413 | float r,g,b,e, m; 414 | /* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ 415 | e = scale * ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); 416 | r = e * img[0]; 417 | g = e * img[1]; 418 | b = e * img[2]; 419 | m = (r > g) ? r : g; 420 | m = (b > m) ? b : m; 421 | /* and encode it into RGBdivA */ 422 | iv = (m != 0.0f) ? (int)sqrtf( 255.0f * 255.0f / m ) : 1.0f; 423 | iv = (iv < 1) ? 1 : iv; 424 | img[3] = (iv > 255) ? 255 : iv; 425 | iv = (int)(img[3] * img[3] * r / 255.0f + 0.5f); 426 | img[0] = (iv > 255) ? 255 : iv; 427 | iv = (int)(img[3] * img[3] * g / 255.0f + 0.5f); 428 | img[1] = (iv > 255) ? 255 : iv; 429 | iv = (int)(img[3] * img[3] * b / 255.0f + 0.5f); 430 | img[2] = (iv > 255) ? 255 : iv; 431 | /* and on to the next pixel */ 432 | img += 4; 433 | } 434 | return 1; 435 | } 436 | -------------------------------------------------------------------------------- /src/test_SOIL.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "SOIL.h" 10 | 11 | LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); 12 | void EnableOpenGL(HWND hwnd, HDC*, HGLRC*); 13 | void DisableOpenGL(HWND, HDC, HGLRC); 14 | 15 | int WINAPI WinMain(HINSTANCE hInstance, 16 | HINSTANCE hPrevInstance, 17 | LPSTR lpCmdLine, 18 | int nCmdShow) 19 | { 20 | WNDCLASSEX wcex; 21 | HWND hwnd; 22 | HDC hDC; 23 | HGLRC hRC; 24 | MSG msg; 25 | BOOL bQuit = FALSE; 26 | float theta = 0.0f; 27 | 28 | // register window class 29 | wcex.cbSize = sizeof(WNDCLASSEX); 30 | wcex.style = CS_OWNDC; 31 | wcex.lpfnWndProc = WindowProc; 32 | wcex.cbClsExtra = 0; 33 | wcex.cbWndExtra = 0; 34 | wcex.hInstance = hInstance; 35 | wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); 36 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 37 | wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); 38 | wcex.lpszMenuName = NULL; 39 | wcex.lpszClassName = "GLSample"; 40 | wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 41 | 42 | 43 | if (!RegisterClassEx(&wcex)) 44 | return 0; 45 | 46 | // create main window 47 | hwnd = CreateWindowEx(0, 48 | "GLSample", 49 | "SOIL Sample", 50 | WS_OVERLAPPEDWINDOW, 51 | CW_USEDEFAULT, 52 | CW_USEDEFAULT, 53 | 512, 54 | 512, 55 | NULL, 56 | NULL, 57 | hInstance, 58 | NULL); 59 | 60 | ShowWindow(hwnd, nCmdShow); 61 | 62 | // check my error handling 63 | /* 64 | SOIL_load_OGL_texture( "img_test.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, 0 ); 65 | std::cout << "'" << SOIL_last_result() << "'" << std::endl; 66 | */ 67 | 68 | 69 | // enable OpenGL for the window 70 | EnableOpenGL(hwnd, &hDC, &hRC); 71 | 72 | glEnable( GL_BLEND ); 73 | //glDisable( GL_BLEND ); 74 | // straight alpha 75 | glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 76 | // premultiplied alpha (remember to do the same in glColor!!) 77 | //glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA ); 78 | 79 | // do I want alpha thresholding? 80 | glEnable( GL_ALPHA_TEST ); 81 | glAlphaFunc( GL_GREATER, 0.5f ); 82 | 83 | // log what the use is asking us to load 84 | std::string load_me = lpCmdLine; 85 | if( load_me.length() > 2 ) 86 | { 87 | //load_me = load_me.substr( 1, load_me.length() - 2 ); 88 | load_me = load_me.substr( 0, load_me.length() - 0 ); 89 | } else 90 | { 91 | //load_me = "img_test_uncompressed.dds"; 92 | //load_me = "img_test_indexed.tga"; 93 | //load_me = "img_test.dds"; 94 | load_me = "img_test.png"; 95 | //load_me = "odd_size.jpg"; 96 | //load_me = "img_cheryl.jpg"; 97 | //load_me = "oak_odd.png"; 98 | //load_me = "field_128_cube.dds"; 99 | //load_me = "field_128_cube_nomip.dds"; 100 | //load_me = "field_128_cube_uc.dds"; 101 | //load_me = "field_128_cube_uc_nomip.dds"; 102 | //load_me = "Goblin.dds"; 103 | //load_me = "parquet.dds"; 104 | //load_me = "stpeters_probe.hdr"; 105 | //load_me = "VeraMoBI_sdf.png"; 106 | 107 | // for testing the texture rectangle code 108 | //load_me = "test_rect.png"; 109 | } 110 | std::cout << "'" << load_me << "'" << std::endl; 111 | 112 | // 1st try to load it as a single-image-cubemap 113 | // (note, need DDS ordered faces: "EWUDNS") 114 | GLuint tex_ID; 115 | int time_me; 116 | 117 | std::cout << "Attempting to load as a cubemap" << std::endl; 118 | time_me = clock(); 119 | tex_ID = SOIL_load_OGL_single_cubemap( 120 | load_me.c_str(), 121 | SOIL_DDS_CUBEMAP_FACE_ORDER, 122 | SOIL_LOAD_AUTO, 123 | SOIL_CREATE_NEW_ID, 124 | SOIL_FLAG_POWER_OF_TWO 125 | | SOIL_FLAG_MIPMAPS 126 | //| SOIL_FLAG_COMPRESS_TO_DXT 127 | //| SOIL_FLAG_TEXTURE_REPEATS 128 | //| SOIL_FLAG_INVERT_Y 129 | | SOIL_FLAG_DDS_LOAD_DIRECT 130 | ); 131 | time_me = clock() - time_me; 132 | std::cout << "the load time was " << 0.001f * time_me << " seconds (warning: low resolution timer)" << std::endl; 133 | if( tex_ID > 0 ) 134 | { 135 | glEnable( GL_TEXTURE_CUBE_MAP ); 136 | glEnable( GL_TEXTURE_GEN_S ); 137 | glEnable( GL_TEXTURE_GEN_T ); 138 | glEnable( GL_TEXTURE_GEN_R ); 139 | glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP ); 140 | glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP ); 141 | glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP ); 142 | glBindTexture( GL_TEXTURE_CUBE_MAP, tex_ID ); 143 | // report 144 | std::cout << "the loaded single cube map ID was " << tex_ID << std::endl; 145 | //std::cout << "the load time was " << 0.001f * time_me << " seconds (warning: low resolution timer)" << std::endl; 146 | } else 147 | { 148 | std::cout << "Attempting to load as a HDR texture" << std::endl; 149 | time_me = clock(); 150 | tex_ID = SOIL_load_OGL_HDR_texture( 151 | load_me.c_str(), 152 | //SOIL_HDR_RGBE, 153 | //SOIL_HDR_RGBdivA, 154 | SOIL_HDR_RGBdivA2, 155 | 0, 156 | SOIL_CREATE_NEW_ID, 157 | SOIL_FLAG_POWER_OF_TWO 158 | | SOIL_FLAG_MIPMAPS 159 | //| SOIL_FLAG_COMPRESS_TO_DXT 160 | ); 161 | time_me = clock() - time_me; 162 | std::cout << "the load time was " << 0.001f * time_me << " seconds (warning: low resolution timer)" << std::endl; 163 | 164 | // did I fail? 165 | if( tex_ID < 1 ) 166 | { 167 | // loading of the single-image-cubemap failed, try it as a simple texture 168 | std::cout << "Attempting to load as a simple 2D texture" << std::endl; 169 | // load the texture, if specified 170 | time_me = clock(); 171 | tex_ID = SOIL_load_OGL_texture( 172 | load_me.c_str(), 173 | SOIL_LOAD_AUTO, 174 | SOIL_CREATE_NEW_ID, 175 | SOIL_FLAG_POWER_OF_TWO 176 | | SOIL_FLAG_MIPMAPS 177 | //| SOIL_FLAG_MULTIPLY_ALPHA 178 | //| SOIL_FLAG_COMPRESS_TO_DXT 179 | | SOIL_FLAG_DDS_LOAD_DIRECT 180 | //| SOIL_FLAG_NTSC_SAFE_RGB 181 | //| SOIL_FLAG_CoCg_Y 182 | //| SOIL_FLAG_TEXTURE_RECTANGLE 183 | ); 184 | time_me = clock() - time_me; 185 | std::cout << "the load time was " << 0.001f * time_me << " seconds (warning: low resolution timer)" << std::endl; 186 | } 187 | 188 | if( tex_ID > 0 ) 189 | { 190 | // enable texturing 191 | glEnable( GL_TEXTURE_2D ); 192 | //glEnable( 0x84F5 );// enables texture rectangle 193 | // bind an OpenGL texture ID 194 | glBindTexture( GL_TEXTURE_2D, tex_ID ); 195 | // report 196 | std::cout << "the loaded texture ID was " << tex_ID << std::endl; 197 | //std::cout << "the load time was " << 0.001f * time_me << " seconds (warning: low resolution timer)" << std::endl; 198 | } else 199 | { 200 | // loading of the texture failed...why? 201 | glDisable( GL_TEXTURE_2D ); 202 | std::cout << "Texture loading failed: '" << SOIL_last_result() << "'" << std::endl; 203 | } 204 | } 205 | 206 | // program main loop 207 | const float ref_mag = 0.1f; 208 | while (!bQuit) 209 | { 210 | // check for messages 211 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 212 | { 213 | // handle or dispatch messages 214 | if (msg.message == WM_QUIT) 215 | { 216 | bQuit = TRUE; 217 | } 218 | else 219 | { 220 | TranslateMessage(&msg); 221 | DispatchMessage(&msg); 222 | } 223 | } 224 | else 225 | { 226 | // OpenGL animation code goes here 227 | theta = clock() * 0.1; 228 | 229 | float tex_u_max = 1.0f;//0.2f; 230 | float tex_v_max = 1.0f;//0.2f; 231 | 232 | glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 233 | glClear(GL_COLOR_BUFFER_BIT); 234 | 235 | glPushMatrix(); 236 | glScalef( 0.8f, 0.8f, 0.8f ); 237 | //glRotatef(-0.314159f*theta, 0.0f, 0.0f, 1.0f); 238 | glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); 239 | glNormal3f( 0.0f, 0.0f, 1.0f ); 240 | glBegin(GL_QUADS); 241 | glNormal3f( -ref_mag, -ref_mag, 1.0f ); 242 | glTexCoord2f( 0.0f, tex_v_max ); 243 | glVertex3f( -1.0f, -1.0f, -0.1f ); 244 | 245 | glNormal3f( ref_mag, -ref_mag, 1.0f ); 246 | glTexCoord2f( tex_u_max, tex_v_max ); 247 | glVertex3f( 1.0f, -1.0f, -0.1f ); 248 | 249 | glNormal3f( ref_mag, ref_mag, 1.0f ); 250 | glTexCoord2f( tex_u_max, 0.0f ); 251 | glVertex3f( 1.0f, 1.0f, -0.1f ); 252 | 253 | glNormal3f( -ref_mag, ref_mag, 1.0f ); 254 | glTexCoord2f( 0.0f, 0.0f ); 255 | glVertex3f( -1.0f, 1.0f, -0.1f ); 256 | glEnd(); 257 | glPopMatrix(); 258 | 259 | tex_u_max = 1.0f; 260 | tex_v_max = 1.0f; 261 | glPushMatrix(); 262 | glScalef( 0.8f, 0.8f, 0.8f ); 263 | glRotatef(theta, 0.0f, 0.0f, 1.0f); 264 | glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); 265 | glNormal3f( 0.0f, 0.0f, 1.0f ); 266 | glBegin(GL_QUADS); 267 | glTexCoord2f( 0.0f, tex_v_max ); glVertex3f( 0.0f, 0.0f, 0.1f ); 268 | glTexCoord2f( tex_u_max, tex_v_max ); glVertex3f( 1.0f, 0.0f, 0.1f ); 269 | glTexCoord2f( tex_u_max, 0.0f ); glVertex3f( 1.0f, 1.0f, 0.1f ); 270 | glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 0.0f, 1.0f, 0.1f ); 271 | glEnd(); 272 | glPopMatrix(); 273 | 274 | { 275 | /* check for errors */ 276 | GLenum err_code = glGetError(); 277 | while( GL_NO_ERROR != err_code ) 278 | { 279 | printf( "OpenGL Error @ %s: %i", "drawing loop", err_code ); 280 | err_code = glGetError(); 281 | } 282 | } 283 | 284 | SwapBuffers(hDC); 285 | 286 | Sleep (1); 287 | } 288 | } 289 | 290 | // and show off the screenshot capability 291 | /* 292 | load_me += "-screenshot.tga"; 293 | SOIL_save_screenshot( load_me.c_str(), SOIL_SAVE_TYPE_TGA, 0, 0, 512, 512 ); 294 | //*/ 295 | //* 296 | load_me += "-screenshot.bmp"; 297 | SOIL_save_screenshot( load_me.c_str(), SOIL_SAVE_TYPE_BMP, 0, 0, 512, 512 ); 298 | //*/ 299 | /* 300 | load_me += "-screenshot.dds"; 301 | SOIL_save_screenshot( load_me.c_str(), SOIL_SAVE_TYPE_DDS, 0, 0, 512, 512 ); 302 | //*/ 303 | 304 | // shutdown OpenGL 305 | DisableOpenGL(hwnd, hDC, hRC); 306 | 307 | // destroy the window explicitly 308 | DestroyWindow(hwnd); 309 | 310 | return msg.wParam; 311 | } 312 | 313 | LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 314 | { 315 | switch (uMsg) 316 | { 317 | case WM_CLOSE: 318 | PostQuitMessage(0); 319 | break; 320 | 321 | case WM_DESTROY: 322 | return 0; 323 | 324 | case WM_KEYDOWN: 325 | { 326 | switch (wParam) 327 | { 328 | case VK_ESCAPE: 329 | PostQuitMessage(0); 330 | break; 331 | } 332 | } 333 | break; 334 | 335 | default: 336 | return DefWindowProc(hwnd, uMsg, wParam, lParam); 337 | } 338 | 339 | return 0; 340 | } 341 | 342 | void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC) 343 | { 344 | PIXELFORMATDESCRIPTOR pfd; 345 | 346 | int iFormat; 347 | 348 | /* get the device context (DC) */ 349 | *hDC = GetDC(hwnd); 350 | 351 | /* set the pixel format for the DC */ 352 | ZeroMemory(&pfd, sizeof(pfd)); 353 | 354 | pfd.nSize = sizeof(pfd); 355 | pfd.nVersion = 1; 356 | pfd.dwFlags = PFD_DRAW_TO_WINDOW | 357 | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 358 | pfd.iPixelType = PFD_TYPE_RGBA; 359 | pfd.cColorBits = 24; 360 | pfd.cDepthBits = 16; 361 | pfd.iLayerType = PFD_MAIN_PLANE; 362 | 363 | iFormat = ChoosePixelFormat(*hDC, &pfd); 364 | 365 | SetPixelFormat(*hDC, iFormat, &pfd); 366 | 367 | /* create and enable the render context (RC) */ 368 | *hRC = wglCreateContext(*hDC); 369 | 370 | wglMakeCurrent(*hDC, *hRC); 371 | } 372 | 373 | void DisableOpenGL (HWND hwnd, HDC hDC, HGLRC hRC) 374 | { 375 | wglMakeCurrent(NULL, NULL); 376 | wglDeleteContext(hRC); 377 | ReleaseDC(hwnd, hDC); 378 | } 379 | 380 | -------------------------------------------------------------------------------- /src/SOIL.h: -------------------------------------------------------------------------------- 1 | /** 2 | @mainpage SOIL 3 | 4 | Jonathan Dummer 5 | 2007-07-26-10.36 6 | 7 | Simple OpenGL Image Library 8 | 9 | A tiny c library for uploading images as 10 | textures into OpenGL. Also saving and 11 | loading of images is supported. 12 | 13 | I'm using Sean's Tool Box image loader as a base: 14 | http://www.nothings.org/ 15 | 16 | I'm upgrading it to load TGA and DDS files, and a direct 17 | path for loading DDS files straight into OpenGL textures, 18 | when applicable. 19 | 20 | Image Formats: 21 | - BMP load & save 22 | - TGA load & save 23 | - DDS load & save 24 | - PNG load 25 | - JPG load 26 | 27 | OpenGL Texture Features: 28 | - resample to power-of-two sizes 29 | - MIPmap generation 30 | - compressed texture S3TC formats (if supported) 31 | - can pre-multiply alpha for you, for better compositing 32 | - can flip image about the y-axis (except pre-compressed DDS files) 33 | 34 | Thanks to: 35 | * Sean Barret - for the awesome stb_image 36 | * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts 37 | * everybody at gamedev.net 38 | **/ 39 | 40 | #ifndef HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY 41 | #define HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | /** 48 | The format of images that may be loaded (force_channels). 49 | SOIL_LOAD_AUTO leaves the image in whatever format it was found. 50 | SOIL_LOAD_L forces the image to load as Luminous (greyscale) 51 | SOIL_LOAD_LA forces the image to load as Luminous with Alpha 52 | SOIL_LOAD_RGB forces the image to load as Red Green Blue 53 | SOIL_LOAD_RGBA forces the image to load as Red Green Blue Alpha 54 | **/ 55 | enum 56 | { 57 | SOIL_LOAD_AUTO = 0, 58 | SOIL_LOAD_L = 1, 59 | SOIL_LOAD_LA = 2, 60 | SOIL_LOAD_RGB = 3, 61 | SOIL_LOAD_RGBA = 4 62 | }; 63 | 64 | /** 65 | Passed in as reuse_texture_ID, will cause SOIL to 66 | register a new texture ID using glGenTextures(). 67 | If the value passed into reuse_texture_ID > 0 then 68 | SOIL will just re-use that texture ID (great for 69 | reloading image assets in-game!) 70 | **/ 71 | enum 72 | { 73 | SOIL_CREATE_NEW_ID = 0 74 | }; 75 | 76 | /** 77 | flags you can pass into SOIL_load_OGL_texture() 78 | and SOIL_create_OGL_texture(). 79 | (note that if SOIL_FLAG_DDS_LOAD_DIRECT is used 80 | the rest of the flags with the exception of 81 | SOIL_FLAG_TEXTURE_REPEATS will be ignored while 82 | loading already-compressed DDS files.) 83 | 84 | SOIL_FLAG_POWER_OF_TWO: force the image to be POT 85 | SOIL_FLAG_MIPMAPS: generate mipmaps for the texture 86 | SOIL_FLAG_TEXTURE_REPEATS: otherwise will clamp 87 | SOIL_FLAG_MULTIPLY_ALPHA: for using (GL_ONE,GL_ONE_MINUS_SRC_ALPHA) blending 88 | SOIL_FLAG_INVERT_Y: flip the image vertically 89 | SOIL_FLAG_COMPRESS_TO_DXT: if the card can display them, will convert RGB to DXT1, RGBA to DXT5 90 | SOIL_FLAG_DDS_LOAD_DIRECT: will load DDS files directly without _ANY_ additional processing 91 | SOIL_FLAG_NTSC_SAFE_RGB: clamps RGB components to the range [16,235] 92 | SOIL_FLAG_CoCg_Y: Google YCoCg; RGB=>CoYCg, RGBA=>CoCgAY 93 | SOIL_FLAG_TEXTURE_RECTANGE: uses ARB_texture_rectangle ; pixel indexed & no repeat or MIPmaps or cubemaps 94 | **/ 95 | enum 96 | { 97 | SOIL_FLAG_POWER_OF_TWO = 1, 98 | SOIL_FLAG_MIPMAPS = 2, 99 | SOIL_FLAG_TEXTURE_REPEATS = 4, 100 | SOIL_FLAG_MULTIPLY_ALPHA = 8, 101 | SOIL_FLAG_INVERT_Y = 16, 102 | SOIL_FLAG_COMPRESS_TO_DXT = 32, 103 | SOIL_FLAG_DDS_LOAD_DIRECT = 64, 104 | SOIL_FLAG_NTSC_SAFE_RGB = 128, 105 | SOIL_FLAG_CoCg_Y = 256, 106 | SOIL_FLAG_TEXTURE_RECTANGLE = 512 107 | }; 108 | 109 | /** 110 | The types of images that may be saved. 111 | (TGA supports uncompressed RGB / RGBA) 112 | (BMP supports uncompressed RGB) 113 | (DDS supports DXT1 and DXT5) 114 | **/ 115 | enum 116 | { 117 | SOIL_SAVE_TYPE_TGA = 0, 118 | SOIL_SAVE_TYPE_BMP = 1, 119 | SOIL_SAVE_TYPE_DDS = 2 120 | }; 121 | 122 | /** 123 | Defines the order of faces in a DDS cubemap. 124 | I recommend that you use the same order in single 125 | image cubemap files, so they will be interchangeable 126 | with DDS cubemaps when using SOIL. 127 | **/ 128 | #define SOIL_DDS_CUBEMAP_FACE_ORDER "EWUDNS" 129 | 130 | /** 131 | The types of internal fake HDR representations 132 | 133 | SOIL_HDR_RGBE: RGB * pow( 2.0, A - 128.0 ) 134 | SOIL_HDR_RGBdivA: RGB / A 135 | SOIL_HDR_RGBdivA2: RGB / (A*A) 136 | **/ 137 | enum 138 | { 139 | SOIL_HDR_RGBE = 0, 140 | SOIL_HDR_RGBdivA = 1, 141 | SOIL_HDR_RGBdivA2 = 2 142 | }; 143 | 144 | /** 145 | Loads an image from disk into an OpenGL texture. 146 | \param filename the name of the file to upload as a texture 147 | \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA 148 | \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) 149 | \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT 150 | \return 0-failed, otherwise returns the OpenGL texture handle 151 | **/ 152 | unsigned int 153 | SOIL_load_OGL_texture 154 | ( 155 | const char *filename, 156 | int force_channels, 157 | unsigned int reuse_texture_ID, 158 | unsigned int flags 159 | ); 160 | 161 | /** 162 | Loads 6 images from disk into an OpenGL cubemap texture. 163 | \param x_pos_file the name of the file to upload as the +x cube face 164 | \param x_neg_file the name of the file to upload as the -x cube face 165 | \param y_pos_file the name of the file to upload as the +y cube face 166 | \param y_neg_file the name of the file to upload as the -y cube face 167 | \param z_pos_file the name of the file to upload as the +z cube face 168 | \param z_neg_file the name of the file to upload as the -z cube face 169 | \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA 170 | \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) 171 | \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT 172 | \return 0-failed, otherwise returns the OpenGL texture handle 173 | **/ 174 | unsigned int 175 | SOIL_load_OGL_cubemap 176 | ( 177 | const char *x_pos_file, 178 | const char *x_neg_file, 179 | const char *y_pos_file, 180 | const char *y_neg_file, 181 | const char *z_pos_file, 182 | const char *z_neg_file, 183 | int force_channels, 184 | unsigned int reuse_texture_ID, 185 | unsigned int flags 186 | ); 187 | 188 | /** 189 | Loads 1 image from disk and splits it into an OpenGL cubemap texture. 190 | \param filename the name of the file to upload as a texture 191 | \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. 192 | \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA 193 | \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) 194 | \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT 195 | \return 0-failed, otherwise returns the OpenGL texture handle 196 | **/ 197 | unsigned int 198 | SOIL_load_OGL_single_cubemap 199 | ( 200 | const char *filename, 201 | const char face_order[6], 202 | int force_channels, 203 | unsigned int reuse_texture_ID, 204 | unsigned int flags 205 | ); 206 | 207 | /** 208 | Loads an HDR image from disk into an OpenGL texture. 209 | \param filename the name of the file to upload as a texture 210 | \param fake_HDR_format SOIL_HDR_RGBE, SOIL_HDR_RGBdivA, SOIL_HDR_RGBdivA2 211 | \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) 212 | \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT 213 | \return 0-failed, otherwise returns the OpenGL texture handle 214 | **/ 215 | unsigned int 216 | SOIL_load_OGL_HDR_texture 217 | ( 218 | const char *filename, 219 | int fake_HDR_format, 220 | int rescale_to_max, 221 | unsigned int reuse_texture_ID, 222 | unsigned int flags 223 | ); 224 | 225 | /** 226 | Loads an image from RAM into an OpenGL texture. 227 | \param buffer the image data in RAM just as if it were still in a file 228 | \param buffer_length the size of the buffer in bytes 229 | \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA 230 | \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) 231 | \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT 232 | \return 0-failed, otherwise returns the OpenGL texture handle 233 | **/ 234 | unsigned int 235 | SOIL_load_OGL_texture_from_memory 236 | ( 237 | const unsigned char *const buffer, 238 | int buffer_length, 239 | int force_channels, 240 | unsigned int reuse_texture_ID, 241 | unsigned int flags 242 | ); 243 | 244 | /** 245 | Loads 6 images from memory into an OpenGL cubemap texture. 246 | \param x_pos_buffer the image data in RAM to upload as the +x cube face 247 | \param x_pos_buffer_length the size of the above buffer 248 | \param x_neg_buffer the image data in RAM to upload as the +x cube face 249 | \param x_neg_buffer_length the size of the above buffer 250 | \param y_pos_buffer the image data in RAM to upload as the +x cube face 251 | \param y_pos_buffer_length the size of the above buffer 252 | \param y_neg_buffer the image data in RAM to upload as the +x cube face 253 | \param y_neg_buffer_length the size of the above buffer 254 | \param z_pos_buffer the image data in RAM to upload as the +x cube face 255 | \param z_pos_buffer_length the size of the above buffer 256 | \param z_neg_buffer the image data in RAM to upload as the +x cube face 257 | \param z_neg_buffer_length the size of the above buffer 258 | \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA 259 | \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) 260 | \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT 261 | \return 0-failed, otherwise returns the OpenGL texture handle 262 | **/ 263 | unsigned int 264 | SOIL_load_OGL_cubemap_from_memory 265 | ( 266 | const unsigned char *const x_pos_buffer, 267 | int x_pos_buffer_length, 268 | const unsigned char *const x_neg_buffer, 269 | int x_neg_buffer_length, 270 | const unsigned char *const y_pos_buffer, 271 | int y_pos_buffer_length, 272 | const unsigned char *const y_neg_buffer, 273 | int y_neg_buffer_length, 274 | const unsigned char *const z_pos_buffer, 275 | int z_pos_buffer_length, 276 | const unsigned char *const z_neg_buffer, 277 | int z_neg_buffer_length, 278 | int force_channels, 279 | unsigned int reuse_texture_ID, 280 | unsigned int flags 281 | ); 282 | 283 | /** 284 | Loads 1 image from RAM and splits it into an OpenGL cubemap texture. 285 | \param buffer the image data in RAM just as if it were still in a file 286 | \param buffer_length the size of the buffer in bytes 287 | \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. 288 | \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA 289 | \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) 290 | \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT 291 | \return 0-failed, otherwise returns the OpenGL texture handle 292 | **/ 293 | unsigned int 294 | SOIL_load_OGL_single_cubemap_from_memory 295 | ( 296 | const unsigned char *const buffer, 297 | int buffer_length, 298 | const char face_order[6], 299 | int force_channels, 300 | unsigned int reuse_texture_ID, 301 | unsigned int flags 302 | ); 303 | 304 | /** 305 | Creates a 2D OpenGL texture from raw image data. Note that the raw data is 306 | _NOT_ freed after the upload (so the user can load various versions). 307 | \param data the raw data to be uploaded as an OpenGL texture 308 | \param width the width of the image in pixels 309 | \param height the height of the image in pixels 310 | \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA 311 | \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) 312 | \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT 313 | \return 0-failed, otherwise returns the OpenGL texture handle 314 | **/ 315 | unsigned int 316 | SOIL_create_OGL_texture 317 | ( 318 | const unsigned char *const data, 319 | int width, int height, int channels, 320 | unsigned int reuse_texture_ID, 321 | unsigned int flags 322 | ); 323 | 324 | /** 325 | Creates an OpenGL cubemap texture by splitting up 1 image into 6 parts. 326 | \param data the raw data to be uploaded as an OpenGL texture 327 | \param width the width of the image in pixels 328 | \param height the height of the image in pixels 329 | \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA 330 | \param face_order the order of the faces in the file, and combination of NSWEUD, for North, South, Up, etc. 331 | \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) 332 | \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT 333 | \return 0-failed, otherwise returns the OpenGL texture handle 334 | **/ 335 | unsigned int 336 | SOIL_create_OGL_single_cubemap 337 | ( 338 | const unsigned char *const data, 339 | int width, int height, int channels, 340 | const char face_order[6], 341 | unsigned int reuse_texture_ID, 342 | unsigned int flags 343 | ); 344 | 345 | /** 346 | Captures the OpenGL window (RGB) and saves it to disk 347 | \return 0 if it failed, otherwise returns 1 348 | **/ 349 | int 350 | SOIL_save_screenshot 351 | ( 352 | const char *filename, 353 | int image_type, 354 | int x, int y, 355 | int width, int height 356 | ); 357 | 358 | /** 359 | Loads an image from disk into an array of unsigned chars. 360 | Note that *channels return the original channel count of the 361 | image. If force_channels was other than SOIL_LOAD_AUTO, 362 | the resulting image has force_channels, but *channels may be 363 | different (if the original image had a different channel 364 | count). 365 | \return 0 if failed, otherwise returns 1 366 | **/ 367 | unsigned char* 368 | SOIL_load_image 369 | ( 370 | const char *filename, 371 | int *width, int *height, int *channels, 372 | int force_channels 373 | ); 374 | 375 | /** 376 | Loads an image from memory into an array of unsigned chars. 377 | Note that *channels return the original channel count of the 378 | image. If force_channels was other than SOIL_LOAD_AUTO, 379 | the resulting image has force_channels, but *channels may be 380 | different (if the original image had a different channel 381 | count). 382 | \return 0 if failed, otherwise returns 1 383 | **/ 384 | unsigned char* 385 | SOIL_load_image_from_memory 386 | ( 387 | const unsigned char *const buffer, 388 | int buffer_length, 389 | int *width, int *height, int *channels, 390 | int force_channels 391 | ); 392 | 393 | /** 394 | Saves an image from an array of unsigned chars (RGBA) to disk 395 | \return 0 if failed, otherwise returns 1 396 | **/ 397 | int 398 | SOIL_save_image 399 | ( 400 | const char *filename, 401 | int image_type, 402 | int width, int height, int channels, 403 | const unsigned char *const data 404 | ); 405 | 406 | /** 407 | Frees the image data (note, this is just C's "free()"...this function is 408 | present mostly so C++ programmers don't forget to use "free()" and call 409 | "delete []" instead [8^) 410 | **/ 411 | void 412 | SOIL_free_image_data 413 | ( 414 | unsigned char *img_data 415 | ); 416 | 417 | /** 418 | This function resturn a pointer to a string describing the last thing 419 | that happened inside SOIL. It can be used to determine why an image 420 | failed to load. 421 | **/ 422 | const char* 423 | SOIL_last_result 424 | ( 425 | void 426 | ); 427 | 428 | 429 | #ifdef __cplusplus 430 | } 431 | #endif 432 | 433 | #endif /* HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY */ 434 | -------------------------------------------------------------------------------- /src/stbi_DDS_aug_c.h: -------------------------------------------------------------------------------- 1 | 2 | /// DDS file support, does decoding, _not_ direct uploading 3 | /// (use SOIL for that ;-) 4 | 5 | /// A bunch of DirectDraw Surface structures and flags 6 | typedef struct { 7 | unsigned int dwMagic; 8 | unsigned int dwSize; 9 | unsigned int dwFlags; 10 | unsigned int dwHeight; 11 | unsigned int dwWidth; 12 | unsigned int dwPitchOrLinearSize; 13 | unsigned int dwDepth; 14 | unsigned int dwMipMapCount; 15 | unsigned int dwReserved1[ 11 ]; 16 | 17 | // DDPIXELFORMAT 18 | struct { 19 | unsigned int dwSize; 20 | unsigned int dwFlags; 21 | unsigned int dwFourCC; 22 | unsigned int dwRGBBitCount; 23 | unsigned int dwRBitMask; 24 | unsigned int dwGBitMask; 25 | unsigned int dwBBitMask; 26 | unsigned int dwAlphaBitMask; 27 | } sPixelFormat; 28 | 29 | // DDCAPS2 30 | struct { 31 | unsigned int dwCaps1; 32 | unsigned int dwCaps2; 33 | unsigned int dwDDSX; 34 | unsigned int dwReserved; 35 | } sCaps; 36 | unsigned int dwReserved2; 37 | } DDS_header ; 38 | 39 | // the following constants were copied directly off the MSDN website 40 | 41 | // The dwFlags member of the original DDSURFACEDESC2 structure 42 | // can be set to one or more of the following values. 43 | #define DDSD_CAPS 0x00000001 44 | #define DDSD_HEIGHT 0x00000002 45 | #define DDSD_WIDTH 0x00000004 46 | #define DDSD_PITCH 0x00000008 47 | #define DDSD_PIXELFORMAT 0x00001000 48 | #define DDSD_MIPMAPCOUNT 0x00020000 49 | #define DDSD_LINEARSIZE 0x00080000 50 | #define DDSD_DEPTH 0x00800000 51 | 52 | // DirectDraw Pixel Format 53 | #define DDPF_ALPHAPIXELS 0x00000001 54 | #define DDPF_FOURCC 0x00000004 55 | #define DDPF_RGB 0x00000040 56 | 57 | // The dwCaps1 member of the DDSCAPS2 structure can be 58 | // set to one or more of the following values. 59 | #define DDSCAPS_COMPLEX 0x00000008 60 | #define DDSCAPS_TEXTURE 0x00001000 61 | #define DDSCAPS_MIPMAP 0x00400000 62 | 63 | // The dwCaps2 member of the DDSCAPS2 structure can be 64 | // set to one or more of the following values. 65 | #define DDSCAPS2_CUBEMAP 0x00000200 66 | #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 67 | #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 68 | #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 69 | #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 70 | #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 71 | #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 72 | #define DDSCAPS2_VOLUME 0x00200000 73 | 74 | static int dds_test(stbi *s) 75 | { 76 | // check the magic number 77 | if (get8(s) != 'D') return 0; 78 | if (get8(s) != 'D') return 0; 79 | if (get8(s) != 'S') return 0; 80 | if (get8(s) != ' ') return 0; 81 | // check header size 82 | if (get32le(s) != 124) return 0; 83 | return 1; 84 | } 85 | #ifndef STBI_NO_STDIO 86 | int stbi_dds_test_file (FILE *f) 87 | { 88 | stbi s; 89 | int r,n = ftell(f); 90 | start_file(&s,f); 91 | r = dds_test(&s); 92 | fseek(f,n,SEEK_SET); 93 | return r; 94 | } 95 | #endif 96 | 97 | int stbi_dds_test_memory (stbi_uc const *buffer, int len) 98 | { 99 | stbi s; 100 | start_mem(&s,buffer, len); 101 | return dds_test(&s); 102 | } 103 | 104 | // helper functions 105 | int stbi_convert_bit_range( int c, int from_bits, int to_bits ) 106 | { 107 | int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1); 108 | return (b + (b >> from_bits)) >> from_bits; 109 | } 110 | void stbi_rgb_888_from_565( unsigned int c, int *r, int *g, int *b ) 111 | { 112 | *r = stbi_convert_bit_range( (c >> 11) & 31, 5, 8 ); 113 | *g = stbi_convert_bit_range( (c >> 05) & 63, 6, 8 ); 114 | *b = stbi_convert_bit_range( (c >> 00) & 31, 5, 8 ); 115 | } 116 | void stbi_decode_DXT1_block( 117 | unsigned char uncompressed[16*4], 118 | unsigned char compressed[8] ) 119 | { 120 | int next_bit = 4*8; 121 | int i, r, g, b; 122 | int c0, c1; 123 | unsigned char decode_colors[4*4]; 124 | // find the 2 primary colors 125 | c0 = compressed[0] + (compressed[1] << 8); 126 | c1 = compressed[2] + (compressed[3] << 8); 127 | stbi_rgb_888_from_565( c0, &r, &g, &b ); 128 | decode_colors[0] = r; 129 | decode_colors[1] = g; 130 | decode_colors[2] = b; 131 | decode_colors[3] = 255; 132 | stbi_rgb_888_from_565( c1, &r, &g, &b ); 133 | decode_colors[4] = r; 134 | decode_colors[5] = g; 135 | decode_colors[6] = b; 136 | decode_colors[7] = 255; 137 | if( c0 > c1 ) 138 | { 139 | // no alpha, 2 interpolated colors 140 | decode_colors[8] = (2*decode_colors[0] + decode_colors[4]) / 3; 141 | decode_colors[9] = (2*decode_colors[1] + decode_colors[5]) / 3; 142 | decode_colors[10] = (2*decode_colors[2] + decode_colors[6]) / 3; 143 | decode_colors[11] = 255; 144 | decode_colors[12] = (decode_colors[0] + 2*decode_colors[4]) / 3; 145 | decode_colors[13] = (decode_colors[1] + 2*decode_colors[5]) / 3; 146 | decode_colors[14] = (decode_colors[2] + 2*decode_colors[6]) / 3; 147 | decode_colors[15] = 255; 148 | } else 149 | { 150 | // 1 interpolated color, alpha 151 | decode_colors[8] = (decode_colors[0] + decode_colors[4]) / 2; 152 | decode_colors[9] = (decode_colors[1] + decode_colors[5]) / 2; 153 | decode_colors[10] = (decode_colors[2] + decode_colors[6]) / 2; 154 | decode_colors[11] = 255; 155 | decode_colors[12] = 0; 156 | decode_colors[13] = 0; 157 | decode_colors[14] = 0; 158 | decode_colors[15] = 0; 159 | } 160 | // decode the block 161 | for( i = 0; i < 16*4; i += 4 ) 162 | { 163 | int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 4; 164 | next_bit += 2; 165 | uncompressed[i+0] = decode_colors[idx+0]; 166 | uncompressed[i+1] = decode_colors[idx+1]; 167 | uncompressed[i+2] = decode_colors[idx+2]; 168 | uncompressed[i+3] = decode_colors[idx+3]; 169 | } 170 | // done 171 | } 172 | void stbi_decode_DXT23_alpha_block( 173 | unsigned char uncompressed[16*4], 174 | unsigned char compressed[8] ) 175 | { 176 | int i, next_bit = 0; 177 | // each alpha value gets 4 bits 178 | for( i = 3; i < 16*4; i += 4 ) 179 | { 180 | uncompressed[i] = stbi_convert_bit_range( 181 | (compressed[next_bit>>3] >> (next_bit&7)) & 15, 182 | 4, 8 ); 183 | next_bit += 4; 184 | } 185 | } 186 | void stbi_decode_DXT45_alpha_block( 187 | unsigned char uncompressed[16*4], 188 | unsigned char compressed[8] ) 189 | { 190 | int i, next_bit = 8*2; 191 | unsigned char decode_alpha[8]; 192 | // each alpha value gets 3 bits, and the 1st 2 bytes are the range 193 | decode_alpha[0] = compressed[0]; 194 | decode_alpha[1] = compressed[1]; 195 | if( decode_alpha[0] > decode_alpha[1] ) 196 | { 197 | // 6 step intermediate 198 | decode_alpha[2] = (6*decode_alpha[0] + 1*decode_alpha[1]) / 7; 199 | decode_alpha[3] = (5*decode_alpha[0] + 2*decode_alpha[1]) / 7; 200 | decode_alpha[4] = (4*decode_alpha[0] + 3*decode_alpha[1]) / 7; 201 | decode_alpha[5] = (3*decode_alpha[0] + 4*decode_alpha[1]) / 7; 202 | decode_alpha[6] = (2*decode_alpha[0] + 5*decode_alpha[1]) / 7; 203 | decode_alpha[7] = (1*decode_alpha[0] + 6*decode_alpha[1]) / 7; 204 | } else 205 | { 206 | // 4 step intermediate, pluss full and none 207 | decode_alpha[2] = (4*decode_alpha[0] + 1*decode_alpha[1]) / 5; 208 | decode_alpha[3] = (3*decode_alpha[0] + 2*decode_alpha[1]) / 5; 209 | decode_alpha[4] = (2*decode_alpha[0] + 3*decode_alpha[1]) / 5; 210 | decode_alpha[5] = (1*decode_alpha[0] + 4*decode_alpha[1]) / 5; 211 | decode_alpha[6] = 0; 212 | decode_alpha[7] = 255; 213 | } 214 | for( i = 3; i < 16*4; i += 4 ) 215 | { 216 | int idx = 0, bit; 217 | bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; 218 | idx += bit << 0; 219 | ++next_bit; 220 | bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; 221 | idx += bit << 1; 222 | ++next_bit; 223 | bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; 224 | idx += bit << 2; 225 | ++next_bit; 226 | uncompressed[i] = decode_alpha[idx & 7]; 227 | } 228 | // done 229 | } 230 | void stbi_decode_DXT_color_block( 231 | unsigned char uncompressed[16*4], 232 | unsigned char compressed[8] ) 233 | { 234 | int next_bit = 4*8; 235 | int i, r, g, b; 236 | int c0, c1; 237 | unsigned char decode_colors[4*3]; 238 | // find the 2 primary colors 239 | c0 = compressed[0] + (compressed[1] << 8); 240 | c1 = compressed[2] + (compressed[3] << 8); 241 | stbi_rgb_888_from_565( c0, &r, &g, &b ); 242 | decode_colors[0] = r; 243 | decode_colors[1] = g; 244 | decode_colors[2] = b; 245 | stbi_rgb_888_from_565( c1, &r, &g, &b ); 246 | decode_colors[3] = r; 247 | decode_colors[4] = g; 248 | decode_colors[5] = b; 249 | // Like DXT1, but no choicees: 250 | // no alpha, 2 interpolated colors 251 | decode_colors[6] = (2*decode_colors[0] + decode_colors[3]) / 3; 252 | decode_colors[7] = (2*decode_colors[1] + decode_colors[4]) / 3; 253 | decode_colors[8] = (2*decode_colors[2] + decode_colors[5]) / 3; 254 | decode_colors[9] = (decode_colors[0] + 2*decode_colors[3]) / 3; 255 | decode_colors[10] = (decode_colors[1] + 2*decode_colors[4]) / 3; 256 | decode_colors[11] = (decode_colors[2] + 2*decode_colors[5]) / 3; 257 | // decode the block 258 | for( i = 0; i < 16*4; i += 4 ) 259 | { 260 | int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 3; 261 | next_bit += 2; 262 | uncompressed[i+0] = decode_colors[idx+0]; 263 | uncompressed[i+1] = decode_colors[idx+1]; 264 | uncompressed[i+2] = decode_colors[idx+2]; 265 | } 266 | // done 267 | } 268 | static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp) 269 | { 270 | // all variables go up front 271 | stbi_uc *dds_data = NULL; 272 | stbi_uc block[16*4]; 273 | stbi_uc compressed[8]; 274 | int flags, DXT_family; 275 | int has_alpha, has_mipmap; 276 | int is_compressed, cubemap_faces; 277 | int block_pitch, num_blocks; 278 | DDS_header header; 279 | int i, sz, cf; 280 | // load the header 281 | if( sizeof( DDS_header ) != 128 ) 282 | { 283 | return NULL; 284 | } 285 | getn( s, (stbi_uc*)(&header), 128 ); 286 | // and do some checking 287 | if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) return NULL; 288 | if( header.dwSize != 124 ) return NULL; 289 | flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; 290 | if( (header.dwFlags & flags) != flags ) return NULL; 291 | /* According to the MSDN spec, the dwFlags should contain 292 | DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if 293 | uncompressed. Some DDS writers do not conform to the 294 | spec, so I need to make my reader more tolerant */ 295 | if( header.sPixelFormat.dwSize != 32 ) return NULL; 296 | flags = DDPF_FOURCC | DDPF_RGB; 297 | if( (header.sPixelFormat.dwFlags & flags) == 0 ) return NULL; 298 | if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) return NULL; 299 | // get the image data 300 | s->img_x = header.dwWidth; 301 | s->img_y = header.dwHeight; 302 | s->img_n = 4; 303 | is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC; 304 | has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS; 305 | has_mipmap = (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1); 306 | cubemap_faces = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP; 307 | /* I need cubemaps to have square faces */ 308 | cubemap_faces &= (s->img_x == s->img_y); 309 | cubemap_faces *= 5; 310 | cubemap_faces += 1; 311 | block_pitch = (s->img_x+3) >> 2; 312 | num_blocks = block_pitch * ((s->img_y+3) >> 2); 313 | /* let the user know what's going on */ 314 | *x = s->img_x; 315 | *y = s->img_y; 316 | *comp = s->img_n; 317 | /* is this uncompressed? */ 318 | if( is_compressed ) 319 | { 320 | /* compressed */ 321 | // note: header.sPixelFormat.dwFourCC is something like (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24)) 322 | DXT_family = 1 + (header.sPixelFormat.dwFourCC >> 24) - '1'; 323 | if( (DXT_family < 1) || (DXT_family > 5) ) return NULL; 324 | /* check the expected size...oops, nevermind... 325 | those non-compliant writers leave 326 | dwPitchOrLinearSize == 0 */ 327 | // passed all the tests, get the RAM for decoding 328 | sz = (s->img_x)*(s->img_y)*4*cubemap_faces; 329 | dds_data = (unsigned char*)malloc( sz ); 330 | /* do this once for each face */ 331 | for( cf = 0; cf < cubemap_faces; ++ cf ) 332 | { 333 | // now read and decode all the blocks 334 | for( i = 0; i < num_blocks; ++i ) 335 | { 336 | // where are we? 337 | int bx, by, bw=4, bh=4; 338 | int ref_x = 4 * (i % block_pitch); 339 | int ref_y = 4 * (i / block_pitch); 340 | // get the next block's worth of compressed data, and decompress it 341 | if( DXT_family == 1 ) 342 | { 343 | // DXT1 344 | getn( s, compressed, 8 ); 345 | stbi_decode_DXT1_block( block, compressed ); 346 | } else if( DXT_family < 4 ) 347 | { 348 | // DXT2/3 349 | getn( s, compressed, 8 ); 350 | stbi_decode_DXT23_alpha_block ( block, compressed ); 351 | getn( s, compressed, 8 ); 352 | stbi_decode_DXT_color_block ( block, compressed ); 353 | } else 354 | { 355 | // DXT4/5 356 | getn( s, compressed, 8 ); 357 | stbi_decode_DXT45_alpha_block ( block, compressed ); 358 | getn( s, compressed, 8 ); 359 | stbi_decode_DXT_color_block ( block, compressed ); 360 | } 361 | // is this a partial block? 362 | if( ref_x + 4 > s->img_x ) 363 | { 364 | bw = s->img_x - ref_x; 365 | } 366 | if( ref_y + 4 > s->img_y ) 367 | { 368 | bh = s->img_y - ref_y; 369 | } 370 | // now drop our decompressed data into the buffer 371 | for( by = 0; by < bh; ++by ) 372 | { 373 | int idx = 4*((ref_y+by+cf*s->img_x)*s->img_x + ref_x); 374 | for( bx = 0; bx < bw*4; ++bx ) 375 | { 376 | 377 | dds_data[idx+bx] = block[by*16+bx]; 378 | } 379 | } 380 | } 381 | /* done reading and decoding the main image... 382 | skip MIPmaps if present */ 383 | if( has_mipmap ) 384 | { 385 | int block_size = 16; 386 | if( DXT_family == 1 ) 387 | { 388 | block_size = 8; 389 | } 390 | for( i = 1; i < header.dwMipMapCount; ++i ) 391 | { 392 | int mx = s->img_x >> (i + 2); 393 | int my = s->img_y >> (i + 2); 394 | if( mx < 1 ) 395 | { 396 | mx = 1; 397 | } 398 | if( my < 1 ) 399 | { 400 | my = 1; 401 | } 402 | skip( s, mx*my*block_size ); 403 | } 404 | } 405 | }/* per cubemap face */ 406 | } else 407 | { 408 | /* uncompressed */ 409 | DXT_family = 0; 410 | s->img_n = 3; 411 | if( has_alpha ) 412 | { 413 | s->img_n = 4; 414 | } 415 | *comp = s->img_n; 416 | sz = s->img_x*s->img_y*s->img_n*cubemap_faces; 417 | dds_data = (unsigned char*)malloc( sz ); 418 | /* do this once for each face */ 419 | for( cf = 0; cf < cubemap_faces; ++ cf ) 420 | { 421 | /* read the main image for this face */ 422 | getn( s, &dds_data[cf*s->img_x*s->img_y*s->img_n], s->img_x*s->img_y*s->img_n ); 423 | /* done reading and decoding the main image... 424 | skip MIPmaps if present */ 425 | if( has_mipmap ) 426 | { 427 | for( i = 1; i < header.dwMipMapCount; ++i ) 428 | { 429 | int mx = s->img_x >> i; 430 | int my = s->img_y >> i; 431 | if( mx < 1 ) 432 | { 433 | mx = 1; 434 | } 435 | if( my < 1 ) 436 | { 437 | my = 1; 438 | } 439 | skip( s, mx*my*s->img_n ); 440 | } 441 | } 442 | } 443 | /* data was BGR, I need it RGB */ 444 | for( i = 0; i < sz; i += s->img_n ) 445 | { 446 | unsigned char temp = dds_data[i]; 447 | dds_data[i] = dds_data[i+2]; 448 | dds_data[i+2] = temp; 449 | } 450 | } 451 | /* finished decompressing into RGBA, 452 | adjust the y size if we have a cubemap 453 | note: sz is already up to date */ 454 | s->img_y *= cubemap_faces; 455 | *y = s->img_y; 456 | // did the user want something else, or 457 | // see if all the alpha values are 255 (i.e. no transparency) 458 | has_alpha = 0; 459 | if( s->img_n == 4) 460 | { 461 | for( i = 3; (i < sz) && (has_alpha == 0); i += 4 ) 462 | { 463 | has_alpha |= (dds_data[i] < 255); 464 | } 465 | } 466 | if( (req_comp <= 4) && (req_comp >= 1) ) 467 | { 468 | // user has some requirements, meet them 469 | if( req_comp != s->img_n ) 470 | { 471 | dds_data = convert_format( dds_data, s->img_n, req_comp, s->img_x, s->img_y ); 472 | *comp = s->img_n; 473 | } 474 | } else 475 | { 476 | // user had no requirements, only drop to RGB is no alpha 477 | if( (has_alpha == 0) && (s->img_n == 4) ) 478 | { 479 | dds_data = convert_format( dds_data, 4, 3, s->img_x, s->img_y ); 480 | *comp = 3; 481 | } 482 | } 483 | // OK, done 484 | return dds_data; 485 | } 486 | 487 | #ifndef STBI_NO_STDIO 488 | stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) 489 | { 490 | stbi s; 491 | start_file(&s,f); 492 | return dds_load(&s,x,y,comp,req_comp); 493 | } 494 | 495 | stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp) 496 | { 497 | stbi_uc *data; 498 | FILE *f = fopen(filename, "rb"); 499 | if (!f) return NULL; 500 | data = stbi_dds_load_from_file(f,x,y,comp,req_comp); 501 | fclose(f); 502 | return data; 503 | } 504 | #endif 505 | 506 | stbi_uc *stbi_dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) 507 | { 508 | stbi s; 509 | start_mem(&s,buffer, len); 510 | return dds_load(&s,x,y,comp,req_comp); 511 | } 512 | -------------------------------------------------------------------------------- /src/stb_image_aug.h: -------------------------------------------------------------------------------- 1 | /* stbi-1.16 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c 2 | when you control the images you're loading 3 | 4 | QUICK NOTES: 5 | Primarily of interest to game developers and other people who can 6 | avoid problematic images and only need the trivial interface 7 | 8 | JPEG baseline (no JPEG progressive, no oddball channel decimations) 9 | PNG non-interlaced 10 | BMP non-1bpp, non-RLE 11 | TGA (not sure what subset, if a subset) 12 | PSD (composited view only, no extra channels) 13 | HDR (radiance rgbE format) 14 | writes BMP,TGA (define STBI_NO_WRITE to remove code) 15 | decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code) 16 | supports installable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) 17 | 18 | TODO: 19 | stbi_info_* 20 | 21 | history: 22 | 1.16 major bugfix - convert_format converted one too many pixels 23 | 1.15 initialize some fields for thread safety 24 | 1.14 fix threadsafe conversion bug; header-file-only version (#define STBI_HEADER_FILE_ONLY before including) 25 | 1.13 threadsafe 26 | 1.12 const qualifiers in the API 27 | 1.11 Support installable IDCT, colorspace conversion routines 28 | 1.10 Fixes for 64-bit (don't use "unsigned long") 29 | optimized upsampling by Fabian "ryg" Giesen 30 | 1.09 Fix format-conversion for PSD code (bad global variables!) 31 | 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz 32 | 1.07 attempt to fix C++ warning/errors again 33 | 1.06 attempt to fix C++ warning/errors again 34 | 1.05 fix TGA loading to return correct *comp and use good luminance calc 35 | 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free 36 | 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR 37 | 1.02 support for (subset of) HDR files, float interface for preferred access to them 38 | 1.01 fix bug: possible bug in handling right-side up bmps... not sure 39 | fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all 40 | 1.00 interface to zlib that skips zlib header 41 | 0.99 correct handling of alpha in palette 42 | 0.98 TGA loader by lonesock; dynamically add loaders (untested) 43 | 0.97 jpeg errors on too large a file; also catch another malloc failure 44 | 0.96 fix detection of invalid v value - particleman@mollyrocket forum 45 | 0.95 during header scan, seek to markers in case of padding 46 | 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same 47 | 0.93 handle jpegtran output; verbose errors 48 | 0.92 read 4,8,16,24,32-bit BMP files of several formats 49 | 0.91 output 24-bit Windows 3.0 BMP files 50 | 0.90 fix a few more warnings; bump version number to approach 1.0 51 | 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd 52 | 0.60 fix compiling as c++ 53 | 0.59 fix warnings: merge Dave Moore's -Wall fixes 54 | 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian 55 | 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less 56 | than 16 available 57 | 0.56 fix bug: zlib uncompressed mode len vs. nlen 58 | 0.55 fix bug: restart_interval not initialized to 0 59 | 0.54 allow NULL for 'int *comp' 60 | 0.53 fix bug in png 3->4; speedup png decoding 61 | 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments 62 | 0.51 obey req_comp requests, 1-component jpegs return as 1-component, 63 | on 'test' only check type, not whether we support this variant 64 | */ 65 | 66 | #ifndef HEADER_STB_IMAGE_AUGMENTED 67 | #define HEADER_STB_IMAGE_AUGMENTED 68 | 69 | //// begin header file //////////////////////////////////////////////////// 70 | // 71 | // Limitations: 72 | // - no progressive/interlaced support (jpeg, png) 73 | // - 8-bit samples only (jpeg, png) 74 | // - not threadsafe 75 | // - channel subsampling of at most 2 in each dimension (jpeg) 76 | // - no delayed line count (jpeg) -- IJG doesn't support either 77 | // 78 | // Basic usage (see HDR discussion below): 79 | // int x,y,n; 80 | // unsigned char *data = stbi_load(filename, &x, &y, &n, 0); 81 | // // ... process data if not NULL ... 82 | // // ... x = width, y = height, n = # 8-bit components per pixel ... 83 | // // ... replace '0' with '1'..'4' to force that many components per pixel 84 | // stbi_image_free(data) 85 | // 86 | // Standard parameters: 87 | // int *x -- outputs image width in pixels 88 | // int *y -- outputs image height in pixels 89 | // int *comp -- outputs # of image components in image file 90 | // int req_comp -- if non-zero, # of image components requested in result 91 | // 92 | // The return value from an image loader is an 'unsigned char *' which points 93 | // to the pixel data. The pixel data consists of *y scanlines of *x pixels, 94 | // with each pixel consisting of N interleaved 8-bit components; the first 95 | // pixel pointed to is top-left-most in the image. There is no padding between 96 | // image scanlines or between pixels, regardless of format. The number of 97 | // components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. 98 | // If req_comp is non-zero, *comp has the number of components that _would_ 99 | // have been output otherwise. E.g. if you set req_comp to 4, you will always 100 | // get RGBA output, but you can check *comp to easily see if it's opaque. 101 | // 102 | // An output image with N components has the following components interleaved 103 | // in this order in each pixel: 104 | // 105 | // N=#comp components 106 | // 1 grey 107 | // 2 grey, alpha 108 | // 3 red, green, blue 109 | // 4 red, green, blue, alpha 110 | // 111 | // If image loading fails for any reason, the return value will be NULL, 112 | // and *x, *y, *comp will be unchanged. The function stbi_failure_reason() 113 | // can be queried for an extremely brief, end-user unfriendly explanation 114 | // of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid 115 | // compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly 116 | // more user-friendly ones. 117 | // 118 | // Paletted PNG and BMP images are automatically depalettized. 119 | // 120 | // 121 | // =========================================================================== 122 | // 123 | // HDR image support (disable by defining STBI_NO_HDR) 124 | // 125 | // stb_image now supports loading HDR images in general, and currently 126 | // the Radiance .HDR file format, although the support is provided 127 | // generically. You can still load any file through the existing interface; 128 | // if you attempt to load an HDR file, it will be automatically remapped to 129 | // LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; 130 | // both of these constants can be reconfigured through this interface: 131 | // 132 | // stbi_hdr_to_ldr_gamma(2.2f); 133 | // stbi_hdr_to_ldr_scale(1.0f); 134 | // 135 | // (note, do not use _inverse_ constants; stbi_image will invert them 136 | // appropriately). 137 | // 138 | // Additionally, there is a new, parallel interface for loading files as 139 | // (linear) floats to preserve the full dynamic range: 140 | // 141 | // float *data = stbi_loadf(filename, &x, &y, &n, 0); 142 | // 143 | // If you load LDR images through this interface, those images will 144 | // be promoted to floating point values, run through the inverse of 145 | // constants corresponding to the above: 146 | // 147 | // stbi_ldr_to_hdr_scale(1.0f); 148 | // stbi_ldr_to_hdr_gamma(2.2f); 149 | // 150 | // Finally, given a filename (or an open file or memory block--see header 151 | // file for details) containing image data, you can query for the "most 152 | // appropriate" interface to use (that is, whether the image is HDR or 153 | // not), using: 154 | // 155 | // stbi_is_hdr(char *filename); 156 | 157 | #ifndef STBI_NO_STDIO 158 | #include 159 | #endif 160 | 161 | #define STBI_VERSION 1 162 | 163 | enum 164 | { 165 | STBI_default = 0, // only used for req_comp 166 | 167 | STBI_grey = 1, 168 | STBI_grey_alpha = 2, 169 | STBI_rgb = 3, 170 | STBI_rgb_alpha = 4, 171 | }; 172 | 173 | typedef unsigned char stbi_uc; 174 | 175 | #ifdef __cplusplus 176 | extern "C" { 177 | #endif 178 | 179 | // WRITING API 180 | 181 | #if !defined(STBI_NO_WRITE) && !defined(STBI_NO_STDIO) 182 | // write a BMP/TGA file given tightly packed 'comp' channels (no padding, nor bmp-stride-padding) 183 | // (you must include the appropriate extension in the filename). 184 | // returns TRUE on success, FALSE if couldn't open file, error writing file 185 | extern int stbi_write_bmp (char const *filename, int x, int y, int comp, void *data); 186 | extern int stbi_write_tga (char const *filename, int x, int y, int comp, void *data); 187 | #endif 188 | 189 | // PRIMARY API - works on images of any type 190 | 191 | // load image by filename, open file, or memory buffer 192 | #ifndef STBI_NO_STDIO 193 | extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); 194 | extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); 195 | extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); 196 | #endif 197 | extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 198 | // for stbi_load_from_file, file pointer is left pointing immediately after image 199 | 200 | #ifndef STBI_NO_HDR 201 | #ifndef STBI_NO_STDIO 202 | extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); 203 | extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); 204 | #endif 205 | extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 206 | 207 | extern void stbi_hdr_to_ldr_gamma(float gamma); 208 | extern void stbi_hdr_to_ldr_scale(float scale); 209 | 210 | extern void stbi_ldr_to_hdr_gamma(float gamma); 211 | extern void stbi_ldr_to_hdr_scale(float scale); 212 | 213 | #endif // STBI_NO_HDR 214 | 215 | // get a VERY brief reason for failure 216 | // NOT THREADSAFE 217 | extern char *stbi_failure_reason (void); 218 | 219 | // free the loaded image -- this is just free() 220 | extern void stbi_image_free (void *retval_from_stbi_load); 221 | 222 | // get image dimensions & components without fully decoding 223 | extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); 224 | extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); 225 | #ifndef STBI_NO_STDIO 226 | extern int stbi_info (char const *filename, int *x, int *y, int *comp); 227 | extern int stbi_is_hdr (char const *filename); 228 | extern int stbi_is_hdr_from_file(FILE *f); 229 | #endif 230 | 231 | // ZLIB client - used by PNG, available for other purposes 232 | 233 | extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); 234 | extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); 235 | extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); 236 | 237 | extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); 238 | extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); 239 | 240 | // TYPE-SPECIFIC ACCESS 241 | 242 | // is it a jpeg? 243 | extern int stbi_jpeg_test_memory (stbi_uc const *buffer, int len); 244 | extern stbi_uc *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 245 | extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); 246 | 247 | #ifndef STBI_NO_STDIO 248 | extern stbi_uc *stbi_jpeg_load (char const *filename, int *x, int *y, int *comp, int req_comp); 249 | extern int stbi_jpeg_test_file (FILE *f); 250 | extern stbi_uc *stbi_jpeg_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); 251 | 252 | extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp); 253 | extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp); 254 | #endif 255 | 256 | // is it a png? 257 | extern int stbi_png_test_memory (stbi_uc const *buffer, int len); 258 | extern stbi_uc *stbi_png_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 259 | extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); 260 | 261 | #ifndef STBI_NO_STDIO 262 | extern stbi_uc *stbi_png_load (char const *filename, int *x, int *y, int *comp, int req_comp); 263 | extern int stbi_png_info (char const *filename, int *x, int *y, int *comp); 264 | extern int stbi_png_test_file (FILE *f); 265 | extern stbi_uc *stbi_png_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); 266 | extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp); 267 | #endif 268 | 269 | // is it a bmp? 270 | extern int stbi_bmp_test_memory (stbi_uc const *buffer, int len); 271 | 272 | extern stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp); 273 | extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 274 | #ifndef STBI_NO_STDIO 275 | extern int stbi_bmp_test_file (FILE *f); 276 | extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); 277 | #endif 278 | 279 | // is it a tga? 280 | extern int stbi_tga_test_memory (stbi_uc const *buffer, int len); 281 | 282 | extern stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp); 283 | extern stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 284 | #ifndef STBI_NO_STDIO 285 | extern int stbi_tga_test_file (FILE *f); 286 | extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); 287 | #endif 288 | 289 | // is it a psd? 290 | extern int stbi_psd_test_memory (stbi_uc const *buffer, int len); 291 | 292 | extern stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp); 293 | extern stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 294 | #ifndef STBI_NO_STDIO 295 | extern int stbi_psd_test_file (FILE *f); 296 | extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); 297 | #endif 298 | 299 | // is it an hdr? 300 | extern int stbi_hdr_test_memory (stbi_uc const *buffer, int len); 301 | 302 | extern float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp); 303 | extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 304 | extern stbi_uc *stbi_hdr_load_rgbe (char const *filename, int *x, int *y, int *comp, int req_comp); 305 | extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 306 | #ifndef STBI_NO_STDIO 307 | extern int stbi_hdr_test_file (FILE *f); 308 | extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); 309 | extern stbi_uc *stbi_hdr_load_rgbe_file (FILE *f, int *x, int *y, int *comp, int req_comp); 310 | #endif 311 | 312 | // define new loaders 313 | typedef struct 314 | { 315 | int (*test_memory)(stbi_uc const *buffer, int len); 316 | stbi_uc * (*load_from_memory)(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); 317 | #ifndef STBI_NO_STDIO 318 | int (*test_file)(FILE *f); 319 | stbi_uc * (*load_from_file)(FILE *f, int *x, int *y, int *comp, int req_comp); 320 | #endif 321 | } stbi_loader; 322 | 323 | // register a loader by filling out the above structure (you must defined ALL functions) 324 | // returns 1 if added or already added, 0 if not added (too many loaders) 325 | // NOT THREADSAFE 326 | extern int stbi_register_loader(stbi_loader *loader); 327 | 328 | // define faster low-level operations (typically SIMD support) 329 | #if STBI_SIMD 330 | typedef void (*stbi_idct_8x8)(uint8 *out, int out_stride, short data[64], unsigned short *dequantize); 331 | // compute an integer IDCT on "input" 332 | // input[x] = data[x] * dequantize[x] 333 | // write results to 'out': 64 samples, each run of 8 spaced by 'out_stride' 334 | // CLAMP results to 0..255 335 | typedef void (*stbi_YCbCr_to_RGB_run)(uint8 *output, uint8 const *y, uint8 const *cb, uint8 const *cr, int count, int step); 336 | // compute a conversion from YCbCr to RGB 337 | // 'count' pixels 338 | // write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B 339 | // y: Y input channel 340 | // cb: Cb input channel; scale/biased to be 0..255 341 | // cr: Cr input channel; scale/biased to be 0..255 342 | 343 | extern void stbi_install_idct(stbi_idct_8x8 func); 344 | extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func); 345 | #endif // STBI_SIMD 346 | 347 | #ifdef __cplusplus 348 | } 349 | #endif 350 | 351 | // 352 | // 353 | //// end header file ///////////////////////////////////////////////////// 354 | #endif // STBI_INCLUDE_STB_IMAGE_H 355 | -------------------------------------------------------------------------------- /soil.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lonesock.net: SOIL 6 | 27 | 28 | 29 |
 30 | Simple OpenGL Image Library
 31 | 
32 |

33 | Introduction:

SOIL is a tiny C library used primarily 34 | for uploading textures into OpenGL. It is based on stb_image version 35 | 1.16, the public domain code from Sean Barrett (found here). 36 | I have extended it to load TGA and DDS files, and to perform common 37 | functions needed in loading OpenGL textures. SOIL can also be used 38 | to save and load images in a variety of formats (useful for loading 39 | height maps, non-OpenGL applications, etc.)
40 |
41 | Download: 42 |
43 |
44 | You can grab the latest version of SOIL here. 45 | (July 7, 2008: see the change log at the bottom of this page.)
46 | You can also checkout the latest code from the new SVN repository, login as guest/guest:
47 | svn://www.twisted-works.com/jdummer/public/SOIL
48 | (thanks for the SVN hosting, Sherief!) 49 |
50 |
51 | License: 52 |
53 |
54 | Public Domain 55 |
56 |
57 | Features: 58 |

59 |
    60 |
  • Readable Image Formats: 61 |
      62 |
    • BMP - non-1bpp, non-RLE (from stb_image documentation) 63 |
    • PNG - non-interlaced (from stb_image documentation) 64 |
    • JPG - JPEG baseline (from stb_image documentation) 65 |
    • TGA - greyscale or RGB or RGBA or indexed, uncompressed or RLE 66 |
    • DDS - DXT1/2/3/4/5, uncompressed, cubemaps (can't read 3D DDS files yet) 67 |
    • PSD - (from stb_image documentation) 68 |
    • HDR - converted to LDR, unless loaded with *HDR* functions (RGBE or RGBdivA or RGBdivA2) 69 |
    70 |
  • Writeable Image Formats: 71 |
      72 |
    • TGA - Greyscale or RGB or RGBA, uncompressed 73 |
    • BMP - RGB, uncompressed 74 |
    • DDS - RGB as DXT1, or RGBA as DXT5 75 |
    76 |
  • Can load an image file directly into a 2D OpenGL texture, optionally performing the following functions: 77 |
      78 |
    • Can generate a new texture handle, or reuse one specified 79 |
    • Can automatically rescale the image to the next largest power-of-two size 80 |
    • Can automatically create MIPmaps 81 |
    • Can scale (not simply clamp) the RGB values into the "safe range" for NTSC displays (16 to 235, as recommended here) 82 |
    • Can multiply alpha on load (for more correct blending / compositing) 83 |
    • Can flip the image vertically 84 |
    • Can compress and upload any image as DXT1 or DXT5 (if EXT_texture_compression_s3tc is available), using an internal (very fast!) compressor 85 |
    • Can convert the RGB to YCoCg color space (useful with DXT5 compression: see this link from NVIDIA) 86 |
    • Will automatically downsize a texture if it is larger than GL_MAX_TEXTURE_SIZE 87 |
    • Can directly upload DDS files (DXT1/3/5/uncompressed/cubemap, with or without MIPmaps). Note: directly uploading the compressed DDS image will disable the other options (no flipping, no pre-multiplying alpha, no rescaling, no creation of MIPmaps, no auto-downsizing) 88 |
    • Can load rectangluar textures for GUI elements or splash screens (requires GL_ARB/EXT/NV_texture_rectangle) 89 |
    90 |
  • Can decompress images from RAM (e.g. via PhysicsFS or similar) into an OpenGL texture (same features as regular 2D textures, above) 91 |
  • Can load cube maps directly into an OpenGL texture (same features as regular 2D textures, above) 92 |
      93 |
    • Can take six image files directly into an OpenGL cube map texture 94 |
    • Can take a single image file where width = 6*height (or vice versa), split it into an OpenGL cube map texture 95 |
    96 |
  • No external dependencies 97 |
  • Tiny 98 |
  • Cross platform (Windows, *nix, Mac OS X) 99 |
  • Public Domain 100 |
101 | 102 |
ToDo:
103 |
    104 |
  • More testing 105 |
  • add HDR functions to load from memory and load to RGBE unsigned char* 106 |
107 |


Usage:

SOIL is meant to be used as a static 108 | library (as it's tiny and in the public domain). You can use the static 109 | library file included in the zip (libSOIL.a works for MinGW and Microsoft 110 | compilers...feel free to rename it to SOIL.lib if that makes you happy), 111 | or compile the library yourself. The code is cross-platform and has been 112 | tested on Windows, Linux, and Mac. (The heaviest testing has been on the 113 | Windows platform, so feel free to email me if you find any issues with 114 | other platforms.) 115 |

Simply include SOIL.h in your C or C++ file, 116 | link in the static library, and then use any of SOIL's functions. The 117 | file SOIL.h contains simple doxygen style documentation. (If you use the 118 | static library, no other header files are needed besides SOIL.h) Below 119 | are some simple usage examples: 120 |

121 |
122 | /* load an image file directly as a new OpenGL texture */
123 | GLuint tex_2d = SOIL_load_OGL_texture
124 | 	(
125 | 		"img.png",
126 | 		SOIL_LOAD_AUTO,
127 | 		SOIL_CREATE_NEW_ID,
128 | 		SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
129 | 	);
130 | 	
131 | /* check for an error during the load process */
132 | if( 0 == tex_2d )
133 | {
134 | 	printf( "SOIL loading error: '%s'\n", SOIL_last_result() );
135 | }
136 | 
137 | /* load another image, but into the same texture ID, overwriting the last one */
138 | tex_2d = SOIL_load_OGL_texture
139 | 	(
140 | 		"some_other_img.dds",
141 | 		SOIL_LOAD_AUTO,
142 | 		tex_2d,
143 | 		SOIL_FLAG_DDS_LOAD_DIRECT
144 | 	);
145 | 	
146 | /* load 6 images into a new OpenGL cube map, forcing RGB */
147 | GLuint tex_cube = SOIL_load_OGL_cubemap
148 | 	(
149 | 		"xp.jpg",
150 | 		"xn.jpg",
151 | 		"yp.jpg",
152 | 		"yn.jpg",
153 | 		"zp.jpg",
154 | 		"zn.jpg",
155 | 		SOIL_LOAD_RGB,
156 | 		SOIL_CREATE_NEW_ID,
157 | 		SOIL_FLAG_MIPMAPS
158 | 	);
159 | 	
160 | /* load and split a single image into a new OpenGL cube map, default format */
161 | /* face order = East South West North Up Down => "ESWNUD", case sensitive! */
162 | GLuint single_tex_cube = SOIL_load_OGL_single_cubemap
163 | 	(
164 | 		"split_cubemap.png",
165 | 		"EWUDNS",
166 | 		SOIL_LOAD_AUTO,
167 | 		SOIL_CREATE_NEW_ID,
168 | 		SOIL_FLAG_MIPMAPS
169 | 	);
170 | 	
171 | /* actually, load a DDS cubemap over the last OpenGL cube map, default format */
172 | /* try to load it directly, but give the order of the faces in case that fails */
173 | /* the DDS cubemap face order is pre-defined as SOIL_DDS_CUBEMAP_FACE_ORDER */
174 | single_tex_cube = SOIL_load_OGL_single_cubemap
175 | 	(
176 | 		"overwrite_cubemap.dds",
177 | 		SOIL_DDS_CUBEMAP_FACE_ORDER,
178 | 		SOIL_LOAD_AUTO,
179 | 		single_tex_cube,
180 | 		SOIL_FLAG_MIPMAPS | SOIL_FLAG_DDS_LOAD_DIRECT
181 | 	);
182 | 	
183 | /* load an image as a heightmap, forcing greyscale (so channels should be 1) */
184 | int width, height, channels;
185 | unsigned char *ht_map = SOIL_load_image
186 | 	(
187 | 		"terrain.tga",
188 | 		&width, &height, &channels,
189 | 		SOIL_LOAD_L
190 | 	);
191 | 	
192 | /* save that image as another type */
193 | int save_result = SOIL_save_image
194 | 	(
195 | 		"new_terrain.dds",
196 | 		SOIL_SAVE_TYPE_DDS,
197 | 		width, height, channels,
198 | 		ht_map
199 | 	);
200 | 	
201 | /* save a screenshot of your awesome OpenGL game engine, running at 1024x768 */
202 | save_result = SOIL_save_screenshot
203 | 	(
204 | 		"awesomenessity.bmp",
205 | 		SOIL_SAVE_TYPE_BMP,
206 | 		0, 0, 1024, 768
207 | 	);
208 | 
209 | /* loaded a file via PhysicsFS, need to decompress the image from RAM, */
210 | /* where it's in a buffer: unsigned char *image_in_RAM */
211 | GLuint tex_2d_from_RAM = SOIL_load_OGL_texture_from_memory
212 | 	(
213 | 		image_in_RAM,
214 | 		image_in_RAM_bytes,
215 | 		SOIL_LOAD_AUTO,
216 | 		SOIL_CREATE_NEW_ID,
217 | 		SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT
218 | 	);
219 | 	
220 | /* done with the heightmap, free up the RAM */
221 | SOIL_free_image_data( ht_map );
222 | 
223 |
224 |
225 | Change Log: 226 |
    227 |
  • July 7, 2008 228 |
      229 |
    • upgraded to stb_image 1.16 (threadsafe! loads PSD and HDR formats) 230 |
    • removed inline keyword from native SOIL functions (thanks Sherief, Boder, Amnesiac5!) 231 |
    • added SOIL_load_OGL_HDR_texture (loads a Radience HDR file into RGBE, RGB/a, RGB/A^2) 232 |
    • fixed a potential bug loading DDS files with a filename 233 |
    • added a VC9 project file (thanks Sherief!) 234 |
    235 |
  • November 10, 2007: added SOIL_FLAG_TEXTURE_RECTANGLE (pixel addressed non POT, useful for GUI, splash screens, etc.). Not useful with cubemaps, and disables repeating and MIPmaps. 236 |
  • November 8, 2007 237 |
      238 |
    • upgraded to stb_image 1.07 239 |
    • fixed some includes and defines for compiling on OS X (thanks Mogui and swiftcoder!) 240 |
    241 |
  • October 30, 2007 242 |
      243 |
    • upgraded to stb_image 1.04, some tiny bug fixes 244 |
    • there is now a makefile (under projects) for ease of building under Linux (thanks D J Peters!) 245 |
    • Visual Studio 6/2003/2005 projects are working again 246 |
    • patched SOIL for better pointer handling of the glCompressedTexImage2D extension (thanks Peter Sperl!) 247 |
    • fixed DDS loading when force_channels=4 but there was no alpha; it was returning 3 channels. (Thanks LaurentGom!) 248 |
    • fixed a bunch of channel issues in general. (Thanks Sean Barrett!) 249 |
    250 |
  • October 27, 2007 251 |
      252 |
    • correctly reports when there is no OpenGL context (thanks Merick Zero!) 253 |
    • upgraded to stb_image 1.03 with support for loading the HDR image format 254 |
    • fixed loading JPEG images while forcing the number of channels (e.g. to RGBA) 255 |
    • changed SOIL_DDS_CUBEMAP_FACE_ORDER to a #define (thanks Dancho!) 256 |
    • reorganized my additions to stb_image (you can define STBI_NO_DDS to compile SOIL without DDS support) 257 |
    • added SOIL_FLAG_CoCg_Y, will convert RGB or RGBA to YCoCg color space (link) 258 |
    259 |
  • October 5, 2007 260 |
      261 |
    • added SOIL_FLAG_NTSC_SAFE_RGB 262 |
    • bugfixed & optimized up_scale_image (used with SOIL_FLAG_POWER_OF_TWO and SOIL_FLAG_MIPMAPS) 263 |
    264 |
  • September 20, 2007 265 |
      266 |
    • upgraded to stb_image 1.0 267 |
    • added the DXT source files to the MSVS projects 268 |
    • removed sqrtf() calls (VS2k3 could not handle them) 269 |
    • distributing only 1 library file (libSOIL.a, compiled with MinGW 4.2.1 tech preview!) for all windows compilers 270 |
    • added an example of the *_from_memory() functions to the Usage section 271 |
    272 |
  • September 6, 2007 273 |
      274 |
    • added a slew of SOIL_load_*_from_memory() functions for people using PhysicsFS or similar 275 |
    • more robust loading of non-compliant DDS files (thanks Dan!) 276 |
    277 |
  • September 1, 2007 - fixed bugs from the last update [8^) 278 |
  • August 31, 2007 279 |
      280 |
    • can load uncompressed and cubemap DDS files 281 |
    • can create a cubemap texture from a single (stitched) image file of any type 282 |
    • sped up the image resizing code 283 |
    284 |
  • August 24, 2007 - updated the documentation examples (at the bottom of this page) 285 |
  • August 22, 2007 286 |
      287 |
    • can load cube maps (needs serious testing) 288 |
    • can compress 1- or 2-channel images to DXT1/5 289 |
    • fixed some malloc() casts 290 |
    • fixed C++ style comments 291 |
    • fixed includes to compile under *nix or Mac (hopefully, needs testing...any volunteers?) 292 |
    293 |
  • August 16, 2007 294 |
      295 |
    • Will now downsize the image if necessary to fit GL_MAX_TEXTURE_SIZE 296 |
    • added SOIL_create_OGL_texture() to upload raw image data that isn't from an image file 297 |
    298 |
  • August 14, 2007 (PM) - Can now load indexed TGA 299 |
  • August 14, 2007 (AM) 300 |
      301 |
    • Updated to stb_image 0.97 302 |
    • added result messages 303 |
    • can now decompress DDS files (DXT1/2/3/4/5) 304 |
    305 |
  • August 11, 2007 - MIPmaps can now handle non-square textures 306 |
  • August 7, 2007 307 |
      308 |
    • Can directly upload DXT1/3/5 DDS files (with or w/o MIPmaps) 309 |
    • can compress any image to DXT1/5 (using a new & fast & simple compression scheme) and upload 310 |
    • can save as DDS 311 |
    312 |
  • July 31, 2007 - added compressing to DXT and flipping about Y 313 |
  • July 30, 2007 - initial release 314 |
315 |
316 |
317 |
back to 
318 | www.lonesock.net
319 | 320 | -------------------------------------------------------------------------------- /src/image_DXT.c: -------------------------------------------------------------------------------- 1 | /* 2 | Jonathan Dummer 3 | 2007-07-31-10.32 4 | 5 | simple DXT compression / decompression code 6 | 7 | public domain 8 | */ 9 | 10 | #include "image_DXT.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | /* set this =1 if you want to use the covarince matrix method... 17 | which is better than my method of using standard deviations 18 | overall, except on the infintesimal chance that the power 19 | method fails for finding the largest eigenvector */ 20 | #define USE_COV_MAT 1 21 | 22 | /********* Function Prototypes *********/ 23 | /* 24 | Takes a 4x4 block of pixels and compresses it into 8 bytes 25 | in DXT1 format (color only, no alpha). Speed is valued 26 | over prettyness, at least for now. 27 | */ 28 | void compress_DDS_color_block( 29 | int channels, 30 | const unsigned char *const uncompressed, 31 | unsigned char compressed[8] ); 32 | /* 33 | Takes a 4x4 block of pixels and compresses the alpha 34 | component it into 8 bytes for use in DXT5 DDS files. 35 | Speed is valued over prettyness, at least for now. 36 | */ 37 | void compress_DDS_alpha_block( 38 | const unsigned char *const uncompressed, 39 | unsigned char compressed[8] ); 40 | 41 | /********* Actual Exposed Functions *********/ 42 | int 43 | save_image_as_DDS 44 | ( 45 | const char *filename, 46 | int width, int height, int channels, 47 | const unsigned char *const data 48 | ) 49 | { 50 | /* variables */ 51 | FILE *fout; 52 | unsigned char *DDS_data; 53 | DDS_header header; 54 | int DDS_size; 55 | /* error check */ 56 | if( (NULL == filename) || 57 | (width < 1) || (height < 1) || 58 | (channels < 1) || (channels > 4) || 59 | (data == NULL ) ) 60 | { 61 | return 0; 62 | } 63 | /* Convert the image */ 64 | if( (channels & 1) == 1 ) 65 | { 66 | /* no alpha, just use DXT1 */ 67 | DDS_data = convert_image_to_DXT1( data, width, height, channels, &DDS_size ); 68 | } else 69 | { 70 | /* has alpha, so use DXT5 */ 71 | DDS_data = convert_image_to_DXT5( data, width, height, channels, &DDS_size ); 72 | } 73 | /* save it */ 74 | memset( &header, 0, sizeof( DDS_header ) ); 75 | header.dwMagic = ('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24); 76 | header.dwSize = 124; 77 | header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE; 78 | header.dwWidth = width; 79 | header.dwHeight = height; 80 | header.dwPitchOrLinearSize = DDS_size; 81 | header.sPixelFormat.dwSize = 32; 82 | header.sPixelFormat.dwFlags = DDPF_FOURCC; 83 | if( (channels & 1) == 1 ) 84 | { 85 | header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24); 86 | } else 87 | { 88 | header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24); 89 | } 90 | header.sCaps.dwCaps1 = DDSCAPS_TEXTURE; 91 | /* write it out */ 92 | fout = fopen( filename, "wb"); 93 | fwrite( &header, sizeof( DDS_header ), 1, fout ); 94 | fwrite( DDS_data, 1, DDS_size, fout ); 95 | fclose( fout ); 96 | /* done */ 97 | free( DDS_data ); 98 | return 1; 99 | } 100 | 101 | unsigned char* convert_image_to_DXT1( 102 | const unsigned char *const uncompressed, 103 | int width, int height, int channels, 104 | int *out_size ) 105 | { 106 | unsigned char *compressed; 107 | int i, j, x, y; 108 | unsigned char ublock[16*3]; 109 | unsigned char cblock[8]; 110 | int index = 0, chan_step = 1; 111 | int block_count = 0; 112 | /* error check */ 113 | *out_size = 0; 114 | if( (width < 1) || (height < 1) || 115 | (NULL == uncompressed) || 116 | (channels < 1) || (channels > 4) ) 117 | { 118 | return NULL; 119 | } 120 | /* for channels == 1 or 2, I do not step forward for R,G,B values */ 121 | if( channels < 3 ) 122 | { 123 | chan_step = 0; 124 | } 125 | /* get the RAM for the compressed image 126 | (8 bytes per 4x4 pixel block) */ 127 | *out_size = ((width+3) >> 2) * ((height+3) >> 2) * 8; 128 | compressed = (unsigned char*)malloc( *out_size ); 129 | /* go through each block */ 130 | for( j = 0; j < height; j += 4 ) 131 | { 132 | for( i = 0; i < width; i += 4 ) 133 | { 134 | /* copy this block into a new one */ 135 | int idx = 0; 136 | int mx = 4, my = 4; 137 | if( j+4 >= height ) 138 | { 139 | my = height - j; 140 | } 141 | if( i+4 >= width ) 142 | { 143 | mx = width - i; 144 | } 145 | for( y = 0; y < my; ++y ) 146 | { 147 | for( x = 0; x < mx; ++x ) 148 | { 149 | ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels]; 150 | ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step]; 151 | ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step]; 152 | } 153 | for( x = mx; x < 4; ++x ) 154 | { 155 | ublock[idx++] = ublock[0]; 156 | ublock[idx++] = ublock[1]; 157 | ublock[idx++] = ublock[2]; 158 | } 159 | } 160 | for( y = my; y < 4; ++y ) 161 | { 162 | for( x = 0; x < 4; ++x ) 163 | { 164 | ublock[idx++] = ublock[0]; 165 | ublock[idx++] = ublock[1]; 166 | ublock[idx++] = ublock[2]; 167 | } 168 | } 169 | /* compress the block */ 170 | ++block_count; 171 | compress_DDS_color_block( 3, ublock, cblock ); 172 | /* copy the data from the block into the main block */ 173 | for( x = 0; x < 8; ++x ) 174 | { 175 | compressed[index++] = cblock[x]; 176 | } 177 | } 178 | } 179 | return compressed; 180 | } 181 | 182 | unsigned char* convert_image_to_DXT5( 183 | const unsigned char *const uncompressed, 184 | int width, int height, int channels, 185 | int *out_size ) 186 | { 187 | unsigned char *compressed; 188 | int i, j, x, y; 189 | unsigned char ublock[16*4]; 190 | unsigned char cblock[8]; 191 | int index = 0, chan_step = 1; 192 | int block_count = 0, has_alpha; 193 | /* error check */ 194 | *out_size = 0; 195 | if( (width < 1) || (height < 1) || 196 | (NULL == uncompressed) || 197 | (channels < 1) || ( channels > 4) ) 198 | { 199 | return NULL; 200 | } 201 | /* for channels == 1 or 2, I do not step forward for R,G,B vales */ 202 | if( channels < 3 ) 203 | { 204 | chan_step = 0; 205 | } 206 | /* # channels = 1 or 3 have no alpha, 2 & 4 do have alpha */ 207 | has_alpha = 1 - (channels & 1); 208 | /* get the RAM for the compressed image 209 | (16 bytes per 4x4 pixel block) */ 210 | *out_size = ((width+3) >> 2) * ((height+3) >> 2) * 16; 211 | compressed = (unsigned char*)malloc( *out_size ); 212 | /* go through each block */ 213 | for( j = 0; j < height; j += 4 ) 214 | { 215 | for( i = 0; i < width; i += 4 ) 216 | { 217 | /* local variables, and my block counter */ 218 | int idx = 0; 219 | int mx = 4, my = 4; 220 | if( j+4 >= height ) 221 | { 222 | my = height - j; 223 | } 224 | if( i+4 >= width ) 225 | { 226 | mx = width - i; 227 | } 228 | for( y = 0; y < my; ++y ) 229 | { 230 | for( x = 0; x < mx; ++x ) 231 | { 232 | ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels]; 233 | ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step]; 234 | ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step]; 235 | ublock[idx++] = 236 | has_alpha * uncompressed[(j+y)*width*channels+(i+x)*channels+channels-1] 237 | + (1-has_alpha)*255; 238 | } 239 | for( x = mx; x < 4; ++x ) 240 | { 241 | ublock[idx++] = ublock[0]; 242 | ublock[idx++] = ublock[1]; 243 | ublock[idx++] = ublock[2]; 244 | ublock[idx++] = ublock[3]; 245 | } 246 | } 247 | for( y = my; y < 4; ++y ) 248 | { 249 | for( x = 0; x < 4; ++x ) 250 | { 251 | ublock[idx++] = ublock[0]; 252 | ublock[idx++] = ublock[1]; 253 | ublock[idx++] = ublock[2]; 254 | ublock[idx++] = ublock[3]; 255 | } 256 | } 257 | /* now compress the alpha block */ 258 | compress_DDS_alpha_block( ublock, cblock ); 259 | /* copy the data from the compressed alpha block into the main buffer */ 260 | for( x = 0; x < 8; ++x ) 261 | { 262 | compressed[index++] = cblock[x]; 263 | } 264 | /* then compress the color block */ 265 | ++block_count; 266 | compress_DDS_color_block( 4, ublock, cblock ); 267 | /* copy the data from the compressed color block into the main buffer */ 268 | for( x = 0; x < 8; ++x ) 269 | { 270 | compressed[index++] = cblock[x]; 271 | } 272 | } 273 | } 274 | return compressed; 275 | } 276 | 277 | /********* Helper Functions *********/ 278 | int convert_bit_range( int c, int from_bits, int to_bits ) 279 | { 280 | int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1); 281 | return (b + (b >> from_bits)) >> from_bits; 282 | } 283 | 284 | int rgb_to_565( int r, int g, int b ) 285 | { 286 | return 287 | (convert_bit_range( r, 8, 5 ) << 11) | 288 | (convert_bit_range( g, 8, 6 ) << 05) | 289 | (convert_bit_range( b, 8, 5 ) << 00); 290 | } 291 | 292 | void rgb_888_from_565( unsigned int c, int *r, int *g, int *b ) 293 | { 294 | *r = convert_bit_range( (c >> 11) & 31, 5, 8 ); 295 | *g = convert_bit_range( (c >> 05) & 63, 6, 8 ); 296 | *b = convert_bit_range( (c >> 00) & 31, 5, 8 ); 297 | } 298 | 299 | void compute_color_line_STDEV( 300 | const unsigned char *const uncompressed, 301 | int channels, 302 | float point[3], float direction[3] ) 303 | { 304 | const float inv_16 = 1.0f / 16.0f; 305 | int i; 306 | float sum_r = 0.0f, sum_g = 0.0f, sum_b = 0.0f; 307 | float sum_rr = 0.0f, sum_gg = 0.0f, sum_bb = 0.0f; 308 | float sum_rg = 0.0f, sum_rb = 0.0f, sum_gb = 0.0f; 309 | /* calculate all data needed for the covariance matrix 310 | ( to compare with _rygdxt code) */ 311 | for( i = 0; i < 16*channels; i += channels ) 312 | { 313 | sum_r += uncompressed[i+0]; 314 | sum_rr += uncompressed[i+0] * uncompressed[i+0]; 315 | sum_g += uncompressed[i+1]; 316 | sum_gg += uncompressed[i+1] * uncompressed[i+1]; 317 | sum_b += uncompressed[i+2]; 318 | sum_bb += uncompressed[i+2] * uncompressed[i+2]; 319 | sum_rg += uncompressed[i+0] * uncompressed[i+1]; 320 | sum_rb += uncompressed[i+0] * uncompressed[i+2]; 321 | sum_gb += uncompressed[i+1] * uncompressed[i+2]; 322 | } 323 | /* convert the sums to averages */ 324 | sum_r *= inv_16; 325 | sum_g *= inv_16; 326 | sum_b *= inv_16; 327 | /* and convert the squares to the squares of the value - avg_value */ 328 | sum_rr -= 16.0f * sum_r * sum_r; 329 | sum_gg -= 16.0f * sum_g * sum_g; 330 | sum_bb -= 16.0f * sum_b * sum_b; 331 | sum_rg -= 16.0f * sum_r * sum_g; 332 | sum_rb -= 16.0f * sum_r * sum_b; 333 | sum_gb -= 16.0f * sum_g * sum_b; 334 | /* the point on the color line is the average */ 335 | point[0] = sum_r; 336 | point[1] = sum_g; 337 | point[2] = sum_b; 338 | #if USE_COV_MAT 339 | /* 340 | The following idea was from ryg. 341 | (https://mollyrocket.com/forums/viewtopic.php?t=392) 342 | The method worked great (less RMSE than mine) most of 343 | the time, but had some issues handling some simple 344 | boundary cases, like full green next to full red, 345 | which would generate a covariance matrix like this: 346 | 347 | | 1 -1 0 | 348 | | -1 1 0 | 349 | | 0 0 0 | 350 | 351 | For a given starting vector, the power method can 352 | generate all zeros! So no starting with {1,1,1} 353 | as I was doing! This kind of error is still a 354 | slight posibillity, but will be very rare. 355 | */ 356 | /* use the covariance matrix directly 357 | (1st iteration, don't use all 1.0 values!) */ 358 | sum_r = 1.0f; 359 | sum_g = 2.718281828f; 360 | sum_b = 3.141592654f; 361 | direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; 362 | direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; 363 | direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; 364 | /* 2nd iteration, use results from the 1st guy */ 365 | sum_r = direction[0]; 366 | sum_g = direction[1]; 367 | sum_b = direction[2]; 368 | direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; 369 | direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; 370 | direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; 371 | /* 3rd iteration, use results from the 2nd guy */ 372 | sum_r = direction[0]; 373 | sum_g = direction[1]; 374 | sum_b = direction[2]; 375 | direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; 376 | direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; 377 | direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; 378 | #else 379 | /* use my standard deviation method 380 | (very robust, a tiny bit slower and less accurate) */ 381 | direction[0] = sqrt( sum_rr ); 382 | direction[1] = sqrt( sum_gg ); 383 | direction[2] = sqrt( sum_bb ); 384 | /* which has a greater component */ 385 | if( sum_gg > sum_rr ) 386 | { 387 | /* green has greater component, so base the other signs off of green */ 388 | if( sum_rg < 0.0f ) 389 | { 390 | direction[0] = -direction[0]; 391 | } 392 | if( sum_gb < 0.0f ) 393 | { 394 | direction[2] = -direction[2]; 395 | } 396 | } else 397 | { 398 | /* red has a greater component */ 399 | if( sum_rg < 0.0f ) 400 | { 401 | direction[1] = -direction[1]; 402 | } 403 | if( sum_rb < 0.0f ) 404 | { 405 | direction[2] = -direction[2]; 406 | } 407 | } 408 | #endif 409 | } 410 | 411 | void LSE_master_colors_max_min( 412 | int *cmax, int *cmin, 413 | int channels, 414 | const unsigned char *const uncompressed ) 415 | { 416 | int i, j; 417 | /* the master colors */ 418 | int c0[3], c1[3]; 419 | /* used for fitting the line */ 420 | float sum_x[] = { 0.0f, 0.0f, 0.0f }; 421 | float sum_x2[] = { 0.0f, 0.0f, 0.0f }; 422 | float dot_max = 1.0f, dot_min = -1.0f; 423 | float vec_len2 = 0.0f; 424 | float dot; 425 | /* error check */ 426 | if( (channels < 3) || (channels > 4) ) 427 | { 428 | return; 429 | } 430 | compute_color_line_STDEV( uncompressed, channels, sum_x, sum_x2 ); 431 | vec_len2 = 1.0f / ( 0.00001f + 432 | sum_x2[0]*sum_x2[0] + sum_x2[1]*sum_x2[1] + sum_x2[2]*sum_x2[2] ); 433 | /* finding the max and min vector values */ 434 | dot_max = 435 | ( 436 | sum_x2[0] * uncompressed[0] + 437 | sum_x2[1] * uncompressed[1] + 438 | sum_x2[2] * uncompressed[2] 439 | ); 440 | dot_min = dot_max; 441 | for( i = 1; i < 16; ++i ) 442 | { 443 | dot = 444 | ( 445 | sum_x2[0] * uncompressed[i*channels+0] + 446 | sum_x2[1] * uncompressed[i*channels+1] + 447 | sum_x2[2] * uncompressed[i*channels+2] 448 | ); 449 | if( dot < dot_min ) 450 | { 451 | dot_min = dot; 452 | } else if( dot > dot_max ) 453 | { 454 | dot_max = dot; 455 | } 456 | } 457 | /* and the offset (from the average location) */ 458 | dot = sum_x2[0]*sum_x[0] + sum_x2[1]*sum_x[1] + sum_x2[2]*sum_x[2]; 459 | dot_min -= dot; 460 | dot_max -= dot; 461 | /* post multiply by the scaling factor */ 462 | dot_min *= vec_len2; 463 | dot_max *= vec_len2; 464 | /* OK, build the master colors */ 465 | for( i = 0; i < 3; ++i ) 466 | { 467 | /* color 0 */ 468 | c0[i] = (int)(0.5f + sum_x[i] + dot_max * sum_x2[i]); 469 | if( c0[i] < 0 ) 470 | { 471 | c0[i] = 0; 472 | } else if( c0[i] > 255 ) 473 | { 474 | c0[i] = 255; 475 | } 476 | /* color 1 */ 477 | c1[i] = (int)(0.5f + sum_x[i] + dot_min * sum_x2[i]); 478 | if( c1[i] < 0 ) 479 | { 480 | c1[i] = 0; 481 | } else if( c1[i] > 255 ) 482 | { 483 | c1[i] = 255; 484 | } 485 | } 486 | /* down_sample (with rounding?) */ 487 | i = rgb_to_565( c0[0], c0[1], c0[2] ); 488 | j = rgb_to_565( c1[0], c1[1], c1[2] ); 489 | if( i > j ) 490 | { 491 | *cmax = i; 492 | *cmin = j; 493 | } else 494 | { 495 | *cmax = j; 496 | *cmin = i; 497 | } 498 | } 499 | 500 | void 501 | compress_DDS_color_block 502 | ( 503 | int channels, 504 | const unsigned char *const uncompressed, 505 | unsigned char compressed[8] 506 | ) 507 | { 508 | /* variables */ 509 | int i; 510 | int next_bit; 511 | int enc_c0, enc_c1; 512 | int c0[4], c1[4]; 513 | float color_line[] = { 0.0f, 0.0f, 0.0f, 0.0f }; 514 | float vec_len2 = 0.0f, dot_offset = 0.0f; 515 | /* stupid order */ 516 | int swizzle4[] = { 0, 2, 3, 1 }; 517 | /* get the master colors */ 518 | LSE_master_colors_max_min( &enc_c0, &enc_c1, channels, uncompressed ); 519 | /* store the 565 color 0 and color 1 */ 520 | compressed[0] = (enc_c0 >> 0) & 255; 521 | compressed[1] = (enc_c0 >> 8) & 255; 522 | compressed[2] = (enc_c1 >> 0) & 255; 523 | compressed[3] = (enc_c1 >> 8) & 255; 524 | /* zero out the compressed data */ 525 | compressed[4] = 0; 526 | compressed[5] = 0; 527 | compressed[6] = 0; 528 | compressed[7] = 0; 529 | /* reconstitute the master color vectors */ 530 | rgb_888_from_565( enc_c0, &c0[0], &c0[1], &c0[2] ); 531 | rgb_888_from_565( enc_c1, &c1[0], &c1[1], &c1[2] ); 532 | /* the new vector */ 533 | vec_len2 = 0.0f; 534 | for( i = 0; i < 3; ++i ) 535 | { 536 | color_line[i] = (float)(c1[i] - c0[i]); 537 | vec_len2 += color_line[i] * color_line[i]; 538 | } 539 | if( vec_len2 > 0.0f ) 540 | { 541 | vec_len2 = 1.0f / vec_len2; 542 | } 543 | /* pre-proform the scaling */ 544 | color_line[0] *= vec_len2; 545 | color_line[1] *= vec_len2; 546 | color_line[2] *= vec_len2; 547 | /* compute the offset (constant) portion of the dot product */ 548 | dot_offset = color_line[0]*c0[0] + color_line[1]*c0[1] + color_line[2]*c0[2]; 549 | /* store the rest of the bits */ 550 | next_bit = 8*4; 551 | for( i = 0; i < 16; ++i ) 552 | { 553 | /* find the dot product of this color, to place it on the line 554 | (should be [-1,1]) */ 555 | int next_value = 0; 556 | float dot_product = 557 | color_line[0] * uncompressed[i*channels+0] + 558 | color_line[1] * uncompressed[i*channels+1] + 559 | color_line[2] * uncompressed[i*channels+2] - 560 | dot_offset; 561 | /* map to [0,3] */ 562 | next_value = (int)( dot_product * 3.0f + 0.5f ); 563 | if( next_value > 3 ) 564 | { 565 | next_value = 3; 566 | } else if( next_value < 0 ) 567 | { 568 | next_value = 0; 569 | } 570 | /* OK, store this value */ 571 | compressed[next_bit >> 3] |= swizzle4[ next_value ] << (next_bit & 7); 572 | next_bit += 2; 573 | } 574 | /* done compressing to DXT1 */ 575 | } 576 | 577 | void 578 | compress_DDS_alpha_block 579 | ( 580 | const unsigned char *const uncompressed, 581 | unsigned char compressed[8] 582 | ) 583 | { 584 | /* variables */ 585 | int i; 586 | int next_bit; 587 | int a0, a1; 588 | float scale_me; 589 | /* stupid order */ 590 | int swizzle8[] = { 1, 7, 6, 5, 4, 3, 2, 0 }; 591 | /* get the alpha limits (a0 > a1) */ 592 | a0 = a1 = uncompressed[3]; 593 | for( i = 4+3; i < 16*4; i += 4 ) 594 | { 595 | if( uncompressed[i] > a0 ) 596 | { 597 | a0 = uncompressed[i]; 598 | } else if( uncompressed[i] < a1 ) 599 | { 600 | a1 = uncompressed[i]; 601 | } 602 | } 603 | /* store those limits, and zero the rest of the compressed dataset */ 604 | compressed[0] = a0; 605 | compressed[1] = a1; 606 | /* zero out the compressed data */ 607 | compressed[2] = 0; 608 | compressed[3] = 0; 609 | compressed[4] = 0; 610 | compressed[5] = 0; 611 | compressed[6] = 0; 612 | compressed[7] = 0; 613 | /* store the all of the alpha values */ 614 | next_bit = 8*2; 615 | scale_me = 7.9999f / (a0 - a1); 616 | for( i = 3; i < 16*4; i += 4 ) 617 | { 618 | /* convert this alpha value to a 3 bit number */ 619 | int svalue; 620 | int value = (int)((uncompressed[i] - a1) * scale_me); 621 | svalue = swizzle8[ value&7 ]; 622 | /* OK, store this value, start with the 1st byte */ 623 | compressed[next_bit >> 3] |= svalue << (next_bit & 7); 624 | if( (next_bit & 7) > 5 ) 625 | { 626 | /* spans 2 bytes, fill in the start of the 2nd byte */ 627 | compressed[1 + (next_bit >> 3)] |= svalue >> (8 - (next_bit & 7) ); 628 | } 629 | next_bit += 3; 630 | } 631 | /* done compressing to DXT1 */ 632 | } 633 | --------------------------------------------------------------------------------