Skip to content

Instantly share code, notes, and snippets.

@gszauer
Created February 28, 2014 17:45
Embed
What would you like to do?
/*
* jpeg_mem.c -- jpeg texture loader
* last modification: sep. 22, 2012
*
* Copyright (c) 2005-2012 David HENRY
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* gcc -Wall -ansi -lGL -lGLU -lglut -ljpeg jpeg_mem.c -o jpeg
*/
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <jpeglib.h>
/* Microsoft Visual C++ */
#ifdef _MSC_VER
#pragma comment (lib, "libjpeg.lib")
#endif /* _MSC_VER */
/* OpenGL texture info */
struct gl_texture_t
{
GLsizei width;
GLsizei height;
GLenum format;
GLint internalFormat;
GLuint id;
GLubyte *texels;
};
/* File buffer struct */
struct file_buffer_t
{
char name[256];
unsigned char *data;
long length;
long offset;
};
/* JPEG error manager */
struct my_error_mgr
{
/* "public" fields */
struct jpeg_error_mgr pub;
/* for return to caller */
jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr* my_error_ptr;
/* Texture id for the demo */
GLuint texId;
static struct file_buffer_t *
readFile (const char *filename)
{
struct file_buffer_t *file;
FILE *fp;
/* Open file */
fp = fopen (filename, "rb");
if (!fp)
{
fprintf (stderr, "error: couldn't open \"%s\"!\n", filename);
return NULL;
}
/* Create a file buffer */
file = (struct file_buffer_t *)
malloc (sizeof (struct file_buffer_t));
if (!file)
{
fprintf (stderr, "Error: memory allocation failed "
"for \"%s\"\n", filename);
fclose (fp);
return NULL;
}
/* Copy file name */
strncpy (file->name, filename, sizeof (file->name));
/* Get file length */
fseek (fp, 0, SEEK_END);
file->length = ftell (fp);
file->offset = 0;
fseek (fp, 0, SEEK_SET);
/* Allocate memory for file data */
file->data = (unsigned char *)malloc (file->length);
if (!file->data)
{
fprintf (stderr, "Error: memory allocation failed "
"for \"%s\"\n", filename);
fclose (fp);
free (file);
return NULL;
}
/* Read whole file data */
fread (file->data, 1, file->length, fp);
fclose (fp);
return file;
}
static void
freeFileBuffer (struct file_buffer_t *file)
{
if (file != NULL)
{
free (file->data);
free (file);
}
}
static void
mem_init_source (j_decompress_ptr cinfo)
{
/* Nothing to do */
}
static boolean
mem_fill_input_buffer (j_decompress_ptr cinfo)
{
JOCTET eoi_buffer[2] = { 0xFF, JPEG_EOI };
struct jpeg_source_mgr *jsrc = cinfo->src;
/* Create a fake EOI marker */
jsrc->next_input_byte = eoi_buffer;
jsrc->bytes_in_buffer = 2;
return TRUE;
}
static void
mem_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
struct jpeg_source_mgr *jsrc = cinfo->src;
if (num_bytes > 0)
{
while (num_bytes > (long)jsrc->bytes_in_buffer)
{
num_bytes -= (long)jsrc->bytes_in_buffer;
mem_fill_input_buffer (cinfo);
}
jsrc->next_input_byte += num_bytes;
jsrc->bytes_in_buffer -= num_bytes;
}
}
static void
mem_term_source (j_decompress_ptr cinfo)
{
/* Nothing to do */
}
static void
err_exit (j_common_ptr cinfo)
{
/* Get error manager */
my_error_ptr jerr = (my_error_ptr)(cinfo->err);
/* Display error message */
(*cinfo->err->output_message) (cinfo);
/* Return control to the setjmp point */
longjmp (jerr->setjmp_buffer, 1);
}
static struct gl_texture_t *
ReadJPEGFromMemory (const struct file_buffer_t *file)
{
struct gl_texture_t *texinfo = NULL;
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
struct jpeg_source_mgr jsrc;
JSAMPROW j;
int i;
/* Create and configure decompress object */
jpeg_create_decompress (&cinfo);
cinfo.err = jpeg_std_error (&jerr.pub);
cinfo.src = &jsrc;
/* Configure error manager */
jerr.pub.error_exit = err_exit;
if (setjmp (jerr.setjmp_buffer))
{
jpeg_destroy_decompress (&cinfo);
if (texinfo)
{
if (texinfo->texels)
free (texinfo->texels);
free (texinfo);
}
return NULL;
}
/* Configure source manager */
jsrc.next_input_byte = file->data;
jsrc.bytes_in_buffer = file->length;
jsrc.init_source = mem_init_source;
jsrc.fill_input_buffer = mem_fill_input_buffer;
jsrc.skip_input_data = mem_skip_input_data;
jsrc.resync_to_restart = jpeg_resync_to_restart;
jsrc.term_source = mem_term_source;
/* Read file's header and prepare for decompression */
jpeg_read_header (&cinfo, TRUE);
jpeg_start_decompress (&cinfo);
/* Initialize image's member variables and allocate
memory for pixels */
texinfo = (struct gl_texture_t *)
malloc (sizeof (struct gl_texture_t));
texinfo->width = cinfo.image_width;
texinfo->height = cinfo.image_height;
texinfo->internalFormat = cinfo.num_components;
texinfo->format = (cinfo.num_components == 1) ? GL_LUMINANCE : GL_RGB;
texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte) * texinfo->width
* texinfo->height * texinfo->internalFormat);
/* Read scanlines */
for (i = 0; i < texinfo->height; ++i)
{
#if 1
j = (texinfo->texels + ((texinfo->height -
(i + 1)) * texinfo->width * texinfo->internalFormat));
#else
j = &texinfo->texels[texinfo->width * i * texinfo->internalFormat];
#endif
jpeg_read_scanlines (&cinfo, &j, 1);
}
/* Finish decompression and release memory */
jpeg_finish_decompress (&cinfo);
jpeg_destroy_decompress (&cinfo);
return texinfo;
}
GLuint
loadJPEGTexture (const struct file_buffer_t *file)
{
struct gl_texture_t *jpeg_tex = NULL;
GLuint tex_id = 0;
GLint alignment;
jpeg_tex = ReadJPEGFromMemory (file);
if (jpeg_tex && jpeg_tex->texels)
{
/* Generate texture */
glGenTextures (1, &jpeg_tex->id);
glBindTexture (GL_TEXTURE_2D, jpeg_tex->id);
glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
/* Setup some parameters for texture filters and mipmapping */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#if 0
glTexImage2D (GL_TEXTURE_2D, 0, jpeg_tex->internalFormat,
jpeg_tex->width, jpeg_tex->height, 0, jpeg_tex->format,
GL_UNSIGNED_BYTE, jpeg_tex->texels);
#else
gluBuild2DMipmaps (GL_TEXTURE_2D, jpeg_tex->internalFormat,
jpeg_tex->width, jpeg_tex->height,
jpeg_tex->format, GL_UNSIGNED_BYTE, jpeg_tex->texels);
#endif
glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);
tex_id = jpeg_tex->id;
/* OpenGL has its own copy of texture data */
free (jpeg_tex->texels);
free (jpeg_tex);
}
return tex_id;
}
static void
cleanup ()
{
glDeleteTextures (1, &texId);
}
static void
init (const char *filename)
{
struct file_buffer_t *file;
/* Initialize OpenGL */
glClearColor (0.5f, 0.5f, 0.5f, 1.0f);
glShadeModel (GL_SMOOTH);
glEnable (GL_DEPTH_TEST);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* Load JPEG file */
file = readFile (filename);
if (!file)
exit (EXIT_FAILURE);
/* Load JPEG texture from memory */
texId = loadJPEGTexture (file);
if (!texId)
{
freeFileBuffer (file);
exit (EXIT_FAILURE);
}
freeFileBuffer (file);
}
static void
reshape (int w, int h)
{
if (h == 0)
h = 1;
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (45.0, w/(GLdouble)h, 0.1, 1000.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glutPostRedisplay ();
}
static void
display ()
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity ();
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texId);
/* Draw textured quad */
glTranslatef (0.0, 0.0, -5.0);
glBegin (GL_QUADS);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (-1.0f, -1.0f, 0.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (1.0f, -1.0f, 0.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (1.0f, 1.0f, 0.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (-1.0f, 1.0f, 0.0f);
glEnd ();
glDisable (GL_TEXTURE_2D);
glutSwapBuffers ();
}
static void
keyboard (unsigned char key, int x, int y)
{
/* Escape */
if (key == 27)
exit (0);
}
int
main (int argc, char *argv[])
{
if (argc < 2)
{
fprintf (stderr, "usage: %s <filename.jpg>\n", argv[0]);
return -1;
}
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize (640, 480);
glutCreateWindow ("JPEG Texture Demo");
atexit (cleanup);
init (argv[1]);
glutReshapeFunc (reshape);
glutDisplayFunc (display);
glutKeyboardFunc (keyboard);
glutMainLoop ();
return 0;
}
/*
* jpeg.c -- jpeg texture loader
* last modification: aug. 14, 2007
*
* Copyright (c) 2005-2007 David HENRY
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* gcc -Wall -ansi -lGL -lGLU -lglut -ljpeg jpeg.c -o jpeg
*/
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jpeglib.h>
/* Microsoft Visual C++ */
#ifdef _MSC_VER
#pragma comment (lib, "libjpeg.lib")
#endif /* _MSC_VER */
/* OpenGL texture info */
struct gl_texture_t
{
GLsizei width;
GLsizei height;
GLenum format;
GLint internalFormat;
GLuint id;
GLubyte *texels;
};
/* Texture id for the demo */
GLuint texId;
static struct gl_texture_t *
ReadJPEGFromFile (const char *filename)
{
struct gl_texture_t *texinfo = NULL;
FILE *fp = NULL;
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW j;
int i;
/* Open image file */
fp = fopen (filename, "rb");
if (!fp)
{
fprintf (stderr, "error: couldn't open \"%s\"!\n", filename);
return NULL;
}
/* Create and configure decompressor */
jpeg_create_decompress (&cinfo);
cinfo.err = jpeg_std_error (&jerr);
jpeg_stdio_src (&cinfo, fp);
/*
* NOTE: this is the simplest "readJpegFile" function. There
* is no advanced error handling. It would be a good idea to
* setup an error manager with a setjmp/longjmp mechanism.
* In this function, if an error occurs during reading the JPEG
* file, the libjpeg abords the program.
* See jpeg_mem.c (or RTFM) for an advanced error handling which
* prevent this kind of behavior (http://tfc.duke.free.fr)
*/
/* Read header and prepare for decompression */
jpeg_read_header (&cinfo, TRUE);
jpeg_start_decompress (&cinfo);
/* Initialize image's member variables */
texinfo = (struct gl_texture_t *)
malloc (sizeof (struct gl_texture_t));
texinfo->width = cinfo.image_width;
texinfo->height = cinfo.image_height;
texinfo->internalFormat = cinfo.num_components;
if (cinfo.num_components == 1)
texinfo->format = GL_LUMINANCE;
else
texinfo->format = GL_RGB;
texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte) * texinfo->width
* texinfo->height * texinfo->internalFormat);
/* Extract each scanline of the image */
for (i = 0; i < texinfo->height; ++i)
{
j = (texinfo->texels +
((texinfo->height - (i + 1)) * texinfo->width * texinfo->internalFormat));
jpeg_read_scanlines (&cinfo, &j, 1);
}
/* Finish decompression and release memory */
jpeg_finish_decompress (&cinfo);
jpeg_destroy_decompress (&cinfo);
fclose (fp);
return texinfo;
}
GLuint
loadJPEGTexture (const char *filename)
{
struct gl_texture_t *jpeg_tex = NULL;
GLuint tex_id = 0;
GLint alignment;
jpeg_tex = ReadJPEGFromFile (filename);
if (jpeg_tex && jpeg_tex->texels)
{
/* Generate texture */
glGenTextures (1, &jpeg_tex->id);
glBindTexture (GL_TEXTURE_2D, jpeg_tex->id);
/* Setup some parameters for texture filters and mipmapping */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
#if 0
glTexImage2D (GL_TEXTURE_2D, 0, jpeg_tex->internalFormat,
jpeg_tex->width, jpeg_tex->height, 0, jpeg_tex->format,
GL_UNSIGNED_BYTE, jpeg_tex->texels);
#else
gluBuild2DMipmaps (GL_TEXTURE_2D, jpeg_tex->internalFormat,
jpeg_tex->width, jpeg_tex->height,
jpeg_tex->format, GL_UNSIGNED_BYTE, jpeg_tex->texels);
#endif
glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);
tex_id = jpeg_tex->id;
/* OpenGL has its own copy of texture data */
free (jpeg_tex->texels);
free (jpeg_tex);
}
return tex_id;
}
static void
cleanup ()
{
glDeleteTextures (1, &texId);
}
static void
init (const char *filename)
{
/* Initialize OpenGL */
glClearColor (0.5f, 0.5f, 0.5f, 1.0f);
glShadeModel (GL_SMOOTH);
glEnable (GL_DEPTH_TEST);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* Load JPEG texture from file */
texId = loadJPEGTexture (filename);
if (!texId)
exit (EXIT_FAILURE);
}
static void
reshape (int w, int h)
{
if (h == 0)
h = 1;
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (45.0, w/(GLdouble)h, 0.1, 1000.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glutPostRedisplay ();
}
static void
display ()
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity ();
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texId);
/* Draw textured quad */
glTranslatef (0.0, 0.0, -5.0);
glBegin (GL_QUADS);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (-1.0f, -1.0f, 0.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (1.0f, -1.0f, 0.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (1.0f, 1.0f, 0.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (-1.0f, 1.0f, 0.0f);
glEnd ();
glDisable (GL_TEXTURE_2D);
glutSwapBuffers ();
}
static void
keyboard (unsigned char key, int x, int y)
{
/* Escape */
if (key == 27)
exit (0);
}
int
main (int argc, char *argv[])
{
if (argc < 2)
{
fprintf (stderr, "usage: %s <filename.jpg>\n", argv[0]);
return -1;
}
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize (640, 480);
glutCreateWindow ("JPEG Texture Demo");
atexit (cleanup);
init (argv[1]);
glutReshapeFunc (reshape);
glutDisplayFunc (display);
glutKeyboardFunc (keyboard);
glutMainLoop ();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment