From 08139ace98fbb322dff13a686c2140ecab6ebac5 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 1 Dec 2009 16:22:45 +0000 Subject: [PATCH 01/17] materials: Get the right blend function for alpha The correct blend function for the alpha channel is: GL_ONE, GL_ONE_MINUS_SRC_ALPHA As per bug 1406. This fix was dropped when the switch to premultiplied alpha was merged. --- cogl/cogl-material.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cogl/cogl-material.c b/cogl/cogl-material.c index 1a641a776..6c292ac67 100644 --- a/cogl/cogl-material.c +++ b/cogl/cogl-material.c @@ -106,7 +106,7 @@ _cogl_material_init_default_material (void) #ifndef HAVE_COGL_GLES material->blend_equation_rgb = GL_FUNC_ADD; material->blend_equation_alpha = GL_FUNC_ADD; - material->blend_src_factor_alpha = GL_SRC_ALPHA; + material->blend_src_factor_alpha = GL_ONE; material->blend_dst_factor_alpha = GL_ONE_MINUS_SRC_ALPHA; material->blend_constant[0] = 0; material->blend_constant[1] = 0; From db881bb3eeab7d059c4db72bcd701bb181a7a6ea Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 9 Dec 2009 23:32:18 +0000 Subject: [PATCH 02/17] Merge branch 'size-cache' into ebassi-next * size-cache: tests: Clean up the BoxLayout interactive test actor: Add debugging notes for size cache Add a cache of size requests From de5c84c4536f4d46ad555ec73895c90a2b773b14 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 4 Jan 2010 11:43:00 +0000 Subject: [PATCH 03/17] cogl: Const-ify vertices in cogl_polygon() The CoglTextureVertex array passed to cogl_polygon() is a pure in-argument and should be const-ified. http://bugzilla.openedhand.com/show_bug.cgi?id=1917 --- cogl/cogl-primitives.c | 27 ++++++++++++++------------- cogl/cogl-texture.h | 6 +++--- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/cogl/cogl-primitives.c b/cogl/cogl-primitives.c index 63bd382c6..e4fdf6a99 100644 --- a/cogl/cogl-primitives.c +++ b/cogl/cogl-primitives.c @@ -61,7 +61,7 @@ typedef struct _TextureSlicedQuadState typedef struct _TextureSlicedPolygonState { - CoglTextureVertex *vertices; + const CoglTextureVertex *vertices; int n_vertices; int stride; } TextureSlicedPolygonState; @@ -709,7 +709,7 @@ draw_polygon_sub_texture_cb (CoglHandle tex_handle, /* handles 2d-sliced textures with > 1 slice */ static void -_cogl_texture_polygon_multiple_primitives (CoglTextureVertex *vertices, +_cogl_texture_polygon_multiple_primitives (const CoglTextureVertex *vertices, unsigned int n_vertices, unsigned int stride, gboolean use_color) @@ -762,7 +762,7 @@ _cogl_texture_polygon_multiple_primitives (CoglTextureVertex *vertices, } static void -_cogl_multitexture_polygon_single_primitive (CoglTextureVertex *vertices, +_cogl_multitexture_polygon_single_primitive (const CoglTextureVertex *vertices, guint n_vertices, guint n_layers, guint stride, @@ -841,14 +841,13 @@ _cogl_multitexture_polygon_single_primitive (CoglTextureVertex *vertices, } void -cogl_polygon (CoglTextureVertex *vertices, - guint n_vertices, - gboolean use_color) +cogl_polygon (const CoglTextureVertex *vertices, + guint n_vertices, + gboolean use_color) { CoglHandle material; - const GList *layers; + const GList *layers, *tmp; int n_layers; - GList *tmp; gboolean use_sliced_polygon_fallback = FALSE; guint32 fallback_layers = 0; int i; @@ -871,10 +870,10 @@ cogl_polygon (CoglTextureVertex *vertices, layers = cogl_material_get_layers (ctx->source_material); n_layers = g_list_length ((GList *)layers); - for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) + for (tmp = layers, i = 0; tmp != NULL; tmp = tmp->next, i++) { - CoglHandle layer = (CoglHandle)tmp->data; - CoglHandle tex_handle = cogl_material_layer_get_texture (layer); + CoglHandle layer = tmp->data; + CoglHandle tex_handle = cogl_material_layer_get_texture (layer); /* COGL_INVALID_HANDLE textures will be handled in * _cogl_material_flush_layers_gl_state */ @@ -904,6 +903,7 @@ cogl_polygon (CoglTextureVertex *vertices, warning_seen = TRUE; } } + use_sliced_polygon_fallback = TRUE; n_layers = 1; @@ -990,9 +990,10 @@ cogl_polygon (CoglTextureVertex *vertices, /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ v + 3 + 2 * i)); } - prev_n_texcoord_arrays_enabled = - ctx->n_texcoord_arrays_enabled; + + prev_n_texcoord_arrays_enabled = ctx->n_texcoord_arrays_enabled; ctx->n_texcoord_arrays_enabled = n_layers; + for (; i < prev_n_texcoord_arrays_enabled; i++) { GE (glClientActiveTexture (GL_TEXTURE0 + i)); diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h index b831d1ae1..7859abd19 100644 --- a/cogl/cogl-texture.h +++ b/cogl/cogl-texture.h @@ -466,9 +466,9 @@ void cogl_rectangles (const float *verts, * * Since: 1.0 */ -void cogl_polygon (CoglTextureVertex *vertices, - guint n_vertices, - gboolean use_color); +void cogl_polygon (const CoglTextureVertex *vertices, + guint n_vertices, + gboolean use_color); G_END_DECLS From 2e510c4ef26858f2766db0f60c833e4c84833f03 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 4 Jan 2010 11:49:13 +0000 Subject: [PATCH 04/17] build: Maintainer cflags go in the _CFLAGS target The maintainer compiler flags are not pre-processor flags. --- cogl/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cogl/Makefile.am b/cogl/Makefile.am index c3b19c424..5ef3c3b9c 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -78,12 +78,11 @@ noinst_LTLIBRARIES = libclutter-cogl.la libclutter_cogl_la_CPPFLAGS = \ $(COGL_DEBUG_CFLAGS) \ $(CLUTTER_DEBUG_CFLAGS) \ - $(MAINTAINER_CFLAGS) \ -DG_DISABLE_SINGLE_INCLUDES \ -DG_LOG_DOMAIN=\"Cogl-$(COGL_WINSYS)\" \ -DCLUTTER_COMPILATION -libclutter_cogl_la_CFLAGS = $(CLUTTER_CFLAGS) +libclutter_cogl_la_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) libclutter_cogl_la_LIBADD = -lm $(CLUTTER_LIBS) \ $(top_builddir)/clutter/cogl/cogl/driver/$(COGL_DRIVER)/libclutter-cogl-driver.la From 9b441ec30954c7f9dffa1df5f2adac70076ccc26 Mon Sep 17 00:00:00 2001 From: Halton Huo Date: Mon, 4 Jan 2010 11:49:50 +0000 Subject: [PATCH 05/17] cogl-texture: Remove return in void functions http://bugzilla.o-hand.com/show_bug.cgi?id=1929 Signed-off-by: Emmanuele Bassi --- cogl/cogl-texture.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index 5b3950bc3..085a23f5b 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -334,8 +334,6 @@ cogl_texture_get_max_waste (CoglHandle handle) tex = COGL_TEXTURE (handle); return tex->vtable->get_max_waste (tex); - - g_return_val_if_reached (0); } gboolean @@ -408,7 +406,7 @@ _cogl_texture_transform_coords_to_gl (CoglHandle handle, { CoglTexture *tex = COGL_TEXTURE (handle); - return tex->vtable->transform_coords_to_gl (tex, s, t); + tex->vtable->transform_coords_to_gl (tex, s, t); } GLenum @@ -446,7 +444,7 @@ _cogl_texture_set_filters (CoglHandle handle, tex = COGL_TEXTURE (handle); - return tex->vtable->set_filters (tex, min_filter, mag_filter); + tex->vtable->set_filters (tex, min_filter, mag_filter); } void @@ -459,7 +457,7 @@ _cogl_texture_ensure_mipmaps (CoglHandle handle) tex = COGL_TEXTURE (handle); - return tex->vtable->ensure_mipmaps (tex); + tex->vtable->ensure_mipmaps (tex); } gboolean From ade4e5839d1c94941d7485ba1483b421e4e226e2 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 4 Jan 2010 11:58:32 +0000 Subject: [PATCH 06/17] build: Move CoglMatrixMode to cogl-matrix-stack.h This avoids a redeclaration of _cogl_matrix_stack_flush_to_gl() from using GLenum to CoglMatrixMode. http://bugzilla.openedhand.com/show_bug.cgi?id=1928 --- cogl/cogl-internal.h | 7 ------- cogl/cogl-matrix-stack.h | 9 +++++++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/cogl/cogl-internal.h b/cogl/cogl-internal.h index 714b75d19..585220a1d 100644 --- a/cogl/cogl-internal.h +++ b/cogl/cogl-internal.h @@ -27,13 +27,6 @@ #include "cogl.h" #include "cogl-matrix-stack.h" -typedef enum -{ - COGL_MATRIX_MODELVIEW, - COGL_MATRIX_PROJECTION, - COGL_MATRIX_TEXTURE -} CoglMatrixMode; - typedef enum { COGL_FRONT_WINDING_CLOCKWISE, diff --git a/cogl/cogl-matrix-stack.h b/cogl/cogl-matrix-stack.h index 648eace84..892e98cb0 100644 --- a/cogl/cogl-matrix-stack.h +++ b/cogl/cogl-matrix-stack.h @@ -28,10 +28,15 @@ #define __COGL_MATRIX_STACK_H #include "cogl-matrix.h" -#include "cogl.h" /* needed for GLenum */ typedef struct _CoglMatrixStack CoglMatrixStack; +typedef enum { + COGL_MATRIX_MODELVIEW, + COGL_MATRIX_PROJECTION, + COGL_MATRIX_TEXTURE +} CoglMatrixMode; + CoglMatrixStack* _cogl_matrix_stack_new (void); void _cogl_matrix_stack_destroy (CoglMatrixStack *stack); void _cogl_matrix_stack_push (CoglMatrixStack *stack); @@ -79,7 +84,7 @@ void _cogl_matrix_stack_get (CoglMatrixStack *stack, void _cogl_matrix_stack_set (CoglMatrixStack *stack, const CoglMatrix *matrix); void _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, - GLenum gl_mode); + CoglMatrixMode mode); void _cogl_matrix_stack_dirty (CoglMatrixStack *stack); #endif /* __COGL_MATRIX_STACK_H */ From 928e1adc3d26ae648b5b7bad617c700e0aec65eb Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 5 Jan 2010 16:11:45 +0000 Subject: [PATCH 07/17] cogl: Fix array annotations The arrays in the cogl_program_set_uniform_* API should be marked as such, and have their length arguments specified. --- cogl/cogl-shader.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cogl/cogl-shader.h b/cogl/cogl-shader.h index 9eec9bb40..2bb082d35 100644 --- a/cogl/cogl-shader.h +++ b/cogl/cogl-shader.h @@ -265,22 +265,22 @@ void cogl_program_uniform_1i (int uniform_no, * @uniform_no: the uniform to set. * @size: Size of float vector. * @count: Size of array of uniforms. - * @value: the new value of the uniform. + * @value: (array length=count): the new value of the uniform. * * Changes the value of a float vector uniform, or uniform array in the - * currently used (see #cogl_program_use) shader program. + * currently used (see cogl_program_use()) shader program. */ -void cogl_program_uniform_float (int uniform_no, - int size, - int count, - const GLfloat *value); +void cogl_program_uniform_float (int uniform_no, + int size, + int count, + const GLfloat *value); /** * cogl_program_uniform_int: * @uniform_no: the uniform to set. * @size: Size of int vector. * @count: Size of array of uniforms. - * @value: the new value of the uniform. + * @value: (array length=count): the new value of the uniform. * * Changes the value of a int vector uniform, or uniform array in the * currently used (see cogl_program_use()) shader program. @@ -296,7 +296,7 @@ void cogl_program_uniform_int (int uniform_no, * @size: Size of matrix. * @count: Size of array of uniforms. * @transpose: Whether to transpose the matrix when setting the uniform. - * @value: the new value of the uniform. + * @value: (array length=count): the new value of the uniform. * * Changes the value of a matrix uniform, or uniform array in the * currently used (see cogl_program_use()) shader program. The @size From 932a9e16abccfd409f14f6fa8977923a9fdcacdb Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 5 Jan 2010 17:54:45 +0000 Subject: [PATCH 08/17] Include cogl-defines.h before using GL types If we are using GL* types we should also be including cogl-defines.h, as that will include the right GL header. --- cogl/cogl-shader.h | 1 + cogl/cogl-texture.h | 1 + 2 files changed, 2 insertions(+) diff --git a/cogl/cogl-shader.h b/cogl/cogl-shader.h index 2bb082d35..4e2ccb97b 100644 --- a/cogl/cogl-shader.h +++ b/cogl/cogl-shader.h @@ -29,6 +29,7 @@ #define __COGL_SHADER_H__ #include +#include G_BEGIN_DECLS diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h index 7859abd19..eaf3e5482 100644 --- a/cogl/cogl-texture.h +++ b/cogl/cogl-texture.h @@ -29,6 +29,7 @@ #define __COGL_TEXTURE_H__ #include +#include G_BEGIN_DECLS From e9c4a0467b8f65531e5f8670332f3c7af07359ee Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 5 Jan 2010 18:02:29 +0000 Subject: [PATCH 09/17] Covert stb_image.c to Unix format The file is still in DOS format (CRLF instead of LF) and this confuses the hell out of some versions of Git. --- cogl/stb_image.c | 7544 +++++++++++++++++++++++----------------------- 1 file changed, 3772 insertions(+), 3772 deletions(-) diff --git a/cogl/stb_image.c b/cogl/stb_image.c index bd3e63b35..c6f8d730d 100644 --- a/cogl/stb_image.c +++ b/cogl/stb_image.c @@ -1,3772 +1,3772 @@ -/* stbi-1.12 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c - when you control the images you're loading - - QUICK NOTES: - Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface - - JPEG baseline (no JPEG progressive, no oddball channel decimations) - PNG non-interlaced - BMP non-1bpp, non-RLE - TGA (not sure what subset, if a subset) - PSD (composited view only, no extra channels) - HDR (radiance rgbE format) - writes BMP,TGA (define STBI_NO_WRITE to remove code) - decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code) - supports installable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) - - TODO: - stbi_info_* - - history: - 1.12 const qualifiers in the API - 1.11 Support installable IDCT, colorspace conversion routines - 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen - 1.09 Fix format-conversion for PSD code (bad global variables!) - 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz - 1.07 attempt to fix C++ warning/errors again - 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) - 0.97 jpeg errors on too large a file; also catch another malloc failure - 0.96 fix detection of invalid v value - particleman@mollyrocket forum - 0.95 during header scan, seek to markers in case of padding - 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same - 0.93 handle jpegtran output; verbose errors - 0.92 read 4,8,16,24,32-bit BMP files of several formats - 0.91 output 24-bit Windows 3.0 BMP files - 0.90 fix a few more warnings; bump version number to approach 1.0 - 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd - 0.60 fix compiling as c++ - 0.59 fix warnings: merge Dave Moore's -Wall fixes - 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less - than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen - 0.55 fix bug: restart_interval not initialized to 0 - 0.54 allow NULL for 'int *comp' - 0.53 fix bug in png 3->4; speedup png decoding - 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments - 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant -*/ - - -//// begin header file //////////////////////////////////////////////////// -// -// Limitations: -// - no progressive/interlaced support (jpeg, png) -// - 8-bit samples only (jpeg, png) -// - not threadsafe -// - channel subsampling of at most 2 in each dimension (jpeg) -// - no delayed line count (jpeg) -- IJG doesn't support either -// -// Basic usage (see HDR discussion below): -// int x,y,n; -// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); -// // ... process data if not NULL ... -// // ... x = width, y = height, n = # 8-bit components per pixel ... -// // ... replace '0' with '1'..'4' to force that many components per pixel -// stbi_image_free(data) -// -// Standard parameters: -// int *x -- outputs image width in pixels -// int *y -- outputs image height in pixels -// int *comp -- outputs # of image components in image file -// int req_comp -- if non-zero, # of image components requested in result -// -// The return value from an image loader is an 'unsigned char *' which points -// to the pixel data. The pixel data consists of *y scanlines of *x pixels, -// with each pixel consisting of N interleaved 8-bit components; the first -// pixel pointed to is top-left-most in the image. There is no padding between -// image scanlines or between pixels, regardless of format. The number of -// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. -// If req_comp is non-zero, *comp has the number of components that _would_ -// have been output otherwise. E.g. if you set req_comp to 4, you will always -// get RGBA output, but you can check *comp to easily see if it's opaque. -// -// An output image with N components has the following components interleaved -// in this order in each pixel: -// -// N=#comp components -// 1 grey -// 2 grey, alpha -// 3 red, green, blue -// 4 red, green, blue, alpha -// -// If image loading fails for any reason, the return value will be NULL, -// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() -// can be queried for an extremely brief, end-user unfriendly explanation -// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid -// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly -// more user-friendly ones. -// -// Paletted PNG and BMP images are automatically depalettized. -// -// -// =========================================================================== -// -// HDR image support (disable by defining STBI_NO_HDR) -// -// stb_image now supports loading HDR images in general, and currently -// the Radiance .HDR file format, although the support is provided -// generically. You can still load any file through the existing interface; -// if you attempt to load an HDR file, it will be automatically remapped to -// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; -// both of these constants can be reconfigured through this interface: -// -// stbi_hdr_to_ldr_gamma(2.2f); -// stbi_hdr_to_ldr_scale(1.0f); -// -// (note, do not use _inverse_ constants; stbi_image will invert them -// appropriately). -// -// Additionally, there is a new, parallel interface for loading files as -// (linear) floats to preserve the full dynamic range: -// -// float *data = stbi_loadf(filename, &x, &y, &n, 0); -// -// If you load LDR images through this interface, those images will -// be promoted to floating point values, run through the inverse of -// constants corresponding to the above: -// -// stbi_ldr_to_hdr_scale(1.0f); -// stbi_ldr_to_hdr_gamma(2.2f); -// -// Finally, given a filename (or an open file or memory block--see header -// file for details) containing image data, you can query for the "most -// appropriate" interface to use (that is, whether the image is HDR or -// not), using: -// -// stbi_is_hdr(char *filename); - - -#ifndef STBI_NO_STDIO -#include -#endif - -#ifndef STBI_NO_HDR -#include // ldexp -#include // strcmp -#endif - -enum -{ - STBI_default = 0, // only used for req_comp - - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4, -}; - -typedef unsigned char stbi_uc; - -#ifdef __cplusplus -extern "C" { -#endif - -// WRITING API - -#if !defined(STBI_NO_WRITE) && !defined(STBI_NO_STDIO) -// write a BMP/TGA file given tightly packed 'comp' channels (no padding, nor bmp-stride-padding) -// (you must include the appropriate extension in the filename). -// returns TRUE on success, FALSE if couldn't open file, error writing file -extern int stbi_write_bmp (char const *filename, int x, int y, int comp, void *data); -extern int stbi_write_tga (char const *filename, int x, int y, int comp, void *data); -#endif - -// PRIMARY API - works on images of any type - -// load image by filename, open file, or memory buffer -#ifndef STBI_NO_STDIO -extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); -#endif -extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); -// for stbi_load_from_file, file pointer is left pointing immediately after image - -#ifndef STBI_NO_HDR -#ifndef STBI_NO_STDIO -extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); -extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -#endif -extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - -extern void stbi_hdr_to_ldr_gamma(float gamma); -extern void stbi_hdr_to_ldr_scale(float scale); - -extern void stbi_ldr_to_hdr_gamma(float gamma); -extern void stbi_ldr_to_hdr_scale(float scale); - -#endif // STBI_NO_HDR - -// get a VERY brief reason for failure -extern char *stbi_failure_reason (void); - -// free the loaded image -- this is just free() -extern void stbi_image_free (void *retval_from_stbi_load); - -// get image dimensions & components without fully decoding -extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); -#ifndef STBI_NO_STDIO -extern int stbi_info (char const *filename, int *x, int *y, int *comp); -extern int stbi_is_hdr (char const *filename); -extern int stbi_is_hdr_from_file(FILE *f); -#endif - -// ZLIB client - used by PNG, available for other purposes - -extern char *stbi_zlib_decode_malloc_guesssize(int initial_size, int *outlen); -extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -// TYPE-SPECIFIC ACCESS - -// is it a jpeg? -extern int stbi_jpeg_test_memory (stbi_uc const *buffer, int len); -extern stbi_uc *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); -extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); - -#ifndef STBI_NO_STDIO -extern stbi_uc *stbi_jpeg_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern int stbi_jpeg_test_file (FILE *f); -extern stbi_uc *stbi_jpeg_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); - -extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp); -extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp); -#endif - -extern int stbi_jpeg_dc_only; // only decode DC component - -// is it a png? -extern int stbi_png_test_memory (stbi_uc const *buffer, int len); -extern stbi_uc *stbi_png_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); -extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); - -#ifndef STBI_NO_STDIO -extern stbi_uc *stbi_png_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern int stbi_png_info (char const *filename, int *x, int *y, int *comp); -extern int stbi_png_test_file (FILE *f); -extern stbi_uc *stbi_png_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp); -#endif - -// is it a bmp? -extern int stbi_bmp_test_memory (stbi_uc const *buffer, int len); - -extern stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); -#ifndef STBI_NO_STDIO -extern int stbi_bmp_test_file (FILE *f); -extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -#endif - -// is it a tga? -extern int stbi_tga_test_memory (stbi_uc const *buffer, int len); - -extern stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); -#ifndef STBI_NO_STDIO -extern int stbi_tga_test_file (FILE *f); -extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -#endif - -// is it a psd? -extern int stbi_psd_test_memory (stbi_uc const *buffer, int len); - -extern stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); -#ifndef STBI_NO_STDIO -extern int stbi_psd_test_file (FILE *f); -extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -#endif - -// is it an hdr? -extern int stbi_hdr_test_memory (stbi_uc const *buffer, int len); - -extern float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp); -extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); -#ifndef STBI_NO_STDIO -extern int stbi_hdr_test_file (FILE *f); -extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -#endif - -// define new loaders -typedef struct -{ - int (*test_memory)(stbi_uc const *buffer, int len); - stbi_uc * (*load_from_memory)(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - #ifndef STBI_NO_STDIO - int (*test_file)(FILE *f); - stbi_uc * (*load_from_file)(FILE *f, int *x, int *y, int *comp, int req_comp); - #endif -} stbi_loader; - -// register a loader by filling out the above structure (you must defined ALL functions) -// returns 1 if added or already added, 0 if not added (too many loaders) -extern int stbi_register_loader(stbi_loader *loader); - -// define faster low-level operations (typically SIMD support) -#if STBI_SIMD -typedef void (*stbi_idct_8x8)(uint8 *out, int out_stride, short data[64], unsigned short *dequantize); -// compute an integer IDCT on "input" -// input[x] = data[x] * dequantize[x] -// write results to 'out': 64 samples, each run of 8 spaced by 'out_stride' -// CLAMP results to 0..255 -typedef void (*stbi_YCbCr_to_RGB_run)(uint8 *output, uint8 const *y, uint8 const *cb, uint8 const *cr, int count, int step); -// compute a conversion from YCbCr to RGB -// 'count' pixels -// write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B -// y: Y input channel -// cb: Cb input channel; scale/biased to be 0..255 -// cr: Cr input channel; scale/biased to be 0..255 - -extern void stbi_install_idct(stbi_idct_8x8 func); -extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func); -#endif // STBI_SIMD - -#ifdef __cplusplus -} -#endif - -// -// -//// end header file ///////////////////////////////////////////////////// - -#ifndef STBI_NO_STDIO -#include -#endif -#include -#include -#include -#include - -#if STBI_SIMD -#include -#endif - -#ifndef _MSC_VER -#define __forceinline -#endif - - -// implementation: -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef signed short int16; -typedef unsigned int uint32; -typedef signed int int32; -typedef unsigned int uint; - -// should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(uint32)==4]; - -#if defined(STBI_NO_STDIO) && !defined(STBI_NO_WRITE) -#define STBI_NO_WRITE -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// Generic API that works on all image types -// - -static char *failure_reason; - -char *stbi_failure_reason(void) -{ - return failure_reason; -} - -static int e(char *str) -{ - failure_reason = str; - return 0; -} - -#ifdef STBI_NO_FAILURE_STRINGS - #define e(x,y) 0 -#elif defined(STBI_FAILURE_USERMSG) - #define e(x,y) e(y) -#else - #define e(x,y) e(x) -#endif - -#define epf(x,y) ((float *) (e(x,y)?NULL:NULL)) -#define epuc(x,y) ((unsigned char *) (e(x,y)?NULL:NULL)) - -void stbi_image_free(void *retval_from_stbi_load) -{ - free(retval_from_stbi_load); -} - -#define MAX_LOADERS 32 -stbi_loader *loaders[MAX_LOADERS]; -static int max_loaders = 0; - -int stbi_register_loader(stbi_loader *loader) -{ - int i; - for (i=0; i < MAX_LOADERS; ++i) { - // already present? - if (loaders[i] == loader) - return 1; - // end of the list? - if (loaders[i] == NULL) { - loaders[i] = loader; - max_loaders = i+1; - return 1; - } - } - // no room for it - return 0; -} - -#ifndef STBI_NO_HDR -static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp); -static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp); -#endif - -#ifndef STBI_NO_STDIO -unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = fopen(filename, "rb"); - unsigned char *result; - if (!f) return epuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - int i; - if (stbi_jpeg_test_file(f)) - return stbi_jpeg_load_from_file(f,x,y,comp,req_comp); - if (stbi_png_test_file(f)) - return stbi_png_load_from_file(f,x,y,comp,req_comp); - if (stbi_bmp_test_file(f)) - return stbi_bmp_load_from_file(f,x,y,comp,req_comp); - if (stbi_psd_test_file(f)) - return stbi_psd_load_from_file(f,x,y,comp,req_comp); - #ifndef STBI_NO_HDR - if (stbi_hdr_test_file(f)) { - float *hdr = stbi_hdr_load_from_file(f, x,y,comp,req_comp); - return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif - for (i=0; i < max_loaders; ++i) - if (loaders[i]->test_file(f)) - return loaders[i]->load_from_file(f,x,y,comp,req_comp); - // test tga last because it's a crappy test! - if (stbi_tga_test_file(f)) - return stbi_tga_load_from_file(f,x,y,comp,req_comp); - return epuc("unknown image type", "Image not of any known type, or corrupt"); -} -#endif - -unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - int i; - if (stbi_jpeg_test_memory(buffer,len)) - return stbi_jpeg_load_from_memory(buffer,len,x,y,comp,req_comp); - if (stbi_png_test_memory(buffer,len)) - return stbi_png_load_from_memory(buffer,len,x,y,comp,req_comp); - if (stbi_bmp_test_memory(buffer,len)) - return stbi_bmp_load_from_memory(buffer,len,x,y,comp,req_comp); - if (stbi_psd_test_memory(buffer,len)) - return stbi_psd_load_from_memory(buffer,len,x,y,comp,req_comp); - #ifndef STBI_NO_HDR - if (stbi_hdr_test_memory(buffer, len)) { - float *hdr = stbi_hdr_load_from_memory(buffer, len,x,y,comp,req_comp); - return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif - for (i=0; i < max_loaders; ++i) - if (loaders[i]->test_memory(buffer,len)) - return loaders[i]->load_from_memory(buffer,len,x,y,comp,req_comp); - // test tga last because it's a crappy test! - if (stbi_tga_test_memory(buffer,len)) - return stbi_tga_load_from_memory(buffer,len,x,y,comp,req_comp); - return epuc("unknown image type", "Image not of any known type, or corrupt"); -} - -#ifndef STBI_NO_HDR - -#ifndef STBI_NO_STDIO -float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = fopen(filename, "rb"); - float *result; - if (!f) return epf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi_hdr_test_file(f)) - return stbi_hdr_load_from_file(f,x,y,comp,req_comp); - #endif - data = stbi_load_from_file(f, x, y, comp, req_comp); - if (data) - return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return epf("unknown image type", "Image not of any known type, or corrupt"); -} -#endif - -float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *data; - #ifndef STBI_NO_HDR - if (stbi_hdr_test_memory(buffer, len)) - return stbi_hdr_load_from_memory(buffer, len,x,y,comp,req_comp); - #endif - data = stbi_load_from_memory(buffer, len, x, y, comp, req_comp); - if (data) - return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return epf("unknown image type", "Image not of any known type, or corrupt"); -} -#endif - -// these is-hdr-or-not is defined independent of whether STBI_NO_HDR is -// defined, for API simplicity; if STBI_NO_HDR is defined, it always -// reports false! - -extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - return stbi_hdr_test_memory(buffer, len); - #else - return 0; - #endif -} - -#ifndef STBI_NO_STDIO -extern int stbi_is_hdr (char const *filename) -{ - FILE *f = fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; -} - -extern int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - return stbi_hdr_test_file(f); - #else - return 0; - #endif -} - -#endif - -// @TODO: get image dimensions & components without fully decoding -#ifndef STBI_NO_STDIO -extern int stbi_info (char const *filename, int *x, int *y, int *comp); -extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); -#endif -extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); - -#ifndef STBI_NO_HDR -static float h2l_gamma_i=1.0f/2.2f, h2l_scale_i=1.0f; -static float l2h_gamma=2.2f, l2h_scale=1.0f; - -void stbi_hdr_to_ldr_gamma(float gamma) { h2l_gamma_i = 1/gamma; } -void stbi_hdr_to_ldr_scale(float scale) { h2l_scale_i = 1/scale; } - -void stbi_ldr_to_hdr_gamma(float gamma) { l2h_gamma = gamma; } -void stbi_ldr_to_hdr_scale(float scale) { l2h_scale = scale; } -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// Common code used by all image loaders -// - -// image width, height, # components -static uint32 img_x, img_y; -static int img_n, img_out_n; - -enum -{ - SCAN_load=0, - SCAN_type, - SCAN_header, -}; - -// An API for reading either from memory or file. -#ifndef STBI_NO_STDIO -static FILE *img_file; -#endif -static uint8 const *img_buffer, *img_buffer_end; - -#ifndef STBI_NO_STDIO -static void start_file(FILE *f) -{ - img_file = f; -} -#endif - -static void start_mem(uint8 const *buffer, int len) -{ -#ifndef STBI_NO_STDIO - img_file = NULL; -#endif - img_buffer = buffer; - img_buffer_end = buffer+len; -} - -static int get8(void) -{ -#ifndef STBI_NO_STDIO - if (img_file) { - int c = fgetc(img_file); - return c == EOF ? 0 : c; - } -#endif - if (img_buffer < img_buffer_end) - return *img_buffer++; - return 0; -} - -static int at_eof(void) -{ -#ifndef STBI_NO_STDIO - if (img_file) - return feof(img_file); -#endif - return img_buffer >= img_buffer_end; -} - -static uint8 get8u(void) -{ - return (uint8) get8(); -} - -static void skip(int n) -{ -#ifndef STBI_NO_STDIO - if (img_file) - fseek(img_file, n, SEEK_CUR); - else -#endif - img_buffer += n; -} - -static int get16(void) -{ - int z = get8(); - return (z << 8) + get8(); -} - -static uint32 get32(void) -{ - uint32 z = get16(); - return (z << 16) + get16(); -} - -static int get16le(void) -{ - int z = get8(); - return z + (get8() << 8); -} - -static uint32 get32le(void) -{ - uint32 z = get16le(); - return z + (get16le() << 16); -} - -static void getn(stbi_uc *buffer, int n) -{ -#ifndef STBI_NO_STDIO - if (img_file) { - fread(buffer, 1, n, img_file); - return; - } -#endif - memcpy(buffer, img_buffer, n); - img_buffer += n; -} - -////////////////////////////////////////////////////////////////////////////// -// -// generic converter from built-in img_n to req_comp -// individual types do this automatically as much as possible (e.g. jpeg -// does all cases internally since it needs to colorspace convert anyway, -// and it never has alpha, so very few cases ). png can automatically -// interleave an alpha=255 channel, but falls back to this for other cases -// -// assume data buffer is malloced, so malloc a new one and free that one -// only failure mode is malloc failing - -static uint8 compute_y(int r, int g, int b) -{ - return (uint8) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static unsigned char *convert_format(unsigned char *data, int img_n, int req_comp) -{ - uint i,j; - unsigned char *good; - - if (req_comp == img_n) return data; - assert(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) malloc(req_comp * img_x * img_y); - if (good == NULL) { - free(data); - return epuc("outofmem", "Out of memory"); - } - - for (j=0; j < img_y; ++j) { - unsigned char *src = data + j * img_x * img_n ; - unsigned char *dest = good + j * img_x * req_comp; - - #define COMBO(a,b) ((a)*8+(b)) - #define CASE(a,b) case COMBO(a,b): for(i=0; i < img_x; ++i, src += a, dest += b) - - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch(COMBO(img_n, req_comp)) { - CASE(1,2) dest[0]=src[0], dest[1]=255; break; - CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; - CASE(2,1) dest[0]=src[0]; break; - CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; - CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; - CASE(3,1) dest[0]=compute_y(src[0],src[1],src[2]); break; - CASE(3,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = 255; break; - CASE(4,1) dest[0]=compute_y(src[0],src[1],src[2]); break; - CASE(4,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; - CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; - default: assert(0); - } - #undef CASE - } - - free(data); - img_out_n = req_comp; - return good; -} - -#ifndef STBI_NO_HDR -static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output = (float *) malloc(x * y * comp * sizeof(float)); - if (output == NULL) { free(data); return epf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) pow(data[i*comp+k]/255.0f, l2h_gamma) * l2h_scale; - } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; - } - free(data); - return output; -} - -#define float2int(x) ((int) (x)) -static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output = (stbi_uc *) malloc(x * y * comp); - if (output == NULL) { free(data); return epuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*h2l_scale_i, h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = float2int(z); - } - } - free(data); - return output; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// "baseline" JPEG/JFIF decoder (not actually fully baseline implementation) -// -// simple implementation -// - channel subsampling of at most 2 in each dimension -// - doesn't support delayed output of y-dimension -// - simple interface (only one output format: 8-bit interleaved RGB) -// - doesn't try to recover corrupt jpegs -// - doesn't allow partial loading, loading multiple at once -// - still fast on x86 (copying globals into locals doesn't help x86) -// - allocates lots of intermediate memory (full size of all components) -// - non-interleaved case requires this anyway -// - allows good upsampling (see next) -// high-quality -// - upsampled channels are bilinearly interpolated, even across blocks -// - quality integer IDCT derived from IJG's 'slow' -// performance -// - fast huffman; reasonable integer IDCT -// - uses a lot of intermediate memory, could cache poorly -// - load http://nothings.org/remote/anemones.jpg 3 times on 2.8Ghz P4 -// stb_jpeg: 1.34 seconds (MSVC6, default release build) -// stb_jpeg: 1.06 seconds (MSVC6, processor = Pentium Pro) -// IJL11.dll: 1.08 seconds (compiled by intel) -// IJG 1998: 0.98 seconds (MSVC6, makefile provided by IJG) -// IJG 1998: 0.95 seconds (MSVC6, makefile + proc=PPro) - -int stbi_jpeg_dc_only; - -// huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache - -typedef struct -{ - uint8 fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - uint16 code[256]; - uint8 values[256]; - uint8 size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' -} huffman; - -static huffman huff_dc[4]; // baseline is 2 tables, extended is 4 -static huffman huff_ac[4]; -static uint8 dequant[4][64]; -#if STBI_SIMD -static __declspec(align(16)) unsigned short dequant2[4][64]; -#endif - -static int build_huffman(huffman *h, int *count) -{ - int i,j,k=0,code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (uint8) (i+1); - h->size[k] = 0; - - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (uint16) (code++); - if (code-1 >= (1 << j)) return e("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; - - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (uint8) i; - } - } - } - return 1; -} - -// sizes for components, interleaved MCUs -static int img_h_max, img_v_max; -static int img_mcu_x, img_mcu_y; -static int img_mcu_w, img_mcu_h; - -// definition of jpeg image component -static struct -{ - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; - - int x,y,w2,h2; - uint8 *data; - void *raw_data; - uint8 *linebuf; -} img_comp[4]; - -static uint32 code_buffer; // jpeg entropy-coded buffer -static int code_bits; // number of valid bits -static unsigned char marker; // marker seen while filling entropy buffer -static int nomore; // flag if we saw a marker so must stop - -static void grow_buffer_unsafe(void) -{ - do { - int b = nomore ? 0 : get8(); - if (b == 0xff) { - int c = get8(); - if (c != 0) { - marker = (unsigned char) c; - nomore = 1; - return; - } - } - code_buffer = (code_buffer << 8) | b; - code_bits += 8; - } while (code_bits <= 24); -} - -// (1 << n) - 1 -static uint32 bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; - -// decode a jpeg huffman value from the bitstream -__forceinline static int decode(huffman *h) -{ - unsigned int temp; - int c,k; - - if (code_bits < 16) grow_buffer_unsafe(); - - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (code_buffer >> (code_bits - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - if (h->size[k] > code_bits) - return -1; - code_bits -= h->size[k]; - return h->values[k]; - } - - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - if (code_bits < 16) - temp = (code_buffer << (16 - code_bits)) & 0xffff; - else - temp = (code_buffer >> (code_bits - 16)) & 0xffff; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - code_bits -= 16; - return -1; - } - - if (k > code_bits) - return -1; - - // convert the huffman code to the symbol id - c = ((code_buffer >> (code_bits - k)) & bmask[k]) + h->delta[k]; - assert((((code_buffer) >> (code_bits - h->size[c])) & bmask[h->size[c]]) == h->code[c]); - - // convert the id to a symbol - code_bits -= k; - return h->values[c]; -} - -// combined JPEG 'receive' and JPEG 'extend', since baseline -// always extends everything it receives. -__forceinline static int extend_receive(int n) -{ - unsigned int m = 1 << (n-1); - unsigned int k; - if (code_bits < n) grow_buffer_unsafe(); - k = (code_buffer >> (code_bits - n)) & bmask[n]; - code_bits -= n; - // the following test is probably a random branch that won't - // predict well. I tried to table accelerate it but failed. - // maybe it's compiling as a conditional move? - if (k < m) - return (-1 << n) + k + 1; - else - return k; -} - -// given a value that's at position X in the zigzag stream, -// where does it appear in the 8x8 matrix coded as row-major? -static uint8 dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; - -// decode one 64-entry block-- -static int decode_block(short data[64], huffman *hdc, huffman *hac, int b) -{ - int diff,dc,k; - int t = decode(hdc); - if (t < 0) return e("bad huffman code","Corrupt JPEG"); - - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); - - diff = t ? extend_receive(t) : 0; - dc = img_comp[b].dc_pred + diff; - img_comp[b].dc_pred = dc; - data[0] = (short) dc; - - // decode AC components, see JPEG spec - k = 1; - do { - int r,s; - int rs = decode(hac); - if (rs < 0) return e("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - data[dezigzag[k++]] = (short) extend_receive(s); - } - } while (k < 64); - return 1; -} - -// take a -128..127 value and clamp it and convert to 0..255 -__forceinline static uint8 clamp(int x) -{ - x += 128; - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (uint8) x; -} - -#define f2f(x) (int) (((x) * 4096 + 0.5)) -#define fsh(x) ((x) << 12) - -// derived from jidctint -- DCT_ISLOW -#define IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * f2f(0.5411961f); \ - t2 = p1 + p3*f2f(-1.847759065f); \ - t3 = p1 + p2*f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = fsh(p2+p3); \ - t1 = fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*f2f( 1.175875602f); \ - t0 = t0*f2f( 0.298631336f); \ - t1 = t1*f2f( 2.053119869f); \ - t2 = t2*f2f( 3.072711026f); \ - t3 = t3*f2f( 1.501321110f); \ - p1 = p5 + p1*f2f(-0.899976223f); \ - p2 = p5 + p2*f2f(-2.562915447f); \ - p3 = p3*f2f(-1.961570560f); \ - p4 = p4*f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; - -#if !STBI_SIMD -// .344 seconds on 3*anemones.jpg -static void idct_block(uint8 *out, int out_stride, short data[64], uint8 *dequantize) -{ - int i,val[64],*v=val; - uint8 *o,*dq = dequantize; - short *d = data; - - if (stbi_jpeg_dc_only) { - // ok, I don't really know why this is right, but it seems to be: - int z = 128 + ((d[0] * dq[0]) >> 3); - for (i=0; i < 8; ++i) { - out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = out[7] = z; - out += out_stride; - } - return; - } - - // columns - for (i=0; i < 8; ++i,++d,++dq, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0] * dq[0] << 2; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24], - d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } - - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - x0 += 65536; x1 += 65536; x2 += 65536; x3 += 65536; - o[0] = clamp((x0+t3) >> 17); - o[7] = clamp((x0-t3) >> 17); - o[1] = clamp((x1+t2) >> 17); - o[6] = clamp((x1-t2) >> 17); - o[2] = clamp((x2+t1) >> 17); - o[5] = clamp((x2-t1) >> 17); - o[3] = clamp((x3+t0) >> 17); - o[4] = clamp((x3-t0) >> 17); - } -} -#else -static void idct_block(uint8 *out, int out_stride, short data[64], unsigned short *dequantize) -{ - int i,val[64],*v=val; - uint8 *o; - unsigned short *dq = dequantize; - short *d = data; - - if (stbi_jpeg_dc_only) { - // ok, I don't really know why this is right, but it seems to be: - int z = 128 + ((d[0] * dq[0]) >> 3); - for (i=0; i < 8; ++i) { - out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = out[7] = z; - out += out_stride; - } - return; - } - - // columns - for (i=0; i < 8; ++i,++d,++dq, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0] * dq[0] << 2; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24], - d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } - - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - x0 += 65536; x1 += 65536; x2 += 65536; x3 += 65536; - o[0] = clamp((x0+t3) >> 17); - o[7] = clamp((x0-t3) >> 17); - o[1] = clamp((x1+t2) >> 17); - o[6] = clamp((x1-t2) >> 17); - o[2] = clamp((x2+t1) >> 17); - o[5] = clamp((x2-t1) >> 17); - o[3] = clamp((x3+t0) >> 17); - o[4] = clamp((x3-t0) >> 17); - } -} -static stbi_idct_8x8 stbi_idct_installed = idct_block; - -extern void stbi_install_idct(stbi_idct_8x8 func) -{ - stbi_idct_installed = func; -} -#endif - -#define MARKER_none 0xff -// if there's a pending marker from the entropy stream, return that -// otherwise, fetch from the stream and get a marker. if there's no -// marker, return 0xff, which is never a valid marker value -static uint8 get_marker(void) -{ - uint8 x; - if (marker != MARKER_none) { x = marker; marker = MARKER_none; return x; } - x = get8u(); - if (x != 0xff) return MARKER_none; - while (x == 0xff) - x = get8u(); - return x; -} - -// in each scan, we'll have scan_n components, and the order -// of the components is specified by order[] -static int scan_n, order[4]; -static int restart_interval, todo; -#define RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) - -// after a restart interval, reset the entropy decoder and -// the dc prediction -static void reset(void) -{ - code_bits = 0; - code_buffer = 0; - nomore = 0; - img_comp[0].dc_pred = img_comp[1].dc_pred = img_comp[2].dc_pred = 0; - marker = MARKER_none; - todo = restart_interval ? restart_interval : 0x7fffffff; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels -} - -static int parse_entropy_coded_data(void) -{ - reset(); - if (scan_n == 1) { - int i,j; - #if STBI_SIMD - __declspec(align(16)) - #endif - short data[64]; - int n = order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (img_comp[n].x+7) >> 3; - int h = (img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - if (!decode_block(data, huff_dc+img_comp[n].hd, huff_ac+img_comp[n].ha, n)) return 0; - #if STBI_SIMD - stbi_idct_installed(img_comp[n].data+img_comp[n].w2*j*8+i*8, img_comp[n].w2, data, dequant2[img_comp[n].tq]); - #else - idct_block(img_comp[n].data+img_comp[n].w2*j*8+i*8, img_comp[n].w2, data, dequant[img_comp[n].tq]); - #endif - // every data block is an MCU, so countdown the restart interval - if (--todo <= 0) { - if (code_bits < 24) grow_buffer_unsafe(); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!RESTART(marker)) return 1; - reset(); - } - } - } - } else { // interleaved! - int i,j,k,x,y; - short data[64]; - for (j=0; j < img_mcu_y; ++j) { - for (i=0; i < img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < scan_n; ++k) { - int n = order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < img_comp[n].v; ++y) { - for (x=0; x < img_comp[n].h; ++x) { - int x2 = (i*img_comp[n].h + x)*8; - int y2 = (j*img_comp[n].v + y)*8; - if (!decode_block(data, huff_dc+img_comp[n].hd, huff_ac+img_comp[n].ha, n)) return 0; - #if STBI_SIMD - stbi_idct_installed(img_comp[n].data+img_comp[n].w2*y2+x2, img_comp[n].w2, data, dequant2[img_comp[n].tq]); - #else - idct_block(img_comp[n].data+img_comp[n].w2*y2+x2, img_comp[n].w2, data, dequant[img_comp[n].tq]); - #endif - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--todo <= 0) { - if (code_bits < 24) grow_buffer_unsafe(); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!RESTART(marker)) return 1; - reset(); - } - } - } - } - return 1; -} - -static int process_marker(int m) -{ - int L; - switch (m) { - case MARKER_none: // no marker found - return e("expected marker","Corrupt JPEG"); - - case 0xC2: // SOF - progressive - return e("progressive jpeg","JPEG format not supported (progressive)"); - - case 0xDD: // DRI - specify restart interval - if (get16() != 4) return e("bad DRI len","Corrupt JPEG"); - restart_interval = get16(); - return 1; - - case 0xDB: // DQT - define quantization table - L = get16()-2; - while (L > 0) { - int z = get8(); - int p = z >> 4; - int t = z & 15,i; - if (p != 0) return e("bad DQT type","Corrupt JPEG"); - if (t > 3) return e("bad DQT table","Corrupt JPEG"); - for (i=0; i < 64; ++i) - dequant[t][dezigzag[i]] = get8u(); - #if STBI_SIMD - for (i=0; i < 64; ++i) - dequant2[t][i] = dequant[t][i]; - #endif - L -= 65; - } - return L==0; - - case 0xC4: // DHT - define huffman table - L = get16()-2; - while (L > 0) { - uint8 *v; - int sizes[16],i,m=0; - int z = get8(); - int tc = z >> 4; - int th = z & 15; - if (tc > 1 || th > 3) return e("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = get8(); - m += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!build_huffman(huff_dc+th, sizes)) return 0; - v = huff_dc[th].values; - } else { - if (!build_huffman(huff_ac+th, sizes)) return 0; - v = huff_ac[th].values; - } - for (i=0; i < m; ++i) - v[i] = get8u(); - L -= m; - } - return L==0; - } - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - skip(get16()-2); - return 1; - } - return 0; -} - -// after we see SOS -static int process_scan_header(void) -{ - int i; - int Ls = get16(); - scan_n = get8(); - if (scan_n < 1 || scan_n > 4 || scan_n > (int) img_n) return e("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*scan_n) return e("bad SOS len","Corrupt JPEG"); - for (i=0; i < scan_n; ++i) { - int id = get8(), which; - int z = get8(); - for (which = 0; which < img_n; ++which) - if (img_comp[which].id == id) - break; - if (which == img_n) return 0; - img_comp[which].hd = z >> 4; if (img_comp[which].hd > 3) return e("bad DC huff","Corrupt JPEG"); - img_comp[which].ha = z & 15; if (img_comp[which].ha > 3) return e("bad AC huff","Corrupt JPEG"); - order[i] = which; - } - if (get8() != 0) return e("bad SOS","Corrupt JPEG"); - get8(); // should be 63, but might be 0 - if (get8() != 0) return e("bad SOS","Corrupt JPEG"); - - return 1; -} - -static int process_frame_header(int scan) -{ - int Lf,p,i,z, h_max=1,v_max=1; - Lf = get16(); if (Lf < 11) return e("bad SOF len","Corrupt JPEG"); // JPEG - p = get8(); if (p != 8) return e("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - img_y = get16(); if (img_y == 0) return e("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - img_x = get16(); if (img_x == 0) return e("0 width","Corrupt JPEG"); // JPEG requires - img_n = get8(); - if (img_n != 3 && img_n != 1) return e("bad component count","Corrupt JPEG"); // JFIF requires - - if (Lf != 8+3*img_n) return e("bad SOF len","Corrupt JPEG"); - - for (i=0; i < img_n; ++i) { - img_comp[i].id = get8(); - if (img_comp[i].id != i+1) // JFIF requires - if (img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! - return e("bad component ID","Corrupt JPEG"); - z = get8(); - img_comp[i].h = (z >> 4); if (!img_comp[i].h || img_comp[i].h > 4) return e("bad H","Corrupt JPEG"); - img_comp[i].v = z & 15; if (!img_comp[i].v || img_comp[i].v > 4) return e("bad V","Corrupt JPEG"); - img_comp[i].tq = get8(); if (img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG"); - } - - if (scan != SCAN_load) return 1; - - if ((1 << 30) / img_x / img_n < img_y) return e("too large", "Image too large to decode"); - - for (i=0; i < img_n; ++i) { - if (img_comp[i].h > h_max) h_max = img_comp[i].h; - if (img_comp[i].v > v_max) v_max = img_comp[i].v; - } - - // compute interleaved mcu info - img_h_max = h_max; - img_v_max = v_max; - img_mcu_w = h_max * 8; - img_mcu_h = v_max * 8; - img_mcu_x = (img_x + img_mcu_w-1) / img_mcu_w; - img_mcu_y = (img_y + img_mcu_h-1) / img_mcu_h; - - for (i=0; i < img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - img_comp[i].x = (img_x * img_comp[i].h + h_max-1) / h_max; - img_comp[i].y = (img_y * img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - img_comp[i].w2 = img_mcu_x * img_comp[i].h * 8; - img_comp[i].h2 = img_mcu_y * img_comp[i].v * 8; - img_comp[i].raw_data = malloc(img_comp[i].w2 * img_comp[i].h2+15); - if (img_comp[i].raw_data == NULL) { - for(--i; i >= 0; --i) { - free(img_comp[i].raw_data); - img_comp[i].data = NULL; - } - return e("outofmem", "Out of memory"); - } - img_comp[i].data = (uint8*) (((int) img_comp[i].raw_data + 15) & ~15); - img_comp[i].linebuf = NULL; - } - - return 1; -} - -// use comparisons since in some cases we handle more than one case (e.g. SOF) -#define DNL(x) ((x) == 0xdc) -#define SOI(x) ((x) == 0xd8) -#define EOI(x) ((x) == 0xd9) -#define SOF(x) ((x) == 0xc0 || (x) == 0xc1) -#define SOS(x) ((x) == 0xda) - -static int decode_jpeg_header(int scan) -{ - int m; - marker = MARKER_none; // initialize cached marker to empty - m = get_marker(); - if (!SOI(m)) return e("no SOI","Corrupt JPEG"); - if (scan == SCAN_type) return 1; - m = get_marker(); - while (!SOF(m)) { - if (!process_marker(m)) return 0; - m = get_marker(); - while (m == MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (at_eof()) return e("no SOF", "Corrupt JPEG"); - m = get_marker(); - } - } - if (!process_frame_header(scan)) return 0; - return 1; -} - -static int decode_jpeg_image(void) -{ - int m; - restart_interval = 0; - if (!decode_jpeg_header(SCAN_load)) return 0; - m = get_marker(); - while (!EOI(m)) { - if (SOS(m)) { - if (!process_scan_header()) return 0; - if (!parse_entropy_coded_data()) return 0; - } else { - if (!process_marker(m)) return 0; - } - m = get_marker(); - } - return 1; -} - -// static jfif-centered resampling (across block boundaries) - -typedef uint8 *(*resample_row_func)(uint8 *out, uint8 *in0, uint8 *in1, - int w, int hs); - -#define div4(x) ((uint8) ((x) >> 2)) - -static uint8 *resample_row_1(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) -{ - return in_near; -} - -static uint8* resample_row_v_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - for (i=0; i < w; ++i) - out[i] = div4(3*in_near[i] + in_far[i] + 2); - return out; -} - -static uint8* resample_row_h_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - uint8 *input = in_near; - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } - - out[0] = input[0]; - out[1] = div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = div4(n+input[i-1]); - out[i*2+1] = div4(n+input[i+1]); - } - out[i*2+0] = div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; - return out; -} - -#define div16(x) ((uint8) ((x) >> 4)) - -static uint8 *resample_row_hv_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - out[0] = div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = div16(3*t0 + t1 + 8); - out[i*2 ] = div16(3*t1 + t0 + 8); - } - out[w*2-1] = div4(t1+2); - return out; -} - -static uint8 *resample_row_generic(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; -} - -#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) - -// 0.38 seconds on 3*anemones.jpg (0.25 with processor = Pro) -// VC6 without processor=Pro is generating multiple LEAs per multiply! -static void YCbCr_to_RGB_row(uint8 *out, uint8 *y, uint8 *pcb, uint8 *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 16) + 32768; // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr*float2fixed(1.40200f); - g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); - b = y_fixed + cb*float2fixed(1.77200f); - r >>= 16; - g >>= 16; - b >>= 16; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (uint8)r; - out[1] = (uint8)g; - out[2] = (uint8)b; - out[3] = 255; - out += step; - } -} - -#if STBI_SIMD -static stbi_YCbCr_to_RGB_run stbi_YCbCr_installed = YCbCr_to_RGB_row; - -void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func) -{ - stbi_YCbCr_installed = func; -} -#endif - - -// clean up the temporary component buffers -static void cleanup_jpeg(void) -{ - int i; - for (i=0; i < img_n; ++i) { - if (img_comp[i].data) { - free(img_comp[i].raw_data); - img_comp[i].data = NULL; - } - if (img_comp[i].linebuf) { - free(img_comp[i].linebuf); - img_comp[i].linebuf = NULL; - } - } -} - -typedef struct -{ - resample_row_func resample; - uint8 *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on -} stbi_resample; - -static uint8 *load_jpeg_image(int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n; - // validate req_comp - if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); - - // load a jpeg image from whichever source - if (!decode_jpeg_image()) { cleanup_jpeg(); return NULL; } - - // determine actual number of components to generate - n = req_comp ? req_comp : img_n; - - if (img_n == 3 && n < 3) - decode_n = 1; - else - decode_n = img_n; - - // resample and color-convert - { - int k; - uint i,j; - uint8 *output; - uint8 *coutput[4]; - - stbi_resample res_comp[4]; - - for (k=0; k < decode_n; ++k) { - stbi_resample *r = &res_comp[k]; - - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - img_comp[k].linebuf = (uint8 *) malloc(img_x + 3); - if (!img_comp[k].linebuf) { cleanup_jpeg(); return epuc("outofmem", "Out of memory"); } - - r->hs = img_h_max / img_comp[k].h; - r->vs = img_v_max / img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = img_comp[k].data; - - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = resample_row_hv_2; - else r->resample = resample_row_generic; - } - - // can't error after this so, this is safe - output = (uint8 *) malloc(n * img_x * img_y + 1); - if (!output) { cleanup_jpeg(); return epuc("outofmem", "Out of memory"); } - - // now go ahead and resample - for (j=0; j < img_y; ++j) { - uint8 *out = output + n * img_x * j; - for (k=0; k < decode_n; ++k) { - stbi_resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < img_comp[k].y) - r->line1 += img_comp[k].w2; - } - } - if (n >= 3) { - uint8 *y = coutput[0]; - if (img_n == 3) { - #if STBI_SIMD - stbi_YCbCr_installed(out, y, coutput[1], coutput[2], img_x, n); - #else - YCbCr_to_RGB_row(out, y, coutput[1], coutput[2], img_x, n); - #endif - } else - for (i=0; i < img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - uint8 *y = coutput[0]; - if (n == 1) - for (i=0; i < img_x; ++i) out[i] = y[i]; - else - for (i=0; i < img_x; ++i) *out++ = y[i], *out++ = 255; - } - } - cleanup_jpeg(); - *out_x = img_x; - *out_y = img_y; - if (comp) *comp = img_n; // report original components, not output - return output; - } -} - -#ifndef STBI_NO_STDIO -unsigned char *stbi_jpeg_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - start_file(f); - return load_jpeg_image(x,y,comp,req_comp); -} - -unsigned char *stbi_jpeg_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - FILE *f = fopen(filename, "rb"); - if (!f) return NULL; - data = stbi_jpeg_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return data; -} -#endif - -unsigned char *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - start_mem(buffer,len); - return load_jpeg_image(x,y,comp,req_comp); -} - -#ifndef STBI_NO_STDIO -int stbi_jpeg_test_file(FILE *f) -{ - int n,r; - n = ftell(f); - start_file(f); - r = decode_jpeg_header(SCAN_type); - fseek(f,n,SEEK_SET); - return r; -} -#endif - -int stbi_jpeg_test_memory(stbi_uc const *buffer, int len) -{ - start_mem(buffer,len); - return decode_jpeg_header(SCAN_type); -} - -// @TODO: -#ifndef STBI_NO_STDIO -extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp); -extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp); -#endif -extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); - -// public domain zlib decode v0.2 Sean Barrett 2006-11-18 -// simple implementation -// - all input must be provided in an upfront buffer -// - all output is written to a single output buffer (can malloc/realloc) -// performance -// - fast huffman - -// fast-way is faster to check than jpeg huffman, but slow way is slower -#define ZFAST_BITS 9 // accelerate all cases in default tables -#define ZFAST_MASK ((1 << ZFAST_BITS) - 1) - -// zlib-style huffman encoding -// (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - uint16 fast[1 << ZFAST_BITS]; - uint16 firstcode[16]; - int maxcode[17]; - uint16 firstsymbol[16]; - uint8 size[288]; - uint16 value[288]; -} zhuffman; - -__forceinline static int bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; -} - -__forceinline static int bit_reverse(int v, int bits) -{ - assert(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return bitreverse16(v) >> (16-bits); -} - -static int zbuild_huffman(zhuffman *z, uint8 *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; - - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 255, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - assert(sizes[i] <= (1 << i)); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (uint16) code; - z->firstsymbol[i] = (uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return e("bad codelengths","Corrupt JPEG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - z->size[c] = (uint8)s; - z->value[c] = (uint16)i; - if (s <= ZFAST_BITS) { - int k = bit_reverse(next_code[s],s); - while (k < (1 << ZFAST_BITS)) { - z->fast[k] = (uint16) c; - k += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; -} - -// zlib-from-memory implementation for PNG reading -// because PNG allows splitting the zlib stream arbitrarily, -// and it's annoying structurally to have PNG call ZLIB call PNG, -// we require PNG read all the IDATs and combine them into a single -// memory buffer - -static uint8 *zbuffer, *zbuffer_end; - -__forceinline static int zget8(void) -{ - if (zbuffer >= zbuffer_end) return 0; - return *zbuffer++; -} - -//static uint32 code_buffer; -static int num_bits; - -static void fill_bits(void) -{ - do { - assert(code_buffer < (1U << num_bits)); - code_buffer |= zget8() << num_bits; - num_bits += 8; - } while (num_bits <= 24); -} - -__forceinline static unsigned int zreceive(int n) -{ - unsigned int k; - if (num_bits < n) fill_bits(); - k = code_buffer & ((1 << n) - 1); - code_buffer >>= n; - num_bits -= n; - return k; -} - -__forceinline static int zhuffman_decode(zhuffman *z) -{ - int b,s,k; - if (num_bits < 16) fill_bits(); - b = z->fast[code_buffer & ZFAST_MASK]; - if (b < 0xffff) { - s = z->size[b]; - code_buffer >>= s; - num_bits -= s; - return z->value[b]; - } - - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = bit_reverse(code_buffer, 16); - for (s=ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s == 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - assert(z->size[b] == s); - code_buffer >>= s; - num_bits -= s; - return z->value[b]; -} - -static char *zout; -static char *zout_start; -static char *zout_end; -static int z_expandable; - -static int expand(int n) // need to make room for n bytes -{ - char *q; - int cur, limit; - if (!z_expandable) return e("output buffer limit","Corrupt PNG"); - cur = (int) (zout - zout_start); - limit = (int) (zout_end - zout_start); - while (cur + n > limit) - limit *= 2; - q = (char *) realloc(zout_start, limit); - if (q == NULL) return e("outofmem", "Out of memory"); - zout_start = q; - zout = q + cur; - zout_end = q + limit; - return 1; -} - -static zhuffman z_length, z_distance; - -static int length_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; - -static int length_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - -static int dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - -static int dist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static int parse_huffman_block(void) -{ - for(;;) { - int z = zhuffman_decode(&z_length); - if (z < 256) { - if (z < 0) return e("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= zout_end) if (!expand(1)) return 0; - *zout++ = (char) z; - } else { - uint8 *p; - int len,dist; - if (z == 256) return 1; - z -= 257; - len = length_base[z]; - if (length_extra[z]) len += zreceive(length_extra[z]); - z = zhuffman_decode(&z_distance); - if (z < 0) return e("bad huffman code","Corrupt PNG"); - dist = dist_base[z]; - if (dist_extra[z]) dist += zreceive(dist_extra[z]); - if (zout - zout_start < dist) return e("bad dist","Corrupt PNG"); - if (zout + len > zout_end) if (!expand(len)) return 0; - p = (uint8 *) (zout - dist); - while (len--) - *zout++ = *p++; - } - } -} - -static int compute_huffman_codes(void) -{ - static uint8 length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - static zhuffman z_codelength; // static just to save stack space - uint8 lencodes[286+32+137];//padding for maximum single op - uint8 codelength_sizes[19]; - int i,n; - - int hlit = zreceive(5) + 257; - int hdist = zreceive(5) + 1; - int hclen = zreceive(4) + 4; - - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = zreceive(3); - codelength_sizes[length_dezigzag[i]] = (uint8) s; - } - if (!zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - - n = 0; - while (n < hlit + hdist) { - int c = zhuffman_decode(&z_codelength); - assert(c >= 0 && c < 19); - if (c < 16) - lencodes[n++] = (uint8) c; - else if (c == 16) { - c = zreceive(2)+3; - memset(lencodes+n, lencodes[n-1], c); - n += c; - } else if (c == 17) { - c = zreceive(3)+3; - memset(lencodes+n, 0, c); - n += c; - } else { - assert(c == 18); - c = zreceive(7)+11; - memset(lencodes+n, 0, c); - n += c; - } - } - if (n != hlit+hdist) return e("bad codelengths","Corrupt PNG"); - if (!zbuild_huffman(&z_length, lencodes, hlit)) return 0; - if (!zbuild_huffman(&z_distance, lencodes+hlit, hdist)) return 0; - return 1; -} - -static int parse_uncompressed_block(void) -{ - uint8 header[4]; - int len,nlen,k; - if (num_bits & 7) - zreceive(num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (num_bits > 0) { - header[k++] = (uint8) (code_buffer & 255); // wtf this warns? - code_buffer >>= 8; - num_bits -= 8; - } - assert(num_bits == 0); - // now fill header the normal way - while (k < 4) - header[k++] = (uint8) zget8(); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return e("zlib corrupt","Corrupt PNG"); - if (zbuffer + len > zbuffer_end) return e("read past buffer","Corrupt PNG"); - if (zout + len > zout_end) - if (!expand(len)) return 0; - memcpy(zout, zbuffer, len); - zbuffer += len; - zout += len; - return 1; -} - -static int parse_zlib_header(void) -{ - int cmf = zget8(); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = zget8(); - if ((cmf*256+flg) % 31 != 0) return e("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return e("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return e("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; -} - -static uint8 default_length[288], default_distance[32]; -static void init_defaults(void) -{ - int i; // use <= to match clearly with spec - for (i=0; i <= 143; ++i) default_length[i] = 8; - for ( ; i <= 255; ++i) default_length[i] = 9; - for ( ; i <= 279; ++i) default_length[i] = 7; - for ( ; i <= 287; ++i) default_length[i] = 8; - - for (i=0; i <= 31; ++i) default_distance[i] = 5; -} - -static int parse_zlib(int parse_header) -{ - int final, type; - if (parse_header) - if (!parse_zlib_header()) return 0; - num_bits = 0; - code_buffer = 0; - do { - final = zreceive(1); - type = zreceive(2); - if (type == 0) { - if (!parse_uncompressed_block()) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!default_length[0]) init_defaults(); - if (!zbuild_huffman(&z_length , default_length , 288)) return 0; - if (!zbuild_huffman(&z_distance, default_distance, 32)) return 0; - } else { - if (!compute_huffman_codes()) return 0; - } - if (!parse_huffman_block()) return 0; - } - } while (!final); - return 1; -} - -static int do_zlib(char *obuf, int olen, int exp, int parse_header) -{ - zout_start = obuf; - zout = obuf; - zout_end = obuf + olen; - z_expandable = exp; - - return parse_zlib(parse_header); -} - -char *stbi_zlib_decode_malloc_guesssize(int initial_size, int *outlen) -{ - char *p = (char *) malloc(initial_size); - if (p == NULL) return NULL; - if (do_zlib(p, initial_size, 1, 1)) { - *outlen = (int) (zout - zout_start); - return zout_start; - } else { - free(zout_start); - return NULL; - } -} - -char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - zbuffer = (uint8 *) buffer; - zbuffer_end = (uint8 *) buffer+len; - return stbi_zlib_decode_malloc_guesssize(16384, outlen); -} - -int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - zbuffer = (uint8 *) ibuffer; - zbuffer_end = (uint8 *) ibuffer + ilen; - if (do_zlib(obuffer, olen, 0, 1)) - return (int) (zout - zout_start); - else - return -1; -} - -char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - char *p = (char *) malloc(16384); - if (p == NULL) return NULL; - zbuffer = (uint8 *) buffer; - zbuffer_end = (uint8 *) buffer+len; - if (do_zlib(p, 16384, 1, 0)) { - *outlen = (int) (zout - zout_start); - return zout_start; - } else { - free(zout_start); - return NULL; - } -} - -int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - zbuffer = (uint8 *) ibuffer; - zbuffer_end = (uint8 *) ibuffer + ilen; - if (do_zlib(obuffer, olen, 0, 0)) - return (int) (zout - zout_start); - else - return -1; -} - -// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 -// simple implementation -// - only 8-bit samples -// - no CRC checking -// - allocates lots of intermediate memory -// - avoids problem of streaming data between subsystems -// - avoids explicit window management -// performance -// - uses stb_zlib, a PD zlib implementation with fast huffman decoding - - -typedef struct -{ - uint32 length; - uint32 type; -} chunk; - -#define PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -static chunk get_chunk_header(void) -{ - chunk c; - c.length = get32(); - c.type = get32(); - return c; -} - -static int check_png_header(void) -{ - static uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (get8() != png_sig[i]) return e("bad png sig","Not a PNG"); - return 1; -} - -static uint8 *idata, *expanded, *out; - -enum { - F_none=0, F_sub=1, F_up=2, F_avg=3, F_paeth=4, - F_avg_first, F_paeth_first, -}; - -static uint8 first_row_filter[5] = -{ - F_none, F_sub, F_none, F_avg_first, F_paeth_first -}; - -static int paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; -} - -// create the png data from post-deflated data -static int create_png_image(uint8 *raw, uint32 raw_len, int out_n) -{ - uint32 i,j,stride = img_x*out_n; - int k; - assert(out_n == img_n || out_n == img_n+1); - out = (uint8 *) malloc(img_x * img_y * out_n); - if (!out) return e("outofmem", "Out of memory"); - if (raw_len != (img_n * img_x + 1) * img_y) return e("not enough pixels","Corrupt PNG"); - for (j=0; j < img_y; ++j) { - uint8 *cur = out + stride*j; - uint8 *prior = cur - stride; - int filter = *raw++; - if (filter > 4) return e("invalid filter","Corrupt PNG"); - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; - // handle first pixel explicitly - for (k=0; k < img_n; ++k) { - switch(filter) { - case F_none : cur[k] = raw[k]; break; - case F_sub : cur[k] = raw[k]; break; - case F_up : cur[k] = raw[k] + prior[k]; break; - case F_avg : cur[k] = raw[k] + (prior[k]>>1); break; - case F_paeth : cur[k] = (uint8) (raw[k] + paeth(0,prior[k],0)); break; - case F_avg_first : cur[k] = raw[k]; break; - case F_paeth_first: cur[k] = raw[k]; break; - } - } - if (img_n != out_n) cur[img_n] = 255; - raw += img_n; - cur += out_n; - prior += out_n; - // this is a little gross, so that we don't switch per-pixel or per-component - if (img_n == out_n) { - #define CASE(f) \ - case f: \ - for (i=1; i < img_x; ++i, raw+=img_n,cur+=img_n,prior+=img_n) \ - for (k=0; k < img_n; ++k) - switch(filter) { - CASE(F_none) cur[k] = raw[k]; break; - CASE(F_sub) cur[k] = raw[k] + cur[k-img_n]; break; - CASE(F_up) cur[k] = raw[k] + prior[k]; break; - CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-img_n])>>1); break; - CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; - CASE(F_avg_first) cur[k] = raw[k] + (cur[k-img_n] >> 1); break; - CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],0,0)); break; - } - #undef CASE - } else { - assert(img_n+1 == out_n); - #define CASE(f) \ - case f: \ - for (i=1; i < img_x; ++i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ - for (k=0; k < img_n; ++k) - switch(filter) { - CASE(F_none) cur[k] = raw[k]; break; - CASE(F_sub) cur[k] = raw[k] + cur[k-out_n]; break; - CASE(F_up) cur[k] = raw[k] + prior[k]; break; - CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-out_n])>>1); break; - CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; - CASE(F_avg_first) cur[k] = raw[k] + (cur[k-out_n] >> 1); break; - CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],0,0)); break; - } - #undef CASE - } - } - return 1; -} - -static int compute_transparency(uint8 tc[3], int out_n) -{ - uint32 i, pixel_count = img_x * img_y; - uint8 *p = out; - - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - assert(out_n == 2 || out_n == 4); - - p = out; - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int expand_palette(uint8 *palette, int len, int pal_img_n) -{ - uint32 i, pixel_count = img_x * img_y; - uint8 *p, *temp_out, *orig = out; - - p = (uint8 *) malloc(pixel_count * pal_img_n); - if (p == NULL) return e("outofmem", "Out of memory"); - - // between here and free(out) below, exitting would leak - temp_out = p; - - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - free(out); - out = temp_out; - return 1; -} - -static int parse_png_file(int scan, int req_comp) -{ - uint8 palette[1024], pal_img_n=0; - uint8 has_trans=0, tc[3]; - uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k; - - if (!check_png_header()) return 0; - - if (scan == SCAN_type) return 1; - - for(;;first=0) { - chunk c = get_chunk_header(); - if (first && c.type != PNG_TYPE('I','H','D','R')) - return e("first not IHDR","Corrupt PNG"); - switch (c.type) { - case PNG_TYPE('I','H','D','R'): { - int depth,color,interlace,comp,filter; - if (!first) return e("multiple IHDR","Corrupt PNG"); - if (c.length != 13) return e("bad IHDR len","Corrupt PNG"); - img_x = get32(); if (img_x > (1 << 24)) return e("too large","Very large image (corrupt?)"); - img_y = get32(); if (img_y > (1 << 24)) return e("too large","Very large image (corrupt?)"); - depth = get8(); if (depth != 8) return e("8bit only","PNG not supported: 8-bit only"); - color = get8(); if (color > 6) return e("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG"); - comp = get8(); if (comp) return e("bad comp method","Corrupt PNG"); - filter= get8(); if (filter) return e("bad filter method","Corrupt PNG"); - interlace = get8(); if (interlace) return e("interlaced","PNG not supported: interlaced mode"); - if (!img_x || !img_y) return e("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / img_x / img_n < img_y) return e("too large", "Image too large to decode"); - if (scan == SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - img_n = 1; - if ((1 << 30) / img_x / 4 < img_y) return e("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } - - case PNG_TYPE('P','L','T','E'): { - if (c.length > 256*3) return e("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return e("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = get8u(); - palette[i*4+1] = get8u(); - palette[i*4+2] = get8u(); - palette[i*4+3] = 255; - } - break; - } - - case PNG_TYPE('t','R','N','S'): { - if (idata) return e("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == SCAN_header) { img_n = 4; return 1; } - if (pal_len == 0) return e("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return e("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = get8u(); - } else { - if (!(img_n & 1)) return e("tRNS with alpha","Corrupt PNG"); - if (c.length != (uint32) img_n*2) return e("bad tRNS len","Corrupt PNG"); - has_trans = 1; - for (k=0; k < img_n; ++k) - tc[k] = (uint8) get16(); // non 8-bit images will be larger - } - break; - } - - case PNG_TYPE('I','D','A','T'): { - if (pal_img_n && !pal_len) return e("no PLTE","Corrupt PNG"); - if (scan == SCAN_header) { img_n = pal_img_n; return 1; } - if (ioff + c.length > idata_limit) { - uint8 *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - p = (uint8 *) realloc(idata, idata_limit); if (p == NULL) return e("outofmem", "Out of memory"); - idata = p; - } - #ifndef STBI_NO_STDIO - if (img_file) - { - if (fread(idata+ioff,1,c.length,img_file) != c.length) return e("outofdata","Corrupt PNG"); - } - else - #endif - { - memcpy(idata+ioff, img_buffer, c.length); - img_buffer += c.length; - } - ioff += c.length; - break; - } - - case PNG_TYPE('I','E','N','D'): { - uint32 raw_len; - if (scan != SCAN_load) return 1; - if (idata == NULL) return e("no IDAT","Corrupt PNG"); - expanded = (uint8 *) stbi_zlib_decode_malloc((char *) idata, ioff, (int *) &raw_len); - if (expanded == NULL) return 0; // zlib should set error - free(idata); idata = NULL; - if ((req_comp == img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - img_out_n = img_n+1; - else - img_out_n = img_n; - if (!create_png_image(expanded, raw_len, img_out_n)) return 0; - if (has_trans) - if (!compute_transparency(tc, img_out_n)) return 0; - if (pal_img_n) { - // pal_img_n == 3 or 4 - img_n = pal_img_n; // record the actual colors we had - img_out_n = pal_img_n; - if (req_comp >= 3) img_out_n = req_comp; - if (!expand_palette(palette, pal_len, img_out_n)) - return 0; - } - free(expanded); expanded = NULL; - return 1; - } - - default: - // if critical, fail - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - static char invalid_chunk[] = "XXXX chunk not known"; - invalid_chunk[0] = (uint8) (c.type >> 24); - invalid_chunk[1] = (uint8) (c.type >> 16); - invalid_chunk[2] = (uint8) (c.type >> 8); - invalid_chunk[3] = (uint8) (c.type >> 0); - #endif - return e(invalid_chunk, "PNG not supported: unknown chunk type"); - } - skip(c.length); - break; - } - // end of chunk, read and skip CRC - get8(); get8(); get8(); get8(); - } -} - -static unsigned char *do_png(int *x, int *y, int *n, int req_comp) -{ - unsigned char *result=NULL; - if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); - if (parse_png_file(SCAN_load, req_comp)) { - result = out; - out = NULL; - if (req_comp && req_comp != img_out_n) { - result = convert_format(result, img_out_n, req_comp); - if (result == NULL) return result; - } - *x = img_x; - *y = img_y; - if (n) *n = img_n; - } - free(out); out = NULL; - free(expanded); expanded = NULL; - free(idata); idata = NULL; - - return result; -} - -#ifndef STBI_NO_STDIO -unsigned char *stbi_png_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - start_file(f); - return do_png(x,y,comp,req_comp); -} - -unsigned char *stbi_png_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - FILE *f = fopen(filename, "rb"); - if (!f) return NULL; - data = stbi_png_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return data; -} -#endif - -unsigned char *stbi_png_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - start_mem(buffer,len); - return do_png(x,y,comp,req_comp); -} - -#ifndef STBI_NO_STDIO -int stbi_png_test_file(FILE *f) -{ - int n,r; - n = ftell(f); - start_file(f); - r = parse_png_file(SCAN_type,STBI_default); - fseek(f,n,SEEK_SET); - return r; -} -#endif - -int stbi_png_test_memory(stbi_uc const *buffer, int len) -{ - start_mem(buffer, len); - return parse_png_file(SCAN_type,STBI_default); -} - -// TODO: load header from png -#ifndef STBI_NO_STDIO -extern int stbi_png_info (char const *filename, int *x, int *y, int *comp); -extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp); -#endif -extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); - -// Microsoft/Windows BMP image - -static int bmp_test(void) -{ - int sz; - if (get8() != 'B') return 0; - if (get8() != 'M') return 0; - get32le(); // discard filesize - get16le(); // discard reserved - get16le(); // discard reserved - get32le(); // discard data offset - sz = get32le(); - if (sz == 12 || sz == 40 || sz == 56 || sz == 108) return 1; - return 0; -} - -#ifndef STBI_NO_STDIO -int stbi_bmp_test_file (FILE *f) -{ - int r,n = ftell(f); - start_file(f); - r = bmp_test(); - fseek(f,n,SEEK_SET); - return r; -} -#endif - -int stbi_bmp_test_memory (stbi_uc const *buffer, int len) -{ - start_mem(buffer, len); - return bmp_test(); -} - -// returns 0..31 for the highest set bit -static int high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; - return n; -} - -static int bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; -} - -static int shiftsigned(int v, int shift, int bits) -{ - int result; - int z=0; - - if (shift < 0) v <<= -shift; - else v >>= shift; - result = v; - - z = bits; - while (z < 8) { - result += v >> z; - z += bits; - } - return result; -} - -static stbi_uc *bmp_load(int *x, int *y, int *comp, int req_comp) -{ - unsigned int mr=0,mg=0,mb=0,ma=0; - stbi_uc pal[256][4]; - int psize=0,i,j,compress=0,width; - int bpp, flip_vertically, pad, target, offset, hsz; - if (get8() != 'B' || get8() != 'M') return epuc("not BMP", "Corrupt BMP"); - get32le(); // discard filesize - get16le(); // discard reserved - get16le(); // discard reserved - offset = get32le(); - hsz = get32le(); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) return epuc("unknown BMP", "BMP type not supported: unknown"); - failure_reason = "bad BMP"; - if (hsz == 12) { - img_x = get16le(); - img_y = get16le(); - } else { - img_x = get32le(); - img_y = get32le(); - } - if (get16le() != 1) return 0; - bpp = get16le(); - if (bpp == 1) return epuc("monochrome", "BMP type not supported: 1-bit"); - flip_vertically = ((int) img_y) > 0; - img_y = abs((int) img_y); - if (hsz == 12) { - if (bpp < 24) - psize = (offset - 14 - 24) / 3; - } else { - compress = get32le(); - if (compress == 1 || compress == 2) return epuc("BMP RLE", "BMP type not supported: RLE"); - get32le(); // discard sizeof - get32le(); // discard hres - get32le(); // discard vres - get32le(); // discard colorsused - get32le(); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - get32le(); - get32le(); - get32le(); - get32le(); - } - if (bpp == 16 || bpp == 32) { - mr = mg = mb = 0; - if (compress == 0) { - if (bpp == 32) { - mr = 0xff << 16; - mg = 0xff << 8; - mb = 0xff << 0; - } else { - mr = 31 << 10; - mg = 31 << 5; - mb = 31 << 0; - } - } else if (compress == 3) { - mr = get32le(); - mg = get32le(); - mb = get32le(); - // not documented, but generated by photoshop and handled by mspaint - if (mr == mg && mg == mb) { - // ?!?!? - return NULL; - } - } else - return NULL; - } - } else { - assert(hsz == 108); - mr = get32le(); - mg = get32le(); - mb = get32le(); - ma = get32le(); - get32le(); // discard color space - for (i=0; i < 12; ++i) - get32le(); // discard color space parameters - } - if (bpp < 16) - psize = (offset - 14 - hsz) >> 2; - } - img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = img_n; // if they want monochrome, we'll post-convert - out = (stbi_uc *) malloc(target * img_x * img_y); - if (!out) return epuc("outofmem", "Out of memory"); - if (bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) return epuc("invalid", "Corrupt BMP"); - for (i=0; i < psize; ++i) { - pal[i][2] = get8(); - pal[i][1] = get8(); - pal[i][0] = get8(); - if (hsz != 12) get8(); - pal[i][3] = 255; - } - skip(offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); - if (bpp == 4) width = (img_x + 1) >> 1; - else if (bpp == 8) width = img_x; - else return epuc("bad bpp", "Corrupt BMP"); - pad = (-width)&3; - for (j=0; j < (int) img_y; ++j) { - for (i=0; i < (int) img_x; i += 2) { - int v=get8(),v2=0; - if (bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) img_x) break; - v = (bpp == 8) ? get8() : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - skip(pad); - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - skip(offset - 14 - hsz); - if (bpp == 24) width = 3 * img_x; - else if (bpp == 16) width = 2*img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (bpp == 24) { - easy = 1; - } else if (bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0xff000000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) return epuc("bad masks", "Corrupt BMP"); - // right shift amt to put high bit in position #7 - rshift = high_bit(mr)-7; rcount = bitcount(mr); - gshift = high_bit(mg)-7; gcount = bitcount(mr); - bshift = high_bit(mb)-7; bcount = bitcount(mr); - ashift = high_bit(ma)-7; acount = bitcount(mr); - } - for (j=0; j < (int) img_y; ++j) { - if (easy) { - for (i=0; i < (int) img_x; ++i) { - int a; - out[z+2] = get8(); - out[z+1] = get8(); - out[z+0] = get8(); - z += 3; - a = (easy == 2 ? get8() : 255); - if (target == 4) out[z++] = a; - } - } else { - for (i=0; i < (int) img_x; ++i) { - uint32 v = (bpp == 16 ? get16le() : get32le()); - int a; - out[z++] = shiftsigned(v & mr, rshift, rcount); - out[z++] = shiftsigned(v & mg, gshift, gcount); - out[z++] = shiftsigned(v & mb, bshift, bcount); - a = (ma ? shiftsigned(v & ma, ashift, acount) : 255); - if (target == 4) out[z++] = a; - } - } - skip(pad); - } - } - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) img_y>>1; ++j) { - stbi_uc *p1 = out + j *img_x*target; - stbi_uc *p2 = out + (img_y-1-j)*img_x*target; - for (i=0; i < (int) img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; - } - } - } - - if (req_comp && req_comp != target) { - out = convert_format(out, target, req_comp); - if (out == NULL) return out; // convert_format frees input on failure - } - - *x = img_x; - *y = img_y; - if (comp) *comp = target; - return out; -} - -#ifndef STBI_NO_STDIO -stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *data; - FILE *f = fopen(filename, "rb"); - if (!f) return NULL; - data = stbi_bmp_load_from_file(f, x,y,comp,req_comp); - fclose(f); - return data; -} - -stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) -{ - start_file(f); - return bmp_load(x,y,comp,req_comp); -} -#endif - -stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - start_mem(buffer, len); - return bmp_load(x,y,comp,req_comp); -} - -// Targa Truevision - TGA -// by Jonathan Dummer - -static int tga_test(void) -{ - int sz; - get8u(); // discard Offset - sz = get8u(); // color type - if( sz > 1 ) return 0; // only RGB or indexed allowed - sz = get8u(); // image type - if( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE - get16(); // discard palette start - get16(); // discard palette length - get8(); // discard bits per palette color entry - get16(); // discard x origin - get16(); // discard y origin - if( get16() < 1 ) return 0; // test width - if( get16() < 1 ) return 0; // test height - sz = get8(); // bits per pixel - if( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) return 0; // only RGB or RGBA or grey allowed - return 1; // seems to have passed everything -} - -#ifndef STBI_NO_STDIO -int stbi_tga_test_file (FILE *f) -{ - int r,n = ftell(f); - start_file(f); - r = tga_test(); - fseek(f,n,SEEK_SET); - return r; -} -#endif - -int stbi_tga_test_memory (stbi_uc const *buffer, int len) -{ - start_mem(buffer, len); - return tga_test(); -} - -static stbi_uc *tga_load(int *x, int *y, int *comp, int req_comp) -{ - // read in the TGA header stuff - int tga_offset = get8u(); - int tga_indexed = get8u(); - int tga_image_type = get8u(); - int tga_is_RLE = 0; - int tga_palette_start = get16le(); - int tga_palette_len = get16le(); - int tga_palette_bits = get8u(); - int tga_x_origin = get16le(); - int tga_y_origin = get16le(); - int tga_width = get16le(); - int tga_height = get16le(); - int tga_bits_per_pixel = get8u(); - int tga_inverted = get8u(); - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4]; - unsigned char trans_data[4]; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - // do a tiny bit of precessing - if( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - /* int tga_alpha_bits = tga_inverted & 15; */ - tga_inverted = 1 - ((tga_inverted >> 5) & 1); - - // error check - if( //(tga_indexed) || - (tga_width < 1) || (tga_height < 1) || - (tga_image_type < 1) || (tga_image_type > 3) || - ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && - (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) - ) - { - return NULL; - } - - // If I'm paletted, then I'll use the number of bits from the palette - if( tga_indexed ) - { - tga_bits_per_pixel = tga_palette_bits; - } - - // tga info - *x = tga_width; - *y = tga_height; - if( (req_comp < 1) || (req_comp > 4) ) - { - // just use whatever the file was - req_comp = tga_bits_per_pixel / 8; - *comp = req_comp; - } else - { - // force a new number of components - *comp = tga_bits_per_pixel/8; - } - tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp ); - - // skip to the data's starting position (offset usually = 0) - skip( tga_offset ); - // do I need to load a palette? - if( tga_indexed ) - { - // any data to skip? (offset usually = 0) - skip( tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 ); - getn( tga_palette, tga_palette_len * tga_palette_bits / 8 ); - } - // load the data - for( i = 0; i < tga_width * tga_height; ++i ) - { - // if I'm in RLE mode, do I need to get a RLE chunk? - if( tga_is_RLE ) - { - if( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = get8u(); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if( read_next_pixel ) - { - // load however much data we did have - if( tga_indexed ) - { - // read in 1 byte, then perform the lookup - int pal_idx = get8u(); - if( pal_idx >= tga_palette_len ) - { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_bits_per_pixel / 8; - for( j = 0; j*8 < tga_bits_per_pixel; ++j ) - { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else - { - // read in the data raw - for( j = 0; j*8 < tga_bits_per_pixel; ++j ) - { - raw_data[j] = get8u(); - } - } - // convert raw to the intermediate format - switch( tga_bits_per_pixel ) - { - case 8: - // Luminous => RGBA - trans_data[0] = raw_data[0]; - trans_data[1] = raw_data[0]; - trans_data[2] = raw_data[0]; - trans_data[3] = 255; - break; - case 16: - // Luminous,Alpha => RGBA - trans_data[0] = raw_data[0]; - trans_data[1] = raw_data[0]; - trans_data[2] = raw_data[0]; - trans_data[3] = raw_data[1]; - break; - case 24: - // BGR => RGBA - trans_data[0] = raw_data[2]; - trans_data[1] = raw_data[1]; - trans_data[2] = raw_data[0]; - trans_data[3] = 255; - break; - case 32: - // BGRA => RGBA - trans_data[0] = raw_data[2]; - trans_data[1] = raw_data[1]; - trans_data[2] = raw_data[0]; - trans_data[3] = raw_data[3]; - break; - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel - // convert to final format - switch( req_comp ) - { - case 1: - // RGBA => Luminance - tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); - break; - case 2: - // RGBA => Luminance,Alpha - tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); - tga_data[i*req_comp+1] = trans_data[3]; - break; - case 3: - // RGBA => RGB - tga_data[i*req_comp+0] = trans_data[0]; - tga_data[i*req_comp+1] = trans_data[1]; - tga_data[i*req_comp+2] = trans_data[2]; - break; - case 4: - // RGBA => RGBA - tga_data[i*req_comp+0] = trans_data[0]; - tga_data[i*req_comp+1] = trans_data[1]; - tga_data[i*req_comp+2] = trans_data[2]; - tga_data[i*req_comp+3] = trans_data[3]; - break; - } - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if( tga_inverted ) - { - for( j = 0; j*2 < tga_height; ++j ) - { - int index1 = j * tga_width * req_comp; - int index2 = (tga_height - 1 - j) * tga_width * req_comp; - for( i = tga_width * req_comp; i > 0; --i ) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if( tga_palette != NULL ) - { - free( tga_palette ); - } - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - // OK, done - return tga_data; -} - -#ifndef STBI_NO_STDIO -stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *data; - FILE *f = fopen(filename, "rb"); - if (!f) return NULL; - data = stbi_tga_load_from_file(f, x,y,comp,req_comp); - fclose(f); - return data; -} - -stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) -{ - start_file(f); - return tga_load(x,y,comp,req_comp); -} -#endif - -stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - start_mem(buffer, len); - return tga_load(x,y,comp,req_comp); -} - - -// ************************************************************************************************* -// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicholas Schulz, tweaked by STB - -static int psd_test(void) -{ - if (get32() != 0x38425053) return 0; // "8BPS" - else return 1; -} - -#ifndef STBI_NO_STDIO -int stbi_psd_test_file(FILE *f) -{ - int r,n = ftell(f); - start_file(f); - r = psd_test(); - fseek(f,n,SEEK_SET); - return r; -} -#endif - -int stbi_psd_test_memory(stbi_uc const *buffer, int len) -{ - start_mem(buffer, len); - return psd_test(); -} - -static stbi_uc *psd_load(int *x, int *y, int *comp, int req_comp) -{ - int pixelCount; - int channelCount, compression; - int channel, i, count, len; - int w,h; - - // Check identifier - if (get32() != 0x38425053) // "8BPS" - return epuc("not PSD", "Corrupt PSD image"); - - // Check file type version. - if (get16() != 1) - return epuc("wrong version", "Unsupported version of PSD image"); - - // Skip 6 reserved bytes. - skip( 6 ); - - // Read the number of channels (R, G, B, A, etc). - channelCount = get16(); - if (channelCount < 0 || channelCount > 16) - return epuc("wrong channel count", "Unsupported number of channels in PSD image"); - - // Read the rows and columns of the image. - h = get32(); - w = get32(); - - // Make sure the depth is 8 bits. - if (get16() != 8) - return epuc("unsupported bit depth", "PSD bit depth is not 8 bit"); - - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (get16() != 3) - return epuc("wrong color format", "PSD is not in RGB color format"); - - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - skip(get32() ); - - // Skip the image resources. (resolution, pen tool paths, etc) - skip( get32() ); - - // Skip the reserved data. - skip( get32() ); - - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = get16(); - if (compression > 1) - return epuc("unknown compression type", "PSD has an unknown compression format"); - - // Create the destination image. - out = (stbi_uc *) malloc(4 * w*h); - if (!out) return epuc("outofmem", "Out of memory"); - pixelCount = w*h; - - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); - - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop - - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, - // which we're going to just skip. - skip( h * channelCount * 2 ); - - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - uint8 *p; - - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; - } else { - // Read the RLE data. - count = 0; - while (count < pixelCount) { - len = get8(); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - count += len; - while (len) { - *p = get8(); - p += 4; - len--; - } - } else if (len > 128) { - uint32 val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len ^= 0x0FF; - len += 2; - val = get8(); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } - } - } - - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit value for each pixel in the image. - - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - uint8 *p; - - p = out + channel; - if (channel > channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; - } else { - // Read the data. - count = 0; - for (i = 0; i < pixelCount; i++) - *p = get8(), p += 4; - } - } - } - - if (req_comp && req_comp != 4) { - img_x = w; - img_y = h; - out = convert_format(out, 4, req_comp); - if (out == NULL) return out; // convert_format frees input on failure - } - - if (comp) *comp = channelCount; - *y = h; - *x = w; - - return out; -} - -#ifndef STBI_NO_STDIO -stbi_uc *stbi_psd_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *data; - FILE *f = fopen(filename, "rb"); - if (!f) return NULL; - data = stbi_psd_load_from_file(f, x,y,comp,req_comp); - fclose(f); - return data; -} - -stbi_uc *stbi_psd_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - start_file(f); - return psd_load(x,y,comp,req_comp); -} -#endif - -stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - start_mem(buffer, len); - return psd_load(x,y,comp,req_comp); -} - - -// ************************************************************************************************* -// Radiance RGBE HDR loader -// originally by Nicolas Schulz -#ifndef STBI_NO_HDR -static int hdr_test(void) -{ - char *signature = "#?RADIANCE\n"; - int i; - for (i=0; signature[i]; ++i) - if (get8() != signature[i]) - return 0; - return 1; -} - -int stbi_hdr_test_memory(stbi_uc const *buffer, int len) -{ - start_mem(buffer, len); - return hdr_test(); -} - -#ifndef STBI_NO_STDIO -int stbi_hdr_test_file(FILE *f) -{ - int r,n = ftell(f); - start_file(f); - r = hdr_test(); - fseek(f,n,SEEK_SET); - return r; -} -#endif - -#define HDR_BUFLEN 1024 -static char *hdr_gettoken(char *buffer) -{ - int len=0; - char *s = buffer, c = '\0'; - - c = get8(); - - while (!at_eof() && c != '\n') { - buffer[len++] = c; - if (len == HDR_BUFLEN-1) { - // flush to end of line - while (!at_eof() && get8() != '\n') - ; - break; - } - c = get8(); - } - - buffer[len] = 0; - return buffer; -} - -static void hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } -} - - -static float *hdr_load(int *x, int *y, int *comp, int req_comp) -{ - char buffer[HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - - - // Check identifier - if (strcmp(hdr_gettoken(buffer), "#?RADIANCE") != 0) - return epf("not HDR", "Corrupt HDR image"); - - // Parse header - while(1) { - token = hdr_gettoken(buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) return epf("unsupported format", "Unsupported HDR format"); - - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = hdr_gettoken(buffer); - if (strncmp(token, "-Y ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = strtol(token, NULL, 10); - - *x = width; - *y = height; - - *comp = 3; - if (req_comp == 0) req_comp = 3; - - // Read data - hdr_data = (float *) malloc(height * width * req_comp * sizeof(float)); - - // Load image data - // image data is stored as some number of sca - if( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - getn(rgbe, 4); - hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; - - for (j = 0; j < height; ++j) { - c1 = get8(); - c2 = get8(); - len = get8(); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4] = { c1,c2,len, get8() }; - hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - free(scanline); - goto main_decode_loop; // yes, this is fucking insane; blame the fucking insane format - } - len <<= 8; - len |= get8(); - if (len != width) { free(hdr_data); free(scanline); return epf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4); - - for (k = 0; k < 4; ++k) { - i = 0; - while (i < width) { - count = get8(); - if (count > 128) { - // Run - value = get8(); - count -= 128; - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = get8(); - } - } - } - for (i=0; i < width; ++i) - hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - free(scanline); - } - - return hdr_data; -} - -#ifndef STBI_NO_STDIO -float *stbi_hdr_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - start_file(f); - return hdr_load(x,y,comp,req_comp); -} -#endif - -float *stbi_hdr_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - start_mem(buffer, len); - return hdr_load(x,y,comp,req_comp); -} - -#endif // STBI_NO_HDR - -/////////////////////// write image /////////////////////// - -#ifndef STBI_NO_WRITE - -static void write8(FILE *f, int x) { uint8 z = (uint8) x; fwrite(&z,1,1,f); } - -static void writefv(FILE *f, char *fmt, va_list v) -{ - while (*fmt) { - switch (*fmt++) { - case ' ': break; - case '1': { uint8 x = va_arg(v, int); write8(f,x); break; } - case '2': { int16 x = va_arg(v, int); write8(f,x); write8(f,x>>8); break; } - case '4': { int32 x = va_arg(v, int); write8(f,x); write8(f,x>>8); write8(f,x>>16); write8(f,x>>24); break; } - default: - assert(0); - va_end(v); - return; - } - } -} - -static void writef(FILE *f, char *fmt, ...) -{ - va_list v; - va_start(v, fmt); - writefv(f,fmt,v); - va_end(v); -} - -static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad) -{ - uint8 bg[3] = { 255, 0, 255}, px[3]; - uint32 zero = 0; - int i,j,k, j_end; - - if (vdir < 0) - j_end = -1, j = y-1; - else - j_end = y, j = 0; - - for (; j != j_end; j += vdir) { - for (i=0; i < x; ++i) { - uint8 *d = (uint8 *) data + (j*x+i)*comp; - if (write_alpha < 0) - fwrite(&d[comp-1], 1, 1, f); - switch (comp) { - case 1: - case 2: writef(f, "111", d[0],d[0],d[0]); - break; - case 4: - if (!write_alpha) { - for (k=0; k < 3; ++k) - px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255; - writef(f, "111", px[1-rgb_dir],px[1],px[1+rgb_dir]); - break; - } - /* FALLTHROUGH */ - case 3: - writef(f, "111", d[1-rgb_dir],d[1],d[1+rgb_dir]); - break; - } - if (write_alpha > 0) - fwrite(&d[comp-1], 1, 1, f); - } - fwrite(&zero,scanline_pad,1,f); - } -} - -static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, char *fmt, ...) -{ - FILE *f = fopen(filename, "wb"); - if (f) { - va_list v; - va_start(v, fmt); - writefv(f, fmt, v); - va_end(v); - write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad); - fclose(f); - } - return f != NULL; -} - -int stbi_write_bmp(char const *filename, int x, int y, int comp, void *data) -{ - int pad = (-x*3) & 3; - return outfile(filename,-1,-1,x,y,comp,data,0,pad, - "11 4 22 4" "4 44 22 444444", - 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header - 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header -} - -int stbi_write_tga(char const *filename, int x, int y, int comp, void *data) -{ - int has_alpha = !(comp & 1); - return outfile(filename, -1,-1, x, y, comp, data, has_alpha, 0, - "111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha); -} - -// any other image formats that do interleaved rgb data? -// PNG: requires adler32,crc32 -- significant amount of code -// PSD: no, channels output separately -// TIFF: no, stripwise-interleaved... i think - -#endif // STBI_NO_WRITE +/* stbi-1.12 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c + when you control the images you're loading + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline (no JPEG progressive, no oddball channel decimations) + PNG non-interlaced + BMP non-1bpp, non-RLE + TGA (not sure what subset, if a subset) + PSD (composited view only, no extra channels) + HDR (radiance rgbE format) + writes BMP,TGA (define STBI_NO_WRITE to remove code) + decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code) + supports installable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) + + TODO: + stbi_info_* + + history: + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less + than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant +*/ + + +//// begin header file //////////////////////////////////////////////////// +// +// Limitations: +// - no progressive/interlaced support (jpeg, png) +// - 8-bit samples only (jpeg, png) +// - not threadsafe +// - channel subsampling of at most 2 in each dimension (jpeg) +// - no delayed line count (jpeg) -- IJG doesn't support either +// +// Basic usage (see HDR discussion below): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *comp -- outputs # of image components in image file +// int req_comp -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. +// If req_comp is non-zero, *comp has the number of components that _would_ +// have been output otherwise. E.g. if you set req_comp to 4, you will always +// get RGBA output, but you can check *comp to easily see if it's opaque. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() +// can be queried for an extremely brief, end-user unfriendly explanation +// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid +// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG and BMP images are automatically depalettized. +// +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); + + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_NO_HDR +#include // ldexp +#include // strcmp +#endif + +enum +{ + STBI_default = 0, // only used for req_comp + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4, +}; + +typedef unsigned char stbi_uc; + +#ifdef __cplusplus +extern "C" { +#endif + +// WRITING API + +#if !defined(STBI_NO_WRITE) && !defined(STBI_NO_STDIO) +// write a BMP/TGA file given tightly packed 'comp' channels (no padding, nor bmp-stride-padding) +// (you must include the appropriate extension in the filename). +// returns TRUE on success, FALSE if couldn't open file, error writing file +extern int stbi_write_bmp (char const *filename, int x, int y, int comp, void *data); +extern int stbi_write_tga (char const *filename, int x, int y, int comp, void *data); +#endif + +// PRIMARY API - works on images of any type + +// load image by filename, open file, or memory buffer +#ifndef STBI_NO_STDIO +extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif +extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +// for stbi_load_from_file, file pointer is left pointing immediately after image + +#ifndef STBI_NO_HDR +#ifndef STBI_NO_STDIO +extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); +extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif +extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + +extern void stbi_hdr_to_ldr_gamma(float gamma); +extern void stbi_hdr_to_ldr_scale(float scale); + +extern void stbi_ldr_to_hdr_gamma(float gamma); +extern void stbi_ldr_to_hdr_scale(float scale); + +#endif // STBI_NO_HDR + +// get a VERY brief reason for failure +extern char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +extern void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +extern int stbi_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_is_hdr (char const *filename); +extern int stbi_is_hdr_from_file(FILE *f); +#endif + +// ZLIB client - used by PNG, available for other purposes + +extern char *stbi_zlib_decode_malloc_guesssize(int initial_size, int *outlen); +extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +// TYPE-SPECIFIC ACCESS + +// is it a jpeg? +extern int stbi_jpeg_test_memory (stbi_uc const *buffer, int len); +extern stbi_uc *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +extern stbi_uc *stbi_jpeg_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern int stbi_jpeg_test_file (FILE *f); +extern stbi_uc *stbi_jpeg_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif + +extern int stbi_jpeg_dc_only; // only decode DC component + +// is it a png? +extern int stbi_png_test_memory (stbi_uc const *buffer, int len); +extern stbi_uc *stbi_png_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +extern stbi_uc *stbi_png_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern int stbi_png_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_png_test_file (FILE *f); +extern stbi_uc *stbi_png_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif + +// is it a bmp? +extern int stbi_bmp_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_bmp_test_file (FILE *f); +extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a tga? +extern int stbi_tga_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_tga_test_file (FILE *f); +extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a psd? +extern int stbi_psd_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_psd_test_file (FILE *f); +extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it an hdr? +extern int stbi_hdr_test_memory (stbi_uc const *buffer, int len); + +extern float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_hdr_test_file (FILE *f); +extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// define new loaders +typedef struct +{ + int (*test_memory)(stbi_uc const *buffer, int len); + stbi_uc * (*load_from_memory)(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + #ifndef STBI_NO_STDIO + int (*test_file)(FILE *f); + stbi_uc * (*load_from_file)(FILE *f, int *x, int *y, int *comp, int req_comp); + #endif +} stbi_loader; + +// register a loader by filling out the above structure (you must defined ALL functions) +// returns 1 if added or already added, 0 if not added (too many loaders) +extern int stbi_register_loader(stbi_loader *loader); + +// define faster low-level operations (typically SIMD support) +#if STBI_SIMD +typedef void (*stbi_idct_8x8)(uint8 *out, int out_stride, short data[64], unsigned short *dequantize); +// compute an integer IDCT on "input" +// input[x] = data[x] * dequantize[x] +// write results to 'out': 64 samples, each run of 8 spaced by 'out_stride' +// CLAMP results to 0..255 +typedef void (*stbi_YCbCr_to_RGB_run)(uint8 *output, uint8 const *y, uint8 const *cb, uint8 const *cr, int count, int step); +// compute a conversion from YCbCr to RGB +// 'count' pixels +// write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B +// y: Y input channel +// cb: Cb input channel; scale/biased to be 0..255 +// cr: Cr input channel; scale/biased to be 0..255 + +extern void stbi_install_idct(stbi_idct_8x8 func); +extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func); +#endif // STBI_SIMD + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// + +#ifndef STBI_NO_STDIO +#include +#endif +#include +#include +#include +#include + +#if STBI_SIMD +#include +#endif + +#ifndef _MSC_VER +#define __forceinline +#endif + + +// implementation: +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef signed short int16; +typedef unsigned int uint32; +typedef signed int int32; +typedef unsigned int uint; + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(uint32)==4]; + +#if defined(STBI_NO_STDIO) && !defined(STBI_NO_WRITE) +#define STBI_NO_WRITE +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// Generic API that works on all image types +// + +static char *failure_reason; + +char *stbi_failure_reason(void) +{ + return failure_reason; +} + +static int e(char *str) +{ + failure_reason = str; + return 0; +} + +#ifdef STBI_NO_FAILURE_STRINGS + #define e(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define e(x,y) e(y) +#else + #define e(x,y) e(x) +#endif + +#define epf(x,y) ((float *) (e(x,y)?NULL:NULL)) +#define epuc(x,y) ((unsigned char *) (e(x,y)?NULL:NULL)) + +void stbi_image_free(void *retval_from_stbi_load) +{ + free(retval_from_stbi_load); +} + +#define MAX_LOADERS 32 +stbi_loader *loaders[MAX_LOADERS]; +static int max_loaders = 0; + +int stbi_register_loader(stbi_loader *loader) +{ + int i; + for (i=0; i < MAX_LOADERS; ++i) { + // already present? + if (loaders[i] == loader) + return 1; + // end of the list? + if (loaders[i] == NULL) { + loaders[i] = loader; + max_loaders = i+1; + return 1; + } + } + // no room for it + return 0; +} + +#ifndef STBI_NO_HDR +static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_STDIO +unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = fopen(filename, "rb"); + unsigned char *result; + if (!f) return epuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + int i; + if (stbi_jpeg_test_file(f)) + return stbi_jpeg_load_from_file(f,x,y,comp,req_comp); + if (stbi_png_test_file(f)) + return stbi_png_load_from_file(f,x,y,comp,req_comp); + if (stbi_bmp_test_file(f)) + return stbi_bmp_load_from_file(f,x,y,comp,req_comp); + if (stbi_psd_test_file(f)) + return stbi_psd_load_from_file(f,x,y,comp,req_comp); + #ifndef STBI_NO_HDR + if (stbi_hdr_test_file(f)) { + float *hdr = stbi_hdr_load_from_file(f, x,y,comp,req_comp); + return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + for (i=0; i < max_loaders; ++i) + if (loaders[i]->test_file(f)) + return loaders[i]->load_from_file(f,x,y,comp,req_comp); + // test tga last because it's a crappy test! + if (stbi_tga_test_file(f)) + return stbi_tga_load_from_file(f,x,y,comp,req_comp); + return epuc("unknown image type", "Image not of any known type, or corrupt"); +} +#endif + +unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + int i; + if (stbi_jpeg_test_memory(buffer,len)) + return stbi_jpeg_load_from_memory(buffer,len,x,y,comp,req_comp); + if (stbi_png_test_memory(buffer,len)) + return stbi_png_load_from_memory(buffer,len,x,y,comp,req_comp); + if (stbi_bmp_test_memory(buffer,len)) + return stbi_bmp_load_from_memory(buffer,len,x,y,comp,req_comp); + if (stbi_psd_test_memory(buffer,len)) + return stbi_psd_load_from_memory(buffer,len,x,y,comp,req_comp); + #ifndef STBI_NO_HDR + if (stbi_hdr_test_memory(buffer, len)) { + float *hdr = stbi_hdr_load_from_memory(buffer, len,x,y,comp,req_comp); + return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + for (i=0; i < max_loaders; ++i) + if (loaders[i]->test_memory(buffer,len)) + return loaders[i]->load_from_memory(buffer,len,x,y,comp,req_comp); + // test tga last because it's a crappy test! + if (stbi_tga_test_memory(buffer,len)) + return stbi_tga_load_from_memory(buffer,len,x,y,comp,req_comp); + return epuc("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_HDR + +#ifndef STBI_NO_STDIO +float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = fopen(filename, "rb"); + float *result; + if (!f) return epf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi_hdr_test_file(f)) + return stbi_hdr_load_from_file(f,x,y,comp,req_comp); + #endif + data = stbi_load_from_file(f, x, y, comp, req_comp); + if (data) + return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return epf("unknown image type", "Image not of any known type, or corrupt"); +} +#endif + +float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + #ifndef STBI_NO_HDR + if (stbi_hdr_test_memory(buffer, len)) + return stbi_hdr_load_from_memory(buffer, len,x,y,comp,req_comp); + #endif + data = stbi_load_from_memory(buffer, len, x, y, comp, req_comp); + if (data) + return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return epf("unknown image type", "Image not of any known type, or corrupt"); +} +#endif + +// these is-hdr-or-not is defined independent of whether STBI_NO_HDR is +// defined, for API simplicity; if STBI_NO_HDR is defined, it always +// reports false! + +extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + return stbi_hdr_test_memory(buffer, len); + #else + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +extern int stbi_is_hdr (char const *filename) +{ + FILE *f = fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +extern int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + return stbi_hdr_test_file(f); + #else + return 0; + #endif +} + +#endif + +// @TODO: get image dimensions & components without fully decoding +#ifndef STBI_NO_STDIO +extern int stbi_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif +extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +#ifndef STBI_NO_HDR +static float h2l_gamma_i=1.0f/2.2f, h2l_scale_i=1.0f; +static float l2h_gamma=2.2f, l2h_scale=1.0f; + +void stbi_hdr_to_ldr_gamma(float gamma) { h2l_gamma_i = 1/gamma; } +void stbi_hdr_to_ldr_scale(float scale) { h2l_scale_i = 1/scale; } + +void stbi_ldr_to_hdr_gamma(float gamma) { l2h_gamma = gamma; } +void stbi_ldr_to_hdr_scale(float scale) { l2h_scale = scale; } +#endif + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +// image width, height, # components +static uint32 img_x, img_y; +static int img_n, img_out_n; + +enum +{ + SCAN_load=0, + SCAN_type, + SCAN_header, +}; + +// An API for reading either from memory or file. +#ifndef STBI_NO_STDIO +static FILE *img_file; +#endif +static uint8 const *img_buffer, *img_buffer_end; + +#ifndef STBI_NO_STDIO +static void start_file(FILE *f) +{ + img_file = f; +} +#endif + +static void start_mem(uint8 const *buffer, int len) +{ +#ifndef STBI_NO_STDIO + img_file = NULL; +#endif + img_buffer = buffer; + img_buffer_end = buffer+len; +} + +static int get8(void) +{ +#ifndef STBI_NO_STDIO + if (img_file) { + int c = fgetc(img_file); + return c == EOF ? 0 : c; + } +#endif + if (img_buffer < img_buffer_end) + return *img_buffer++; + return 0; +} + +static int at_eof(void) +{ +#ifndef STBI_NO_STDIO + if (img_file) + return feof(img_file); +#endif + return img_buffer >= img_buffer_end; +} + +static uint8 get8u(void) +{ + return (uint8) get8(); +} + +static void skip(int n) +{ +#ifndef STBI_NO_STDIO + if (img_file) + fseek(img_file, n, SEEK_CUR); + else +#endif + img_buffer += n; +} + +static int get16(void) +{ + int z = get8(); + return (z << 8) + get8(); +} + +static uint32 get32(void) +{ + uint32 z = get16(); + return (z << 16) + get16(); +} + +static int get16le(void) +{ + int z = get8(); + return z + (get8() << 8); +} + +static uint32 get32le(void) +{ + uint32 z = get16le(); + return z + (get16le() << 16); +} + +static void getn(stbi_uc *buffer, int n) +{ +#ifndef STBI_NO_STDIO + if (img_file) { + fread(buffer, 1, n, img_file); + return; + } +#endif + memcpy(buffer, img_buffer, n); + img_buffer += n; +} + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static uint8 compute_y(int r, int g, int b) +{ + return (uint8) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *convert_format(unsigned char *data, int img_n, int req_comp) +{ + uint i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + assert(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) malloc(req_comp * img_x * img_y); + if (good == NULL) { + free(data); + return epuc("outofmem", "Out of memory"); + } + + for (j=0; j < img_y; ++j) { + unsigned char *src = data + j * img_x * img_n ; + unsigned char *dest = good + j * img_x * req_comp; + + #define COMBO(a,b) ((a)*8+(b)) + #define CASE(a,b) case COMBO(a,b): for(i=0; i < img_x; ++i, src += a, dest += b) + + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch(COMBO(img_n, req_comp)) { + CASE(1,2) dest[0]=src[0], dest[1]=255; break; + CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; + CASE(2,1) dest[0]=src[0]; break; + CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; + CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; + CASE(3,1) dest[0]=compute_y(src[0],src[1],src[2]); break; + CASE(3,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = 255; break; + CASE(4,1) dest[0]=compute_y(src[0],src[1],src[2]); break; + CASE(4,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; + CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; + default: assert(0); + } + #undef CASE + } + + free(data); + img_out_n = req_comp; + return good; +} + +#ifndef STBI_NO_HDR +static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output = (float *) malloc(x * y * comp * sizeof(float)); + if (output == NULL) { free(data); return epf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) pow(data[i*comp+k]/255.0f, l2h_gamma) * l2h_scale; + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + free(data); + return output; +} + +#define float2int(x) ((int) (x)) +static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output = (stbi_uc *) malloc(x * y * comp); + if (output == NULL) { free(data); return epuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*h2l_scale_i, h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = float2int(z); + } + } + free(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder (not actually fully baseline implementation) +// +// simple implementation +// - channel subsampling of at most 2 in each dimension +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - uses a lot of intermediate memory, could cache poorly +// - load http://nothings.org/remote/anemones.jpg 3 times on 2.8Ghz P4 +// stb_jpeg: 1.34 seconds (MSVC6, default release build) +// stb_jpeg: 1.06 seconds (MSVC6, processor = Pentium Pro) +// IJL11.dll: 1.08 seconds (compiled by intel) +// IJG 1998: 0.98 seconds (MSVC6, makefile provided by IJG) +// IJG 1998: 0.95 seconds (MSVC6, makefile + proc=PPro) + +int stbi_jpeg_dc_only; + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + uint8 fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + uint16 code[256]; + uint8 values[256]; + uint8 size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} huffman; + +static huffman huff_dc[4]; // baseline is 2 tables, extended is 4 +static huffman huff_ac[4]; +static uint8 dequant[4][64]; +#if STBI_SIMD +static __declspec(align(16)) unsigned short dequant2[4][64]; +#endif + +static int build_huffman(huffman *h, int *count) +{ + int i,j,k=0,code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (uint8) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (uint16) (code++); + if (code-1 >= (1 << j)) return e("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (uint8) i; + } + } + } + return 1; +} + +// sizes for components, interleaved MCUs +static int img_h_max, img_v_max; +static int img_mcu_x, img_mcu_y; +static int img_mcu_w, img_mcu_h; + +// definition of jpeg image component +static struct +{ + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + uint8 *data; + void *raw_data; + uint8 *linebuf; +} img_comp[4]; + +static uint32 code_buffer; // jpeg entropy-coded buffer +static int code_bits; // number of valid bits +static unsigned char marker; // marker seen while filling entropy buffer +static int nomore; // flag if we saw a marker so must stop + +static void grow_buffer_unsafe(void) +{ + do { + int b = nomore ? 0 : get8(); + if (b == 0xff) { + int c = get8(); + if (c != 0) { + marker = (unsigned char) c; + nomore = 1; + return; + } + } + code_buffer = (code_buffer << 8) | b; + code_bits += 8; + } while (code_bits <= 24); +} + +// (1 << n) - 1 +static uint32 bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +__forceinline static int decode(huffman *h) +{ + unsigned int temp; + int c,k; + + if (code_bits < 16) grow_buffer_unsafe(); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (code_buffer >> (code_bits - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + if (h->size[k] > code_bits) + return -1; + code_bits -= h->size[k]; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + if (code_bits < 16) + temp = (code_buffer << (16 - code_bits)) & 0xffff; + else + temp = (code_buffer >> (code_bits - 16)) & 0xffff; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + code_bits -= 16; + return -1; + } + + if (k > code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((code_buffer >> (code_bits - k)) & bmask[k]) + h->delta[k]; + assert((((code_buffer) >> (code_bits - h->size[c])) & bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + code_bits -= k; + return h->values[c]; +} + +// combined JPEG 'receive' and JPEG 'extend', since baseline +// always extends everything it receives. +__forceinline static int extend_receive(int n) +{ + unsigned int m = 1 << (n-1); + unsigned int k; + if (code_bits < n) grow_buffer_unsafe(); + k = (code_buffer >> (code_bits - n)) & bmask[n]; + code_bits -= n; + // the following test is probably a random branch that won't + // predict well. I tried to table accelerate it but failed. + // maybe it's compiling as a conditional move? + if (k < m) + return (-1 << n) + k + 1; + else + return k; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static uint8 dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int decode_block(short data[64], huffman *hdc, huffman *hac, int b) +{ + int diff,dc,k; + int t = decode(hdc); + if (t < 0) return e("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? extend_receive(t) : 0; + dc = img_comp[b].dc_pred + diff; + img_comp[b].dc_pred = dc; + data[0] = (short) dc; + + // decode AC components, see JPEG spec + k = 1; + do { + int r,s; + int rs = decode(hac); + if (rs < 0) return e("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + data[dezigzag[k++]] = (short) extend_receive(s); + } + } while (k < 64); + return 1; +} + +// take a -128..127 value and clamp it and convert to 0..255 +__forceinline static uint8 clamp(int x) +{ + x += 128; + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (uint8) x; +} + +#define f2f(x) (int) (((x) * 4096 + 0.5)) +#define fsh(x) ((x) << 12) + +// derived from jidctint -- DCT_ISLOW +#define IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * f2f(0.5411961f); \ + t2 = p1 + p3*f2f(-1.847759065f); \ + t3 = p1 + p2*f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = fsh(p2+p3); \ + t1 = fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*f2f( 1.175875602f); \ + t0 = t0*f2f( 0.298631336f); \ + t1 = t1*f2f( 2.053119869f); \ + t2 = t2*f2f( 3.072711026f); \ + t3 = t3*f2f( 1.501321110f); \ + p1 = p5 + p1*f2f(-0.899976223f); \ + p2 = p5 + p2*f2f(-2.562915447f); \ + p3 = p3*f2f(-1.961570560f); \ + p4 = p4*f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +#if !STBI_SIMD +// .344 seconds on 3*anemones.jpg +static void idct_block(uint8 *out, int out_stride, short data[64], uint8 *dequantize) +{ + int i,val[64],*v=val; + uint8 *o,*dq = dequantize; + short *d = data; + + if (stbi_jpeg_dc_only) { + // ok, I don't really know why this is right, but it seems to be: + int z = 128 + ((d[0] * dq[0]) >> 3); + for (i=0; i < 8; ++i) { + out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = out[7] = z; + out += out_stride; + } + return; + } + + // columns + for (i=0; i < 8; ++i,++d,++dq, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] * dq[0] << 2; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24], + d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + x0 += 65536; x1 += 65536; x2 += 65536; x3 += 65536; + o[0] = clamp((x0+t3) >> 17); + o[7] = clamp((x0-t3) >> 17); + o[1] = clamp((x1+t2) >> 17); + o[6] = clamp((x1-t2) >> 17); + o[2] = clamp((x2+t1) >> 17); + o[5] = clamp((x2-t1) >> 17); + o[3] = clamp((x3+t0) >> 17); + o[4] = clamp((x3-t0) >> 17); + } +} +#else +static void idct_block(uint8 *out, int out_stride, short data[64], unsigned short *dequantize) +{ + int i,val[64],*v=val; + uint8 *o; + unsigned short *dq = dequantize; + short *d = data; + + if (stbi_jpeg_dc_only) { + // ok, I don't really know why this is right, but it seems to be: + int z = 128 + ((d[0] * dq[0]) >> 3); + for (i=0; i < 8; ++i) { + out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] = out[7] = z; + out += out_stride; + } + return; + } + + // columns + for (i=0; i < 8; ++i,++d,++dq, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] * dq[0] << 2; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24], + d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + x0 += 65536; x1 += 65536; x2 += 65536; x3 += 65536; + o[0] = clamp((x0+t3) >> 17); + o[7] = clamp((x0-t3) >> 17); + o[1] = clamp((x1+t2) >> 17); + o[6] = clamp((x1-t2) >> 17); + o[2] = clamp((x2+t1) >> 17); + o[5] = clamp((x2-t1) >> 17); + o[3] = clamp((x3+t0) >> 17); + o[4] = clamp((x3-t0) >> 17); + } +} +static stbi_idct_8x8 stbi_idct_installed = idct_block; + +extern void stbi_install_idct(stbi_idct_8x8 func) +{ + stbi_idct_installed = func; +} +#endif + +#define MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static uint8 get_marker(void) +{ + uint8 x; + if (marker != MARKER_none) { x = marker; marker = MARKER_none; return x; } + x = get8u(); + if (x != 0xff) return MARKER_none; + while (x == 0xff) + x = get8u(); + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +static int scan_n, order[4]; +static int restart_interval, todo; +#define RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, reset the entropy decoder and +// the dc prediction +static void reset(void) +{ + code_bits = 0; + code_buffer = 0; + nomore = 0; + img_comp[0].dc_pred = img_comp[1].dc_pred = img_comp[2].dc_pred = 0; + marker = MARKER_none; + todo = restart_interval ? restart_interval : 0x7fffffff; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int parse_entropy_coded_data(void) +{ + reset(); + if (scan_n == 1) { + int i,j; + #if STBI_SIMD + __declspec(align(16)) + #endif + short data[64]; + int n = order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (img_comp[n].x+7) >> 3; + int h = (img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + if (!decode_block(data, huff_dc+img_comp[n].hd, huff_ac+img_comp[n].ha, n)) return 0; + #if STBI_SIMD + stbi_idct_installed(img_comp[n].data+img_comp[n].w2*j*8+i*8, img_comp[n].w2, data, dequant2[img_comp[n].tq]); + #else + idct_block(img_comp[n].data+img_comp[n].w2*j*8+i*8, img_comp[n].w2, data, dequant[img_comp[n].tq]); + #endif + // every data block is an MCU, so countdown the restart interval + if (--todo <= 0) { + if (code_bits < 24) grow_buffer_unsafe(); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!RESTART(marker)) return 1; + reset(); + } + } + } + } else { // interleaved! + int i,j,k,x,y; + short data[64]; + for (j=0; j < img_mcu_y; ++j) { + for (i=0; i < img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < scan_n; ++k) { + int n = order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < img_comp[n].v; ++y) { + for (x=0; x < img_comp[n].h; ++x) { + int x2 = (i*img_comp[n].h + x)*8; + int y2 = (j*img_comp[n].v + y)*8; + if (!decode_block(data, huff_dc+img_comp[n].hd, huff_ac+img_comp[n].ha, n)) return 0; + #if STBI_SIMD + stbi_idct_installed(img_comp[n].data+img_comp[n].w2*y2+x2, img_comp[n].w2, data, dequant2[img_comp[n].tq]); + #else + idct_block(img_comp[n].data+img_comp[n].w2*y2+x2, img_comp[n].w2, data, dequant[img_comp[n].tq]); + #endif + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--todo <= 0) { + if (code_bits < 24) grow_buffer_unsafe(); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!RESTART(marker)) return 1; + reset(); + } + } + } + } + return 1; +} + +static int process_marker(int m) +{ + int L; + switch (m) { + case MARKER_none: // no marker found + return e("expected marker","Corrupt JPEG"); + + case 0xC2: // SOF - progressive + return e("progressive jpeg","JPEG format not supported (progressive)"); + + case 0xDD: // DRI - specify restart interval + if (get16() != 4) return e("bad DRI len","Corrupt JPEG"); + restart_interval = get16(); + return 1; + + case 0xDB: // DQT - define quantization table + L = get16()-2; + while (L > 0) { + int z = get8(); + int p = z >> 4; + int t = z & 15,i; + if (p != 0) return e("bad DQT type","Corrupt JPEG"); + if (t > 3) return e("bad DQT table","Corrupt JPEG"); + for (i=0; i < 64; ++i) + dequant[t][dezigzag[i]] = get8u(); + #if STBI_SIMD + for (i=0; i < 64; ++i) + dequant2[t][i] = dequant[t][i]; + #endif + L -= 65; + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = get16()-2; + while (L > 0) { + uint8 *v; + int sizes[16],i,m=0; + int z = get8(); + int tc = z >> 4; + int th = z & 15; + if (tc > 1 || th > 3) return e("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = get8(); + m += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!build_huffman(huff_dc+th, sizes)) return 0; + v = huff_dc[th].values; + } else { + if (!build_huffman(huff_ac+th, sizes)) return 0; + v = huff_ac[th].values; + } + for (i=0; i < m; ++i) + v[i] = get8u(); + L -= m; + } + return L==0; + } + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + skip(get16()-2); + return 1; + } + return 0; +} + +// after we see SOS +static int process_scan_header(void) +{ + int i; + int Ls = get16(); + scan_n = get8(); + if (scan_n < 1 || scan_n > 4 || scan_n > (int) img_n) return e("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*scan_n) return e("bad SOS len","Corrupt JPEG"); + for (i=0; i < scan_n; ++i) { + int id = get8(), which; + int z = get8(); + for (which = 0; which < img_n; ++which) + if (img_comp[which].id == id) + break; + if (which == img_n) return 0; + img_comp[which].hd = z >> 4; if (img_comp[which].hd > 3) return e("bad DC huff","Corrupt JPEG"); + img_comp[which].ha = z & 15; if (img_comp[which].ha > 3) return e("bad AC huff","Corrupt JPEG"); + order[i] = which; + } + if (get8() != 0) return e("bad SOS","Corrupt JPEG"); + get8(); // should be 63, but might be 0 + if (get8() != 0) return e("bad SOS","Corrupt JPEG"); + + return 1; +} + +static int process_frame_header(int scan) +{ + int Lf,p,i,z, h_max=1,v_max=1; + Lf = get16(); if (Lf < 11) return e("bad SOF len","Corrupt JPEG"); // JPEG + p = get8(); if (p != 8) return e("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + img_y = get16(); if (img_y == 0) return e("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + img_x = get16(); if (img_x == 0) return e("0 width","Corrupt JPEG"); // JPEG requires + img_n = get8(); + if (img_n != 3 && img_n != 1) return e("bad component count","Corrupt JPEG"); // JFIF requires + + if (Lf != 8+3*img_n) return e("bad SOF len","Corrupt JPEG"); + + for (i=0; i < img_n; ++i) { + img_comp[i].id = get8(); + if (img_comp[i].id != i+1) // JFIF requires + if (img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! + return e("bad component ID","Corrupt JPEG"); + z = get8(); + img_comp[i].h = (z >> 4); if (!img_comp[i].h || img_comp[i].h > 4) return e("bad H","Corrupt JPEG"); + img_comp[i].v = z & 15; if (!img_comp[i].v || img_comp[i].v > 4) return e("bad V","Corrupt JPEG"); + img_comp[i].tq = get8(); if (img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG"); + } + + if (scan != SCAN_load) return 1; + + if ((1 << 30) / img_x / img_n < img_y) return e("too large", "Image too large to decode"); + + for (i=0; i < img_n; ++i) { + if (img_comp[i].h > h_max) h_max = img_comp[i].h; + if (img_comp[i].v > v_max) v_max = img_comp[i].v; + } + + // compute interleaved mcu info + img_h_max = h_max; + img_v_max = v_max; + img_mcu_w = h_max * 8; + img_mcu_h = v_max * 8; + img_mcu_x = (img_x + img_mcu_w-1) / img_mcu_w; + img_mcu_y = (img_y + img_mcu_h-1) / img_mcu_h; + + for (i=0; i < img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + img_comp[i].x = (img_x * img_comp[i].h + h_max-1) / h_max; + img_comp[i].y = (img_y * img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + img_comp[i].w2 = img_mcu_x * img_comp[i].h * 8; + img_comp[i].h2 = img_mcu_y * img_comp[i].v * 8; + img_comp[i].raw_data = malloc(img_comp[i].w2 * img_comp[i].h2+15); + if (img_comp[i].raw_data == NULL) { + for(--i; i >= 0; --i) { + free(img_comp[i].raw_data); + img_comp[i].data = NULL; + } + return e("outofmem", "Out of memory"); + } + img_comp[i].data = (uint8*) (((int) img_comp[i].raw_data + 15) & ~15); + img_comp[i].linebuf = NULL; + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define DNL(x) ((x) == 0xdc) +#define SOI(x) ((x) == 0xd8) +#define EOI(x) ((x) == 0xd9) +#define SOF(x) ((x) == 0xc0 || (x) == 0xc1) +#define SOS(x) ((x) == 0xda) + +static int decode_jpeg_header(int scan) +{ + int m; + marker = MARKER_none; // initialize cached marker to empty + m = get_marker(); + if (!SOI(m)) return e("no SOI","Corrupt JPEG"); + if (scan == SCAN_type) return 1; + m = get_marker(); + while (!SOF(m)) { + if (!process_marker(m)) return 0; + m = get_marker(); + while (m == MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (at_eof()) return e("no SOF", "Corrupt JPEG"); + m = get_marker(); + } + } + if (!process_frame_header(scan)) return 0; + return 1; +} + +static int decode_jpeg_image(void) +{ + int m; + restart_interval = 0; + if (!decode_jpeg_header(SCAN_load)) return 0; + m = get_marker(); + while (!EOI(m)) { + if (SOS(m)) { + if (!process_scan_header()) return 0; + if (!parse_entropy_coded_data()) return 0; + } else { + if (!process_marker(m)) return 0; + } + m = get_marker(); + } + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef uint8 *(*resample_row_func)(uint8 *out, uint8 *in0, uint8 *in1, + int w, int hs); + +#define div4(x) ((uint8) ((x) >> 2)) + +static uint8 *resample_row_1(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + return in_near; +} + +static uint8* resample_row_v_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + for (i=0; i < w; ++i) + out[i] = div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static uint8* resample_row_h_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + uint8 *input = in_near; + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = div4(n+input[i-1]); + out[i*2+1] = div4(n+input[i+1]); + } + out[i*2+0] = div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + return out; +} + +#define div16(x) ((uint8) ((x) >> 4)) + +static uint8 *resample_row_hv_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = div16(3*t0 + t1 + 8); + out[i*2 ] = div16(3*t1 + t0 + 8); + } + out[w*2-1] = div4(t1+2); + return out; +} + +static uint8 *resample_row_generic(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) + +// 0.38 seconds on 3*anemones.jpg (0.25 with processor = Pro) +// VC6 without processor=Pro is generating multiple LEAs per multiply! +static void YCbCr_to_RGB_row(uint8 *out, uint8 *y, uint8 *pcb, uint8 *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 16) + 32768; // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr*float2fixed(1.40200f); + g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); + b = y_fixed + cb*float2fixed(1.77200f); + r >>= 16; + g >>= 16; + b >>= 16; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (uint8)r; + out[1] = (uint8)g; + out[2] = (uint8)b; + out[3] = 255; + out += step; + } +} + +#if STBI_SIMD +static stbi_YCbCr_to_RGB_run stbi_YCbCr_installed = YCbCr_to_RGB_row; + +void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func) +{ + stbi_YCbCr_installed = func; +} +#endif + + +// clean up the temporary component buffers +static void cleanup_jpeg(void) +{ + int i; + for (i=0; i < img_n; ++i) { + if (img_comp[i].data) { + free(img_comp[i].raw_data); + img_comp[i].data = NULL; + } + if (img_comp[i].linebuf) { + free(img_comp[i].linebuf); + img_comp[i].linebuf = NULL; + } + } +} + +typedef struct +{ + resample_row_func resample; + uint8 *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi_resample; + +static uint8 *load_jpeg_image(int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n; + // validate req_comp + if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source + if (!decode_jpeg_image()) { cleanup_jpeg(); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : img_n; + + if (img_n == 3 && n < 3) + decode_n = 1; + else + decode_n = img_n; + + // resample and color-convert + { + int k; + uint i,j; + uint8 *output; + uint8 *coutput[4]; + + stbi_resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi_resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + img_comp[k].linebuf = (uint8 *) malloc(img_x + 3); + if (!img_comp[k].linebuf) { cleanup_jpeg(); return epuc("outofmem", "Out of memory"); } + + r->hs = img_h_max / img_comp[k].h; + r->vs = img_v_max / img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = resample_row_hv_2; + else r->resample = resample_row_generic; + } + + // can't error after this so, this is safe + output = (uint8 *) malloc(n * img_x * img_y + 1); + if (!output) { cleanup_jpeg(); return epuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < img_y; ++j) { + uint8 *out = output + n * img_x * j; + for (k=0; k < decode_n; ++k) { + stbi_resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < img_comp[k].y) + r->line1 += img_comp[k].w2; + } + } + if (n >= 3) { + uint8 *y = coutput[0]; + if (img_n == 3) { + #if STBI_SIMD + stbi_YCbCr_installed(out, y, coutput[1], coutput[2], img_x, n); + #else + YCbCr_to_RGB_row(out, y, coutput[1], coutput[2], img_x, n); + #endif + } else + for (i=0; i < img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + uint8 *y = coutput[0]; + if (n == 1) + for (i=0; i < img_x; ++i) out[i] = y[i]; + else + for (i=0; i < img_x; ++i) *out++ = y[i], *out++ = 255; + } + } + cleanup_jpeg(); + *out_x = img_x; + *out_y = img_y; + if (comp) *comp = img_n; // report original components, not output + return output; + } +} + +#ifndef STBI_NO_STDIO +unsigned char *stbi_jpeg_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + start_file(f); + return load_jpeg_image(x,y,comp,req_comp); +} + +unsigned char *stbi_jpeg_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_jpeg_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return data; +} +#endif + +unsigned char *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + start_mem(buffer,len); + return load_jpeg_image(x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +int stbi_jpeg_test_file(FILE *f) +{ + int n,r; + n = ftell(f); + start_file(f); + r = decode_jpeg_header(SCAN_type); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_jpeg_test_memory(stbi_uc const *buffer, int len) +{ + start_mem(buffer,len); + return decode_jpeg_header(SCAN_type); +} + +// @TODO: +#ifndef STBI_NO_STDIO +extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif +extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define ZFAST_BITS 9 // accelerate all cases in default tables +#define ZFAST_MASK ((1 << ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + uint16 fast[1 << ZFAST_BITS]; + uint16 firstcode[16]; + int maxcode[17]; + uint16 firstsymbol[16]; + uint8 size[288]; + uint16 value[288]; +} zhuffman; + +__forceinline static int bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +__forceinline static int bit_reverse(int v, int bits) +{ + assert(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return bitreverse16(v) >> (16-bits); +} + +static int zbuild_huffman(zhuffman *z, uint8 *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 255, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + assert(sizes[i] <= (1 << i)); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (uint16) code; + z->firstsymbol[i] = (uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return e("bad codelengths","Corrupt JPEG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + z->size[c] = (uint8)s; + z->value[c] = (uint16)i; + if (s <= ZFAST_BITS) { + int k = bit_reverse(next_code[s],s); + while (k < (1 << ZFAST_BITS)) { + z->fast[k] = (uint16) c; + k += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +static uint8 *zbuffer, *zbuffer_end; + +__forceinline static int zget8(void) +{ + if (zbuffer >= zbuffer_end) return 0; + return *zbuffer++; +} + +//static uint32 code_buffer; +static int num_bits; + +static void fill_bits(void) +{ + do { + assert(code_buffer < (1U << num_bits)); + code_buffer |= zget8() << num_bits; + num_bits += 8; + } while (num_bits <= 24); +} + +__forceinline static unsigned int zreceive(int n) +{ + unsigned int k; + if (num_bits < n) fill_bits(); + k = code_buffer & ((1 << n) - 1); + code_buffer >>= n; + num_bits -= n; + return k; +} + +__forceinline static int zhuffman_decode(zhuffman *z) +{ + int b,s,k; + if (num_bits < 16) fill_bits(); + b = z->fast[code_buffer & ZFAST_MASK]; + if (b < 0xffff) { + s = z->size[b]; + code_buffer >>= s; + num_bits -= s; + return z->value[b]; + } + + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = bit_reverse(code_buffer, 16); + for (s=ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + assert(z->size[b] == s); + code_buffer >>= s; + num_bits -= s; + return z->value[b]; +} + +static char *zout; +static char *zout_start; +static char *zout_end; +static int z_expandable; + +static int expand(int n) // need to make room for n bytes +{ + char *q; + int cur, limit; + if (!z_expandable) return e("output buffer limit","Corrupt PNG"); + cur = (int) (zout - zout_start); + limit = (int) (zout_end - zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) realloc(zout_start, limit); + if (q == NULL) return e("outofmem", "Out of memory"); + zout_start = q; + zout = q + cur; + zout_end = q + limit; + return 1; +} + +static zhuffman z_length, z_distance; + +static int length_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static int length_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static int dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static int dist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int parse_huffman_block(void) +{ + for(;;) { + int z = zhuffman_decode(&z_length); + if (z < 256) { + if (z < 0) return e("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= zout_end) if (!expand(1)) return 0; + *zout++ = (char) z; + } else { + uint8 *p; + int len,dist; + if (z == 256) return 1; + z -= 257; + len = length_base[z]; + if (length_extra[z]) len += zreceive(length_extra[z]); + z = zhuffman_decode(&z_distance); + if (z < 0) return e("bad huffman code","Corrupt PNG"); + dist = dist_base[z]; + if (dist_extra[z]) dist += zreceive(dist_extra[z]); + if (zout - zout_start < dist) return e("bad dist","Corrupt PNG"); + if (zout + len > zout_end) if (!expand(len)) return 0; + p = (uint8 *) (zout - dist); + while (len--) + *zout++ = *p++; + } + } +} + +static int compute_huffman_codes(void) +{ + static uint8 length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static zhuffman z_codelength; // static just to save stack space + uint8 lencodes[286+32+137];//padding for maximum single op + uint8 codelength_sizes[19]; + int i,n; + + int hlit = zreceive(5) + 257; + int hdist = zreceive(5) + 1; + int hclen = zreceive(4) + 4; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = zreceive(3); + codelength_sizes[length_dezigzag[i]] = (uint8) s; + } + if (!zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < hlit + hdist) { + int c = zhuffman_decode(&z_codelength); + assert(c >= 0 && c < 19); + if (c < 16) + lencodes[n++] = (uint8) c; + else if (c == 16) { + c = zreceive(2)+3; + memset(lencodes+n, lencodes[n-1], c); + n += c; + } else if (c == 17) { + c = zreceive(3)+3; + memset(lencodes+n, 0, c); + n += c; + } else { + assert(c == 18); + c = zreceive(7)+11; + memset(lencodes+n, 0, c); + n += c; + } + } + if (n != hlit+hdist) return e("bad codelengths","Corrupt PNG"); + if (!zbuild_huffman(&z_length, lencodes, hlit)) return 0; + if (!zbuild_huffman(&z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int parse_uncompressed_block(void) +{ + uint8 header[4]; + int len,nlen,k; + if (num_bits & 7) + zreceive(num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (num_bits > 0) { + header[k++] = (uint8) (code_buffer & 255); // wtf this warns? + code_buffer >>= 8; + num_bits -= 8; + } + assert(num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = (uint8) zget8(); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return e("zlib corrupt","Corrupt PNG"); + if (zbuffer + len > zbuffer_end) return e("read past buffer","Corrupt PNG"); + if (zout + len > zout_end) + if (!expand(len)) return 0; + memcpy(zout, zbuffer, len); + zbuffer += len; + zout += len; + return 1; +} + +static int parse_zlib_header(void) +{ + int cmf = zget8(); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = zget8(); + if ((cmf*256+flg) % 31 != 0) return e("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return e("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return e("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static uint8 default_length[288], default_distance[32]; +static void init_defaults(void) +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) default_length[i] = 8; + for ( ; i <= 255; ++i) default_length[i] = 9; + for ( ; i <= 279; ++i) default_length[i] = 7; + for ( ; i <= 287; ++i) default_length[i] = 8; + + for (i=0; i <= 31; ++i) default_distance[i] = 5; +} + +static int parse_zlib(int parse_header) +{ + int final, type; + if (parse_header) + if (!parse_zlib_header()) return 0; + num_bits = 0; + code_buffer = 0; + do { + final = zreceive(1); + type = zreceive(2); + if (type == 0) { + if (!parse_uncompressed_block()) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!default_length[0]) init_defaults(); + if (!zbuild_huffman(&z_length , default_length , 288)) return 0; + if (!zbuild_huffman(&z_distance, default_distance, 32)) return 0; + } else { + if (!compute_huffman_codes()) return 0; + } + if (!parse_huffman_block()) return 0; + } + } while (!final); + return 1; +} + +static int do_zlib(char *obuf, int olen, int exp, int parse_header) +{ + zout_start = obuf; + zout = obuf; + zout_end = obuf + olen; + z_expandable = exp; + + return parse_zlib(parse_header); +} + +char *stbi_zlib_decode_malloc_guesssize(int initial_size, int *outlen) +{ + char *p = (char *) malloc(initial_size); + if (p == NULL) return NULL; + if (do_zlib(p, initial_size, 1, 1)) { + *outlen = (int) (zout - zout_start); + return zout_start; + } else { + free(zout_start); + return NULL; + } +} + +char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + zbuffer = (uint8 *) buffer; + zbuffer_end = (uint8 *) buffer+len; + return stbi_zlib_decode_malloc_guesssize(16384, outlen); +} + +int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + zbuffer = (uint8 *) ibuffer; + zbuffer_end = (uint8 *) ibuffer + ilen; + if (do_zlib(obuffer, olen, 0, 1)) + return (int) (zout - zout_start); + else + return -1; +} + +char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + char *p = (char *) malloc(16384); + if (p == NULL) return NULL; + zbuffer = (uint8 *) buffer; + zbuffer_end = (uint8 *) buffer+len; + if (do_zlib(p, 16384, 1, 0)) { + *outlen = (int) (zout - zout_start); + return zout_start; + } else { + free(zout_start); + return NULL; + } +} + +int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + zbuffer = (uint8 *) ibuffer; + zbuffer_end = (uint8 *) ibuffer + ilen; + if (do_zlib(obuffer, olen, 0, 0)) + return (int) (zout - zout_start); + else + return -1; +} + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + + +typedef struct +{ + uint32 length; + uint32 type; +} chunk; + +#define PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + +static chunk get_chunk_header(void) +{ + chunk c; + c.length = get32(); + c.type = get32(); + return c; +} + +static int check_png_header(void) +{ + static uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (get8() != png_sig[i]) return e("bad png sig","Not a PNG"); + return 1; +} + +static uint8 *idata, *expanded, *out; + +enum { + F_none=0, F_sub=1, F_up=2, F_avg=3, F_paeth=4, + F_avg_first, F_paeth_first, +}; + +static uint8 first_row_filter[5] = +{ + F_none, F_sub, F_none, F_avg_first, F_paeth_first +}; + +static int paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +// create the png data from post-deflated data +static int create_png_image(uint8 *raw, uint32 raw_len, int out_n) +{ + uint32 i,j,stride = img_x*out_n; + int k; + assert(out_n == img_n || out_n == img_n+1); + out = (uint8 *) malloc(img_x * img_y * out_n); + if (!out) return e("outofmem", "Out of memory"); + if (raw_len != (img_n * img_x + 1) * img_y) return e("not enough pixels","Corrupt PNG"); + for (j=0; j < img_y; ++j) { + uint8 *cur = out + stride*j; + uint8 *prior = cur - stride; + int filter = *raw++; + if (filter > 4) return e("invalid filter","Corrupt PNG"); + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + // handle first pixel explicitly + for (k=0; k < img_n; ++k) { + switch(filter) { + case F_none : cur[k] = raw[k]; break; + case F_sub : cur[k] = raw[k]; break; + case F_up : cur[k] = raw[k] + prior[k]; break; + case F_avg : cur[k] = raw[k] + (prior[k]>>1); break; + case F_paeth : cur[k] = (uint8) (raw[k] + paeth(0,prior[k],0)); break; + case F_avg_first : cur[k] = raw[k]; break; + case F_paeth_first: cur[k] = raw[k]; break; + } + } + if (img_n != out_n) cur[img_n] = 255; + raw += img_n; + cur += out_n; + prior += out_n; + // this is a little gross, so that we don't switch per-pixel or per-component + if (img_n == out_n) { + #define CASE(f) \ + case f: \ + for (i=1; i < img_x; ++i, raw+=img_n,cur+=img_n,prior+=img_n) \ + for (k=0; k < img_n; ++k) + switch(filter) { + CASE(F_none) cur[k] = raw[k]; break; + CASE(F_sub) cur[k] = raw[k] + cur[k-img_n]; break; + CASE(F_up) cur[k] = raw[k] + prior[k]; break; + CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-img_n])>>1); break; + CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; + CASE(F_avg_first) cur[k] = raw[k] + (cur[k-img_n] >> 1); break; + CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],0,0)); break; + } + #undef CASE + } else { + assert(img_n+1 == out_n); + #define CASE(f) \ + case f: \ + for (i=1; i < img_x; ++i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ + for (k=0; k < img_n; ++k) + switch(filter) { + CASE(F_none) cur[k] = raw[k]; break; + CASE(F_sub) cur[k] = raw[k] + cur[k-out_n]; break; + CASE(F_up) cur[k] = raw[k] + prior[k]; break; + CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-out_n])>>1); break; + CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(F_avg_first) cur[k] = raw[k] + (cur[k-out_n] >> 1); break; + CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],0,0)); break; + } + #undef CASE + } + } + return 1; +} + +static int compute_transparency(uint8 tc[3], int out_n) +{ + uint32 i, pixel_count = img_x * img_y; + uint8 *p = out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + assert(out_n == 2 || out_n == 4); + + p = out; + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int expand_palette(uint8 *palette, int len, int pal_img_n) +{ + uint32 i, pixel_count = img_x * img_y; + uint8 *p, *temp_out, *orig = out; + + p = (uint8 *) malloc(pixel_count * pal_img_n); + if (p == NULL) return e("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + free(out); + out = temp_out; + return 1; +} + +static int parse_png_file(int scan, int req_comp) +{ + uint8 palette[1024], pal_img_n=0; + uint8 has_trans=0, tc[3]; + uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k; + + if (!check_png_header()) return 0; + + if (scan == SCAN_type) return 1; + + for(;;first=0) { + chunk c = get_chunk_header(); + if (first && c.type != PNG_TYPE('I','H','D','R')) + return e("first not IHDR","Corrupt PNG"); + switch (c.type) { + case PNG_TYPE('I','H','D','R'): { + int depth,color,interlace,comp,filter; + if (!first) return e("multiple IHDR","Corrupt PNG"); + if (c.length != 13) return e("bad IHDR len","Corrupt PNG"); + img_x = get32(); if (img_x > (1 << 24)) return e("too large","Very large image (corrupt?)"); + img_y = get32(); if (img_y > (1 << 24)) return e("too large","Very large image (corrupt?)"); + depth = get8(); if (depth != 8) return e("8bit only","PNG not supported: 8-bit only"); + color = get8(); if (color > 6) return e("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG"); + comp = get8(); if (comp) return e("bad comp method","Corrupt PNG"); + filter= get8(); if (filter) return e("bad filter method","Corrupt PNG"); + interlace = get8(); if (interlace) return e("interlaced","PNG not supported: interlaced mode"); + if (!img_x || !img_y) return e("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / img_x / img_n < img_y) return e("too large", "Image too large to decode"); + if (scan == SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + img_n = 1; + if ((1 << 30) / img_x / 4 < img_y) return e("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case PNG_TYPE('P','L','T','E'): { + if (c.length > 256*3) return e("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return e("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = get8u(); + palette[i*4+1] = get8u(); + palette[i*4+2] = get8u(); + palette[i*4+3] = 255; + } + break; + } + + case PNG_TYPE('t','R','N','S'): { + if (idata) return e("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == SCAN_header) { img_n = 4; return 1; } + if (pal_len == 0) return e("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return e("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = get8u(); + } else { + if (!(img_n & 1)) return e("tRNS with alpha","Corrupt PNG"); + if (c.length != (uint32) img_n*2) return e("bad tRNS len","Corrupt PNG"); + has_trans = 1; + for (k=0; k < img_n; ++k) + tc[k] = (uint8) get16(); // non 8-bit images will be larger + } + break; + } + + case PNG_TYPE('I','D','A','T'): { + if (pal_img_n && !pal_len) return e("no PLTE","Corrupt PNG"); + if (scan == SCAN_header) { img_n = pal_img_n; return 1; } + if (ioff + c.length > idata_limit) { + uint8 *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + p = (uint8 *) realloc(idata, idata_limit); if (p == NULL) return e("outofmem", "Out of memory"); + idata = p; + } + #ifndef STBI_NO_STDIO + if (img_file) + { + if (fread(idata+ioff,1,c.length,img_file) != c.length) return e("outofdata","Corrupt PNG"); + } + else + #endif + { + memcpy(idata+ioff, img_buffer, c.length); + img_buffer += c.length; + } + ioff += c.length; + break; + } + + case PNG_TYPE('I','E','N','D'): { + uint32 raw_len; + if (scan != SCAN_load) return 1; + if (idata == NULL) return e("no IDAT","Corrupt PNG"); + expanded = (uint8 *) stbi_zlib_decode_malloc((char *) idata, ioff, (int *) &raw_len); + if (expanded == NULL) return 0; // zlib should set error + free(idata); idata = NULL; + if ((req_comp == img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + img_out_n = img_n+1; + else + img_out_n = img_n; + if (!create_png_image(expanded, raw_len, img_out_n)) return 0; + if (has_trans) + if (!compute_transparency(tc, img_out_n)) return 0; + if (pal_img_n) { + // pal_img_n == 3 or 4 + img_n = pal_img_n; // record the actual colors we had + img_out_n = pal_img_n; + if (req_comp >= 3) img_out_n = req_comp; + if (!expand_palette(palette, pal_len, img_out_n)) + return 0; + } + free(expanded); expanded = NULL; + return 1; + } + + default: + // if critical, fail + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + static char invalid_chunk[] = "XXXX chunk not known"; + invalid_chunk[0] = (uint8) (c.type >> 24); + invalid_chunk[1] = (uint8) (c.type >> 16); + invalid_chunk[2] = (uint8) (c.type >> 8); + invalid_chunk[3] = (uint8) (c.type >> 0); + #endif + return e(invalid_chunk, "PNG not supported: unknown chunk type"); + } + skip(c.length); + break; + } + // end of chunk, read and skip CRC + get8(); get8(); get8(); get8(); + } +} + +static unsigned char *do_png(int *x, int *y, int *n, int req_comp) +{ + unsigned char *result=NULL; + if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); + if (parse_png_file(SCAN_load, req_comp)) { + result = out; + out = NULL; + if (req_comp && req_comp != img_out_n) { + result = convert_format(result, img_out_n, req_comp); + if (result == NULL) return result; + } + *x = img_x; + *y = img_y; + if (n) *n = img_n; + } + free(out); out = NULL; + free(expanded); expanded = NULL; + free(idata); idata = NULL; + + return result; +} + +#ifndef STBI_NO_STDIO +unsigned char *stbi_png_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + start_file(f); + return do_png(x,y,comp,req_comp); +} + +unsigned char *stbi_png_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_png_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return data; +} +#endif + +unsigned char *stbi_png_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + start_mem(buffer,len); + return do_png(x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +int stbi_png_test_file(FILE *f) +{ + int n,r; + n = ftell(f); + start_file(f); + r = parse_png_file(SCAN_type,STBI_default); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_png_test_memory(stbi_uc const *buffer, int len) +{ + start_mem(buffer, len); + return parse_png_file(SCAN_type,STBI_default); +} + +// TODO: load header from png +#ifndef STBI_NO_STDIO +extern int stbi_png_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif +extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +// Microsoft/Windows BMP image + +static int bmp_test(void) +{ + int sz; + if (get8() != 'B') return 0; + if (get8() != 'M') return 0; + get32le(); // discard filesize + get16le(); // discard reserved + get16le(); // discard reserved + get32le(); // discard data offset + sz = get32le(); + if (sz == 12 || sz == 40 || sz == 56 || sz == 108) return 1; + return 0; +} + +#ifndef STBI_NO_STDIO +int stbi_bmp_test_file (FILE *f) +{ + int r,n = ftell(f); + start_file(f); + r = bmp_test(); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_bmp_test_memory (stbi_uc const *buffer, int len) +{ + start_mem(buffer, len); + return bmp_test(); +} + +// returns 0..31 for the highest set bit +static int high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; + return n; +} + +static int bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +static int shiftsigned(int v, int shift, int bits) +{ + int result; + int z=0; + + if (shift < 0) v <<= -shift; + else v >>= shift; + result = v; + + z = bits; + while (z < 8) { + result += v >> z; + z += bits; + } + return result; +} + +static stbi_uc *bmp_load(int *x, int *y, int *comp, int req_comp) +{ + unsigned int mr=0,mg=0,mb=0,ma=0; + stbi_uc pal[256][4]; + int psize=0,i,j,compress=0,width; + int bpp, flip_vertically, pad, target, offset, hsz; + if (get8() != 'B' || get8() != 'M') return epuc("not BMP", "Corrupt BMP"); + get32le(); // discard filesize + get16le(); // discard reserved + get16le(); // discard reserved + offset = get32le(); + hsz = get32le(); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) return epuc("unknown BMP", "BMP type not supported: unknown"); + failure_reason = "bad BMP"; + if (hsz == 12) { + img_x = get16le(); + img_y = get16le(); + } else { + img_x = get32le(); + img_y = get32le(); + } + if (get16le() != 1) return 0; + bpp = get16le(); + if (bpp == 1) return epuc("monochrome", "BMP type not supported: 1-bit"); + flip_vertically = ((int) img_y) > 0; + img_y = abs((int) img_y); + if (hsz == 12) { + if (bpp < 24) + psize = (offset - 14 - 24) / 3; + } else { + compress = get32le(); + if (compress == 1 || compress == 2) return epuc("BMP RLE", "BMP type not supported: RLE"); + get32le(); // discard sizeof + get32le(); // discard hres + get32le(); // discard vres + get32le(); // discard colorsused + get32le(); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + get32le(); + get32le(); + get32le(); + get32le(); + } + if (bpp == 16 || bpp == 32) { + mr = mg = mb = 0; + if (compress == 0) { + if (bpp == 32) { + mr = 0xff << 16; + mg = 0xff << 8; + mb = 0xff << 0; + } else { + mr = 31 << 10; + mg = 31 << 5; + mb = 31 << 0; + } + } else if (compress == 3) { + mr = get32le(); + mg = get32le(); + mb = get32le(); + // not documented, but generated by photoshop and handled by mspaint + if (mr == mg && mg == mb) { + // ?!?!? + return NULL; + } + } else + return NULL; + } + } else { + assert(hsz == 108); + mr = get32le(); + mg = get32le(); + mb = get32le(); + ma = get32le(); + get32le(); // discard color space + for (i=0; i < 12; ++i) + get32le(); // discard color space parameters + } + if (bpp < 16) + psize = (offset - 14 - hsz) >> 2; + } + img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = img_n; // if they want monochrome, we'll post-convert + out = (stbi_uc *) malloc(target * img_x * img_y); + if (!out) return epuc("outofmem", "Out of memory"); + if (bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) return epuc("invalid", "Corrupt BMP"); + for (i=0; i < psize; ++i) { + pal[i][2] = get8(); + pal[i][1] = get8(); + pal[i][0] = get8(); + if (hsz != 12) get8(); + pal[i][3] = 255; + } + skip(offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); + if (bpp == 4) width = (img_x + 1) >> 1; + else if (bpp == 8) width = img_x; + else return epuc("bad bpp", "Corrupt BMP"); + pad = (-width)&3; + for (j=0; j < (int) img_y; ++j) { + for (i=0; i < (int) img_x; i += 2) { + int v=get8(),v2=0; + if (bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) img_x) break; + v = (bpp == 8) ? get8() : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + skip(pad); + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + skip(offset - 14 - hsz); + if (bpp == 24) width = 3 * img_x; + else if (bpp == 16) width = 2*img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (bpp == 24) { + easy = 1; + } else if (bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0xff000000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) return epuc("bad masks", "Corrupt BMP"); + // right shift amt to put high bit in position #7 + rshift = high_bit(mr)-7; rcount = bitcount(mr); + gshift = high_bit(mg)-7; gcount = bitcount(mr); + bshift = high_bit(mb)-7; bcount = bitcount(mr); + ashift = high_bit(ma)-7; acount = bitcount(mr); + } + for (j=0; j < (int) img_y; ++j) { + if (easy) { + for (i=0; i < (int) img_x; ++i) { + int a; + out[z+2] = get8(); + out[z+1] = get8(); + out[z+0] = get8(); + z += 3; + a = (easy == 2 ? get8() : 255); + if (target == 4) out[z++] = a; + } + } else { + for (i=0; i < (int) img_x; ++i) { + uint32 v = (bpp == 16 ? get16le() : get32le()); + int a; + out[z++] = shiftsigned(v & mr, rshift, rcount); + out[z++] = shiftsigned(v & mg, gshift, gcount); + out[z++] = shiftsigned(v & mb, bshift, bcount); + a = (ma ? shiftsigned(v & ma, ashift, acount) : 255); + if (target == 4) out[z++] = a; + } + } + skip(pad); + } + } + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) img_y>>1; ++j) { + stbi_uc *p1 = out + j *img_x*target; + stbi_uc *p2 = out + (img_y-1-j)*img_x*target; + for (i=0; i < (int) img_x*target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = convert_format(out, target, req_comp); + if (out == NULL) return out; // convert_format frees input on failure + } + + *x = img_x; + *y = img_y; + if (comp) *comp = target; + return out; +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_bmp_load_from_file(f, x,y,comp,req_comp); + fclose(f); + return data; +} + +stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) +{ + start_file(f); + return bmp_load(x,y,comp,req_comp); +} +#endif + +stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + start_mem(buffer, len); + return bmp_load(x,y,comp,req_comp); +} + +// Targa Truevision - TGA +// by Jonathan Dummer + +static int tga_test(void) +{ + int sz; + get8u(); // discard Offset + sz = get8u(); // color type + if( sz > 1 ) return 0; // only RGB or indexed allowed + sz = get8u(); // image type + if( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE + get16(); // discard palette start + get16(); // discard palette length + get8(); // discard bits per palette color entry + get16(); // discard x origin + get16(); // discard y origin + if( get16() < 1 ) return 0; // test width + if( get16() < 1 ) return 0; // test height + sz = get8(); // bits per pixel + if( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) return 0; // only RGB or RGBA or grey allowed + return 1; // seems to have passed everything +} + +#ifndef STBI_NO_STDIO +int stbi_tga_test_file (FILE *f) +{ + int r,n = ftell(f); + start_file(f); + r = tga_test(); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_tga_test_memory (stbi_uc const *buffer, int len) +{ + start_mem(buffer, len); + return tga_test(); +} + +static stbi_uc *tga_load(int *x, int *y, int *comp, int req_comp) +{ + // read in the TGA header stuff + int tga_offset = get8u(); + int tga_indexed = get8u(); + int tga_image_type = get8u(); + int tga_is_RLE = 0; + int tga_palette_start = get16le(); + int tga_palette_len = get16le(); + int tga_palette_bits = get8u(); + int tga_x_origin = get16le(); + int tga_y_origin = get16le(); + int tga_width = get16le(); + int tga_height = get16le(); + int tga_bits_per_pixel = get8u(); + int tga_inverted = get8u(); + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4]; + unsigned char trans_data[4]; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + // do a tiny bit of precessing + if( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + /* int tga_alpha_bits = tga_inverted & 15; */ + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // error check + if( //(tga_indexed) || + (tga_width < 1) || (tga_height < 1) || + (tga_image_type < 1) || (tga_image_type > 3) || + ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && + (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) + ) + { + return NULL; + } + + // If I'm paletted, then I'll use the number of bits from the palette + if( tga_indexed ) + { + tga_bits_per_pixel = tga_palette_bits; + } + + // tga info + *x = tga_width; + *y = tga_height; + if( (req_comp < 1) || (req_comp > 4) ) + { + // just use whatever the file was + req_comp = tga_bits_per_pixel / 8; + *comp = req_comp; + } else + { + // force a new number of components + *comp = tga_bits_per_pixel/8; + } + tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp ); + + // skip to the data's starting position (offset usually = 0) + skip( tga_offset ); + // do I need to load a palette? + if( tga_indexed ) + { + // any data to skip? (offset usually = 0) + skip( tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 ); + getn( tga_palette, tga_palette_len * tga_palette_bits / 8 ); + } + // load the data + for( i = 0; i < tga_width * tga_height; ++i ) + { + // if I'm in RLE mode, do I need to get a RLE chunk? + if( tga_is_RLE ) + { + if( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = get8u(); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if( read_next_pixel ) + { + // load however much data we did have + if( tga_indexed ) + { + // read in 1 byte, then perform the lookup + int pal_idx = get8u(); + if( pal_idx >= tga_palette_len ) + { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_bits_per_pixel / 8; + for( j = 0; j*8 < tga_bits_per_pixel; ++j ) + { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else + { + // read in the data raw + for( j = 0; j*8 < tga_bits_per_pixel; ++j ) + { + raw_data[j] = get8u(); + } + } + // convert raw to the intermediate format + switch( tga_bits_per_pixel ) + { + case 8: + // Luminous => RGBA + trans_data[0] = raw_data[0]; + trans_data[1] = raw_data[0]; + trans_data[2] = raw_data[0]; + trans_data[3] = 255; + break; + case 16: + // Luminous,Alpha => RGBA + trans_data[0] = raw_data[0]; + trans_data[1] = raw_data[0]; + trans_data[2] = raw_data[0]; + trans_data[3] = raw_data[1]; + break; + case 24: + // BGR => RGBA + trans_data[0] = raw_data[2]; + trans_data[1] = raw_data[1]; + trans_data[2] = raw_data[0]; + trans_data[3] = 255; + break; + case 32: + // BGRA => RGBA + trans_data[0] = raw_data[2]; + trans_data[1] = raw_data[1]; + trans_data[2] = raw_data[0]; + trans_data[3] = raw_data[3]; + break; + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + // convert to final format + switch( req_comp ) + { + case 1: + // RGBA => Luminance + tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); + break; + case 2: + // RGBA => Luminance,Alpha + tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); + tga_data[i*req_comp+1] = trans_data[3]; + break; + case 3: + // RGBA => RGB + tga_data[i*req_comp+0] = trans_data[0]; + tga_data[i*req_comp+1] = trans_data[1]; + tga_data[i*req_comp+2] = trans_data[2]; + break; + case 4: + // RGBA => RGBA + tga_data[i*req_comp+0] = trans_data[0]; + tga_data[i*req_comp+1] = trans_data[1]; + tga_data[i*req_comp+2] = trans_data[2]; + tga_data[i*req_comp+3] = trans_data[3]; + break; + } + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if( tga_inverted ) + { + for( j = 0; j*2 < tga_height; ++j ) + { + int index1 = j * tga_width * req_comp; + int index2 = (tga_height - 1 - j) * tga_width * req_comp; + for( i = tga_width * req_comp; i > 0; --i ) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if( tga_palette != NULL ) + { + free( tga_palette ); + } + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_tga_load_from_file(f, x,y,comp,req_comp); + fclose(f); + return data; +} + +stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) +{ + start_file(f); + return tga_load(x,y,comp,req_comp); +} +#endif + +stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + start_mem(buffer, len); + return tga_load(x,y,comp,req_comp); +} + + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicholas Schulz, tweaked by STB + +static int psd_test(void) +{ + if (get32() != 0x38425053) return 0; // "8BPS" + else return 1; +} + +#ifndef STBI_NO_STDIO +int stbi_psd_test_file(FILE *f) +{ + int r,n = ftell(f); + start_file(f); + r = psd_test(); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_psd_test_memory(stbi_uc const *buffer, int len) +{ + start_mem(buffer, len); + return psd_test(); +} + +static stbi_uc *psd_load(int *x, int *y, int *comp, int req_comp) +{ + int pixelCount; + int channelCount, compression; + int channel, i, count, len; + int w,h; + + // Check identifier + if (get32() != 0x38425053) // "8BPS" + return epuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (get16() != 1) + return epuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + skip( 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = get16(); + if (channelCount < 0 || channelCount > 16) + return epuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = get32(); + w = get32(); + + // Make sure the depth is 8 bits. + if (get16() != 8) + return epuc("unsupported bit depth", "PSD bit depth is not 8 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (get16() != 3) + return epuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + skip(get32() ); + + // Skip the image resources. (resolution, pen tool paths, etc) + skip( get32() ); + + // Skip the reserved data. + skip( get32() ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = get16(); + if (compression > 1) + return epuc("unknown compression type", "PSD has an unknown compression format"); + + // Create the destination image. + out = (stbi_uc *) malloc(4 * w*h); + if (!out) return epuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + skip( h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + uint8 *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; + } else { + // Read the RLE data. + count = 0; + while (count < pixelCount) { + len = get8(); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + count += len; + while (len) { + *p = get8(); + p += 4; + len--; + } + } else if (len > 128) { + uint32 val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len ^= 0x0FF; + len += 2; + val = get8(); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + uint8 *p; + + p = out + channel; + if (channel > channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; + } else { + // Read the data. + count = 0; + for (i = 0; i < pixelCount; i++) + *p = get8(), p += 4; + } + } + } + + if (req_comp && req_comp != 4) { + img_x = w; + img_y = h; + out = convert_format(out, 4, req_comp); + if (out == NULL) return out; // convert_format frees input on failure + } + + if (comp) *comp = channelCount; + *y = h; + *x = w; + + return out; +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi_psd_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_psd_load_from_file(f, x,y,comp,req_comp); + fclose(f); + return data; +} + +stbi_uc *stbi_psd_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + start_file(f); + return psd_load(x,y,comp,req_comp); +} +#endif + +stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + start_mem(buffer, len); + return psd_load(x,y,comp,req_comp); +} + + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int hdr_test(void) +{ + char *signature = "#?RADIANCE\n"; + int i; + for (i=0; signature[i]; ++i) + if (get8() != signature[i]) + return 0; + return 1; +} + +int stbi_hdr_test_memory(stbi_uc const *buffer, int len) +{ + start_mem(buffer, len); + return hdr_test(); +} + +#ifndef STBI_NO_STDIO +int stbi_hdr_test_file(FILE *f) +{ + int r,n = ftell(f); + start_file(f); + r = hdr_test(); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +#define HDR_BUFLEN 1024 +static char *hdr_gettoken(char *buffer) +{ + int len=0; + char *s = buffer, c = '\0'; + + c = get8(); + + while (!at_eof() && c != '\n') { + buffer[len++] = c; + if (len == HDR_BUFLEN-1) { + // flush to end of line + while (!at_eof() && get8() != '\n') + ; + break; + } + c = get8(); + } + + buffer[len] = 0; + return buffer; +} + +static void hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + + +static float *hdr_load(int *x, int *y, int *comp, int req_comp) +{ + char buffer[HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + + + // Check identifier + if (strcmp(hdr_gettoken(buffer), "#?RADIANCE") != 0) + return epf("not HDR", "Corrupt HDR image"); + + // Parse header + while(1) { + token = hdr_gettoken(buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return epf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = hdr_gettoken(buffer); + if (strncmp(token, "-Y ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = strtol(token, NULL, 10); + + *x = width; + *y = height; + + *comp = 3; + if (req_comp == 0) req_comp = 3; + + // Read data + hdr_data = (float *) malloc(height * width * req_comp * sizeof(float)); + + // Load image data + // image data is stored as some number of sca + if( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + getn(rgbe, 4); + hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = get8(); + c2 = get8(); + len = get8(); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4] = { c1,c2,len, get8() }; + hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + free(scanline); + goto main_decode_loop; // yes, this is fucking insane; blame the fucking insane format + } + len <<= 8; + len |= get8(); + if (len != width) { free(hdr_data); free(scanline); return epf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4); + + for (k = 0; k < 4; ++k) { + i = 0; + while (i < width) { + count = get8(); + if (count > 128) { + // Run + value = get8(); + count -= 128; + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = get8(); + } + } + } + for (i=0; i < width; ++i) + hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + free(scanline); + } + + return hdr_data; +} + +#ifndef STBI_NO_STDIO +float *stbi_hdr_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + start_file(f); + return hdr_load(x,y,comp,req_comp); +} +#endif + +float *stbi_hdr_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + start_mem(buffer, len); + return hdr_load(x,y,comp,req_comp); +} + +#endif // STBI_NO_HDR + +/////////////////////// write image /////////////////////// + +#ifndef STBI_NO_WRITE + +static void write8(FILE *f, int x) { uint8 z = (uint8) x; fwrite(&z,1,1,f); } + +static void writefv(FILE *f, char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { uint8 x = va_arg(v, int); write8(f,x); break; } + case '2': { int16 x = va_arg(v, int); write8(f,x); write8(f,x>>8); break; } + case '4': { int32 x = va_arg(v, int); write8(f,x); write8(f,x>>8); write8(f,x>>16); write8(f,x>>24); break; } + default: + assert(0); + va_end(v); + return; + } + } +} + +static void writef(FILE *f, char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + writefv(f,fmt,v); + va_end(v); +} + +static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad) +{ + uint8 bg[3] = { 255, 0, 255}, px[3]; + uint32 zero = 0; + int i,j,k, j_end; + + if (vdir < 0) + j_end = -1, j = y-1; + else + j_end = y, j = 0; + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + uint8 *d = (uint8 *) data + (j*x+i)*comp; + if (write_alpha < 0) + fwrite(&d[comp-1], 1, 1, f); + switch (comp) { + case 1: + case 2: writef(f, "111", d[0],d[0],d[0]); + break; + case 4: + if (!write_alpha) { + for (k=0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255; + writef(f, "111", px[1-rgb_dir],px[1],px[1+rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + writef(f, "111", d[1-rgb_dir],d[1],d[1+rgb_dir]); + break; + } + if (write_alpha > 0) + fwrite(&d[comp-1], 1, 1, f); + } + fwrite(&zero,scanline_pad,1,f); + } +} + +static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, char *fmt, ...) +{ + FILE *f = fopen(filename, "wb"); + if (f) { + va_list v; + va_start(v, fmt); + writefv(f, fmt, v); + va_end(v); + write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad); + fclose(f); + } + return f != NULL; +} + +int stbi_write_bmp(char const *filename, int x, int y, int comp, void *data) +{ + int pad = (-x*3) & 3; + return outfile(filename,-1,-1,x,y,comp,data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +} + +int stbi_write_tga(char const *filename, int x, int y, int comp, void *data) +{ + int has_alpha = !(comp & 1); + return outfile(filename, -1,-1, x, y, comp, data, has_alpha, 0, + "111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha); +} + +// any other image formats that do interleaved rgb data? +// PNG: requires adler32,crc32 -- significant amount of code +// PSD: no, channels output separately +// TIFF: no, stripwise-interleaved... i think + +#endif // STBI_NO_WRITE From fbad0a75b684cebbff874ba689810c2ff763b6e8 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Fri, 3 Jul 2009 16:22:35 +0100 Subject: [PATCH 10/17] profiling: Adds initial UProf accounting to Cogl This adds gives Cogl a dedicated UProf context which will be linked together with Clutter's context during clutter_init_real(). Initial timers cover _cogl_journal_flush and _cogl_journal_log_quad You can explicitly ask for a report of Cogl statistics by exporting COGL_PROFILE_OUTPUT_REPORT=1 but since the context is linked with Clutter's the statisitcs will also be shown in the automatic Clutter reports. --- cogl/Makefile.am | 2 ++ cogl/cogl-journal.c | 19 ++++++++++++++++ cogl/cogl-profile.c | 30 +++++++++++++++++++++++++ cogl/cogl-profile.h | 54 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 cogl/cogl-profile.c create mode 100644 cogl/cogl-profile.h diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 5ef3c3b9c..7d78106f5 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -134,6 +134,8 @@ libclutter_cogl_la_SOURCES = \ $(srcdir)/cogl-framebuffer.c \ $(srcdir)/cogl-matrix-mesa.h \ $(srcdir)/cogl-matrix-mesa.c \ + $(srcdir)/cogl-profile.h \ + $(srcdir)/cogl-profile.c \ $(NULL) EXTRA_DIST += $(cogl_winsys_sources) diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c index db406ea9c..fbb419a90 100644 --- a/cogl/cogl-journal.c +++ b/cogl/cogl-journal.c @@ -33,6 +33,7 @@ #include "cogl-material-private.h" #include "cogl-vertex-buffer-private.h" #include "cogl-framebuffer-private.h" +#include "cogl-profile.h" #include #include @@ -535,12 +536,19 @@ _cogl_journal_flush (void) (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; CoglHandle framebuffer; CoglMatrixStack *modelview_stack; + COGL_STATIC_TIMER (flush_timer, + "Mainloop", /* parent */ + "Journal Flush", + "The time spent flushing the Cogl journal", + 0 /* no application private data */); _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (ctx->journal->len == 0) return; + COGL_TIMER_START (_cogl_uprof_context, flush_timer); + if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING)) g_print ("BATCHING: journal len = %d\n", ctx->journal->len); @@ -608,6 +616,8 @@ _cogl_journal_flush (void) g_array_set_size (ctx->journal, 0); g_array_set_size (ctx->logged_vertices, 0); + + COGL_TIMER_STOP (_cogl_uprof_context, flush_timer); } static void @@ -644,9 +654,16 @@ _cogl_journal_log_quad (float x_1, int next_entry; guint32 disable_layers; CoglJournalEntry *entry; + COGL_STATIC_TIMER (log_timer, + "Mainloop", /* parent */ + "Journal Log", + "The time spent logging in the Cogl journal", + 0 /* no application private data */); _COGL_GET_CONTEXT (ctx, NO_RETVAL); + COGL_TIMER_START (_cogl_uprof_context, log_timer); + if (ctx->logged_vertices->len == 0) _cogl_journal_init (); @@ -765,5 +782,7 @@ _cogl_journal_log_quad (float x_1, if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_BATCHING || cogl_debug_flags & COGL_DEBUG_RECTANGLES)) _cogl_journal_flush (); + + COGL_TIMER_STOP (_cogl_uprof_context, log_timer); } diff --git a/cogl/cogl-profile.c b/cogl/cogl-profile.c new file mode 100644 index 000000000..e17acda38 --- /dev/null +++ b/cogl/cogl-profile.c @@ -0,0 +1,30 @@ + +#ifdef COGL_ENABLE_PROFILE + +#include "cogl-profile.h" + +#include + +UProfContext *_cogl_uprof_context; + + +static void __attribute__ ((constructor)) +cogl_uprof_constructor (void) +{ + _cogl_uprof_context = uprof_context_new ("Cogl"); +} + +static void __attribute__ ((destructor)) +cogl_uprof_destructor (void) +{ + if (getenv ("COGL_PROFILE_OUTPUT_REPORT")) + { + UProfReport *report = uprof_report_new ("Cogl report"); + uprof_report_add_context (report, _cogl_uprof_context); + uprof_report_print (report); + uprof_report_unref (report); + } + uprof_context_unref (_cogl_uprof_context); +} + +#endif diff --git a/cogl/cogl-profile.h b/cogl/cogl-profile.h new file mode 100644 index 000000000..302b146c1 --- /dev/null +++ b/cogl/cogl-profile.h @@ -0,0 +1,54 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __COGL_PROFILE_H__ +#define __COGL_PROFILE_H__ + + +#ifdef COGL_ENABLE_PROFILE + +#include + +extern UProfContext *_cogl_uprof_context; + +#define COGL_STATIC_TIMER UPROF_STATIC_TIMER +#define COGL_STATIC_COUNTER UPROF_STATIC_COUNTER +#define COGL_COUNTER_INC UPROF_COUNTER_INC +#define COGL_COUNTER_DEC UPROF_COUNTER_DEC +#define COGL_TIMER_START UPROF_TIMER_START +#define COGL_TIMER_STOP UPROF_TIMER_STOP + +#else + +#define COGL_STATIC_TIMER(A,B,C,D,E) extern void _cogl_dummy_decl (void) +#define COGL_STATIC_COUNTER(A,B,C,D) extern void _cogl_dummy_decl (void) +#define COGL_COUNTER_INC(A,B) G_STMT_START{ (void)0; }G_STMT_END +#define COGL_COUNTER_DEC(A,B) G_STMT_START{ (void)0; }G_STMT_END +#define COGL_TIMER_START(A,B) G_STMT_START{ (void)0; }G_STMT_END +#define COGL_TIMER_STOP(A,B) G_STMT_START{ (void)0; }G_STMT_END + + +#endif + +#endif /* __COGL_PROFILE_H__ */ + From 05ce533fc8b865ed45f60abdf50625003b841576 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Wed, 25 Nov 2009 14:26:32 +0000 Subject: [PATCH 11/17] framebuffers: cogl_offscreen_new_to_texture should take a ref on the texture We weren't taking a reference on the texture to be used as the color buffer for offscreen rendering, so it was possible to free the texture leaving the framebuffer in an inconsistent state. --- cogl/cogl-framebuffer-private.h | 1 + cogl/cogl-framebuffer.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h index eb94c6f7f..946adfe25 100644 --- a/cogl/cogl-framebuffer-private.h +++ b/cogl/cogl-framebuffer-private.h @@ -57,6 +57,7 @@ typedef struct _CoglOffscreen CoglFramebuffer _parent; GLuint fbo_handle; GLuint gl_stencil_handle; + CoglHandle texture; } CoglOffscreen; #define COGL_OFFSCREEN(X) ((CoglOffscreen *)(X)) diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index 585b67663..a34eaaa5c 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -339,6 +339,7 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) offscreen->fbo_handle = fbo_gl_handle; offscreen->gl_stencil_handle = gl_stencil_handle; + offscreen->texture = cogl_handle_ref (texhandle); /* XXX: Can we get a away with removing this? It wasn't documented, and most * users of the API are hopefully setting up the modelview from scratch @@ -362,6 +363,8 @@ _cogl_offscreen_free (CoglOffscreen *offscreen) if (offscreen->gl_stencil_handle) GE (glDeleteRenderbuffers (1, &offscreen->gl_stencil_handle)); + if (offscreen->texture != COGL_INVALID_HANDLE) + cogl_handle_unref (offscreen->texture); GE (glDeleteFramebuffers (1, &offscreen->fbo_handle)); g_free (offscreen); } From 9690913fefdad782c74efa5c546ece0d873c05e4 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Mon, 30 Nov 2009 20:04:41 +0000 Subject: [PATCH 12/17] cogl: Support multiple fallbacks in cogl_offscreen_new_to_texture() The Intel drivers in Mesa 7.6 (and possibly earlier versions) don't support creating FBOs with a stencil buffer but without a depth buffer. This reworks framebuffer allocation so that we try a number of fallback options before failing. The options we try in order are: - the same options that were sucessful last time if available - combined depth and stencil - separate depth and stencil - just stencil, no depth - just depth, no stencil - neither depth or stencil --- cogl/cogl-framebuffer-private.h | 2 +- cogl/cogl-framebuffer.c | 242 +++++++++++++++++++++----------- 2 files changed, 158 insertions(+), 86 deletions(-) diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h index 946adfe25..1f21a670a 100644 --- a/cogl/cogl-framebuffer-private.h +++ b/cogl/cogl-framebuffer-private.h @@ -56,7 +56,7 @@ typedef struct _CoglOffscreen { CoglFramebuffer _parent; GLuint fbo_handle; - GLuint gl_stencil_handle; + GSList *renderbuffers; CoglHandle texture; } CoglOffscreen; diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index a34eaaa5c..a6b62bed8 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -71,6 +71,15 @@ #ifndef GL_STENCIL_INDEX8 #define GL_STENCIL_INDEX8 0x8D48 #endif +#ifndef GL_DEPTH_STENCIL +#define GL_DEPTH_STENCIL 0x84F9 +#endif + +typedef enum { + _TRY_DEPTH_STENCIL = 1L<<0, + _TRY_DEPTH = 1L<<1, + _TRY_STENCIL = 1L<<2 +} TryFBOFlags; static void _cogl_framebuffer_free (CoglFramebuffer *framebuffer); static void _cogl_onscreen_free (CoglOnscreen *onscreen); @@ -232,17 +241,123 @@ _cogl_framebuffer_get_projection_stack (CoglHandle handle) return framebuffer->projection_stack; } +static TryFBOFlags +try_creating_fbo (CoglOffscreen *offscreen, + TryFBOFlags flags, + CoglHandle texture) +{ + GLuint gl_depth_stencil_handle; + GLuint gl_depth_handle; + GLuint gl_stencil_handle; + GLuint tex_gl_handle; + GLenum tex_gl_target; + GLuint fbo_gl_handle; + GLenum status; + + _COGL_GET_CONTEXT (ctx, FALSE); + + if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target)) + return 0; + + if (tex_gl_target != GL_TEXTURE_2D +#ifdef HAVE_COGL_GL + && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB +#endif + ) + return 0; + + /* We are about to generate and bind a new fbo, so when next flushing the + * journal, we will need to rebind the current framebuffer... */ + ctx->dirty_bound_framebuffer = 1; + + /* Generate framebuffer */ + glGenFramebuffers (1, &fbo_gl_handle); + GE (glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle)); + offscreen->fbo_handle = fbo_gl_handle; + + GE (glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + tex_gl_target, tex_gl_handle, 0)); + + if (flags & _TRY_DEPTH_STENCIL) + { + /* Create a renderbuffer for depth and stenciling */ + GE (glGenRenderbuffers (1, &gl_depth_stencil_handle)); + GE (glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle)); + GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_STENCIL, + cogl_texture_get_width (texture), + cogl_texture_get_height (texture))); + GE (glBindRenderbuffer (GL_RENDERBUFFER, 0)); + GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, gl_depth_stencil_handle)); + GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, gl_depth_stencil_handle)); + offscreen->renderbuffers = + g_slist_prepend (offscreen->renderbuffers, + GUINT_TO_POINTER (gl_depth_stencil_handle)); + } + + if (flags & _TRY_DEPTH) + { + GE (glGenRenderbuffers (1, &gl_depth_handle)); + GE (glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle)); + /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's + * available under GLES */ + GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + cogl_texture_get_width (texture), + cogl_texture_get_height (texture))); + GE (glBindRenderbuffer (GL_RENDERBUFFER, 0)); + GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, gl_depth_handle)); + offscreen->renderbuffers = + g_slist_prepend (offscreen->renderbuffers, + GUINT_TO_POINTER (gl_depth_handle)); + } + + if (flags & _TRY_STENCIL) + { + GE (glGenRenderbuffers (1, &gl_stencil_handle)); + GE (glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle)); + GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8, + cogl_texture_get_width (texture), + cogl_texture_get_height (texture))); + GE (glBindRenderbuffer (GL_RENDERBUFFER, 0)); + GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, gl_stencil_handle)); + offscreen->renderbuffers = + g_slist_prepend (offscreen->renderbuffers, + GUINT_TO_POINTER (gl_stencil_handle)); + } + + /* Make sure it's complete */ + status = glCheckFramebufferStatus (GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + GSList *l; + + GE (glDeleteFramebuffers (1, &fbo_gl_handle)); + + for (l = offscreen->renderbuffers; l; l = l->next) + { + GLuint renderbuffer = GPOINTER_TO_UINT (l->data); + GE (glDeleteRenderbuffers (1, &renderbuffer)); + } + return 0; + } + + return flags; +} + CoglHandle cogl_offscreen_new_to_texture (CoglHandle texhandle) { - CoglOffscreen *offscreen; - int width; - int height; - GLuint tex_gl_handle; - GLenum tex_gl_target; - GLuint fbo_gl_handle; - GLuint gl_stencil_handle; - GLenum status; + CoglOffscreen *offscreen; + TryFBOFlags flags; + static TryFBOFlags last_working_flags = 0; _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); @@ -257,42 +372,6 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) if (cogl_texture_is_sliced (texhandle)) return COGL_INVALID_HANDLE; - /* Pick the single texture slice width, height and GL id */ - - width = cogl_texture_get_width (texhandle); - height = cogl_texture_get_height (texhandle); - - if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target)) - return COGL_INVALID_HANDLE; - - if (tex_gl_target != GL_TEXTURE_2D -#ifdef HAVE_COGL_GL - && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB -#endif - ) - return COGL_INVALID_HANDLE; - - /* Create a renderbuffer for stenciling */ - GE (glGenRenderbuffers (1, &gl_stencil_handle)); - GE (glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle)); - GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8, - cogl_texture_get_width (texhandle), - cogl_texture_get_height (texhandle))); - GE (glBindRenderbuffer (GL_RENDERBUFFER, 0)); - - /* We are about to generate and bind a new fbo, so when next flushing the - * journal, we will need to rebind the current framebuffer... */ - ctx->dirty_bound_framebuffer = 1; - - /* Generate framebuffer */ - glGenFramebuffers (1, &fbo_gl_handle); - GE (glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle)); - GE (glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - tex_gl_target, tex_gl_handle, 0)); - GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, gl_stencil_handle)); - /* XXX: The framebuffer_object spec isn't clear in defining whether attaching * a texture as a renderbuffer with mipmap filtering enabled while the * mipmaps have not been uploaded should result in an incomplete framebuffer @@ -305,50 +384,34 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) */ _cogl_texture_set_filters (texhandle, GL_NEAREST, GL_NEAREST); - /* Make sure it's complete */ - status = glCheckFramebufferStatus (GL_FRAMEBUFFER); + offscreen = g_new0 (CoglOffscreen, 1); + offscreen->texture = cogl_handle_ref (texhandle); - if (status != GL_FRAMEBUFFER_COMPLETE) + if (!(last_working_flags && + (flags = try_creating_fbo (offscreen, last_working_flags, + texhandle))) && + !(flags = try_creating_fbo (offscreen, _TRY_DEPTH_STENCIL, + texhandle)) && + !(flags = try_creating_fbo (offscreen, _TRY_DEPTH | _TRY_STENCIL, + texhandle)) && + !(flags = try_creating_fbo (offscreen, _TRY_STENCIL, texhandle)) && + !(flags = try_creating_fbo (offscreen, _TRY_DEPTH, texhandle)) && + !(flags = try_creating_fbo (offscreen, 0, texhandle))) { - /* Stencil renderbuffers aren't always supported. Try again - without the stencil buffer */ - GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, - 0)); - GE (glDeleteRenderbuffers (1, &gl_stencil_handle)); - gl_stencil_handle = 0; - - status = glCheckFramebufferStatus (GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - /* Still failing, so give up */ - GE (glDeleteFramebuffers (1, &fbo_gl_handle)); - GE (glBindFramebuffer (GL_FRAMEBUFFER, 0)); - return COGL_INVALID_HANDLE; - } + g_free (offscreen); + last_working_flags = 0; + /* XXX: This API should probably have been defined to take a GError */ + g_warning ("%s: Failed to create an OpenGL framebuffer", G_STRLOC); + return COGL_INVALID_HANDLE; } - - offscreen = g_new0 (CoglOffscreen, 1); + /* Save the final set of flags that worked so we can hopefully construct + * subsequent buffers faster. */ + last_working_flags = flags; _cogl_framebuffer_init (COGL_FRAMEBUFFER (offscreen), COGL_FRAMEBUFFER_TYPE_OFFSCREEN, - width, - height); - - offscreen->fbo_handle = fbo_gl_handle; - offscreen->gl_stencil_handle = gl_stencil_handle; - offscreen->texture = cogl_handle_ref (texhandle); - - /* XXX: Can we get a away with removing this? It wasn't documented, and most - * users of the API are hopefully setting up the modelview from scratch - * anyway */ -#if 0 - cogl_matrix_translate (&framebuffer->modelview, -1.0f, -1.0f, 0.0f); - cogl_matrix_scale (&framebuffer->modelview, - 2.0f / framebuffer->width, 2.0f / framebuffer->height, 1.0f); -#endif + cogl_texture_get_width (texhandle), + cogl_texture_get_height (texhandle)); return _cogl_offscreen_handle_new (offscreen); } @@ -356,16 +419,25 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) static void _cogl_offscreen_free (CoglOffscreen *offscreen) { + GSList *l; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Chain up to parent */ _cogl_framebuffer_free (COGL_FRAMEBUFFER (offscreen)); - if (offscreen->gl_stencil_handle) - GE (glDeleteRenderbuffers (1, &offscreen->gl_stencil_handle)); + for (l = offscreen->renderbuffers; l; l = l->next) + { + GLuint renderbuffer = GPOINTER_TO_UINT (l->data); + GE (glDeleteRenderbuffers (1, &renderbuffer)); + } + g_slist_free (offscreen->renderbuffers); + + GE (glDeleteFramebuffers (1, &offscreen->fbo_handle)); + if (offscreen->texture != COGL_INVALID_HANDLE) cogl_handle_unref (offscreen->texture); - GE (glDeleteFramebuffers (1, &offscreen->fbo_handle)); + g_free (offscreen); } From e2fcb62990c7f72c9ffcff5b39b2794352eaa610 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 12 Jan 2010 11:02:09 +0000 Subject: [PATCH 13/17] journal: Fixes logging of multiple sets of texture coordinates If a user supplied multiple groups of texture coordinates with cogl_rectangle_with_multitexture_coords() then we would repeatedly log only the first group in the journal. This fixes that bug and adds a conformance test to verify the fix. Thanks to Gord Allott for reporting this bug. --- cogl/cogl-journal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c index fbb419a90..601d53d9a 100644 --- a/cogl/cogl-journal.c +++ b/cogl/cogl-journal.c @@ -740,13 +740,13 @@ _cogl_journal_log_quad (float x_1, next_vert + POS_STRIDE + COLOR_STRIDE + TEX_STRIDE * i); - t[0] = tex_coords[0]; t[1] = tex_coords[1]; + t[0] = tex_coords[i * 4 + 0]; t[1] = tex_coords[i * 4 + 1]; t += stride; - t[0] = tex_coords[0]; t[1] = tex_coords[3]; + t[0] = tex_coords[i * 4 + 0]; t[1] = tex_coords[i * 4 + 3]; t += stride; - t[0] = tex_coords[2]; t[1] = tex_coords[3]; + t[0] = tex_coords[i * 4 + 2]; t[1] = tex_coords[i * 4 + 3]; t += stride; - t[0] = tex_coords[2]; t[1] = tex_coords[1]; + t[0] = tex_coords[i * 4 + 2]; t[1] = tex_coords[i * 4 + 1]; } if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL)) From dfc3dd9c439b33ca655b00223ec387c3316e9371 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 12 Jan 2010 14:43:36 +0000 Subject: [PATCH 14/17] cogl: Remove the CGL_* defines These macros used to define Cogl wrappers for the GLenum values. There are now Cogl enums everywhere in the API where these were required so we shouldn't need them anymore. They were in the public headers but as they are not neccessary and were not in the API docs for Clutter 1.0 it should be safe to remove them. --- cogl/cogl-material.c | 10 +- cogl/cogl-primitives.c | 2 +- cogl/cogl-shader.h | 2 +- cogl/cogl-texture.h | 7 +- cogl/driver/gl/cogl-defines.h.in | 655 -------------------------- cogl/driver/gl/cogl-texture-driver.c | 2 +- cogl/driver/gles/cogl-defines.h.in | 597 ----------------------- cogl/driver/gles/cogl-gles2-wrapper.c | 4 +- cogl/driver/gles/cogl-gles2-wrapper.h | 65 +-- 9 files changed, 51 insertions(+), 1293 deletions(-) diff --git a/cogl/cogl-material.c b/cogl/cogl-material.c index 6c292ac67..00c376fb5 100644 --- a/cogl/cogl-material.c +++ b/cogl/cogl-material.c @@ -48,6 +48,12 @@ #include "../gles/cogl-gles2-wrapper.h" #endif +#ifdef HAVE_COGL_GLES +#define COGL_MATERIAL_MAX_TEXTURE_UNITS GL_MAX_TEXTURE_UNITS +#else +#define COGL_MATERIAL_MAX_TEXTURE_UNITS GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS +#endif + #ifdef HAVE_COGL_GL #define glActiveTexture ctx->drv.pf_glActiveTexture #define glClientActiveTexture ctx->drv.pf_glClientActiveTexture @@ -822,7 +828,7 @@ cogl_material_set_layer (CoglHandle material_handle, _cogl_material_pre_change_notify (material, FALSE, NULL); material->n_layers = g_list_length (material->layers); - if (material->n_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + if (material->n_layers >= COGL_MATERIAL_MAX_TEXTURE_UNITS) { if (!(material->flags & COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING)) { @@ -1531,7 +1537,7 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material, layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DIRTY; - if ((i+1) >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + if ((i+1) >= COGL_MATERIAL_MAX_TEXTURE_UNITS) break; } diff --git a/cogl/cogl-primitives.c b/cogl/cogl-primitives.c index e4fdf6a99..60a452dea 100644 --- a/cogl/cogl-primitives.c +++ b/cogl/cogl-primitives.c @@ -915,7 +915,7 @@ cogl_polygon (const CoglTextureVertex *vertices, { g_warning ("cogl_texture_polygon does not work for sliced textures " "when the minification and magnification filters are not " - "CGL_NEAREST"); + "COGL_MATERIAL_FILTER_NEAREST"); warning_seen = TRUE; } return; diff --git a/cogl/cogl-shader.h b/cogl/cogl-shader.h index 4e2ccb97b..f92b85fae 100644 --- a/cogl/cogl-shader.h +++ b/cogl/cogl-shader.h @@ -59,7 +59,7 @@ typedef enum { /** * cogl_create_shader: - * @shader_type: CGL_VERTEX_SHADER or CGL_FRAGMENT_SHADER. + * @shader_type: COGL_SHADER_TYPE_VERTEX or COGL_SHADER_TYPE_FRAGMENT. * * Create a new shader handle, use #cogl_shader_source to set the source code * to be used on it. diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h index eaf3e5482..93ead5436 100644 --- a/cogl/cogl-texture.h +++ b/cogl/cogl-texture.h @@ -461,9 +461,10 @@ void cogl_rectangles (const float *verts, * All of the texture coordinates must be in the range [0,1] and repeating the * texture is not supported. * - * Because of the way this function is implemented it will currently only work - * if either the texture is not sliced or the backend is not OpenGL ES and the - * minifying and magnifying functions are both set to CGL_NEAREST. + * Because of the way this function is implemented it will currently + * only work if either the texture is not sliced or the backend is not + * OpenGL ES and the minifying and magnifying functions are both set + * to COGL_MATERIAL_FILTER_NEAREST. * * Since: 1.0 */ diff --git a/cogl/driver/gl/cogl-defines.h.in b/cogl/driver/gl/cogl-defines.h.in index 3196095b7..e8035b054 100644 --- a/cogl/driver/gl/cogl-defines.h.in +++ b/cogl/driver/gl/cogl-defines.h.in @@ -29,661 +29,6 @@ G_BEGIN_DECLS -/* FIXME + DOCUMENT */ - -#define COPENSTEP OPENSTEP -#define CGLAPI GLAPI -#define CGLAPI GLAPI -#define CGLAPI GLAPI -#define CGLAPIENTRY GLAPIENTRY -#define CGLAPI GLAPI -#define CGLAPIENTRY GLAPIENTRY -#define CGLAPI GLAPI -#define CGLAPIENTRY GLAPIENTRY -#define CPRAGMA_EXPORT_SUPPORTED PRAGMA_EXPORT_SUPPORTED -#define CGLAPI GLAPI -#define CGLAPIENTRY GLAPIENTRY -#define CAPIENTRY APIENTRY -#define CAPIENTRYP APIENTRYP -#define CGLAPIENTRYP GLAPIENTRYP -#define CGL_FALSE GL_FALSE -#define CGL_TRUE GL_TRUE -#define CGL_BYTE GL_BYTE -#define CGL_UNSIGNED_BYTE GL_UNSIGNED_BYTE -#define CGL_SHORT GL_SHORT -#define CGL_UNSIGNED_SHORT GL_UNSIGNED_SHORT -#define CGL_INT GL_INT -#define CGL_UNSIGNED_INT GL_UNSIGNED_INT -#define CGL_FLOAT GL_FLOAT -#define CGL_DOUBLE GL_DOUBLE -#define CGL_POINTS GL_POINTS -#define CGL_LINES GL_LINES -#define CGL_LINE_LOOP GL_LINE_LOOP -#define CGL_LINE_STRIP GL_LINE_STRIP -#define CGL_TRIANGLES GL_TRIANGLES -#define CGL_TRIANGLE_STRIP GL_TRIANGLE_STRIP -#define CGL_TRIANGLE_FAN GL_TRIANGLE_FAN -#define CGL_QUADS GL_QUADS -#define CGL_QUAD_STRIP GL_QUAD_STRIP -#define CGL_POLYGON GL_POLYGON -#define CGL_VERTEX_ARRAY GL_VERTEX_ARRAY -#define CGL_NORMAL_ARRAY GL_NORMAL_ARRAY -#define CGL_COLOR_ARRAY GL_COLOR_ARRAY -#define CGL_INDEX_ARRAY GL_INDEX_ARRAY -#define CGL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY -#define CGL_EDGE_FLAG_ARRAY GL_EDGE_FLAG_ARRAY -#define CGL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_SIZE -#define CGL_VERTEX_ARRAY_TYPE GL_VERTEX_ARRAY_TYPE -#define CGL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_STRIDE -#define CGL_NORMAL_ARRAY_TYPE GL_NORMAL_ARRAY_TYPE -#define CGL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_STRIDE -#define CGL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_SIZE -#define CGL_COLOR_ARRAY_TYPE GL_COLOR_ARRAY_TYPE -#define CGL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_STRIDE -#define CGL_INDEX_ARRAY_TYPE GL_INDEX_ARRAY_TYPE -#define CGL_INDEX_ARRAY_STRIDE GL_INDEX_ARRAY_STRIDE -#define CGL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_SIZE -#define CGL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_COORD_ARRAY_TYPE -#define CGL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_STRIDE -#define CGL_EDGE_FLAG_ARRAY_STRIDE GL_EDGE_FLAG_ARRAY_STRIDE -#define CGL_VERTEX_ARRAY_POINTER GL_VERTEX_ARRAY_POINTER -#define CGL_NORMAL_ARRAY_POINTER GL_NORMAL_ARRAY_POINTER -#define CGL_COLOR_ARRAY_POINTER GL_COLOR_ARRAY_POINTER -#define CGL_INDEX_ARRAY_POINTER GL_INDEX_ARRAY_POINTER -#define CGL_TEXTURE_COORD_ARRAY_POINTER GL_TEXTURE_COORD_ARRAY_POINTER -#define CGL_EDGE_FLAG_ARRAY_POINTER GL_EDGE_FLAG_ARRAY_POINTER -#define CGL_MATRIX_MODE GL_MATRIX_MODE -#define CGL_MODELVIEW GL_MODELVIEW -#define CGL_PROJECTION GL_PROJECTION -#define CGL_TEXTURE GL_TEXTURE -#define CGL_POINT_SMOOTH GL_POINT_SMOOTH -#define CGL_POINT_SIZE GL_POINT_SIZE -#define CGL_POINT_SIZE_GRANULARITY GL_POINT_SIZE_GRANULARITY -#define CGL_POINT_SIZE_RANGE GL_POINT_SIZE_RANGE -#define CGL_LINE_SMOOTH GL_LINE_SMOOTH -#define CGL_LINE_STIPPLE GL_LINE_STIPPLE -#define CGL_LINE_STIPPLE_PATTERN GL_LINE_STIPPLE_PATTERN -#define CGL_LINE_STIPPLE_REPEAT GL_LINE_STIPPLE_REPEAT -#define CGL_LINE_WIDTH GL_LINE_WIDTH -#define CGL_LINE_WIDTH_GRANULARITY GL_LINE_WIDTH_GRANULARITY -#define CGL_LINE_WIDTH_RANGE GL_LINE_WIDTH_RANGE -#define CGL_POINT GL_POINT -#define CGL_LINE GL_LINE -#define CGL_FILL GL_FILL -#define CGL_CW GL_CW -#define CGL_CCW GL_CCW -#define CGL_FRONT GL_FRONT -#define CGL_BACK GL_BACK -#define CGL_POLYGON_MODE GL_POLYGON_MODE -#define CGL_POLYGON_SMOOTH GL_POLYGON_SMOOTH -#define CGL_POLYGON_STIPPLE GL_POLYGON_STIPPLE -#define CGL_EDGE_FLAG GL_EDGE_FLAG -#define CGL_CULL_FACE GL_CULL_FACE -#define CGL_CULL_FACE_MODE GL_CULL_FACE_MODE -#define CGL_FRONT_FACE GL_FRONT_FACE -#define CGL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FACTOR -#define CGL_POLYGON_OFFSET_UNITS GL_POLYGON_OFFSET_UNITS -#define CGL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_POINT -#define CGL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_LINE -#define CGL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_FILL -#define CGL_COMPILE GL_COMPILE -#define CGL_COMPILE_AND_EXECUTE GL_COMPILE_AND_EXECUTE -#define CGL_LIST_BASE GL_LIST_BASE -#define CGL_LIST_INDEX GL_LIST_INDEX -#define CGL_LIST_MODE GL_LIST_MODE -#define CGL_NEVER GL_NEVER -#define CGL_LESS GL_LESS -#define CGL_EQUAL GL_EQUAL -#define CGL_LEQUAL GL_LEQUAL -#define CGL_GREATER GL_GREATER -#define CGL_NOTEQUAL GL_NOTEQUAL -#define CGL_GEQUAL GL_GEQUAL -#define CGL_ALWAYS GL_ALWAYS -#define CGL_DEPTH_TEST GL_DEPTH_TEST -#define CGL_DEPTH_BITS GL_DEPTH_BITS -#define CGL_DEPTH_CLEAR_VALUE GL_DEPTH_CLEAR_VALUE -#define CGL_DEPTH_FUNC GL_DEPTH_FUNC -#define CGL_DEPTH_RANGE GL_DEPTH_RANGE -#define CGL_DEPTH_WRITEMASK GL_DEPTH_WRITEMASK -#define CGL_DEPTH_COMPONENT GL_DEPTH_COMPONENT -#define CGL_LIGHTING GL_LIGHTING -#define CGL_SPOT_EXPONENT GL_SPOT_EXPONENT -#define CGL_SPOT_CUTOFF GL_SPOT_CUTOFF -#define CGL_CONSTANT_ATTENUATION GL_CONSTANT_ATTENUATION -#define CGL_LINEAR_ATTENUATION GL_LINEAR_ATTENUATION -#define CGL_QUADRATIC_ATTENUATION GL_QUADRATIC_ATTENUATION -#define CGL_AMBIENT GL_AMBIENT -#define CGL_DIFFUSE GL_DIFFUSE -#define CGL_SPECULAR GL_SPECULAR -#define CGL_SHININESS GL_SHININESS -#define CGL_EMISSION GL_EMISSION -#define CGL_POSITION GL_POSITION -#define CGL_SPOT_DIRECTION GL_SPOT_DIRECTION -#define CGL_AMBIENT_AND_DIFFUSE GL_AMBIENT_AND_DIFFUSE -#define CGL_COLOR_INDEXES GL_COLOR_INDEXES -#define CGL_LIGHT_MODEL_TWO_SIDE GL_LIGHT_MODEL_TWO_SIDE -#define CGL_LIGHT_MODEL_LOCAL_VIEWER GL_LIGHT_MODEL_LOCAL_VIEWER -#define CGL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_AMBIENT -#define CGL_FRONT_AND_BACK GL_FRONT_AND_BACK -#define CGL_SHADE_MODEL GL_SHADE_MODEL -#define CGL_FLAT GL_FLAT -#define CGL_SMOOTH GL_SMOOTH -#define CGL_COLOR_MATERIAL GL_COLOR_MATERIAL -#define CGL_COLOR_MATERIAL_FACE GL_COLOR_MATERIAL_FACE -#define CGL_COLOR_MATERIAL_PARAMETER GL_COLOR_MATERIAL_PARAMETER -#define CGL_NORMALIZE GL_NORMALIZE -#define CGL_ACCUM_RED_BITS GL_ACCUM_RED_BITS -#define CGL_ACCUM_GREEN_BITS GL_ACCUM_GREEN_BITS -#define CGL_ACCUM_BLUE_BITS GL_ACCUM_BLUE_BITS -#define CGL_ACCUM_ALPHA_BITS GL_ACCUM_ALPHA_BITS -#define CGL_ACCUM_CLEAR_VALUE GL_ACCUM_CLEAR_VALUE -#define CGL_ACCUM GL_ACCUM -#define CGL_ADD GL_ADD -#define CGL_LOAD GL_LOAD -#define CGL_MULT GL_MULT -#define CGL_RETURN GL_RETURN -#define CGL_ALPHA_TEST GL_ALPHA_TEST -#define CGL_ALPHA_TEST_REF GL_ALPHA_TEST_REF -#define CGL_ALPHA_TEST_FUNC GL_ALPHA_TEST_FUNC -#define CGL_BLEND GL_BLEND -#define CGL_BLEND_SRC GL_BLEND_SRC -#define CGL_BLEND_DST GL_BLEND_DST -#define CGL_ZERO GL_ZERO -#define CGL_ONE GL_ONE -#define CGL_SRC_COLOR GL_SRC_COLOR -#define CGL_ONE_MINUS_SRC_COLOR GL_ONE_MINUS_SRC_COLOR -#define CGL_SRC_ALPHA GL_SRC_ALPHA -#define CGL_ONE_MINUS_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA -#define CGL_DST_ALPHA GL_DST_ALPHA -#define CGL_ONE_MINUS_DST_ALPHA GL_ONE_MINUS_DST_ALPHA -#define CGL_DST_COLOR GL_DST_COLOR -#define CGL_ONE_MINUS_DST_COLOR GL_ONE_MINUS_DST_COLOR -#define CGL_SRC_ALPHA_SATURATE GL_SRC_ALPHA_SATURATE -#define CGL_FEEDBACK GL_FEEDBACK -#define CGL_RENDER GL_RENDER -#define CGL_SELECT GL_SELECT -#define CGL_POINT_TOKEN GL_POINT_TOKEN -#define CGL_LINE_TOKEN GL_LINE_TOKEN -#define CGL_LINE_RESET_TOKEN GL_LINE_RESET_TOKEN -#define CGL_POLYGON_TOKEN GL_POLYGON_TOKEN -#define CGL_BITMAP_TOKEN GL_BITMAP_TOKEN -#define CGL_DRAW_PIXEL_TOKEN GL_DRAW_PIXEL_TOKEN -#define CGL_COPY_PIXEL_TOKEN GL_COPY_PIXEL_TOKEN -#define CGL_PASS_THROUGH_TOKEN GL_PASS_THROUGH_TOKEN -#define CGL_FEEDBACK_BUFFER_POINTER GL_FEEDBACK_BUFFER_POINTER -#define CGL_FEEDBACK_BUFFER_SIZE GL_FEEDBACK_BUFFER_SIZE -#define CGL_FEEDBACK_BUFFER_TYPE GL_FEEDBACK_BUFFER_TYPE -#define CGL_SELECTION_BUFFER_POINTER GL_SELECTION_BUFFER_POINTER -#define CGL_SELECTION_BUFFER_SIZE GL_SELECTION_BUFFER_SIZE -#define CGL_FOG GL_FOG -#define CGL_FOG_MODE GL_FOG_MODE -#define CGL_FOG_DENSITY GL_FOG_DENSITY -#define CGL_FOG_COLOR GL_FOG_COLOR -#define CGL_FOG_INDEX GL_FOG_INDEX -#define CGL_FOG_START GL_FOG_START -#define CGL_FOG_END GL_FOG_END -#define CGL_EXP GL_EXP -#define CGL_LOGIC_OP GL_LOGIC_OP -#define CGL_INDEX_LOGIC_OP GL_INDEX_LOGIC_OP -#define CGL_COLOR_LOGIC_OP GL_COLOR_LOGIC_OP -#define CGL_LOGIC_OP_MODE GL_LOGIC_OP_MODE -#define CGL_CLEAR GL_CLEAR -#define CGL_SET GL_SET -#define CGL_COPY GL_COPY -#define CGL_COPY_INVERTED GL_COPY_INVERTED -#define CGL_NOOP GL_NOOP -#define CGL_INVERT GL_INVERT -#define CGL_AND GL_AND -#define CGL_NAND GL_NAND -#define CGL_OR GL_OR -#define CGL_NOR GL_NOR -#define CGL_XOR GL_XOR -#define CGL_EQUIV GL_EQUIV -#define CGL_AND_REVERSE GL_AND_REVERSE -#define CGL_AND_INVERTED GL_AND_INVERTED -#define CGL_OR_REVERSE GL_OR_REVERSE -#define CGL_OR_INVERTED GL_OR_INVERTED -#define CGL_STENCIL_BITS GL_STENCIL_BITS -#define CGL_STENCIL_TEST GL_STENCIL_TEST -#define CGL_STENCIL_CLEAR_VALUE GL_STENCIL_CLEAR_VALUE -#define CGL_STENCIL_FUNC GL_STENCIL_FUNC -#define CGL_STENCIL_VALUE_MASK GL_STENCIL_VALUE_MASK -#define CGL_STENCIL_FAIL GL_STENCIL_FAIL -#define CGL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_FAIL -#define CGL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_PASS_DEPTH_PASS -#define CGL_STENCIL_REF GL_STENCIL_REF -#define CGL_STENCIL_WRITEMASK GL_STENCIL_WRITEMASK -#define CGL_STENCIL_INDEX GL_STENCIL_INDEX -#define CGL_KEEP GL_KEEP -#define CGL_REPLACE GL_REPLACE -#define CGL_INCR GL_INCR -#define CGL_DECR GL_DECR -#define CGL_NONE GL_NONE -#define CGL_LEFT GL_LEFT -#define CGL_RIGHT GL_RIGHT -#define CGL_FRONT_LEFT GL_FRONT_LEFT -#define CGL_FRONT_RIGHT GL_FRONT_RIGHT -#define CGL_BACK_LEFT GL_BACK_LEFT -#define CGL_BACK_RIGHT GL_BACK_RIGHT -#define CGL_COLOR_INDEX GL_COLOR_INDEX -#define CGL_RED GL_RED -#define CGL_GREEN GL_GREEN -#define CGL_BLUE GL_BLUE -#define CGL_ALPHA GL_ALPHA -#define CGL_LUMINANCE GL_LUMINANCE -#define CGL_LUMINANCE_ALPHA GL_LUMINANCE_ALPHA -#define CGL_ALPHA_BITS GL_ALPHA_BITS -#define CGL_RED_BITS GL_RED_BITS -#define CGL_GREEN_BITS GL_GREEN_BITS -#define CGL_BLUE_BITS GL_BLUE_BITS -#define CGL_INDEX_BITS GL_INDEX_BITS -#define CGL_SUBPIXEL_BITS GL_SUBPIXEL_BITS -#define CGL_AUX_BUFFERS GL_AUX_BUFFERS -#define CGL_READ_BUFFER GL_READ_BUFFER -#define CGL_DRAW_BUFFER GL_DRAW_BUFFER -#define CGL_DOUBLEBUFFER GL_DOUBLEBUFFER -#define CGL_STEREO GL_STEREO -#define CGL_BITMAP GL_BITMAP -#define CGL_COLOR GL_COLOR -#define CGL_DEPTH GL_DEPTH -#define CGL_STENCIL GL_STENCIL -#define CGL_DITHER GL_DITHER -#define CGL_RGB GL_RGB -#define CGL_RGBA GL_RGBA -#define CGL_MAX_LIST_NESTING GL_MAX_LIST_NESTING -#define CGL_MAX_EVAL_ORDER GL_MAX_EVAL_ORDER -#define CGL_MAX_LIGHTS GL_MAX_LIGHTS -#define CGL_MAX_CLIP_PLANES GL_MAX_CLIP_PLANES -#define CGL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_SIZE -#define CGL_MAX_PIXEL_MAP_TABLE GL_MAX_PIXEL_MAP_TABLE -#define CGL_MAX_ATTRIB_STACK_DEPTH GL_MAX_ATTRIB_STACK_DEPTH -#define CGL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_MODELVIEW_STACK_DEPTH -#define CGL_MAX_NAME_STACK_DEPTH GL_MAX_NAME_STACK_DEPTH -#define CGL_MAX_PROJECTION_STACK_DEPTH GL_MAX_PROJECTION_STACK_DEPTH -#define CGL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_STACK_DEPTH -#define CGL_MAX_VIEWPORT_DIMS GL_MAX_VIEWPORT_DIMS -#define CGL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH -#define CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS GL_MAX_TEXTURE_UNITS -#define CGL_ATTRIB_STACK_DEPTH GL_ATTRIB_STACK_DEPTH -#define CGL_CLIENT_ATTRIB_STACK_DEPTH GL_CLIENT_ATTRIB_STACK_DEPTH -#define CGL_COLOR_CLEAR_VALUE GL_COLOR_CLEAR_VALUE -#define CGL_COLOR_WRITEMASK GL_COLOR_WRITEMASK -#define CGL_CURRENT_INDEX GL_CURRENT_INDEX -#define CGL_CURRENT_COLOR GL_CURRENT_COLOR -#define CGL_CURRENT_NORMAL GL_CURRENT_NORMAL -#define CGL_CURRENT_RASTER_COLOR GL_CURRENT_RASTER_COLOR -#define CGL_CURRENT_RASTER_DISTANCE GL_CURRENT_RASTER_DISTANCE -#define CGL_CURRENT_RASTER_INDEX GL_CURRENT_RASTER_INDEX -#define CGL_CURRENT_RASTER_POSITION GL_CURRENT_RASTER_POSITION -#define CGL_CURRENT_RASTER_TEXTURE_COORDS GL_CURRENT_RASTER_TEXTURE_COORDS -#define CGL_CURRENT_RASTER_POSITION_VALID GL_CURRENT_RASTER_POSITION_VALID -#define CGL_CURRENT_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS -#define CGL_INDEX_CLEAR_VALUE GL_INDEX_CLEAR_VALUE -#define CGL_INDEX_MODE GL_INDEX_MODE -#define CGL_INDEX_WRITEMASK GL_INDEX_WRITEMASK -#define CGL_MODELVIEW_MATRIX GL_MODELVIEW_MATRIX -#define CGL_MODELVIEW_STACK_DEPTH GL_MODELVIEW_STACK_DEPTH -#define CGL_NAME_STACK_DEPTH GL_NAME_STACK_DEPTH -#define CGL_PROJECTION_MATRIX GL_PROJECTION_MATRIX -#define CGL_PROJECTION_STACK_DEPTH GL_PROJECTION_STACK_DEPTH -#define CGL_RENDER_MODE GL_RENDER_MODE -#define CGL_RGBA_MODE GL_RGBA_MODE -#define CGL_TEXTURE_MATRIX GL_TEXTURE_MATRIX -#define CGL_TEXTURE_STACK_DEPTH GL_TEXTURE_STACK_DEPTH -#define CGL_VIEWPORT GL_VIEWPORT -#define CGL_AUTO_NORMAL GL_AUTO_NORMAL -#define CGL_COEFF GL_COEFF -#define CGL_ORDER GL_ORDER -#define CGL_DOMAIN GL_DOMAIN -#define CGL_PERSPECTIVE_CORRECTION_HINT GL_PERSPECTIVE_CORRECTION_HINT -#define CGL_POINT_SMOOTH_HINT GL_POINT_SMOOTH_HINT -#define CGL_LINE_SMOOTH_HINT GL_LINE_SMOOTH_HINT -#define CGL_POLYGON_SMOOTH_HINT GL_POLYGON_SMOOTH_HINT -#define CGL_FOG_HINT GL_FOG_HINT -#define CGL_DONT_CARE GL_DONT_CARE -#define CGL_FASTEST GL_FASTEST -#define CGL_NICEST GL_NICEST -#define CGL_SCISSOR_BOX GL_SCISSOR_BOX -#define CGL_SCISSOR_TEST GL_SCISSOR_TEST -#define CGL_MAP_COLOR GL_MAP_COLOR -#define CGL_MAP_STENCIL GL_MAP_STENCIL -#define CGL_INDEX_SHIFT GL_INDEX_SHIFT -#define CGL_INDEX_OFFSET GL_INDEX_OFFSET -#define CGL_RED_SCALE GL_RED_SCALE -#define CGL_RED_BIAS GL_RED_BIAS -#define CGL_GREEN_SCALE GL_GREEN_SCALE -#define CGL_GREEN_BIAS GL_GREEN_BIAS -#define CGL_BLUE_SCALE GL_BLUE_SCALE -#define CGL_BLUE_BIAS GL_BLUE_BIAS -#define CGL_ALPHA_SCALE GL_ALPHA_SCALE -#define CGL_ALPHA_BIAS GL_ALPHA_BIAS -#define CGL_DEPTH_SCALE GL_DEPTH_SCALE -#define CGL_DEPTH_BIAS GL_DEPTH_BIAS -#define CGL_PIXEL_MAP_S_TO_S_SIZE GL_PIXEL_MAP_S_TO_S_SIZE -#define CGL_PIXEL_MAP_I_TO_I_SIZE GL_PIXEL_MAP_I_TO_I_SIZE -#define CGL_PIXEL_MAP_I_TO_R_SIZE GL_PIXEL_MAP_I_TO_R_SIZE -#define CGL_PIXEL_MAP_I_TO_G_SIZE GL_PIXEL_MAP_I_TO_G_SIZE -#define CGL_PIXEL_MAP_I_TO_B_SIZE GL_PIXEL_MAP_I_TO_B_SIZE -#define CGL_PIXEL_MAP_I_TO_A_SIZE GL_PIXEL_MAP_I_TO_A_SIZE -#define CGL_PIXEL_MAP_R_TO_R_SIZE GL_PIXEL_MAP_R_TO_R_SIZE -#define CGL_PIXEL_MAP_G_TO_G_SIZE GL_PIXEL_MAP_G_TO_G_SIZE -#define CGL_PIXEL_MAP_B_TO_B_SIZE GL_PIXEL_MAP_B_TO_B_SIZE -#define CGL_PIXEL_MAP_A_TO_A_SIZE GL_PIXEL_MAP_A_TO_A_SIZE -#define CGL_PIXEL_MAP_S_TO_S GL_PIXEL_MAP_S_TO_S -#define CGL_PIXEL_MAP_I_TO_I GL_PIXEL_MAP_I_TO_I -#define CGL_PIXEL_MAP_I_TO_R GL_PIXEL_MAP_I_TO_R -#define CGL_PIXEL_MAP_I_TO_G GL_PIXEL_MAP_I_TO_G -#define CGL_PIXEL_MAP_I_TO_B GL_PIXEL_MAP_I_TO_B -#define CGL_PIXEL_MAP_I_TO_A GL_PIXEL_MAP_I_TO_A -#define CGL_PIXEL_MAP_R_TO_R GL_PIXEL_MAP_R_TO_R -#define CGL_PIXEL_MAP_G_TO_G GL_PIXEL_MAP_G_TO_G -#define CGL_PIXEL_MAP_B_TO_B GL_PIXEL_MAP_B_TO_B -#define CGL_PIXEL_MAP_A_TO_A GL_PIXEL_MAP_A_TO_A -#define CGL_PACK_ALIGNMENT GL_PACK_ALIGNMENT -#define CGL_PACK_LSB_FIRST GL_PACK_LSB_FIRST -#define CGL_PACK_ROW_LENGTH GL_PACK_ROW_LENGTH -#define CGL_PACK_SKIP_PIXELS GL_PACK_SKIP_PIXELS -#define CGL_PACK_SKIP_ROWS GL_PACK_SKIP_ROWS -#define CGL_PACK_SWAP_BYTES GL_PACK_SWAP_BYTES -#define CGL_UNPACK_ALIGNMENT GL_UNPACK_ALIGNMENT -#define CGL_UNPACK_LSB_FIRST GL_UNPACK_LSB_FIRST -#define CGL_UNPACK_ROW_LENGTH GL_UNPACK_ROW_LENGTH -#define CGL_UNPACK_SKIP_PIXELS GL_UNPACK_SKIP_PIXELS -#define CGL_UNPACK_SKIP_ROWS GL_UNPACK_SKIP_ROWS -#define CGL_UNPACK_SWAP_BYTES GL_UNPACK_SWAP_BYTES -#define CGL_ZOOM_X GL_ZOOM_X -#define CGL_ZOOM_Y GL_ZOOM_Y -#define CGL_TEXTURE_ENV GL_TEXTURE_ENV -#define CGL_TEXTURE_ENV_MODE GL_TEXTURE_ENV_MODE -#define CGL_TEXTURE_WRAP_S GL_TEXTURE_WRAP_S -#define CGL_TEXTURE_WRAP_T GL_TEXTURE_WRAP_T -#define CGL_TEXTURE_MAG_FILTER GL_TEXTURE_MAG_FILTER -#define CGL_TEXTURE_MIN_FILTER GL_TEXTURE_MIN_FILTER -#define CGL_TEXTURE_ENV_COLOR GL_TEXTURE_ENV_COLOR -#define CGL_TEXTURE_GEN_S GL_TEXTURE_GEN_S -#define CGL_TEXTURE_GEN_T GL_TEXTURE_GEN_T -#define CGL_TEXTURE_GEN_MODE GL_TEXTURE_GEN_MODE -#define CGL_TEXTURE_BORDER_COLOR GL_TEXTURE_BORDER_COLOR -#define CGL_TEXTURE_WIDTH GL_TEXTURE_WIDTH -#define CGL_TEXTURE_HEIGHT GL_TEXTURE_HEIGHT -#define CGL_TEXTURE_BORDER GL_TEXTURE_BORDER -#define CGL_TEXTURE_COMPONENTS GL_TEXTURE_COMPONENTS -#define CGL_TEXTURE_RED_SIZE GL_TEXTURE_RED_SIZE -#define CGL_TEXTURE_GREEN_SIZE GL_TEXTURE_GREEN_SIZE -#define CGL_TEXTURE_BLUE_SIZE GL_TEXTURE_BLUE_SIZE -#define CGL_TEXTURE_ALPHA_SIZE GL_TEXTURE_ALPHA_SIZE -#define CGL_TEXTURE_LUMINANCE_SIZE GL_TEXTURE_LUMINANCE_SIZE -#define CGL_TEXTURE_INTENSITY_SIZE GL_TEXTURE_INTENSITY_SIZE -#define CGL_OBJECT_LINEAR GL_OBJECT_LINEAR -#define CGL_OBJECT_PLANE GL_OBJECT_PLANE -#define CGL_EYE_LINEAR GL_EYE_LINEAR -#define CGL_EYE_PLANE GL_EYE_PLANE -#define CGL_SPHERE_MAP GL_SPHERE_MAP -#define CGL_DECAL GL_DECAL -#define CGL_MODULATE GL_MODULATE -#define CGL_REPEAT GL_REPEAT -#define CGL_CLAMP GL_CLAMP -#define CGL_S GL_S -#define CGL_T GL_T -#define CGL_R GL_R -#define CGL_Q GL_Q -#define CGL_TEXTURE_GEN_R GL_TEXTURE_GEN_R -#define CGL_TEXTURE_GEN_Q GL_TEXTURE_GEN_Q -#define CGL_VENDOR GL_VENDOR -#define CGL_RENDERER GL_RENDERER -#define CGL_VERSION GL_VERSION -#define CGL_EXTENSIONS GL_EXTENSIONS -#define CGL_NO_ERROR GL_NO_ERROR -#define CGL_INVALID_ENUM GL_INVALID_ENUM -#define CGL_INVALID_VALUE GL_INVALID_VALUE -#define CGL_INVALID_OPERATION GL_INVALID_OPERATION -#define CGL_STACK_OVERFLOW GL_STACK_OVERFLOW -#define CGL_STACK_UNDERFLOW GL_STACK_UNDERFLOW -#define CGL_OUT_OF_MEMORY GL_OUT_OF_MEMORY -#define CGL_CURRENT_BIT GL_CURRENT_BIT -#define CGL_POINT_BIT GL_POINT_BIT -#define CGL_LINE_BIT GL_LINE_BIT -#define CGL_POLYGON_BIT GL_POLYGON_BIT -#define CGL_POLYGON_STIPPLE_BIT GL_POLYGON_STIPPLE_BIT -#define CGL_PIXEL_MODE_BIT GL_PIXEL_MODE_BIT -#define CGL_LIGHTING_BIT GL_LIGHTING_BIT -#define CGL_FOG_BIT GL_FOG_BIT -#define CGL_DEPTH_BUFFER_BIT GL_DEPTH_BUFFER_BIT -#define CGL_ACCUM_BUFFER_BIT GL_ACCUM_BUFFER_BIT -#define CGL_STENCIL_BUFFER_BIT GL_STENCIL_BUFFER_BIT -#define CGL_VIEWPORT_BIT GL_VIEWPORT_BIT -#define CGL_TRANSFORM_BIT GL_TRANSFORM_BIT -#define CGL_ENABLE_BIT GL_ENABLE_BIT -#define CGL_COLOR_BUFFER_BIT GL_COLOR_BUFFER_BIT -#define CGL_HINT_BIT GL_HINT_BIT -#define CGL_EVAL_BIT GL_EVAL_BIT -#define CGL_LIST_BIT GL_LIST_BIT -#define CGL_TEXTURE_BIT GL_TEXTURE_BIT -#define CGL_SCISSOR_BIT GL_SCISSOR_BIT -#define CGL_ALL_ATTRIB_BITS GL_ALL_ATTRIB_BITS -#define CGL_TEXTURE_PRIORITY GL_TEXTURE_PRIORITY -#define CGL_TEXTURE_RESIDENT GL_TEXTURE_RESIDENT -#define CGL_TEXTURE_INTERNAL_FORMAT GL_TEXTURE_INTERNAL_FORMAT -#define CGL_INTENSITY GL_INTENSITY -#define CGL_CLIENT_PIXEL_STORE_BIT GL_CLIENT_PIXEL_STORE_BIT -#define CGL_CLIENT_VERTEX_ARRAY_BIT GL_CLIENT_VERTEX_ARRAY_BIT -#define CGL_ALL_CLIENT_ATTRIB_BITS GL_ALL_CLIENT_ATTRIB_BITS -#define CGL_CLIENT_ALL_ATTRIB_BITS GL_CLIENT_ALL_ATTRIB_BITS -#define CGL_RESCALE_NORMAL GL_RESCALE_NORMAL -#define CGL_CLAMP_TO_EDGE GL_CLAMP_TO_EDGE -#define CGL_MAX_ELEMENTS_VERTICES GL_MAX_ELEMENTS_VERTICES -#define CGL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_INDICES -#define CGL_BGR GL_BGR -#define CGL_BGRA GL_BGRA -#define CGL_LIGHT_MODEL_COLOR_CONTROL GL_LIGHT_MODEL_COLOR_CONTROL -#define CGL_SINGLE_COLOR GL_SINGLE_COLOR -#define CGL_SEPARATE_SPECULAR_COLOR GL_SEPARATE_SPECULAR_COLOR -#define CGL_TEXTURE_MIN_LOD GL_TEXTURE_MIN_LOD -#define CGL_TEXTURE_MAX_LOD GL_TEXTURE_MAX_LOD -#define CGL_TEXTURE_BASE_LEVEL GL_TEXTURE_BASE_LEVEL -#define CGL_TEXTURE_MAX_LEVEL GL_TEXTURE_MAX_LEVEL -#define CGL_SMOOTH_POINT_SIZE_RANGE GL_SMOOTH_POINT_SIZE_RANGE -#define CGL_SMOOTH_POINT_SIZE_GRANULARITY GL_SMOOTH_POINT_SIZE_GRANULARITY -#define CGL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_LINE_WIDTH_RANGE -#define CGL_SMOOTH_LINE_WIDTH_GRANULARITY GL_SMOOTH_LINE_WIDTH_GRANULARITY -#define CGL_ALIASED_POINT_SIZE_RANGE GL_ALIASED_POINT_SIZE_RANGE -#define CGL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_LINE_WIDTH_RANGE -#define CGL_PACK_SKIP_IMAGES GL_PACK_SKIP_IMAGES -#define CGL_PACK_IMAGE_HEIGHT GL_PACK_IMAGE_HEIGHT -#define CGL_UNPACK_SKIP_IMAGES GL_UNPACK_SKIP_IMAGES -#define CGL_UNPACK_IMAGE_HEIGHT GL_UNPACK_IMAGE_HEIGHT -#define CGL_TEXTURE_DEPTH GL_TEXTURE_DEPTH -#define CGL_TEXTURE_WRAP_R GL_TEXTURE_WRAP_R -#define CGL_CONSTANT_COLOR GL_CONSTANT_COLOR -#define CGL_ONE_MINUS_CONSTANT_COLOR GL_ONE_MINUS_CONSTANT_COLOR -#define CGL_CONSTANT_ALPHA GL_CONSTANT_ALPHA -#define CGL_ONE_MINUS_CONSTANT_ALPHA GL_ONE_MINUS_CONSTANT_ALPHA -#define CGL_COLOR_TABLE GL_COLOR_TABLE -#define CGL_POST_CONVOLUTION_COLOR_TABLE GL_POST_CONVOLUTION_COLOR_TABLE -#define CGL_POST_COLOR_MATRIX_COLOR_TABLE GL_POST_COLOR_MATRIX_COLOR_TABLE -#define CGL_PROXY_COLOR_TABLE GL_PROXY_COLOR_TABLE -#define CGL_PROXY_POST_CONVOLUTION_COLOR_TABLE GL_PROXY_POST_CONVOLUTION_COLOR_TABLE -#define CGL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE -#define CGL_COLOR_TABLE_SCALE GL_COLOR_TABLE_SCALE -#define CGL_COLOR_TABLE_BIAS GL_COLOR_TABLE_BIAS -#define CGL_COLOR_TABLE_FORMAT GL_COLOR_TABLE_FORMAT -#define CGL_COLOR_TABLE_WIDTH GL_COLOR_TABLE_WIDTH -#define CGL_COLOR_TABLE_RED_SIZE GL_COLOR_TABLE_RED_SIZE -#define CGL_COLOR_TABLE_GREEN_SIZE GL_COLOR_TABLE_GREEN_SIZE -#define CGL_COLOR_TABLE_BLUE_SIZE GL_COLOR_TABLE_BLUE_SIZE -#define CGL_COLOR_TABLE_ALPHA_SIZE GL_COLOR_TABLE_ALPHA_SIZE -#define CGL_COLOR_TABLE_LUMINANCE_SIZE GL_COLOR_TABLE_LUMINANCE_SIZE -#define CGL_COLOR_TABLE_INTENSITY_SIZE GL_COLOR_TABLE_INTENSITY_SIZE -#define CGL_CONVOLUTION_BORDER_MODE GL_CONVOLUTION_BORDER_MODE -#define CGL_CONVOLUTION_FILTER_SCALE GL_CONVOLUTION_FILTER_SCALE -#define CGL_CONVOLUTION_FILTER_BIAS GL_CONVOLUTION_FILTER_BIAS -#define CGL_REDUCE GL_REDUCE -#define CGL_CONVOLUTION_FORMAT GL_CONVOLUTION_FORMAT -#define CGL_CONVOLUTION_WIDTH GL_CONVOLUTION_WIDTH -#define CGL_CONVOLUTION_HEIGHT GL_CONVOLUTION_HEIGHT -#define CGL_MAX_CONVOLUTION_WIDTH GL_MAX_CONVOLUTION_WIDTH -#define CGL_MAX_CONVOLUTION_HEIGHT GL_MAX_CONVOLUTION_HEIGHT -#define CGL_POST_CONVOLUTION_RED_SCALE GL_POST_CONVOLUTION_RED_SCALE -#define CGL_POST_CONVOLUTION_GREEN_SCALE GL_POST_CONVOLUTION_GREEN_SCALE -#define CGL_POST_CONVOLUTION_BLUE_SCALE GL_POST_CONVOLUTION_BLUE_SCALE -#define CGL_POST_CONVOLUTION_ALPHA_SCALE GL_POST_CONVOLUTION_ALPHA_SCALE -#define CGL_POST_CONVOLUTION_RED_BIAS GL_POST_CONVOLUTION_RED_BIAS -#define CGL_POST_CONVOLUTION_GREEN_BIAS GL_POST_CONVOLUTION_GREEN_BIAS -#define CGL_POST_CONVOLUTION_BLUE_BIAS GL_POST_CONVOLUTION_BLUE_BIAS -#define CGL_POST_CONVOLUTION_ALPHA_BIAS GL_POST_CONVOLUTION_ALPHA_BIAS -#define CGL_CONSTANT_BORDER GL_CONSTANT_BORDER -#define CGL_REPLICATE_BORDER GL_REPLICATE_BORDER -#define CGL_CONVOLUTION_BORDER_COLOR GL_CONVOLUTION_BORDER_COLOR -#define CGL_COLOR_MATRIX GL_COLOR_MATRIX -#define CGL_COLOR_MATRIX_STACK_DEPTH GL_COLOR_MATRIX_STACK_DEPTH -#define CGL_MAX_COLOR_MATRIX_STACK_DEPTH GL_MAX_COLOR_MATRIX_STACK_DEPTH -#define CGL_POST_COLOR_MATRIX_RED_SCALE GL_POST_COLOR_MATRIX_RED_SCALE -#define CGL_POST_COLOR_MATRIX_GREEN_SCALE GL_POST_COLOR_MATRIX_GREEN_SCALE -#define CGL_POST_COLOR_MATRIX_BLUE_SCALE GL_POST_COLOR_MATRIX_BLUE_SCALE -#define CGL_POST_COLOR_MATRIX_ALPHA_SCALE GL_POST_COLOR_MATRIX_ALPHA_SCALE -#define CGL_POST_COLOR_MATRIX_RED_BIAS GL_POST_COLOR_MATRIX_RED_BIAS -#define CGL_POST_COLOR_MATRIX_GREEN_BIAS GL_POST_COLOR_MATRIX_GREEN_BIAS -#define CGL_POST_COLOR_MATRIX_BLUE_BIAS GL_POST_COLOR_MATRIX_BLUE_BIAS -#define CGL_POST_COLOR_MATRIX_ALPHA_BIAS GL_POST_COLOR_MATRIX_ALPHA_BIAS -#define CGL_HISTOGRAM GL_HISTOGRAM -#define CGL_PROXY_HISTOGRAM GL_PROXY_HISTOGRAM -#define CGL_HISTOGRAM_WIDTH GL_HISTOGRAM_WIDTH -#define CGL_HISTOGRAM_FORMAT GL_HISTOGRAM_FORMAT -#define CGL_HISTOGRAM_RED_SIZE GL_HISTOGRAM_RED_SIZE -#define CGL_HISTOGRAM_GREEN_SIZE GL_HISTOGRAM_GREEN_SIZE -#define CGL_HISTOGRAM_BLUE_SIZE GL_HISTOGRAM_BLUE_SIZE -#define CGL_HISTOGRAM_ALPHA_SIZE GL_HISTOGRAM_ALPHA_SIZE -#define CGL_HISTOGRAM_LUMINANCE_SIZE GL_HISTOGRAM_LUMINANCE_SIZE -#define CGL_HISTOGRAM_SINK GL_HISTOGRAM_SINK -#define CGL_MINMAX GL_MINMAX -#define CGL_MINMAX_FORMAT GL_MINMAX_FORMAT -#define CGL_MINMAX_SINK GL_MINMAX_SINK -#define CGL_TABLE_TOO_LARGE GL_TABLE_TOO_LARGE -#define CGL_BLEND_EQUATION GL_BLEND_EQUATION -#define CGL_MIN GL_MIN -#define CGL_MAX GL_MAX -#define CGL_FUNC_ADD GL_FUNC_ADD -#define CGL_FUNC_SUBTRACT GL_FUNC_SUBTRACT -#define CGL_FUNC_REVERSE_SUBTRACT GL_FUNC_REVERSE_SUBTRACT -#define CGL_BLEND_COLOR GL_BLEND_COLOR -#define CGL_ACTIVE_TEXTURE GL_ACTIVE_TEXTURE -#define CGL_CLIENT_ACTIVE_TEXTURE GL_CLIENT_ACTIVE_TEXTURE -#define CGL_MAX_TEXTURE_UNITS GL_MAX_TEXTURE_UNITS -#define CGL_NORMAL_MAP GL_NORMAL_MAP -#define CGL_REFLECTION_MAP GL_REFLECTION_MAP -#define CGL_TEXTURE_CUBE_MAP GL_TEXTURE_CUBE_MAP -#define CGL_TEXTURE_BINDING_CUBE_MAP GL_TEXTURE_BINDING_CUBE_MAP -#define CGL_TEXTURE_CUBE_MAP_POSITIVE_X GL_TEXTURE_CUBE_MAP_POSITIVE_X -#define CGL_TEXTURE_CUBE_MAP_NEGATIVE_X GL_TEXTURE_CUBE_MAP_NEGATIVE_X -#define CGL_TEXTURE_CUBE_MAP_POSITIVE_Y GL_TEXTURE_CUBE_MAP_POSITIVE_Y -#define CGL_TEXTURE_CUBE_MAP_NEGATIVE_Y GL_TEXTURE_CUBE_MAP_NEGATIVE_Y -#define CGL_TEXTURE_CUBE_MAP_POSITIVE_Z GL_TEXTURE_CUBE_MAP_POSITIVE_Z -#define CGL_TEXTURE_CUBE_MAP_NEGATIVE_Z GL_TEXTURE_CUBE_MAP_NEGATIVE_Z -#define CGL_PROXY_TEXTURE_CUBE_MAP GL_PROXY_TEXTURE_CUBE_MAP -#define CGL_MAX_CUBE_MAP_TEXTURE_SIZE GL_MAX_CUBE_MAP_TEXTURE_SIZE -#define CGL_COMPRESSED_ALPHA GL_COMPRESSED_ALPHA -#define CGL_COMPRESSED_LUMINANCE GL_COMPRESSED_LUMINANCE -#define CGL_COMPRESSED_LUMINANCE_ALPHA GL_COMPRESSED_LUMINANCE_ALPHA -#define CGL_COMPRESSED_INTENSITY GL_COMPRESSED_INTENSITY -#define CGL_COMPRESSED_RGB GL_COMPRESSED_RGB -#define CGL_COMPRESSED_RGBA GL_COMPRESSED_RGBA -#define CGL_TEXTURE_COMPRESSION_HINT GL_TEXTURE_COMPRESSION_HINT -#define CGL_TEXTURE_COMPRESSED_IMAGE_SIZE GL_TEXTURE_COMPRESSED_IMAGE_SIZE -#define CGL_TEXTURE_COMPRESSED GL_TEXTURE_COMPRESSED -#define CGL_NUM_COMPRESSED_TEXTURE_FORMATS GL_NUM_COMPRESSED_TEXTURE_FORMATS -#define CGL_COMPRESSED_TEXTURE_FORMATS GL_COMPRESSED_TEXTURE_FORMATS -#define CGL_MULTISAMPLE GL_MULTISAMPLE -#define CGL_SAMPLE_ALPHA_TO_COVERAGE GL_SAMPLE_ALPHA_TO_COVERAGE -#define CGL_SAMPLE_ALPHA_TO_ONE GL_SAMPLE_ALPHA_TO_ONE -#define CGL_SAMPLE_COVERAGE GL_SAMPLE_COVERAGE -#define CGL_SAMPLE_BUFFERS GL_SAMPLE_BUFFERS -#define CGL_SAMPLES GL_SAMPLES -#define CGL_SAMPLE_COVERAGE_VALUE GL_SAMPLE_COVERAGE_VALUE -#define CGL_SAMPLE_COVERAGE_INVERT GL_SAMPLE_COVERAGE_INVERT -#define CGL_MULTISAMPLE_BIT GL_MULTISAMPLE_BIT -#define CGL_TRANSPOSE_MODELVIEW_MATRIX GL_TRANSPOSE_MODELVIEW_MATRIX -#define CGL_TRANSPOSE_PROJECTION_MATRIX GL_TRANSPOSE_PROJECTION_MATRIX -#define CGL_TRANSPOSE_TEXTURE_MATRIX GL_TRANSPOSE_TEXTURE_MATRIX -#define CGL_TRANSPOSE_COLOR_MATRIX GL_TRANSPOSE_COLOR_MATRIX -#define CGL_COMBINE GL_COMBINE -#define CGL_COMBINE_RGB GL_COMBINE_RGB -#define CGL_COMBINE_ALPHA GL_COMBINE_ALPHA -#define CGL_RGB_SCALE GL_RGB_SCALE -#define CGL_ADD_SIGNED GL_ADD_SIGNED -#define CGL_INTERPOLATE GL_INTERPOLATE -#define CGL_SUBTRACT GL_SUBTRACT -#define CGL_CONSTANT GL_CONSTANT -#define CGL_PRIMARY_COLOR GL_PRIMARY_COLOR -#define CGL_PREVIOUS GL_PREVIOUS -#define CGL_CLAMP_TO_BORDER GL_CLAMP_TO_BORDER -#define CGL_ACTIVE_TEXTURE_ARB GL_ACTIVE_TEXTURE_ARB -#define CGL_CLIENT_ACTIVE_TEXTURE_ARB GL_CLIENT_ACTIVE_TEXTURE_ARB -#define CGL_MAX_TEXTURE_UNITS_ARB GL_MAX_TEXTURE_UNITS_ARB -#define CGL_DEBUG_OBJECT_MESA GL_DEBUG_OBJECT_MESA -#define CGL_DEBUG_PRINT_MESA GL_DEBUG_PRINT_MESA -#define CGL_DEBUG_ASSERT_MESA GL_DEBUG_ASSERT_MESA -#define CGL_TRACE_ALL_BITS_MESA GL_TRACE_ALL_BITS_MESA -#define CGL_TRACE_OPERATIONS_BIT_MESA GL_TRACE_OPERATIONS_BIT_MESA -#define CGL_TRACE_PRIMITIVES_BIT_MESA GL_TRACE_PRIMITIVES_BIT_MESA -#define CGL_TRACE_ARRAYS_BIT_MESA GL_TRACE_ARRAYS_BIT_MESA -#define CGL_TRACE_TEXTURES_BIT_MESA GL_TRACE_TEXTURES_BIT_MESA -#define CGL_TRACE_PIXELS_BIT_MESA GL_TRACE_PIXELS_BIT_MESA -#define CGL_TRACE_ERRORS_BIT_MESA GL_TRACE_ERRORS_BIT_MESA -#define CGL_TRACE_MASK_MESA GL_TRACE_MASK_MESA -#define CGL_TRACE_NAME_MESA GL_TRACE_NAME_MESA -#define CGL_DEPTH_STENCIL_MESA GL_DEPTH_STENCIL_MESA -#define CGL_FRAGMENT_PROGRAM_POSITION_MESA GL_FRAGMENT_PROGRAM_POSITION_MESA -#define CGL_FRAGMENT_PROGRAM_CALLBACK_MESA GL_FRAGMENT_PROGRAM_CALLBACK_MESA -#define CGL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA -#define CGL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA -#define CGL_VERTEX_PROGRAM_POSITION_MESA GL_VERTEX_PROGRAM_POSITION_MESA -#define CGL_VERTEX_PROGRAM_CALLBACK_MESA GL_VERTEX_PROGRAM_CALLBACK_MESA -#define CGL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA -#define CGL_VERTEX_PROGRAM_CALLBACK_DATA_MESA GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA -#define CGL_ALPHA_BLEND_EQUATION_ATI GL_ALPHA_BLEND_EQUATION_ATI -#define CGL_TIME_ELAPSED_EXT GL_TIME_ELAPSED_EXT -#define CGL_READ_FRAMEBUFFER_EXT GL_READ_FRAMEBUFFER_EXT -#define CGL_DRAW_FRAMEBUFFER_EXT GL_DRAW_FRAMEBUFFER_EXT -#define CGL_DRAW_FRAMEBUFFER_BINDING_EXT GL_DRAW_FRAMEBUFFER_BINDING_EXT -#define CGL_READ_FRAMEBUFFER_BINDING_EXT GL_READ_FRAMEBUFFER_BINDING_EXT -#define CGL_DEPTH_STENCIL_EXT GL_DEPTH_STENCIL_EXT -#define CGL_TEXTURE_STENCIL_SIZE_EXT GL_TEXTURE_STENCIL_SIZE_EXT -#define CGL_SRGB_EXT GL_SRGB_EXT -#define CGL_SRGB_ALPHA_EXT GL_SRGB_ALPHA_EXT -#define CGL_SLUMINANCE_ALPHA_EXT GL_SLUMINANCE_ALPHA_EXT -#define CGL_SLUMINANCE_EXT GL_SLUMINANCE_EXT -#define CGL_COMPRESSED_SRGB_EXT GL_COMPRESSED_SRGB_EXT -#define CGL_COMPRESSED_SRGB_ALPHA_EXT GL_COMPRESSED_SRGB_ALPHA_EXT -#define CGL_COMPRESSED_SLUMINANCE_EXT GL_COMPRESSED_SLUMINANCE_EXT -#define CGL_COMPRESSED_SLUMINANCE_ALPHA_EXT GL_COMPRESSED_SLUMINANCE_ALPHA_EXT - -#define CGL_DOT3_RGB GL_DOT3_RGB -#define CGL_DOT3_RGBA GL_DOT3_RGBA - -/* extras */ - -#define CGL_TEXTURE_2D GL_TEXTURE_2D -#define CGL_ARGB GL_ARGB -#define CGL_UNSIGNED_INT_8_8_8_8_REV GL_UNSIGNED_INT_8_8_8_8_REV - -#ifdef GL_TEXTURE_RECTANGLE_ARB -#define CGL_TEXTURE_RECTANGLE_ARB GL_TEXTURE_RECTANGLE_ARB -#else -#define CGL_TEXTURE_RECTANGLE_ARB 0 -#endif - -#ifdef GL_YCBCR_MESA -#define CGL_YCBCR_MESA GL_YCBCR_MESA -#define CGL_UNSIGNED_SHORT_8_8_REV_MESA GL_UNSIGNED_SHORT_8_8_REV_MESA -#define CGL_UNSIGNED_SHORT_8_8_MESA GL_UNSIGNED_SHORT_8_8_MESA -#else -#define CGL_YCBCR_MESA 0 -#define CGL_UNSIGNED_SHORT_8_8_REV_MESA 0 -#define CGL_UNSIGNED_SHORT_8_8_MESA 0 -#endif - -#define CGL_OBJECT_COMPILE_STATUS GL_OBJECT_COMPILE_STATUS_ARB - #define CLUTTER_COGL_HAS_GL 1 #define COGL_HAS_GL 1 diff --git a/cogl/driver/gl/cogl-texture-driver.c b/cogl/driver/gl/cogl-texture-driver.c index 742fab807..4e54babd2 100644 --- a/cogl/driver/gl/cogl-texture-driver.c +++ b/cogl/driver/gl/cogl-texture-driver.c @@ -346,7 +346,7 @@ _cogl_texture_driver_allows_foreign_gl_target (GLenum gl_target) (for example, no mipmapping and complicated shader support) */ /* Allow 2-dimensional or rectangle textures only */ - if (gl_target != GL_TEXTURE_2D && gl_target != CGL_TEXTURE_RECTANGLE_ARB) + if (gl_target != GL_TEXTURE_2D && gl_target != GL_TEXTURE_RECTANGLE_ARB) return FALSE; return TRUE; diff --git a/cogl/driver/gles/cogl-defines.h.in b/cogl/driver/gles/cogl-defines.h.in index 97045df94..b7e76529d 100644 --- a/cogl/driver/gles/cogl-defines.h.in +++ b/cogl/driver/gles/cogl-defines.h.in @@ -33,606 +33,9 @@ G_BEGIN_DECLS #define @COGL_GLES_VERSION@ 1 -/* ClearBufferMask */ -#define CGL_DEPTH_BUFFER_BIT GL_DEPTH_BUFFER_BIT -#define CGL_STENCIL_BUFFER_BIT GL_STENCIL_BUFFER_BIT -#define CGL_COLOR_BUFFER_BIT GL_COLOR_BUFFER_BIT - -/* Boolean */ -#define CGL_FALSE GL_FALSE -#define CGL_TRUE GL_TRUE - -/* BeginMode */ -#define CGL_POINTS GL_POINTS -#define CGL_LINES GL_LINES -#define CGL_LINE_LOOP GL_LINE_LOOP -#define CGL_LINE_STRIP GL_LINE_STRIP -#define CGL_TRIANGLES GL_TRIANGLES -#define CGL_TRIANGLE_STRIP GL_TRIANGLE_STRIP -#define CGL_TRIANGLE_FAN GL_TRIANGLE_FAN - -/* AlphaFunction */ -#define CGL_NEVER GL_NEVER -#define CGL_LESS GL_LESS -#define CGL_EQUAL GL_EQUAL -#define CGL_LEQUAL GL_LEQUAL -#define CGL_GREATER GL_GREATER -#define CGL_NOTEQUAL GL_NOTEQUAL -#define CGL_GEQUAL GL_GEQUAL -#define CGL_ALWAYS GL_ALWAYS - -/* BlendingFactorDest */ -#define CGL_ZERO GL_ZERO -#define CGL_ONE GL_ONE -#define CGL_SRC_COLOR GL_SRC_COLOR -#define CGL_ONE_MINUS_SRC_COLOR GL_ONE_MINUS_SRC_COLOR -#define CGL_SRC_ALPHA GL_SRC_ALPHA -#define CGL_ONE_MINUS_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA -#define CGL_DST_ALPHA GL_DST_ALPHA -#define CGL_ONE_MINUS_DST_ALPHA GL_ONE_MINUS_DST_ALPHA - -/* BlendingFactorSrc */ -#define CGL_DST_COLOR GL_DST_COLOR -#define CGL_ONE_MINUS_DST_COLOR GL_ONE_MINUS_DST_COLOR -#define CGL_SRC_ALPHA_SATURATE GL_SRC_ALPHA_SATURATE -/* Missing; */ -/* GL_ZERO */ -/* GL_ONE */ -/* GL_SRC_ALPHA */ -/* GL_ONE_MINUS_SRC_ALPHA */ -/* GL_DST_ALPHA */ -/* GL_ONE_MINUS_DST_ALPHA */ - -/* CullFaceMode */ -#define CGL_FRONT GL_FRONT -#define CGL_BACK GL_BACK -#define CGL_FRONT_AND_BACK GL_FRONT_AND_BACK - -/* EnableCap */ -#define CGL_FOG GL_FOG -#define CGL_LIGHTING GL_LIGHTING -#define CGL_CULL_FACE GL_CULL_FACE -#define CGL_ALPHA_TEST GL_ALPHA_TEST -#define CGL_BLEND GL_BLEND -#define CGL_COLOR_LOGIC_OP GL_COLOR_LOGIC_OP -#define CGL_DITHER GL_DITHER -#define CGL_STENCIL_TEST GL_STENCIL_TEST -#define CGL_DEPTH_TEST GL_DEPTH_TEST -#define CGL_POINT_SMOOTH GL_POINT_SMOOTH -#define CGL_LINE_SMOOTH GL_LINE_SMOOTH -#define CGL_SCISSOR_TEST GL_SCISSOR_TEST -#define CGL_COLOR_MATERIAL GL_COLOR_MATERIAL -#define CGL_NORMALIZE GL_NORMALIZE -#define CGL_RESCALE_NORMAL GL_RESCALE_NORMAL -#define CGL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_FILL -#define CGL_VERTEX_ARRAY GL_VERTEX_ARRAY -#define CGL_NORMAL_ARRAY GL_NORMAL_ARRAY -#define CGL_COLOR_ARRAY GL_COLOR_ARRAY -#define CGL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY -#define CGL_MULTISAMPLE GL_MULTISAMPLE -#define CGL_SAMPLE_ALPHA_TO_COVERAGE GL_SAMPLE_ALPHA_TO_COVERAGE -#define CGL_SAMPLE_ALPHA_TO_ONE GL_SAMPLE_ALPHA_TO_ONE -#define CGL_SAMPLE_COVERAGE GL_SAMPLE_COVERAGE - -/* Errors */ -#define CGL_NO_ERROR GL_NO_ERROR -#define CGL_INVALID_ENUM GL_INVALID_ENUM -#define CGL_INVALID_VALUE GL_INVALID_VALUE -#define CGL_INVALID_OPERATION GL_INVALID_OPERATION -#define CGL_STACK_OVERFLOW GL_STACK_OVERFLOW -#define CGL_STACK_UNDERFLOW GL_STACK_UNDERFLOW -#define CGL_OUT_OF_MEMORY GL_OUT_OF_MEMORY - -/* Fog mode */ -#define CGL_EXP GL_EXP -#define CGL_EXP2 GL_EXP2 -#define CGL_FOG_DENSITY GL_FOG_DENSITY - -/* FogParameter */ -#define CGL_FOG_START GL_FOG_START -#define CGL_FOG_END GL_FOG_END -#define CGL_FOG_MODE GL_FOG_MODE -#define CGL_FOG_COLOR GL_FOG_COLOR -#define CGL_CW GL_CW -#define CGL_CCW GL_CCW - -/* GetPName */ -#define CGL_CURRENT_COLOR GL_CURRENT_COLOR -#define CGL_CURRENT_NORMAL GL_CURRENT_NORMAL -#define CGL_CURRENT_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS -#define CGL_POINT_SIZE GL_POINT_SIZE -#define CGL_POINT_SIZE_MIN GL_POINT_SIZE_MIN -#define CGL_POINT_SIZE_MAX GL_POINT_SIZE_MAX -#define CGL_POINT_FADE_THRESHOLD_SIZE GL_POINT_FADE_THRESHOLD_SIZE -#define CGL_POINT_DISTANCE_ATTENUATION GL_POINT_DISTANCE_ATTENUATION -#define CGL_SMOOTH_POINT_SIZE_RANGE GL_SMOOTH_POINT_SIZE_RANGE -#define CGL_LINE_WIDTH GL_LINE_WIDTH -#define CGL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_LINE_WIDTH_RANGE -#define CGL_ALIASED_POINT_SIZE_RANGE GL_ALIASED_POINT_SIZE_RANGE -#define CGL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_LINE_WIDTH_RANGE -#define CGL_CULL_FACE_MODE GL_CULL_FACE_MODE -#define CGL_FRONT_FACE GL_FRONT_FACE -#define CGL_SHADE_MODEL GL_SHADE_MODEL -#define CGL_DEPTH_RANGE GL_DEPTH_RANGE -#define CGL_DEPTH_WRITEMASK GL_DEPTH_WRITEMASK -#define CGL_DEPTH_CLEAR_VALUE GL_DEPTH_CLEAR_VALUE -#define CGL_DEPTH_FUNC GL_DEPTH_FUNC -#define CGL_STENCIL_CLEAR_VALUE GL_STENCIL_CLEAR_VALUE -#define CGL_STENCIL_FUNC GL_STENCIL_FUNC -#define CGL_STENCIL_VALUE_MASK GL_STENCIL_VALUE_MASK -#define CGL_STENCIL_FAIL GL_STENCIL_FAIL -#define CGL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_FAIL -#define CGL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_PASS_DEPTH_PASS -#define CGL_STENCIL_REF GL_STENCIL_REF -#define CGL_STENCIL_WRITEMASK GL_STENCIL_WRITEMASK -#ifdef COGL_HAS_GLES2 -#define CGL_MATRIX_MODE 0x0BA0 /* bad style but works for now */ -#else -#define CGL_MATRIX_MODE GL_MATRIX_MODE -#endif -#define CGL_VIEWPORT GL_VIEWPORT -#define CGL_MODELVIEW_STACK_DEPTH GL_MODELVIEW_STACK_DEPTH -#define CGL_PROJECTION_STACK_DEPTH GL_PROJECTION_STACK_DEPTH -#define CGL_TEXTURE_STACK_DEPTH GL_TEXTURE_STACK_DEPTH -#define CGL_MODELVIEW_MATRIX GL_MODELVIEW_MATRIX -#define CGL_PROJECTION_MATRIX GL_PROJECTION_MATRIX -#define CGL_TEXTURE_MATRIX GL_TEXTURE_MATRIX -#define CGL_ALPHA_TEST_FUNC GL_ALPHA_TEST_FUNC -#define CGL_ALPHA_TEST_REF GL_ALPHA_TEST_REF -#define CGL_BLEND_DST GL_BLEND_DST -#define CGL_BLEND_SRC GL_BLEND_SRC -#define CGL_LOGIC_OP_MODE GL_LOGIC_OP_MODE -#define CGL_SCISSOR_BOX GL_SCISSOR_BOX -#define CGL_SCISSOR_TEST GL_SCISSOR_TEST -#define CGL_COLOR_CLEAR_VALUE GL_COLOR_CLEAR_VALUE -#define CGL_COLOR_WRITEMASK GL_COLOR_WRITEMASK -#define CGL_UNPACK_ALIGNMENT GL_UNPACK_ALIGNMENT -#define CGL_PACK_ALIGNMENT GL_PACK_ALIGNMENT -#define CGL_MAX_LIGHTS GL_MAX_LIGHTS -#define CGL_MAX_CLIP_PLANES GL_MAX_CLIP_PLANES -#define CGL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_SIZE -#define CGL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_MODELVIEW_STACK_DEPTH -#define CGL_MAX_PROJECTION_STACK_DEPTH GL_MAX_PROJECTION_STACK_DEPTH -#define CGL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_STACK_DEPTH -#define CGL_MAX_VIEWPORT_DIMS GL_MAX_VIEWPORT_DIMS -#define CGL_MAX_ELEMENTS_VERTICES GL_MAX_ELEMENTS_VERTICES -#define CGL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_INDICES -#ifdef COGL_HAS_GLES2 -#define CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS -#else -#define CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS GL_MAX_TEXTURE_UNITS -#endif -#define CGL_SUBPIXEL_BITS GL_SUBPIXEL_BITS -#define CGL_RED_BITS GL_RED_BITS -#define CGL_GREEN_BITS GL_GREEN_BITS -#define CGL_BLUE_BITS GL_BLUE_BITS -#define CGL_ALPHA_BITS GL_ALPHA_BITS -#define CGL_DEPTH_BITS GL_DEPTH_BITS -#define CGL_STENCIL_BITS GL_STENCIL_BITS -#define CGL_POLYGON_OFFSET_UNITS GL_POLYGON_OFFSET_UNITS -#define CGL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_FILL -#define CGL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FACTOR -#define CGL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_SIZE -#define CGL_VERTEX_ARRAY_TYPE GL_VERTEX_ARRAY_TYPE -#define CGL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_STRIDE -#define CGL_NORMAL_ARRAY_TYPE GL_NORMAL_ARRAY_TYPE -#define CGL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_STRIDE -#define CGL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_SIZE -#define CGL_COLOR_ARRAY_TYPE GL_COLOR_ARRAY_TYPE -#define CGL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_STRIDE -#define CGL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_SIZE -#define CGL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_COORD_ARRAY_TYPE -#define CGL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_STRIDE -#define CGL_VERTEX_ARRAY_POINTER GL_VERTEX_ARRAY_POINTER -#define CGL_NORMAL_ARRAY_POINTER GL_NORMAL_ARRAY_POINTER -#define CGL_COLOR_ARRAY_POINTER GL_COLOR_ARRAY_POINTER -#define CGL_TEXTURE_COORD_ARRAY_POINTER GL_TEXTURE_COORD_ARRAY_POINTER -#define CGL_SAMPLE_BUFFERS GL_SAMPLE_BUFFERS -#define CGL_SAMPLES GL_SAMPLES -#define CGL_SAMPLE_COVERAGE_VALUE GL_SAMPLE_COVERAGE_VALUE -#define CGL_SAMPLE_COVERAGE_INVERT GL_SAMPLE_COVERAGE_INVERT - -/* GetTextureParameter - missing */ -/* GL_TEXTURE_MAG_FILTER */ -/* GL_TEXTURE_MIN_FILTER */ -/* GL_TEXTURE_WRAP_S */ -/* GL_TEXTURE_WRAP_T */ - - -#define CGL_IMPLEMENTATION_COLOR_READ_TYPE_OES GL_IMPLEMENTATION_COLOR_READ_TYPE_OES -#define CGL_IMPLEMENTATION_COLOR_READ_FORMAT_OES GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES -#define CGL_NUM_COMPRESSED_TEXTURE_FORMATS GL_NUM_COMPRESSED_TEXTURE_FORMATS -#define CGL_COMPRESSED_TEXTURE_FORMATS GL_COMPRESSED_TEXTURE_FORMATS - -/* OES_matrix_get */ -#define CGL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS -#define CGL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS -#define CGL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS -/* HintMode */ -#define CGL_DONT_CARE GL_DONT_CARE -#define CGL_FASTEST GL_FASTEST -#define CGL_NICEST GL_NICEST - -/* HintTarget */ -#define CGL_PERSPECTIVE_CORRECTION_HINT GL_PERSPECTIVE_CORRECTION_HINT -#define CGL_POINT_SMOOTH_HINT GL_POINT_SMOOTH_HINT -#define CGL_LINE_SMOOTH_HINT GL_LINE_SMOOTH_HINT -#define CGL_POLYGON_SMOOTH_HINT GL_POLYGON_SMOOTH_HINT -#define CGL_FOG_HINT GL_FOG_HINT -#define CGL_GENERATE_MIPMAP_HINT GL_GENERATE_MIPMAP_HINT - -/* LightModelParameter */ -#define CGL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_AMBIENT -#define CGL_LIGHT_MODEL_TWO_SIDE GL_LIGHT_MODEL_TWO_SIDE - -/* LightParameter */ -#define CGL_POSITION GL_POSITION -#define CGL_SPOT_DIRECTION GL_SPOT_DIRECTION -#define CGL_SPOT_EXPONENT GL_SPOT_EXPONENT -#define CGL_SPOT_CUTOFF GL_SPOT_CUTOFF -#define CGL_CONSTANT_ATTENUATION GL_CONSTANT_ATTENUATION -#define CGL_LINEAR_ATTENUATION GL_LINEAR_ATTENUATION -#define CGL_QUADRATIC_ATTENUATION GL_QUADRATIC_ATTENUATION - -/* DataType */ -#define CGL_BYTE GL_BYTE -#define CGL_UNSIGNED_BYTE GL_UNSIGNED_BYTE -#define CGL_SHORT GL_SHORT -#define CGL_UNSIGNED_SHORT GL_UNSIGNED_SHORT -#define CGL_FLOAT GL_FLOAT -#define CGL_FIXED GL_FIXED - -/* LogicOp */ -#define CGL_CLEAR GL_CLEAR -#define CGL_AND GL_AND -#define CGL_AND_REVERSE GL_AND_REVERSE -#define CGL_COPY GL_COPY -#define CGL_AND_INVERTED GL_AND_INVERTED -#define CGL_NOOP GL_NOOP -#define CGL_XOR GL_XOR -#define CGL_OR GL_OR -#define CGL_NOR GL_NOR -#define CGL_EQUIV GL_EQUIV -#define CGL_INVERT GL_INVERT -#define CGL_OR_REVERSE GL_OR_REVERSE -#define CGL_COPY_INVERTED GL_COPY_INVERTED -#define CGL_OR_INVERTED GL_OR_INVERTED -#define CGL_NAND GL_NAND -#define CGL_SET GL_SET - -/* MaterialParameter */ -#define CGL_AMBIENT_AND_DIFFUSE GL_AMBIENT_AND_DIFFUSE - -/* MatrixMode */ -#define CGL_MODELVIEW GL_MODELVIEW -#define CGL_PROJECTION GL_PROJECTION -#define CGL_TEXTURE GL_TEXTURE - -/* PixelFormat */ -#define CGL_ALPHA GL_ALPHA -#define CGL_RGB GL_RGB -#define CGL_RGBA GL_RGBA -#define CGL_LUMINANCE GL_LUMINANCE -#define CGL_LUMINANCE_ALPHA GL_LUMINANCE_ALPHA - -/* PixelStoreParameter */ -#define CGL_UNPACK_ALIGNMENT GL_UNPACK_ALIGNMENT -#define CGL_PACK_ALIGNMENT GL_PACK_ALIGNMENT - -/* PixelType */ -/* GL_UNSIGNED_BYTE */ -#define CGL_UNSIGNED_SHORT_4_4_4_4 GL_UNSIGNED_SHORT_4_4_4_4 -#define CGL_UNSIGNED_SHORT_5_5_5_1 GL_UNSIGNED_SHORT_5_5_5_1 -#define CGL_UNSIGNED_SHORT_5_6_5 CGL_UNSIGNED_SHORT_5_6_5 - -/* ShadingModel */ -#define CGL_FLAT GL_FLAT -#define CGL_SMOOTH GL_SMOOTH - -/* StencilFunction */ -/* GL_NEVER */ -/* GL_LESS */ -/* GL_EQUAL */ -/* GL_LEQUAL */ -/* GL_GREATER */ -/* GL_NOTEQUAL */ -/* GL_GEQUAL */ -/* GL_ALWAYS */ - -/* StencilOp */ -#define CGL_KEEP GL_KEEP -#define CGL_REPLACE GL_REPLACE -#define CGL_INCR GL_INCR -#define CGL_DECR GL_DECR - -/* StringName */ -#define CGL_VENDOR GL_VENDOR -#define CGL_RENDERER GL_RENDERER -#define CGL_VERSION GL_VERSION -#define CGL_EXTENSIONS GL_EXTENSIONS - -/* TextureEnvMode */ -#define CGL_DECAL GL_DECAL -/* GL_BLEND */ -/* GL_REPLACE */ - -/* TextureEnvParameter */ -#define CGL_TEXTURE_ENV_MODE GL_TEXTURE_ENV_MODE -#define CGL_TEXTURE_ENV_COLOR GL_TEXTURE_ENV_COLOR - -/* TextureEnvTarget */ -#define CGL_TEXTURE_ENV GL_TEXTURE_ENV - -/* TextureMagFilter */ -#define CGL_NEAREST GL_NEAREST -#define CGL_LINEAR GL_LINEAR - -/* TextureMinFilter */ -/* GL_NEAREST */ -/* GL_LINEAR */ -#define CGL_NEAREST_MIPMAP_NEAREST GL_NEAREST_MIPMAP_NEAREST -#define CGL_LINEAR_MIPMAP_NEAREST GL_LINEAR_MIPMAP_NEAREST -#define CGL_NEAREST_MIPMAP_LINEAR GL_NEAREST_MIPMAP_LINEAR -#define CGL_LINEAR_MIPMAP_LINEAR GL_LINEAR_MIPMAP_LINEAR - -/* TextureParameterName */ -#define CGL_TEXTURE_MAG_FILTER GL_TEXTURE_MAG_FILTER -#define CGL_TEXTURE_MIN_FILTER GL_TEXTURE_MIN_FILTER -#define CGL_TEXTURE_WRAP_S GL_TEXTURE_WRAP_S -#define CGL_TEXTURE_WRAP_T GL_TEXTURE_WRAP_T -#define CGL_GENERATE_MIPMAP GL_GENERATE_MIPMAP - -#define CGL_ACTIVE_TEXTURE GL_ACTIVE_TEXTURE -#define CGL_CLIENT_ACTIVE_TEXTURE GL_CLIENT_ACTIVE_TEXTURE - -/* TextureWrapMode */ -#define CGL_REPEAT GL_REPEAT -#define CGL_CLAMP_TO_EDGE GL_CLAMP_TO_EDGE - -/* PixelInternalFormat */ - -/* Buffer Objects */ -#define CGL_ARRAY_BUFFER GL_ARRAY_BUFFER -#define CGL_ELEMENT_ARRAY_BUFFER GL_ELEMENT_ARRAY_BUFFER -#define CGL_ARRAY_BUFFER_BINDING GL_ARRAY_BUFFER_BINDING -#define CGL_ELEMENT_ARRAY_BUFFER_BINDING GL_ELEMENT_ARRAY_BUFFER_BINDING -#define CGL_VERTEX_ARRAY_BUFFER_BINDING GL_VERTEX_ARRAY_BUFFER_BINDING -#define CGL_NORMAL_ARRAY_BUFFER_BINDING GL_NORMAL_ARRAY_BUFFER_BINDING -#define CGL_COLOR_ARRAY_BUFFER_BINDING GL_COLOR_ARRAY_BUFFER_BINDING -#define CGL_TEXTURE_COORD_ARRAY_BUFFER_BINDING GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING -#define CGL_STATIC_DRAW GL_STATIC_DRAW -#define CGL_DYNAMIC_DRAW GL_DYNAMIC_DRAW -#define CGL_WRITE_ONLY GL_WRITE_ONLY -#define CGL_BUFFER_SIZE GL_BUFFER_SIZE -#define CGL_BUFFER_USAGE GL_BUFFER_USAGE -#define CGL_BUFFER_ACCESS GL_BUFFER_ACCESS -#define CGL_RGB_SCALE GL_RGB_SCALE -#define CGL_ALPHA_SCALE GL_ALPHA_SCALE -#define CGL_POINT_SPRITE_OES GL_POINT_SPRITE_OES -#define CGL_COORD_REPLACE_OES GL_COORD_REPLACE_OES -#define CGL_POINT_SIZE_ARRAY_OES GL_POINT_SIZE_ARRAY_OES -#define CGL_POINT_SIZE_ARRAY_TYPE_OES GL_POINT_SIZE_ARRAY_TYPE_OES -#define CGL_POINT_SIZE_ARRAY_STRIDE_OES GL_POINT_SIZE_ARRAY_STRIDE_OES -#define CGL_POINT_SIZE_ARRAY_POINTER_OES GL_POINT_SIZE_ARRAY_POINTER_OES -#define CGL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES -#define CGL_MAX_VERTEX_UNITS_OES GL_MAX_VERTEX_UNITS_OES -#define CGL_MAX_PALETTE_MATRICES_OES GL_MAX_PALETTE_MATRICES_OES -#define CGL_MATRIX_PALETTE_OES GL_MATRIX_PALETTE_OES -#define CGL_MATRIX_INDEX_ARRAY_OES GL_MATRIX_INDEX_ARRAY_OES -#define CGL_WEIGHT_ARRAY_OES GL_WEIGHT_ARRAY_OES -#define CGL_MATRIX_INDEX_ARRAY_SIZE_OES GL_MATRIX_INDEX_ARRAY_SIZE_OES -#define CGL_MATRIX_INDEX_ARRAY_TYPE_OES GL_MATRIX_INDEX_ARRAY_TYPE_OES -#define CGL_MATRIX_INDEX_ARRAY_STRIDE_OES GL_MATRIX_INDEX_ARRAY_STRIDE_OES -#define CGL_MATRIX_INDEX_ARRAY_POINTER_OES GL_MATRIX_INDEX_ARRAY_POINTER_OES -#define CGL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES -#define CGL_WEIGHT_ARRAY_SIZE_OES GL_WEIGHT_ARRAY_SIZE_OES -#define CGL_WEIGHT_ARRAY_TYPE_OES GL_WEIGHT_ARRAY_TYPE_OES -#define CGL_WEIGHT_ARRAY_STRIDE_OES GL_WEIGHT_ARRAY_STRIDE_OES -#define CGL_WEIGHT_ARRAY_POINTER_OES GL_WEIGHT_ARRAY_POINTER_OES -#define CGL_WEIGHT_ARRAY_BUFFER_BINDING_OES GL_WEIGHT_ARRAY_BUFFER_BINDING_OES -#define CGL_TEXTURE_CROP_RECT_OES GL_TEXTURE_CROP_RECT_OES - -/* extras */ - -/* YUV textures also unsupported */ -#define CGL_YCBCR_MESA 0 -#define CGL_UNSIGNED_SHORT_8_8_REV_MESA 0 -#define CGL_UNSIGNED_SHORT_8_8_MESA 0 - -#if defined(GL_OBJECT_COMPILE_STATUS) -#define CGL_OBJECT_COMPILE_STATUS GL_OBJECT_COMPILE_STATUS -#elif defined(GL_COMPILE_STATUS) -#define CGL_OBJECT_COMPILE_STATUS GL_COMPILE_STATUS -#else -#define CGL_OBJECT_COMPILE_STATUS 0 -#endif - #define CLUTTER_COGL_HAS_GLES 1 #define COGL_HAS_GLES 1 -/* These aren't always defined under GLES 2 but if they are then we - should probably use the GL_* macro instead of assuming the - number */ -#ifdef GL_MODULATE -#define CGL_MODULATE GL_MODULATE -#else -#define CGL_MODULATE 0x2100 -#endif - -#ifdef GL_ADD -#define CGL_ADD GL_ADD -#else -#define CGL_ADD 0x0104 -#endif - -#ifdef GL_ADD_SIGNED -#define CGL_ADD_SIGNED GL_ADD_SIGNED -#else -#define CGL_ADD_SIGNED 0x8574 -#endif - -#ifdef GL_INTERPOLATE -#define CGL_INTERPOLATE GL_INTERPOLATE -#else -#define CGL_INTERPOLATE 0x8575 -#endif - -#ifdef GL_SUBTRACT -#define CGL_SUBTRACT GL_SUBTRACT -#else -#define CGL_SUBTRACT 0x84e7 -#endif - -#ifdef GL_DOT3_RGB -#define CGL_DOT3_RGB GL_DOT3_RGB -#else -#define CGL_DOT3_RGB 0x86ae -#endif - -#ifdef GL_DOT3_RGBA -#define CGL_DOT3_RGBA GL_DOT3_RGBA -#else -#define CGL_DOT3_RGBA 0x86af -#endif - -#ifdef GL_CONSTANT -#define CGL_CONSTANT GL_CONSTANT -#else -#define CGL_CONSTANT 0x8576 -#endif - -#ifdef GL_PRIMARY_COLOR -#define CGL_PRIMARY_COLOR GL_PRIMARY_COLOR -#else -#define CGL_PRIMARY_COLOR 0x8577 -#endif - -#ifdef GL_PREVIOUS -#define CGL_PREVIOUS GL_PREVIOUS -#else -#define CGL_PREVIOUS 0x8578 -#endif - -#ifdef GL_COMBINE -#define CGL_COMBINE GL_COMBINE -#else -#define CGL_COMBINE 0x8570 -#endif - -#ifdef GL_COMBINE_RGB -#define CGL_COMBINE_RGB GL_COMBINE_RGB -#else -#define CGL_COMBINE_RGB 0x8571 -#endif - -#ifdef GL_COMBINE_ALPHA -#define CGL_COMBINE_ALPHA GL_COMBINE_ALPHA -#else -#define CGL_COMBINE_ALPHA 0x8572 -#endif - -#ifdef GL_SRC0_RGB -#define CGL_SRC0_RGB GL_SRC0_RGB -#else -#define CGL_SRC0_RGB 0x8580 -#endif - -#ifdef GL_OPERAND0_RGB -#define CGL_OPERAND0_RGB GL_OPERAND0_RGB -#else -#define CGL_OPERAND0_RGB 0x8590 -#endif - -#ifdef GL_SRC1_RGB -#define CGL_SRC1_RGB GL_SRC1_RGB -#else -#define CGL_SRC1_RGB 0x8581 -#endif - -#ifdef GL_OPERAND1_RGB -#define CGL_OPERAND1_RGB GL_OPERAND1_RGB -#else -#define CGL_OPERAND1_RGB 0x8591 -#endif - -#ifdef GL_SRC2_RGB -#define CGL_SRC2_RGB GL_SRC2_RGB -#else -#define CGL_SRC2_RGB 0x8582 -#endif - -#ifdef GL_OPERAND2_RGB -#define CGL_OPERAND2_RGB GL_OPERAND2_RGB -#else -#define CGL_OPERAND2_RGB 0x8592 -#endif - -#ifdef GL_SRC0_ALPHA -#define CGL_SRC0_ALPHA GL_SRC0_ALPHA -#else -#define CGL_SRC0_ALPHA 0x8588 -#endif - -#ifdef GL_OPERAND0_ALPHA -#define CGL_OPERAND0_ALPHA GL_OPERAND0_ALPHA -#else -#define CGL_OPERAND0_ALPHA 0x8598 -#endif - -#ifdef GL_SRC1_ALPHA -#define CGL_SRC1_ALPHA GL_SRC1_ALPHA -#else -#define CGL_SRC1_ALPHA 0x8589 -#endif - -#ifdef GL_OPERAND1_ALPHA -#define CGL_OPERAND1_ALPHA GL_OPERAND1_ALPHA -#else -#define CGL_OPERAND1_ALPHA 0x8599 -#endif - -#ifdef GL_SRC2_ALPHA -#define CGL_SRC2_ALPHA GL_SRC2_ALPHA -#else -#define CGL_SRC2_ALPHA 0x858a -#endif - -#ifdef GL_OPERAND2_ALPHA -#define CGL_OPERAND2_ALPHA GL_OPERAND2_ALPHA -#else -#define CGL_OPERAND2_ALPHA 0x859a -#endif - -#ifdef GL_AMBIENT -#define CGL_AMBIENT GL_AMBIENT -#else -#define CGL_AMBIENT 0x1200 -#endif - -#ifdef GL_DIFFUSE -#define CGL_DIFFUSE GL_DIFFUSE -#else -#define CGL_DIFFUSE 0x1201 -#endif - -#ifdef GL_SPECULAR -#define CGL_SPECULAR GL_SPECULAR -#else -#define CGL_SPECULAR 0x1202 -#endif - -#ifdef GL_EMISSION -#define CGL_EMISSION GL_EMISSION -#else -#define CGL_EMISSION 0x1600 -#endif - -#ifdef GL_SHININESS -#define CGL_SHININESS GL_SHININESS -#else -#define CGL_SHININESS 0x1601 -#endif - G_END_DECLS #endif diff --git a/cogl/driver/gles/cogl-gles2-wrapper.c b/cogl/driver/gles/cogl-gles2-wrapper.c index 267071f23..65d29956f 100644 --- a/cogl/driver/gles/cogl-gles2-wrapper.c +++ b/cogl/driver/gles/cogl-gles2-wrapper.c @@ -118,7 +118,7 @@ initialize_texture_units (CoglGles2Wrapper *w) /* We will need to set the matrix mode to GL_TEXTURE to * initialise any new texture units, so we save the current * mode for restoring afterwards */ - GE( cogl_wrap_glGetIntegerv (CGL_MATRIX_MODE, &prev_mode)); + GE( cogl_wrap_glGetIntegerv (GL_MATRIX_MODE, &prev_mode)); for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++) { @@ -1281,7 +1281,7 @@ cogl_wrap_glGetIntegerv (GLenum pname, GLint *params) *params = 0; break; - case CGL_MATRIX_MODE: + case GL_MATRIX_MODE: *params = w->matrix_mode; break; diff --git a/cogl/driver/gles/cogl-gles2-wrapper.h b/cogl/driver/gles/cogl-gles2-wrapper.h index 4968e251a..52b812385 100644 --- a/cogl/driver/gles/cogl-gles2-wrapper.h +++ b/cogl/driver/gles/cogl-gles2-wrapper.h @@ -224,12 +224,14 @@ struct _CoglGles2WrapperShader #ifndef GL_MODELVIEW +#define GL_MATRIX_MODE 0x0BA0 + #define GL_MODELVIEW 0x1700 #define GL_PROJECTION 0x1701 #ifdef COGL_ENABLE_DEBUG -#define GL_STACK_OVERFLOW 0x0503 -#define GL_STACK_UNDERFLOW 0x0504 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 #endif #define GL_VERTEX_ARRAY 0x8074 @@ -268,35 +270,36 @@ struct _CoglGles2WrapperShader #define GL_EXP 0x8000 #define GL_EXP2 0x8001 -#define GL_ADD CGL_ADD -#define GL_ADD_SIGNED CGL_ADD_SIGNED -#define GL_INTERPOLATE CGL_INTERPOLATE -#define GL_SUBTRACT CGL_SUBTRACT -#define GL_DOT3_RGB CGL_DOT3_RGB -#define GL_DOT3_RGBA CGL_DOT3_RGBA -#define GL_CONSTANT CGL_CONSTANT -#define GL_PRIMARY_COLOR CGL_PRIMARY_COLOR -#define GL_PREVIOUS CGL_PREVIOUS -#define GL_COMBINE CGL_COMBINE -#define GL_COMBINE_RGB CGL_COMBINE_RGB -#define GL_COMBINE_ALPHA CGL_COMBINE_ALPHA -#define GL_SRC0_RGB CGL_SRC0_RGB -#define GL_OPERAND0_RGB CGL_OPERAND0_RGB -#define GL_SRC1_RGB CGL_SRC1_RGB -#define GL_OPERAND1_RGB CGL_OPERAND1_RGB -#define GL_SRC2_RGB CGL_SRC2_RGB -#define GL_OPERAND2_RGB CGL_OPERAND2_RGB -#define GL_SRC0_ALPHA CGL_SRC0_ALPHA -#define GL_OPERAND0_ALPHA CGL_OPERAND0_ALPHA -#define GL_SRC1_ALPHA CGL_SRC1_ALPHA -#define GL_OPERAND1_ALPHA CGL_OPERAND1_ALPHA -#define GL_SRC2_ALPHA CGL_SRC2_ALPHA -#define GL_OPERAND2_ALPHA CGL_OPERAND2_ALPHA -#define GL_AMBIENT CGL_AMBIENT -#define GL_DIFFUSE CGL_DIFFUSE -#define GL_SPECULAR CGL_SPECULAR -#define GL_EMISSION CGL_EMISSION -#define GL_SHININESS CGL_SHININESS +#define GL_MODULATE 0x2100 +#define GL_ADD 0x0104 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84e7 +#define GL_DOT3_RGB 0x86ae +#define GL_DOT3_RGBA 0x86af +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SRC0_RGB 0x8580 +#define GL_OPERAND0_RGB 0x8590 +#define GL_SRC1_RGB 0x8581 +#define GL_OPERAND1_RGB 0x8591 +#define GL_SRC2_RGB 0x8582 +#define GL_OPERAND2_RGB 0x8592 +#define GL_SRC0_ALPHA 0x8588 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_SRC1_ALPHA 0x8589 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_SRC2_ALPHA 0x858a +#define GL_OPERAND2_ALPHA 0x859a +#define GL_AMBIENT 0x1200 +#define GL_DIFFUSE 0x1201 +#define GL_SPECULAR 0x1202 +#define GL_EMISSION 0x1600 +#define GL_SHININESS 0x1601 #endif /* GL_MODELVIEW */ From d1c56ae9a718cddb7c985b046709ff1e59a1b35b Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 12 Jan 2010 14:49:55 +0000 Subject: [PATCH 15/17] cogl-framebuffer: Add some missing GL defines Since 755cce33a7 the framebuffer code is using the GL enums GL_DEPTH_ATTACHMENT and GL_DEPTH_COMPONENT16. These aren't available directly under GLES except with the OES suffix so we need to define them manually as we do with the other framebuffer constants. --- cogl/cogl-framebuffer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index a6b62bed8..64f586385 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -74,6 +74,12 @@ #ifndef GL_DEPTH_STENCIL #define GL_DEPTH_STENCIL 0x84F9 #endif +#ifndef GL_DEPTH_ATTACHMENT +#define GL_DEPTH_ATTACHMENT 0x8D00 +#endif +#ifndef GL_DEPTH_COMPONENT16 +#define GL_DEPTH_COMPONENT16 0x81A5 +#endif typedef enum { _TRY_DEPTH_STENCIL = 1L<<0, From deecf83c4a120b8db311566154af2a37c8613111 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 13 Jan 2010 15:40:36 +0000 Subject: [PATCH 16/17] build: Clean up COGL build flags --- cogl/Makefile.am | 53 ++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 7d78106f5..59121ab09 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -34,6 +34,17 @@ INCLUDES = \ -I$(top_builddir)/clutter/cogl \ $(NULL) +AM_CPPFLAGS = \ + -DG_DISABLE_SINGLE_INCLUDES \ + -DG_DISABLE_DEPRECATED \ + -DG_LOG_DOMAIN=\"Cogl-$(COGL_WINSYS)\" \ + -DCLUTTER_COMPILATION \ + $(COGL_DEBUG_CFLAGS) \ + $(CLUTTER_DEBUG_CFLAGS) \ + $(NULL) + +AM_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) + cogl-defines.h: $(top_builddir)/clutter/cogl/cogl/driver/gl/cogl-defines.h $(top_builddir)/clutter/cogl/cogl/driver/gles/cogl-defines.h $(QUIET_GEN)cp -f $(top_builddir)/clutter/cogl/cogl/driver/$(COGL_DRIVER)/cogl-defines.h $(@F) @@ -68,27 +79,7 @@ cogl_winsys_sources = \ $(srcdir)/winsys/cogl-win32.c \ $(NULL) -# glib-mkenums rules -glib_enum_h = cogl-enum-types.h -glib_enum_c = cogl-enum-types.c -glib_enum_headers = $(cogl_public_h) -include $(top_srcdir)/build/autotools/Makefile.am.enums - -noinst_LTLIBRARIES = libclutter-cogl.la -libclutter_cogl_la_CPPFLAGS = \ - $(COGL_DEBUG_CFLAGS) \ - $(CLUTTER_DEBUG_CFLAGS) \ - -DG_DISABLE_SINGLE_INCLUDES \ - -DG_LOG_DOMAIN=\"Cogl-$(COGL_WINSYS)\" \ - -DCLUTTER_COMPILATION - -libclutter_cogl_la_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) - -libclutter_cogl_la_LIBADD = -lm $(CLUTTER_LIBS) \ - $(top_builddir)/clutter/cogl/cogl/driver/$(COGL_DRIVER)/libclutter-cogl-driver.la - -libclutter_cogl_la_SOURCES = \ - $(BUILT_SOURCES) \ +cogl_sources_c = \ $(srcdir)/winsys/cogl-winsys.h \ $(srcdir)/winsys/cogl-@COGL_WINSYS@.c \ $(srcdir)/cogl-handle.h \ @@ -138,6 +129,18 @@ libclutter_cogl_la_SOURCES = \ $(srcdir)/cogl-profile.c \ $(NULL) +# glib-mkenums rules +glib_enum_h = cogl-enum-types.h +glib_enum_c = cogl-enum-types.c +glib_enum_headers = $(cogl_public_h) +include $(top_srcdir)/build/autotools/Makefile.am.enums + +noinst_LTLIBRARIES = libclutter-cogl.la + +libclutter_cogl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/cogl/driver/$(COGL_DRIVER)/libclutter-cogl-driver.la + +libclutter_cogl_la_SOURCES = $(BUILT_SOURCES) $(cogl_sources_c) + EXTRA_DIST += $(cogl_winsys_sources) EXTRA_DIST += stb_image.c @@ -156,11 +159,8 @@ if HAVE_INTROSPECTION Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-cogl.la $(QUIET_GEN)$(INTROSPECTION_SCANNER) -v \ --namespace Cogl --nsversion=@CLUTTER_API_VERSION@ \ - -I$(srcdir) \ - -I$(srcdir)/.. \ - -I$(srcdir)/winsys \ - -I$(srcdir)/driver/@COGL_DRIVER@ \ - -DCLUTTER_COMPILATION \ + $(INCLUDES) \ + $(AM_CPPFLAGS) \ --c-include='cogl/cogl.h' \ --include=GL-1.0 \ --include=GObject-2.0 \ @@ -177,4 +177,3 @@ gir_DATA = $(BUILT_GIRSOURCES) CLEANFILES += $(BUILT_GIRSOURCES) endif - From 18b96c84bf188e211cb3c21be2603c56f279332e Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 12 Jan 2010 21:44:40 +0000 Subject: [PATCH 17/17] cogl-framebuffer: Return gboolean from try_creating_fbo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When try_creating_fbo fails it returns 0 to report the error and if it succeeds it returns ‘flags’. However cogl_offscreen_new_to_texture also passes in 0 for the flags as the last fallback to create the fbo with nothing but the color buffer. In that case it will return 0 regardless of whether it succeeded so the last fallback will always be considered a failure. To fix this it now just returns a gboolean to indicate whether it succeeded and the flags used for each attempt is assigned when passing the argument rather than from the return value of the function. Also if the only configuration that succeeded was with flags==0 then it would always try all combinations because last_working_flags would also be zero. To avoid this it now uses a separate gboolean to mark whether we found a successful set of flags. http://bugzilla.openedhand.com/show_bug.cgi?id=1873 --- cogl/cogl-framebuffer.c | 56 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index 64f586385..8124186d0 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -247,7 +247,7 @@ _cogl_framebuffer_get_projection_stack (CoglHandle handle) return framebuffer->projection_stack; } -static TryFBOFlags +static gboolean try_creating_fbo (CoglOffscreen *offscreen, TryFBOFlags flags, CoglHandle texture) @@ -263,14 +263,14 @@ try_creating_fbo (CoglOffscreen *offscreen, _COGL_GET_CONTEXT (ctx, FALSE); if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target)) - return 0; + return FALSE; if (tex_gl_target != GL_TEXTURE_2D #ifdef HAVE_COGL_GL && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB #endif ) - return 0; + return FALSE; /* We are about to generate and bind a new fbo, so when next flushing the * journal, we will need to rebind the current framebuffer... */ @@ -352,18 +352,18 @@ try_creating_fbo (CoglOffscreen *offscreen, GLuint renderbuffer = GPOINTER_TO_UINT (l->data); GE (glDeleteRenderbuffers (1, &renderbuffer)); } - return 0; + return FALSE; } - return flags; + return TRUE; } CoglHandle cogl_offscreen_new_to_texture (CoglHandle texhandle) { CoglOffscreen *offscreen; - TryFBOFlags flags; - static TryFBOFlags last_working_flags = 0; + static TryFBOFlags flags; + static gboolean have_working_flags = FALSE; _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); @@ -393,33 +393,33 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle) offscreen = g_new0 (CoglOffscreen, 1); offscreen->texture = cogl_handle_ref (texhandle); - if (!(last_working_flags && - (flags = try_creating_fbo (offscreen, last_working_flags, - texhandle))) && - !(flags = try_creating_fbo (offscreen, _TRY_DEPTH_STENCIL, - texhandle)) && - !(flags = try_creating_fbo (offscreen, _TRY_DEPTH | _TRY_STENCIL, - texhandle)) && - !(flags = try_creating_fbo (offscreen, _TRY_STENCIL, texhandle)) && - !(flags = try_creating_fbo (offscreen, _TRY_DEPTH, texhandle)) && - !(flags = try_creating_fbo (offscreen, 0, texhandle))) + if ((have_working_flags && + try_creating_fbo (offscreen, flags, texhandle)) || + try_creating_fbo (offscreen, flags = _TRY_DEPTH_STENCIL, texhandle) || + try_creating_fbo (offscreen, flags = _TRY_DEPTH | _TRY_STENCIL, + texhandle) || + try_creating_fbo (offscreen, flags = _TRY_STENCIL, texhandle) || + try_creating_fbo (offscreen, flags = _TRY_DEPTH, texhandle) || + try_creating_fbo (offscreen, flags = 0, texhandle)) + { + /* Record that the last set of flags succeeded so that we can + try that set first next time */ + have_working_flags = TRUE; + + _cogl_framebuffer_init (COGL_FRAMEBUFFER (offscreen), + COGL_FRAMEBUFFER_TYPE_OFFSCREEN, + cogl_texture_get_width (texhandle), + cogl_texture_get_height (texhandle)); + + return _cogl_offscreen_handle_new (offscreen); + } + else { g_free (offscreen); - last_working_flags = 0; /* XXX: This API should probably have been defined to take a GError */ g_warning ("%s: Failed to create an OpenGL framebuffer", G_STRLOC); return COGL_INVALID_HANDLE; } - /* Save the final set of flags that worked so we can hopefully construct - * subsequent buffers faster. */ - last_working_flags = flags; - - _cogl_framebuffer_init (COGL_FRAMEBUFFER (offscreen), - COGL_FRAMEBUFFER_TYPE_OFFSCREEN, - cogl_texture_get_width (texhandle), - cogl_texture_get_height (texhandle)); - - return _cogl_offscreen_handle_new (offscreen); } static void