/* * GRacer * * Copyright (C) 1999 Takashi Matsuda * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include #include #include #include "gr_global.h" #include "gr_memory.h" #include "gr_texture.h" #include "gr_debug.h" #include #include #include #include #include #include #include #ifdef ENABLE_GIF static int gif_decode (GifFileType *file, GifRecordType find); static int read_gif_file (GrTexture *texture, char *filename); #endif #ifdef ENABLE_JPEG static int read_jpeg_file (GrTexture *texture, char *filename); #endif #ifdef ENABLE_PNG static int read_png_file (GrTexture *texture, char *filename); #endif static int texture_is_active = 1; typedef struct _GrTextureImport GrTextureImport; struct _GrTextureImport { const char *ext; int length; int (*func) (GrTexture *, char *); }; static GrTextureImport texture_import[] = { #ifdef ENABLE_GIF {".gif", 4, read_gif_file}, #endif #ifdef ENABLE_JPEG {".jpg", 4, read_jpeg_file}, #endif #ifdef ENABLE_PNG {".png", 4, read_png_file}, #endif {NULL, 0, NULL}, }; static void gr_texture_free (GrTexture *texture) { free (texture->texel); free (texture); } GrTexture * gr_texture_new (void) { GrTexture *texture; texture = gr_new0 (GrTexture, 1); gr_FREE_FUNC (texture, gr_texture_free); return texture; } GrTexture * gr_texture_new_from_file (char *filename) { GrTexture *texture; int success = 0; int length; GrTextureImport *import; int i; if (filename == NULL) return NULL; texture = gr_texture_new (); length = strlen (filename); for (i=0; texture_import[i].ext != NULL; i++) { import = &texture_import[i]; if (strcasecmp (filename + (length - import->length), import->ext) == 0) { if ((*import->func)(texture, filename) == 0) success = 1; break; } } if (!success) { gr_DECREF (texture); return NULL; } return texture; } void gr_texture_set_active (int state) { if (state) { texture_is_active = 1; } else { texture_is_active = 0; } } int gr_texture_get_active (void) { return texture_is_active; } void gr_texture_setup_gl (GrTexture *texture, GrObjectDrawOption option) { if (texture->name == 0) { GL_CHECK(glGenTextures (1, &(texture->name))); GL_CHECK(glBindTexture (GL_TEXTURE_2D, texture->name)); GL_CHECK(glPixelStorei (GL_UNPACK_ALIGNMENT, 1)); GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)); if (option & GR_OBJECT_MAG_LINEAR) { GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); } else { GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); } if (option & (GR_OBJECT_MIPMAP)) { switch (option & (GR_OBJECT_MIN_LINEAR | GR_OBJECT_MIP_LINEAR)) { default: GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST)); break; case GR_OBJECT_MIP_LINEAR: GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR)); break; case GR_OBJECT_MIN_LINEAR: GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST)); break; case GR_OBJECT_MIN_LINEAR | GR_OBJECT_MIP_LINEAR: GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); break; } } else { if (option & GR_OBJECT_MIN_LINEAR) { GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); } else { GL_CHECK(glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); } } if (option & GR_OBJECT_MIPMAP) { GL_CHECK(gluBuild2DMipmaps (GL_TEXTURE_2D, texture->format, texture->width, texture->height, texture->format, GL_UNSIGNED_BYTE, texture->texel)); } else { GL_CHECK(glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height, 0, texture->format, GL_UNSIGNED_BYTE, texture->texel)); } } } void gr_texture_release_gl (GrTexture *texture) { if (texture->name) { glDeleteTextures (1, &texture->name); } texture->name = 0; } void gr_texture_bind (GrTexture *texture) { GL_CHECK(glBindTexture (GL_TEXTURE_2D, texture->name)); } #ifdef ENABLE_GIF static int gif_decode (GifFileType *file, GifRecordType find) { int code; GifRecordType type; GifByteType *ext; while (1) { if (DGifGetRecordType (file, &type) == GIF_ERROR) { gr_warning ("can't get record type"); return -1; } switch (type) { case UNDEFINED_RECORD_TYPE: break; case SCREEN_DESC_RECORD_TYPE: DGifGetScreenDesc (file); break; case IMAGE_DESC_RECORD_TYPE: DGifGetImageDesc (file); break; case EXTENSION_RECORD_TYPE: if (find == EXTENSION_RECORD_TYPE) return 1; DGifGetExtension (file, &code, &ext); while (ext != NULL) { DGifGetExtensionNext (file, &ext); } break; case TERMINATE_RECORD_TYPE: return 0; } if (find == type) return 1; } } static int read_gif_file (GrTexture *texture, char *filename) { GifFileType *file; GifPixelType *line_buf; int i, j; int index; int width, height; #if GIFLIB_MAJOR >= 5 file = DGifOpenFileName (filename, NULL); #else file = DGifOpenFileName (filename); #endif if (!file) return -1; width = texture->width = file->SWidth; height = texture->height = file->SHeight; texture->texel = (GLubyte *) gr_new0 (GLubyte, width * height * 4); line_buf = gr_new (GifPixelType, width); if (gif_decode (file, IMAGE_DESC_RECORD_TYPE) != 1) { gr_warning ("can not fine screen desc in gif image file."); free (line_buf); return -1; } index = file->Image.Top * width + file->Image.Left; for (i=0; iImage.Height; i++) { DGifGetLine (file, line_buf, width); for (j=0; jImage.Width; j++) { GLubyte *texel = texture->texel + (index + i * width + j) * 4; if (line_buf[j] == file->SBackGroundColor) { texel[3] = 0; } else { texel[3] = 255; } if (file->SColorMap) { texel[0] = file->SColorMap->Colors[line_buf[j]].Red; texel[1] = file->SColorMap->Colors[line_buf[j]].Green; texel[2] = file->SColorMap->Colors[line_buf[j]].Blue; } else { texel[0] = texel[1] = texel[2] = line_buf[j]; } } } texture->format = GL_RGBA; free (line_buf); return 0; } #endif /* ENABLE_GIF */ #ifdef ENABLE_JPEG static int read_jpeg_file (GrTexture *texture, char *filename) { FILE *file; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buffer; unsigned char *data = NULL; int width; int height; int pixelsize; int line_length; int res; int i; cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); file = fopen (filename, "r"); if (!file) { return -1; } jpeg_stdio_src (&cinfo, file); res = jpeg_read_header (&cinfo, 1); if (res != JPEG_HEADER_OK) { goto ERROR; } jpeg_start_decompress (&cinfo); if (cinfo.data_precision != 8) { goto ERROR; } texture->width = width = cinfo.output_width; texture->height = height = cinfo.output_height; pixelsize = cinfo.output_components; line_length = width * pixelsize; switch (cinfo.out_color_space) { case JCS_GRAYSCALE: texture->format = GL_LUMINANCE; break; case JCS_RGB: texture->format = GL_RGB; break; default: goto ERROR; } texture->texel = data = gr_new (unsigned char, line_length * height); if (!data) { jpeg_destroy_decompress (&cinfo); return -1; } buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, line_length, 1); for (i=0; iformat = GL_LUMINANCE; break; case PNG_COLOR_TYPE_GRAY_ALPHA: texture->format = GL_LUMINANCE_ALPHA; break; case PNG_COLOR_TYPE_RGB: texture->format = GL_RGB; break; case PNG_COLOR_TYPE_RGB_ALPHA: texture->format = GL_RGBA; break; default: goto ERROR; } texture->texel = buf; texture->width = width; texture->height = height; png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL); free (row_pointers); fclose (file); return 0; ERROR: if (file) { fclose (file); } if (png_ptr && info_ptr) { png_destroy_info_struct (png_ptr, NULL); } if (png_ptr) { png_destroy_read_struct (&png_ptr, NULL, NULL); } free (buf); free (row_pointers); return -1; } #endif /* ENABLE_PNG */