Skip to content

Instantly share code, notes, and snippets.

@gszauer
Created February 28, 2014 17:48
Embed
What would you like to do?
/*
* tga.c -- tga 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 tga.c -o tga
*/
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
/* OpenGL texture info */
struct gl_texture_t
{
GLsizei width;
GLsizei height;
GLenum format;
GLint internalFormat;
GLuint id;
GLubyte *texels;
};
#pragma pack(push, 1)
/* TGA header */
struct tga_header_t
{
GLubyte id_lenght; /* size of image id */
GLubyte colormap_type; /* 1 is has a colormap */
GLubyte image_type; /* compression type */
short cm_first_entry; /* colormap origin */
short cm_length; /* colormap length */
GLubyte cm_size; /* colormap size */
short x_origin; /* bottom left x coord origin */
short y_origin; /* bottom left y coord origin */
short width; /* picture width (in pixels) */
short height; /* picture height (in pixels) */
GLubyte pixel_depth; /* bits per pixel: 8, 16, 24 or 32 */
GLubyte image_descriptor; /* 24 bits = 0x00; 32 bits = 0x80 */
};
#pragma pack(pop)
/* Texture id for the demo */
GLuint texId = 0;
static void
GetTextureInfo (const struct tga_header_t *header,
struct gl_texture_t *texinfo)
{
texinfo->width = header->width;
texinfo->height = header->height;
switch (header->image_type)
{
case 3: /* Grayscale 8 bits */
case 11: /* Grayscale 8 bits (RLE) */
{
if (header->pixel_depth == 8)
{
texinfo->format = GL_LUMINANCE;
texinfo->internalFormat = 1;
}
else /* 16 bits */
{
texinfo->format = GL_LUMINANCE_ALPHA;
texinfo->internalFormat = 2;
}
break;
}
case 1: /* 8 bits color index */
case 2: /* BGR 16-24-32 bits */
case 9: /* 8 bits color index (RLE) */
case 10: /* BGR 16-24-32 bits (RLE) */
{
/* 8 bits and 16 bits images will be converted to 24 bits */
if (header->pixel_depth <= 24)
{
texinfo->format = GL_RGB;
texinfo->internalFormat = 3;
}
else /* 32 bits */
{
texinfo->format = GL_RGBA;
texinfo->internalFormat = 4;
}
break;
}
}
}
static void
ReadTGA8bits (FILE *fp, const GLubyte *colormap,
struct gl_texture_t *texinfo)
{
int i;
GLubyte color;
for (i = 0; i < texinfo->width * texinfo->height; ++i)
{
/* Read index color byte */
color = (GLubyte)fgetc (fp);
/* Convert to RGB 24 bits */
texinfo->texels[(i * 3) + 2] = colormap[(color * 3) + 0];
texinfo->texels[(i * 3) + 1] = colormap[(color * 3) + 1];
texinfo->texels[(i * 3) + 0] = colormap[(color * 3) + 2];
}
}
static void
ReadTGA16bits (FILE *fp, struct gl_texture_t *texinfo)
{
int i;
unsigned short color;
for (i = 0; i < texinfo->width * texinfo->height; ++i)
{
/* Read color word */
color = fgetc (fp) + (fgetc (fp) << 8);
/* Convert BGR to RGB */
texinfo->texels[(i * 3) + 0] = (GLubyte)(((color & 0x7C00) >> 10) << 3);
texinfo->texels[(i * 3) + 1] = (GLubyte)(((color & 0x03E0) >> 5) << 3);
texinfo->texels[(i * 3) + 2] = (GLubyte)(((color & 0x001F) >> 0) << 3);
}
}
static void
ReadTGA24bits (FILE *fp, struct gl_texture_t *texinfo)
{
int i;
for (i = 0; i < texinfo->width * texinfo->height; ++i)
{
/* Read and convert BGR to RGB */
texinfo->texels[(i * 3) + 2] = (GLubyte)fgetc (fp);
texinfo->texels[(i * 3) + 1] = (GLubyte)fgetc (fp);
texinfo->texels[(i * 3) + 0] = (GLubyte)fgetc (fp);
}
}
static void
ReadTGA32bits (FILE *fp, struct gl_texture_t *texinfo)
{
int i;
for (i = 0; i < texinfo->width * texinfo->height; ++i)
{
/* Read and convert BGRA to RGBA */
texinfo->texels[(i * 4) + 2] = (GLubyte)fgetc (fp);
texinfo->texels[(i * 4) + 1] = (GLubyte)fgetc (fp);
texinfo->texels[(i * 4) + 0] = (GLubyte)fgetc (fp);
texinfo->texels[(i * 4) + 3] = (GLubyte)fgetc (fp);
}
}
static void
ReadTGAgray8bits (FILE *fp, struct gl_texture_t *texinfo)
{
int i;
for (i = 0; i < texinfo->width * texinfo->height; ++i)
{
/* Read grayscale color byte */
texinfo->texels[i] = (GLubyte)fgetc (fp);
}
}
static void
ReadTGAgray16bits (FILE *fp, struct gl_texture_t *texinfo)
{
int i;
for (i = 0; i < texinfo->width * texinfo->height; ++i)
{
/* Read grayscale color + alpha channel bytes */
texinfo->texels[(i * 2) + 0] = (GLubyte)fgetc (fp);
texinfo->texels[(i * 2) + 1] = (GLubyte)fgetc (fp);
}
}
static void
ReadTGA8bitsRLE (FILE *fp, const GLubyte *colormap,
struct gl_texture_t *texinfo)
{
int i, size;
GLubyte color;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 3)
{
/* Read first byte */
packet_header = (GLubyte)fgetc (fp);
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
color = (GLubyte)fgetc (fp);
for (i = 0; i < size; ++i, ptr += 3)
{
ptr[0] = colormap[(color * 3) + 2];
ptr[1] = colormap[(color * 3) + 1];
ptr[2] = colormap[(color * 3) + 0];
}
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr += 3)
{
color = (GLubyte)fgetc (fp);
ptr[0] = colormap[(color * 3) + 2];
ptr[1] = colormap[(color * 3) + 1];
ptr[2] = colormap[(color * 3) + 0];
}
}
}
}
static void
ReadTGA16bitsRLE (FILE *fp, struct gl_texture_t *texinfo)
{
int i, size;
unsigned short color;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 3)
{
/* Read first byte */
packet_header = fgetc (fp);
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
color = fgetc (fp) + (fgetc (fp) << 8);
for (i = 0; i < size; ++i, ptr += 3)
{
ptr[0] = (GLubyte)(((color & 0x7C00) >> 10) << 3);
ptr[1] = (GLubyte)(((color & 0x03E0) >> 5) << 3);
ptr[2] = (GLubyte)(((color & 0x001F) >> 0) << 3);
}
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr += 3)
{
color = fgetc (fp) + (fgetc (fp) << 8);
ptr[0] = (GLubyte)(((color & 0x7C00) >> 10) << 3);
ptr[1] = (GLubyte)(((color & 0x03E0) >> 5) << 3);
ptr[2] = (GLubyte)(((color & 0x001F) >> 0) << 3);
}
}
}
}
static void
ReadTGA24bitsRLE (FILE *fp, struct gl_texture_t *texinfo)
{
int i, size;
GLubyte rgb[3];
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 3)
{
/* Read first byte */
packet_header = (GLubyte)fgetc (fp);
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
fread (rgb, sizeof (GLubyte), 3, fp);
for (i = 0; i < size; ++i, ptr += 3)
{
ptr[0] = rgb[2];
ptr[1] = rgb[1];
ptr[2] = rgb[0];
}
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr += 3)
{
ptr[2] = (GLubyte)fgetc (fp);
ptr[1] = (GLubyte)fgetc (fp);
ptr[0] = (GLubyte)fgetc (fp);
}
}
}
}
static void
ReadTGA32bitsRLE (FILE *fp, struct gl_texture_t *texinfo)
{
int i, size;
GLubyte rgba[4];
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 4)
{
/* Read first byte */
packet_header = (GLubyte)fgetc (fp);
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
fread (rgba, sizeof (GLubyte), 4, fp);
for (i = 0; i < size; ++i, ptr += 4)
{
ptr[0] = rgba[2];
ptr[1] = rgba[1];
ptr[2] = rgba[0];
ptr[3] = rgba[3];
}
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr += 4)
{
ptr[2] = (GLubyte)fgetc (fp);
ptr[1] = (GLubyte)fgetc (fp);
ptr[0] = (GLubyte)fgetc (fp);
ptr[3] = (GLubyte)fgetc (fp);
}
}
}
}
static void
ReadTGAgray8bitsRLE (FILE *fp, struct gl_texture_t *texinfo)
{
int i, size;
GLubyte color;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height))
{
/* Read first byte */
packet_header = (GLubyte)fgetc (fp);
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
color = (GLubyte)fgetc (fp);
for (i = 0; i < size; ++i, ptr++)
*ptr = color;
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr++)
*ptr = (GLubyte)fgetc (fp);
}
}
}
static void
ReadTGAgray16bitsRLE (FILE *fp, struct gl_texture_t *texinfo)
{
int i, size;
GLubyte color, alpha;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 2)
{
/* Read first byte */
packet_header = (GLubyte)fgetc (fp);
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
color = (GLubyte)fgetc (fp);
alpha = (GLubyte)fgetc (fp);
for (i = 0; i < size; ++i, ptr += 2)
{
ptr[0] = color;
ptr[1] = alpha;
}
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr += 2)
{
ptr[0] = (GLubyte)fgetc (fp);
ptr[1] = (GLubyte)fgetc (fp);
}
}
}
}
static struct gl_texture_t *
ReadTGAFile (const char *filename)
{
FILE *fp;
struct gl_texture_t *texinfo;
struct tga_header_t header;
GLubyte *colormap = NULL;
fp = fopen (filename, "rb");
if (!fp)
{
fprintf (stderr, "error: couldn't open \"%s\"!\n", filename);
return NULL;
}
/* Read header */
fread (&header, sizeof (struct tga_header_t), 1, fp);
texinfo = (struct gl_texture_t *)
malloc (sizeof (struct gl_texture_t));
GetTextureInfo (&header, texinfo);
fseek (fp, header.id_lenght, SEEK_CUR);
/* Memory allocation */
texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte) *
texinfo->width * texinfo->height * texinfo->internalFormat);
if (!texinfo->texels)
{
free (texinfo);
return NULL;
}
/* Read color map */
if (header.colormap_type)
{
/* NOTE: color map is stored in BGR format */
colormap = (GLubyte *)malloc (sizeof (GLubyte)
* header.cm_length * (header.cm_size >> 3));
fread (colormap, sizeof (GLubyte), header.cm_length
* (header.cm_size >> 3), fp);
}
/* Read image data */
switch (header.image_type)
{
case 0:
/* No data */
break;
case 1:
/* Uncompressed 8 bits color index */
ReadTGA8bits (fp, colormap, texinfo);
break;
case 2:
/* Uncompressed 16-24-32 bits */
switch (header.pixel_depth)
{
case 16:
ReadTGA16bits (fp, texinfo);
break;
case 24:
ReadTGA24bits (fp, texinfo);
break;
case 32:
ReadTGA32bits (fp, texinfo);
break;
}
break;
case 3:
/* Uncompressed 8 or 16 bits grayscale */
if (header.pixel_depth == 8)
ReadTGAgray8bits (fp, texinfo);
else /* 16 */
ReadTGAgray16bits (fp, texinfo);
break;
case 9:
/* RLE compressed 8 bits color index */
ReadTGA8bitsRLE (fp, colormap, texinfo);
break;
case 10:
/* RLE compressed 16-24-32 bits */
switch (header.pixel_depth)
{
case 16:
ReadTGA16bitsRLE (fp, texinfo);
break;
case 24:
ReadTGA24bitsRLE (fp, texinfo);
break;
case 32:
ReadTGA32bitsRLE (fp, texinfo);
break;
}
break;
case 11:
/* RLE compressed 8 or 16 bits grayscale */
if (header.pixel_depth == 8)
ReadTGAgray8bitsRLE (fp, texinfo);
else /* 16 */
ReadTGAgray16bitsRLE (fp, texinfo);
break;
default:
/* Image type is not correct */
fprintf (stderr, "error: unknown TGA image type %i!\n", header.image_type);
free (texinfo->texels);
free (texinfo);
texinfo = NULL;
break;
}
/* No longer need colormap data */
if (colormap)
free (colormap);
fclose (fp);
return texinfo;
}
GLuint
loadTGATexture (const char *filename)
{
struct gl_texture_t *tga_tex = NULL;
GLuint tex_id = 0;
GLint alignment;
tga_tex = ReadTGAFile (filename);
if (tga_tex && tga_tex->texels)
{
/* Generate texture */
glGenTextures (1, &tga_tex->id);
glBindTexture (GL_TEXTURE_2D, tga_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, tga_tex->internalFormat,
tga_tex->width, tga_tex->height, 0, tga_tex->format,
GL_UNSIGNED_BYTE, tga_tex->texels);
#else
gluBuild2DMipmaps (GL_TEXTURE_2D, tga_tex->internalFormat,
tga_tex->width, tga_tex->height,
tga_tex->format, GL_UNSIGNED_BYTE, tga_tex->texels);
#endif
glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);
tex_id = tga_tex->id;
/* OpenGL has its own copy of texture data */
free (tga_tex->texels);
free (tga_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 TGA texture from file */
texId = loadTGATexture (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.tga>\n", argv[0]);
return -1;
}
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize (640, 480);
glutCreateWindow ("TGA Texture Demo");
atexit (cleanup);
init (argv[1]);
glutReshapeFunc (reshape);
glutDisplayFunc (display);
glutKeyboardFunc (keyboard);
glutMainLoop ();
return 0;
}
/*
* tga_mem.c -- tga 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 tga_mem.c -o tga_mem
*/
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* OpenGL texture info */
struct gl_texture_t
{
GLsizei width;
GLsizei height;
GLenum format;
GLint internalFormat;
GLuint id;
GLubyte *texels;
};
#pragma pack(push, 1)
/* TGA header */
struct tga_header_t
{
GLubyte id_lenght; /* size of image id */
GLubyte colormap_type; /* 1 is has a colormap */
GLubyte image_type; /* compression type */
short cm_first_entry; /* colormap origin */
short cm_length; /* colormap length */
GLubyte cm_size; /* colormap size */
short x_origin; /* bottom left x coord origin */
short y_origin; /* bottom left y coord origin */
short width; /* picture width (in pixels) */
short height; /* picture height (in pixels) */
GLubyte pixel_depth; /* bits per pixel: 8, 16, 24 or 32 */
GLubyte image_descriptor; /* 24 bits = 0x00; 32 bits = 0x80 */
};
#pragma pack(pop)
/* Texture id for the demo */
GLuint texId = 0;
static void
GetTextureInfo (const struct tga_header_t *header,
struct gl_texture_t *texinfo)
{
texinfo->width = header->width;
texinfo->height = header->height;
switch (header->image_type)
{
case 3: /* Grayscale 8 bits */
case 11: /* Grayscale 8 bits (RLE) */
{
if (header->pixel_depth == 8)
{
texinfo->format = GL_LUMINANCE;
texinfo->internalFormat = 1;
}
else /* 16 bits */
{
texinfo->format = GL_LUMINANCE_ALPHA;
texinfo->internalFormat = 2;
}
break;
}
case 1: /* 8 bits color index */
case 2: /* BGR 16-24-32 bits */
case 9: /* 8 bits color index (RLE) */
case 10: /* BGR 16-24-32 bits (RLE) */
{
/* 8 bits and 16 bits images will be converted to 24 bits */
if (header->pixel_depth <= 24)
{
texinfo->format = GL_RGB;
texinfo->internalFormat = 3;
}
else /* 32 bits */
{
texinfo->format = GL_RGBA;
texinfo->internalFormat = 4;
}
break;
}
}
}
static void
ReadTGA8bits (const GLubyte *data, const GLubyte *colormap,
struct gl_texture_t *texinfo)
{
int i;
GLubyte color;
for (i = 0; i < texinfo->width * texinfo->height; ++i)
{
/* Read index color byte */
color = data[i];
/* Convert to RGB 24 bits */
texinfo->texels[(i * 3) + 2] = colormap[(color * 3) + 0];
texinfo->texels[(i * 3) + 1] = colormap[(color * 3) + 1];
texinfo->texels[(i * 3) + 0] = colormap[(color * 3) + 2];
}
}
static void
ReadTGA16bits (const GLubyte *data, struct gl_texture_t *texinfo)
{
int i, j = 0;
unsigned short color;
for (i = 0; i < texinfo->width * texinfo->height; ++i, j += 2)
{
/* Read color word */
color = data[j] + (data[j + 1] << 8);
/* Convert BGR to RGB */
texinfo->texels[(i * 3) + 0] = (GLubyte)(((color & 0x7C00) >> 10) << 3);
texinfo->texels[(i * 3) + 1] = (GLubyte)(((color & 0x03E0) >> 5) << 3);
texinfo->texels[(i * 3) + 2] = (GLubyte)(((color & 0x001F) >> 0) << 3);
}
}
static void
ReadTGA24bits (const GLubyte *data, struct gl_texture_t *texinfo)
{
int i, j = 0;
for (i = 0; i < texinfo->width * texinfo->height; ++i, j += 3)
{
/* Read and convert BGR to RGB */
texinfo->texels[(i * 3) + 2] = data[j + 0];
texinfo->texels[(i * 3) + 1] = data[j + 1];
texinfo->texels[(i * 3) + 0] = data[j + 2];
}
}
static void
ReadTGA32bits (const GLubyte *data, struct gl_texture_t *texinfo)
{
int i, j = 0;
for (i = 0; i < texinfo->width * texinfo->height; ++i, j += 4)
{
/* Read and convert BGRA to RGBA */
texinfo->texels[(i * 4) + 2] = data[j + 0];
texinfo->texels[(i * 4) + 1] = data[j + 1];
texinfo->texels[(i * 4) + 0] = data[j + 2];
texinfo->texels[(i * 4) + 3] = data[j + 3];
}
}
static void
ReadTGAgray8bits (const GLubyte *data, struct gl_texture_t *texinfo)
{
memcpy (texinfo->texels, data, sizeof (GLubyte) *
texinfo->width * texinfo->height);
}
static void
ReadTGAgray16bits (const GLubyte *data, struct gl_texture_t *texinfo)
{
memcpy (texinfo->texels, data, sizeof (GLubyte) *
texinfo->width * texinfo->height * 2);
}
static void
ReadTGA8bitsRLE (const GLubyte *data, const GLubyte *colormap,
struct gl_texture_t *texinfo)
{
int i, size, j = 0;
GLubyte color;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 3)
{
/* Read first byte */
packet_header = data[j++];
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
color = data[j++];
for (i = 0; i < size; ++i, ptr += 3)
{
ptr[0] = colormap[(color * 3) + 2];
ptr[1] = colormap[(color * 3) + 1];
ptr[2] = colormap[(color * 3) + 0];
}
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr += 3)
{
color = data[j++];
ptr[0] = colormap[(color * 3) + 2];
ptr[1] = colormap[(color * 3) + 1];
ptr[2] = colormap[(color * 3) + 0];
}
}
}
}
static void
ReadTGA16bitsRLE (const GLubyte *data, struct gl_texture_t *texinfo)
{
int i, size, j = 0;
unsigned short color;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 3)
{
/* Read first byte */
packet_header = data[j++];
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
color = data[j] + (data[j + 1] << 8);
j += 2;
for (i = 0; i < size; ++i, ptr += 3)
{
ptr[0] = (GLubyte)(((color & 0x7C00) >> 10) << 3);
ptr[1] = (GLubyte)(((color & 0x03E0) >> 5) << 3);
ptr[2] = (GLubyte)(((color & 0x001F) >> 0) << 3);
}
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr += 3, j += 2)
{
color = data[j] + (data[j + 1] << 8);
ptr[0] = (GLubyte)(((color & 0x7C00) >> 10) << 3);
ptr[1] = (GLubyte)(((color & 0x03E0) >> 5) << 3);
ptr[2] = (GLubyte)(((color & 0x001F) >> 0) << 3);
}
}
}
}
static void
ReadTGA24bitsRLE (const GLubyte *data, struct gl_texture_t *texinfo)
{
int i, size, j = 0;
const GLubyte *rgb;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 3)
{
/* Read first byte */
packet_header = data[j++];
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
rgb = &data[j];
j += 3;
for (i = 0; i < size; ++i, ptr += 3)
{
ptr[0] = rgb[2];
ptr[1] = rgb[1];
ptr[2] = rgb[0];
}
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr += 3, j += 3)
{
ptr[2] = data[j + 0];
ptr[1] = data[j + 1];
ptr[0] = data[j + 2];
}
}
}
}
static void
ReadTGA32bitsRLE (const GLubyte *data, struct gl_texture_t *texinfo)
{
int i, size, j = 0;
const GLubyte *rgba;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 4)
{
/* Read first byte */
packet_header = data[j++];
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
rgba = &data[j];
j += 4;
for (i = 0; i < size; ++i, ptr += 4)
{
ptr[0] = rgba[2];
ptr[1] = rgba[1];
ptr[2] = rgba[0];
ptr[3] = rgba[3];
}
}
else
{
/* Non run-length packet */
for (i = 0; i < size; ++i, ptr += 4, j += 4)
{
ptr[2] = data[j + 0];
ptr[1] = data[j + 1];
ptr[0] = data[j + 2];
ptr[3] = data[j + 3];
}
}
}
}
static void
ReadTGAgray8bitsRLE (const GLubyte *data, struct gl_texture_t *texinfo)
{
int i, size, j = 0;
GLubyte color;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height))
{
/* Read first byte */
packet_header = data[j++];
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
color = data[j++];
for (i = 0; i < size; ++i, ptr++)
*ptr = color;
}
else
{
/* Non run-length packet */
memcpy (ptr, data + j, size * sizeof (GLubyte));
ptr += size;
j += size;
}
}
}
static void
ReadTGAgray16bitsRLE (const GLubyte *data, struct gl_texture_t *texinfo)
{
int i, size, j = 0;
GLubyte color, alpha;
GLubyte packet_header;
GLubyte *ptr = texinfo->texels;
while (ptr < texinfo->texels + (texinfo->width * texinfo->height) * 2)
{
/* Read first byte */
packet_header = data[j++];
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
color = data[j++];
alpha = data[j++];
for (i = 0; i < size; ++i, ptr += 2)
{
ptr[0] = color;
ptr[1] = alpha;
}
}
else
{
/* Non run-length packet */
memcpy (ptr, data + j, size * sizeof (GLubyte) * 2);
ptr += size * 2;
j += size * 2;
}
}
}
static struct gl_texture_t *
ReadTGAFile (const char *filename)
{
FILE *fp;
struct gl_texture_t *texinfo;
struct tga_header_t *header;
GLubyte *buffer = NULL;
GLubyte *colormap = NULL;
GLubyte *ptr;
long length;
/* Open file */
fp = fopen (filename, "rb");
if (!fp)
{
fprintf (stderr, "error: couldn't open \"%s\"!\n", filename);
return NULL;
}
/* Get file length */
fseek (fp, 0, SEEK_END);
length = ftell (fp);
fseek (fp, 0, SEEK_SET);
buffer = (GLubyte *) malloc (sizeof (GLubyte) * length);
if (!buffer)
{
fprintf (stderr, "Error: memory allocation failed "
"for \"%s\"\n", filename);
fclose (fp);
return NULL;
}
/* Read whole file data */
fread (buffer, sizeof (GLubyte), length, fp);
fclose (fp);
ptr = buffer;
/* Extract header */
header = (struct tga_header_t *)ptr;
ptr += sizeof (struct tga_header_t);
texinfo = (struct gl_texture_t *)malloc (sizeof (struct gl_texture_t));
GetTextureInfo (header, texinfo);
ptr += header->id_lenght;
/* Memory allocation for pixel data */
texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte) *
texinfo->width * texinfo->height * texinfo->internalFormat);
if (!texinfo->texels)
{
free (texinfo);
return NULL;
}
/* Read color map */
if (header->colormap_type)
{
/* NOTE: color map is stored in BGR format */
colormap = ptr;
ptr += header->cm_length * (header->cm_size >> 3);
}
/* Read image data */
switch (header->image_type)
{
case 0:
/* No data */
break;
case 1:
/* Uncompressed 8 bits color index */
ReadTGA8bits (ptr, colormap, texinfo);
break;
case 2:
/* Uncompressed 16-24-32 bits */
switch (header->pixel_depth)
{
case 16:
ReadTGA16bits (ptr, texinfo);
break;
case 24:
ReadTGA24bits (ptr, texinfo);
break;
case 32:
ReadTGA32bits (ptr, texinfo);
break;
}
break;
case 3:
/* Uncompressed 8 or 16 bits grayscale */
if (header->pixel_depth == 8)
ReadTGAgray8bits (ptr, texinfo);
else /* 16 */
ReadTGAgray16bits (ptr, texinfo);
break;
case 9:
/* RLE compressed 8 bits color index */
ReadTGA8bitsRLE (ptr, colormap, texinfo);
break;
case 10:
/* RLE compressed 16-24-32 bits */
switch (header->pixel_depth)
{
case 16:
ReadTGA16bitsRLE (ptr, texinfo);
break;
case 24:
ReadTGA24bitsRLE (ptr, texinfo);
break;
case 32:
ReadTGA32bitsRLE (ptr, texinfo);
break;
}
break;
case 11:
/* RLE compressed 8 or 16 bits grayscale */
if (header->pixel_depth == 8)
ReadTGAgray8bitsRLE (ptr, texinfo);
else /* 16 */
ReadTGAgray16bitsRLE (ptr, texinfo);
break;
default:
/* Image type is not correct */
fprintf (stderr, "error: unknown TGA image type %i!\n",
header->image_type);
free (texinfo->texels);
free (texinfo);
texinfo = NULL;
break;
}
if (buffer)
free (buffer);
return texinfo;
}
GLuint
loadTGATexture (const char *filename)
{
struct gl_texture_t *tga_tex = NULL;
GLuint tex_id = 0;
GLint alignment;
tga_tex = ReadTGAFile (filename);
if (tga_tex && tga_tex->texels)
{
/* Generate texture */
glGenTextures (1, &tga_tex->id);
glBindTexture (GL_TEXTURE_2D, tga_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, tga_tex->internalFormat,
tga_tex->width, tga_tex->height, 0, tga_tex->format,
GL_UNSIGNED_BYTE, tga_tex->texels);
#else
gluBuild2DMipmaps (GL_TEXTURE_2D, tga_tex->internalFormat,
tga_tex->width, tga_tex->height,
tga_tex->format, GL_UNSIGNED_BYTE, tga_tex->texels);
#endif
glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);
tex_id = tga_tex->id;
/* OpenGL has its own copy of texture data */
free (tga_tex->texels);
free (tga_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 TGA texture from file */
texId = loadTGATexture (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.tga>\n", argv[0]);
return -1;
}
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize (640, 480);
glutCreateWindow ("TGA Texture Demo");
atexit (cleanup);
init (argv[1]);
glutReshapeFunc (reshape);
glutDisplayFunc (display);
glutKeyboardFunc (keyboard);
glutMainLoop ();
return 0;
}
/*
* tga_r_mem.c -- tga texture loader (reverse height)
* last modification: apr. 6, 2009
*
* Copyright (c) 2005-2009 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 tga_mem.c -o tga_mem
*/
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
/* File buffer struct */
struct file_buffer_t
{
char name[256];
uint8_t *data;
long length;
long offset;
};
/* OpenGL texture info */
struct gl_texture_t
{
GLsizei width;
GLsizei height;
GLenum format;
GLint internalFormat;
GLuint id;
GLubyte *texels;
};
#pragma pack(push, 1)
/* TGA header */
#if 1
struct tga_header_t
{
uint8_t id_lenght; /* size of image id */
uint8_t colormap_type; /* 1 is has a colormap */
/*uint8_t image_type;*/ /* compression type */
uint8_t image_type : 3; /* 1 = color mapped, 2 = true color; 3 = grayscale */
uint8_t compression : 1; /* 1 is rle encoding */
uint8_t : 4; /* padding */
uint16_t cm_first_entry; /* colormap origin */
uint16_t cm_length; /* colormap length */
uint8_t cm_size; /* colormap size */
int16_t x_origin; /* bottom left x coord origin */
int16_t y_origin; /* bottom left y coord origin */
int16_t width; /* picture width (in pixels) */
int16_t height; /* picture height (in pixels) */
uint8_t pixel_depth; /* bits per pixel: 8, 16, 24 or 32 */
uint8_t image_descriptor; /* 24 bits = 0x00; 32 bits = 0x80 */
};
#else
struct tga_header_t
{
unsigned id_lenght : 8; /* size of image id */
unsigned colormap_type : 8; /* 1 is has a colormap */
unsigned image_type : 3; /* 1 = color mapped, 2 = true color; 3 = grayscale */
unsigned compression : 1; /* 1 is rle encoding */
unsigned : 4; /* padding */
unsigned cm_first_entry : 16; /* colormap origin */
unsigned cm_length : 16; /* colormap length */
unsigned cm_size : 8; /* colormap size */
unsigned x_origin : 16; /* bottom left x coord origin */
unsigned y_origin : 16; /* bottom left y coord origin */
unsigned width : 16; /* picture width (in pixels) */
unsigned height : 16; /* picture height (in pixels) */
unsigned pixel_depth : 8; /* bits per pixel: 8, 16, 24 or 32 */
unsigned image_descriptor : 8; /* 24 bits = 0x00; 32 bits = 0x80 */
};
#endif
#pragma pack(pop)
/* TGA file reader structure */
struct tga_file_t
{
const struct tga_header_t *header;
const uint8_t *colormap;
const uint8_t *data;
long offset;
};
#define TGA_COLOR_MAPPED 0x01
#define TGA_TRUE_COLOR 0x02
#define TGA_GRAYSCALE 0x03
#define TGA_RLE_COMPRESSION 0x08
/* Texture id for the demo */
GLuint texId = 0;
static inline bool
tga_is_color_mapped (const struct tga_file_t *tga)
{
return (tga->header->image_type == TGA_COLOR_MAPPED);
}
static inline bool
tga_is_true_color (const struct tga_file_t *tga)
{
return (tga->header->image_type == TGA_TRUE_COLOR);
}
static inline bool
tga_is_grayscale (const struct tga_file_t *tga)
{
return (tga->header->image_type == TGA_GRAYSCALE);
}
static inline bool
tga_is_compressed (const struct tga_file_t *tga)
{
return tga->header->compression;
}
void
GetTextureInfo (const struct tga_header_t *header,
struct gl_texture_t *texinfo)
{
texinfo->width = header->width;
texinfo->height = header->height;
switch (header->image_type)
{
case TGA_COLOR_MAPPED:
case TGA_TRUE_COLOR:
{
/* 8 bits and 16 bits images will be converted to 24 bits */
if (header->pixel_depth <= 24)
{
texinfo->format = GL_BGR;
texinfo->internalFormat = 3;
}
else /* 32 bits */
{
texinfo->format = GL_BGRA;
texinfo->internalFormat = 4;
}
break;
}
case TGA_GRAYSCALE:
{
if (header->pixel_depth == 8)
{
texinfo->format = GL_LUMINANCE;
texinfo->internalFormat = 1;
}
else /* 16 bits */
{
texinfo->format = GL_LUMINANCE_ALPHA;
texinfo->internalFormat = 2;
}
break;
}
}
}
void
tga_read_raw_packet (struct tga_file_t *tga, int size,
GLubyte *dest, int dest_depth)
{
const uint8_t *src = &tga->data[tga->offset];
GLubyte *ptr = dest;
int i, j;
if (tga_is_color_mapped (tga))
{
/* Convert to BGR 24 bits */
for (i = 0; i < size; i++, ptr += 3)
memcpy (ptr, &tga->colormap[src[i] * 3], 3);
}
else if (tga_is_true_color (tga) && tga->header->pixel_depth == 16)
{
for (i = 0, j = 0; i < size; i++, ptr += 3, j += 2)
{
/* Read color word */
uint16_t color = src[j] + (src[j + 1] << 8);
/* Convert to BGR 24 bits */
ptr[0] = (GLubyte)(((color & 0x001F) >> 0) << 3);
ptr[1] = (GLubyte)(((color & 0x03E0) >> 5) << 3);
ptr[2] = (GLubyte)(((color & 0x7C00) >> 10) << 3);
}
}
else
{
memcpy (ptr, src, size * dest_depth);
}
tga->offset += size * tga->header->pixel_depth / 8;
}
void
tga_read_rle_packet (struct tga_file_t *tga, int size,
GLubyte *dest, int dest_depth)
{
const uint8_t *src = &tga->data[tga->offset];
GLubyte *ptr = dest;
int i;
if (tga_is_color_mapped (tga))
{
/* Convert to BGR 24 bits */
for (i = 0; i < size; i++, ptr += 3)
memcpy (ptr, &tga->colormap[src[0] * 3], 3);
}
else if (tga_is_true_color (tga) &&
tga->header->pixel_depth == 16)
{
/* Read color word */
uint16_t color = src[0] + (src[1] << 8);
for (i = 0; i < size; i++, ptr += 3)
{
/* Convert to BGR 24 bits */
ptr[0] = (GLubyte)(((color & 0x001F) >> 0) << 3);
ptr[1] = (GLubyte)(((color & 0x03E0) >> 5) << 3);
ptr[2] = (GLubyte)(((color & 0x7C00) >> 10) << 3);
}
}
else
{
for (i = 0; i < size; i++, ptr += dest_depth)
memcpy (ptr, src, dest_depth);
}
tga->offset += tga->header->pixel_depth / 8;
}
void
tga_read_scanline_rle (struct tga_file_t *tga,
GLubyte *dest, int dest_depth)
{
int size;
GLubyte packet_header;
GLubyte *ptr = dest;
while (ptr < dest + tga->header->width * dest_depth)
{
/* Read first byte */
packet_header = tga->data[tga->offset++];
size = 1 + (packet_header & 0x7f);
if (packet_header & 0x80)
{
/* Run-length packet */
tga_read_rle_packet (tga, size, ptr, dest_depth);
}
else
{
/* Raw packet (non-run-length encoded) */
tga_read_raw_packet (tga, size, ptr, dest_depth);
}
ptr += size * dest_depth;
}
}
void
tga_read_scanline_uncompressed (struct tga_file_t *tga, GLubyte *dest)
{
tga_read_raw_packet (tga, tga->header->width, dest,
tga->header->pixel_depth / 8);
}
bool
tga_read_file (const struct file_buffer_t *buffer,
struct gl_texture_t *texinfo)
{
struct tga_file_t tga;
GLubyte *line;
int i;
tga.data = buffer->data;
tga.offset = 0;
/* Extract header */
tga.header = (struct tga_header_t *)tga.data;
tga.offset = sizeof (struct tga_header_t) + tga.header->id_lenght;
GetTextureInfo (tga.header, texinfo);
/* Read color map data */
if (tga.header->colormap_type)
{
/* NOTE: color map is stored in BGR format */
tga.colormap = &tga.data[tga.offset];
tga.offset += tga.header->cm_length * (tga.header->cm_size / 8);
}
/* No pixel data, but still a valid TGA image file */
if (tga.header->image_type == 0)
return true;
/* Memory allocation for pixel data */
texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte) *
texinfo->width * texinfo->height * texinfo->internalFormat);
if (!texinfo->texels)
return false;
/* Read image data */
for (i = 0; i < texinfo->height; i++)
{
#if 0
line = &texinfo->texels[texinfo->width * i * texinfo->internalFormat];
#else
line = &texinfo->texels[(texinfo->height - (i + 1))
* texinfo->width * texinfo->internalFormat];
#endif
if (tga_is_compressed (&tga))
tga_read_scanline_rle (&tga, line, texinfo->internalFormat);
else
tga_read_scanline_uncompressed (&tga, line);
}
return true;
}
bool
read_file (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 false;
}
/* 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 = (uint8_t *)malloc (file->length);
if (!file->data)
{
fprintf (stderr, "Error: memory allocation failed "
"for \"%s\"\n", filename);
fclose (fp);
return false;
}
/* Read whole file data */
fread (file->data, 1, file->length, fp);
fclose (fp);
return true;
}
GLuint
loadTGATexture (const char *filename)
{
struct gl_texture_t tga_tex;
struct file_buffer_t buffer;
GLuint tex_id = 0;
GLint alignment;
if (!read_file (filename, &buffer))
return 0;
if (tga_read_file (&buffer, &tga_tex))
{
glGenTextures (1, &tga_tex.id);
glBindTexture (GL_TEXTURE_2D, tga_tex.id);
glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
#if 0
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D (GL_TEXTURE_2D, 0, tga_tex.internalFormat,
tga_tex.width, tga_tex.height, 0, tga_tex.format,
GL_UNSIGNED_BYTE, tga_tex.texels);
#else
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gluBuild2DMipmaps (GL_TEXTURE_2D, tga_tex.internalFormat,
tga_tex.width, tga_tex.height,
tga_tex.format, GL_UNSIGNED_BYTE, tga_tex.texels);
#endif
glPixelStorei (GL_UNPACK_ALIGNMENT, alignment);
tex_id = tga_tex.id;
}
if (tga_tex.texels)
free (tga_tex.texels);
free (buffer.data);
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 TGA texture from file */
texId = loadTGATexture (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, 1.0f);
glVertex3f (-1.0f, -1.0f, 0.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (1.0f, -1.0f, 0.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (1.0f, 1.0f, 0.0f);
glTexCoord2f (0.0f, 0.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.tga>\n", argv[0]);
return -1;
}
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize (640, 480);
glutCreateWindow ("TGA 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