00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "images.h"
00028
00029
00030
00031 #undef HAVE_STDLIB_H
00032
00033 #include <jpeglib.h>
00034 #include <png.h>
00035
00037 static char *IMAGE_TYPES[] = { "tga", "png", "jpg", NULL };
00038
00040 static SDL_PixelFormat format = {
00041 NULL,
00042 32,
00043 4,
00044 0,
00045 0,
00046 0,
00047 0,
00048 24,
00049 16,
00050 8,
00051 0,
00052 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00053 0xff000000,
00054 0x00ff0000,
00055 0x0000ff00,
00056 0x000000ff,
00057 #else
00058 0x000000ff,
00059 0x0000ff00,
00060 0x00ff0000,
00061 0xff000000,
00062 #endif
00063 0,
00064 1
00065 };
00066
00067 #define TGA_UNMAP_UNCOMP 2
00068 #define TGA_UNMAP_COMP 10
00069
00070 const char** Img_GetImageTypes (void)
00071 {
00072 return (const char **)IMAGE_TYPES;
00073 }
00074
00080 void R_WritePNG (qFILE *f, byte *buffer, int width, int height)
00081 {
00082 int i;
00083 png_structp png_ptr;
00084 png_infop info_ptr;
00085 png_bytep *row_pointers;
00086
00087 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00088 if (!png_ptr) {
00089 return;
00090 }
00091
00092 info_ptr = png_create_info_struct(png_ptr);
00093 if (!info_ptr) {
00094 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00095 return;
00096 }
00097
00098 png_init_io(png_ptr, f->f);
00099
00100 png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
00101 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
00102
00103 png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
00104 png_set_compression_mem_level(png_ptr, 9);
00105
00106 png_write_info(png_ptr, info_ptr);
00107
00108 row_pointers = malloc(height * sizeof(png_bytep));
00109 for (i = 0; i < height; i++)
00110 row_pointers[i] = buffer + (height - 1 - i) * 3 * width;
00111
00112 png_write_image(png_ptr, row_pointers);
00113 png_write_end(png_ptr, info_ptr);
00114
00115 png_destroy_write_struct(&png_ptr, &info_ptr);
00116
00117 free(row_pointers);
00118 }
00119
00120 #define TGA_CHANNELS 3
00121
00126 void R_WriteCompressedTGA (qFILE *f, const byte *buffer, int width, int height)
00127 {
00128 byte pixel_data[TGA_CHANNELS];
00129 byte block_data[TGA_CHANNELS * 128];
00130 byte rle_packet;
00131 int compress = 0;
00132 size_t block_length = 0;
00133 byte header[18];
00134 char footer[26];
00135
00136 int y;
00137 size_t x;
00138
00139 memset(header, 0, sizeof(header));
00140 memset(footer, 0, sizeof(footer));
00141
00142
00143
00144
00145 header[2] = TGA_UNMAP_COMP;
00146
00147
00148 header[12] = width & 255;
00149 header[13] = (width >> 8) & 255;
00150
00151 header[14] = height & 255;
00152 header[15] = (height >> 8) & 255;
00153 header[16] = 8 * TGA_CHANNELS;
00154 header[17] = 0x20;
00155
00156
00157 FS_Write(header, sizeof(header), f);
00158
00159 for (y = height - 1; y >= 0; y--) {
00160 for (x = 0; x < width; x++) {
00161 const size_t index = y * width * TGA_CHANNELS + x * TGA_CHANNELS;
00162 pixel_data[0] = buffer[index + 2];
00163 pixel_data[1] = buffer[index + 1];
00164 pixel_data[2] = buffer[index];
00165
00166 if (block_length == 0) {
00167 memcpy(block_data, pixel_data, TGA_CHANNELS);
00168 block_length++;
00169 compress = 0;
00170 } else {
00171 if (!compress) {
00172
00173 if (memcmp(&block_data[(block_length - 1) * TGA_CHANNELS], pixel_data, TGA_CHANNELS) != 0) {
00174
00175 memcpy(&block_data[block_length * TGA_CHANNELS], pixel_data, TGA_CHANNELS);
00176
00177 block_length++;
00178 } else {
00179
00180 if (block_length > 1) {
00181
00182 rle_packet = block_length - 2;
00183 FS_Write(&rle_packet,1, f);
00184 FS_Write(block_data, (block_length - 1) * TGA_CHANNELS, f);
00185 block_length = 1;
00186 }
00187 memcpy(block_data, pixel_data, TGA_CHANNELS);
00188 block_length++;
00189 compress = 1;
00190 }
00191 } else {
00192
00193 if (memcmp(block_data, pixel_data, TGA_CHANNELS) == 0) {
00194 block_length++;
00195 } else {
00196
00197 if (block_length > 1) {
00198
00199 rle_packet = block_length + 127;
00200 FS_Write(&rle_packet, 1, f);
00201 FS_Write(block_data, TGA_CHANNELS, f);
00202 block_length = 0;
00203 }
00204 memcpy(&block_data[block_length * TGA_CHANNELS], pixel_data, TGA_CHANNELS);
00205 block_length++;
00206 compress = 0;
00207 }
00208 }
00209 }
00210
00211 if (block_length == 128) {
00212 rle_packet = block_length - 1;
00213 if (!compress) {
00214 FS_Write(&rle_packet, 1, f);
00215 FS_Write(block_data, 128 * TGA_CHANNELS, f);
00216 } else {
00217 rle_packet += 128;
00218 FS_Write(&rle_packet, 1, f);
00219 FS_Write(block_data, TGA_CHANNELS, f);
00220 }
00221
00222 block_length = 0;
00223 compress = 0;
00224 }
00225 }
00226 }
00227
00228
00229 if (block_length) {
00230 rle_packet = block_length - 1;
00231 if (!compress) {
00232 FS_Write(&rle_packet, 1, f);
00233 FS_Write(block_data, block_length * TGA_CHANNELS, f);
00234 } else {
00235 rle_packet += 128;
00236 FS_Write(&rle_packet, 1, f);
00237 FS_Write(block_data, TGA_CHANNELS, f);
00238 }
00239 }
00240
00241
00242 strncpy(&footer[8] , "TRUEVISION-XFILE", 16);
00243 footer[24] = '.';
00244 footer[25] = 0;
00245 FS_Write(footer, sizeof(footer), f);
00246 }
00247
00252 void R_WriteJPG (qFILE *f, byte *buffer, int width, int height, int quality)
00253 {
00254 int offset, w3;
00255 struct jpeg_compress_struct cinfo;
00256 struct jpeg_error_mgr jerr;
00257 byte *s;
00258
00259
00260 cinfo.err = jpeg_std_error(&jerr);
00261 jpeg_create_compress(&cinfo);
00262 jpeg_stdio_dest(&cinfo, f->f);
00263
00264
00265 cinfo.image_width = width;
00266 cinfo.image_height = height;
00267 cinfo.in_color_space = JCS_RGB;
00268 cinfo.input_components = 3;
00269 cinfo.progressive_mode = TRUE;
00270
00271 jpeg_set_defaults(&cinfo);
00272 jpeg_set_quality(&cinfo, quality, TRUE);
00273 jpeg_start_compress(&cinfo, qtrue);
00274 jpeg_write_marker(&cinfo, JPEG_COM, (const byte *) "UFOAI", (uint32_t) 5);
00275
00276
00277 w3 = cinfo.image_width * 3;
00278 offset = w3 * cinfo.image_height - w3;
00279 while (cinfo.next_scanline < cinfo.image_height) {
00280 s = &buffer[offset - (cinfo.next_scanline * w3)];
00281 jpeg_write_scanlines(&cinfo, &s, 1);
00282 }
00283
00284
00285 jpeg_finish_compress(&cinfo);
00286 jpeg_destroy_compress(&cinfo);
00287 }
00288
00293 static qboolean Img_LoadTypedImage (const char *name, char *type, SDL_Surface **surf)
00294 {
00295 char path[MAX_QPATH];
00296 byte *buf;
00297 int len;
00298 SDL_RWops *rw;
00299 SDL_Surface *s;
00300
00301 snprintf(path, sizeof(path), "%s.%s", name, type);
00302
00303 if ((len = FS_LoadFile(path, &buf)) == -1)
00304 return qfalse;
00305
00306 if (!(rw = SDL_RWFromMem(buf, len))) {
00307 FS_FreeFile(buf);
00308 return qfalse;
00309 }
00310
00311 if (!(*surf = IMG_LoadTyped_RW(rw, 0, type))) {
00312 SDL_FreeRW(rw);
00313 FS_FreeFile(buf);
00314 return qfalse;
00315 }
00316
00317 SDL_FreeRW(rw);
00318 FS_FreeFile(buf);
00319
00320 if (!(s = SDL_ConvertSurface(*surf, &format, 0))) {
00321 SDL_FreeSurface(*surf);
00322 return qfalse;
00323 }
00324
00325 SDL_FreeSurface(*surf);
00326 *surf = s;
00327
00328 return qtrue;
00329 }
00330
00338 qboolean Img_LoadImage (const char *name, SDL_Surface **surf)
00339 {
00340 int i;
00341
00342 i = 0;
00343 while (IMAGE_TYPES[i]) {
00344 if (Img_LoadTypedImage(name, IMAGE_TYPES[i++], surf))
00345 return qtrue;
00346 }
00347
00348 return qfalse;
00349 }