00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "shared.h"
00027 #include "imagelib.h"
00028
00029 #include <jpeglib.h>
00030 #include <png.h>
00031
00032
00033
00034
00035
00036
00037
00038 typedef struct _TargaHeader {
00039 unsigned char id_length, colormap_type, image_type;
00040 unsigned short colormap_index, colormap_length;
00041 unsigned char colormap_size;
00042 unsigned short x_origin, y_origin, width, height;
00043 unsigned char pixel_size, attributes;
00044 } TargaHeader;
00045
00046 static void LoadTGA (const char *name, byte ** pic, int *width, int *height)
00047 {
00048 int columns, rows, numPixels;
00049 byte *pixbuf;
00050 int row, column;
00051 byte *buf_p;
00052 byte *buffer;
00053 int length;
00054 TargaHeader targa_header;
00055 byte *targa_rgba;
00056 byte tmp[2];
00057
00058 if (*pic != NULL)
00059 Sys_Error("possible mem leak in LoadTGA");
00060
00061
00062 length = FS_LoadFile(name, (byte **) &buffer);
00063 if (length == -1)
00064 return;
00065
00066 buf_p = buffer;
00067
00068 targa_header.id_length = *buf_p++;
00069 targa_header.colormap_type = *buf_p++;
00070 targa_header.image_type = *buf_p++;
00071
00072 tmp[0] = buf_p[0];
00073 tmp[1] = buf_p[1];
00074 targa_header.colormap_index = LittleShort(*((short *) tmp));
00075 buf_p += 2;
00076 tmp[0] = buf_p[0];
00077 tmp[1] = buf_p[1];
00078 targa_header.colormap_length = LittleShort(*((short *) tmp));
00079 buf_p += 2;
00080 targa_header.colormap_size = *buf_p++;
00081 targa_header.x_origin = LittleShort(*((short *) buf_p));
00082 buf_p += 2;
00083 targa_header.y_origin = LittleShort(*((short *) buf_p));
00084 buf_p += 2;
00085 targa_header.width = LittleShort(*((short *) buf_p));
00086 buf_p += 2;
00087 targa_header.height = LittleShort(*((short *) buf_p));
00088 buf_p += 2;
00089 targa_header.pixel_size = *buf_p++;
00090 targa_header.attributes = *buf_p++;
00091
00092 if (targa_header.image_type != 2 && targa_header.image_type != 10)
00093 Sys_Error("LoadTGA: Only type 2 and 10 targa RGB images supported (%s) (type: %i)", name, targa_header.image_type);
00094
00095 if (targa_header.colormap_type != 0 || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24))
00096 Sys_Error("LoadTGA: Only 32 or 24 bit images supported (no colormaps) (%s) (pixel_size: %i)", name, targa_header.pixel_size);
00097
00098 columns = targa_header.width;
00099 rows = targa_header.height;
00100 numPixels = columns * rows;
00101
00102 if (width)
00103 *width = columns;
00104 if (height)
00105 *height = rows;
00106
00107 targa_rgba = Mem_Alloc(numPixels * 4);
00108 *pic = targa_rgba;
00109
00110 if (targa_header.id_length != 0)
00111 buf_p += targa_header.id_length;
00112
00113 if (targa_header.image_type == 2) {
00114 for (row = rows - 1; row >= 0; row--) {
00115 pixbuf = targa_rgba + row * columns * 4;
00116 for (column = 0; column < columns; column++) {
00117 unsigned char red, green, blue, alphabyte;
00118
00119 red = green = blue = alphabyte = 0;
00120 switch (targa_header.pixel_size) {
00121 case 24:
00122
00123 blue = *buf_p++;
00124 green = *buf_p++;
00125 red = *buf_p++;
00126 *pixbuf++ = red;
00127 *pixbuf++ = green;
00128 *pixbuf++ = blue;
00129 *pixbuf++ = 255;
00130 break;
00131 case 32:
00132 blue = *buf_p++;
00133 green = *buf_p++;
00134 red = *buf_p++;
00135 alphabyte = *buf_p++;
00136 *pixbuf++ = red;
00137 *pixbuf++ = green;
00138 *pixbuf++ = blue;
00139 *pixbuf++ = alphabyte;
00140 break;
00141 default:
00142 break;
00143 }
00144 }
00145 }
00146 } else if (targa_header.image_type == 10) {
00147 unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j;
00148
00149 red = green = blue = alphabyte = 0;
00150 for (row = rows - 1; row >= 0; row--) {
00151 pixbuf = targa_rgba + row * columns * 4;
00152 for (column = 0; column < columns;) {
00153 packetHeader = *buf_p++;
00154
00155 packetSize = 1 + (packetHeader & SCHAR_MAX);
00156 if (packetHeader & 0x80) {
00157 switch (targa_header.pixel_size) {
00158 case 24:
00159 blue = *buf_p++;
00160 green = *buf_p++;
00161 red = *buf_p++;
00162 alphabyte = 255;
00163 break;
00164 case 32:
00165 blue = *buf_p++;
00166 green = *buf_p++;
00167 red = *buf_p++;
00168 alphabyte = *buf_p++;
00169 break;
00170 default:
00171 break;
00172 }
00173
00174 for (j = 0; j < packetSize; j++) {
00175 *pixbuf++ = red;
00176 *pixbuf++ = green;
00177 *pixbuf++ = blue;
00178 *pixbuf++ = alphabyte;
00179 column++;
00180 if (column == columns) {
00181 column = 0;
00182 if (row > 0)
00183 row--;
00184 else
00185 goto breakOut;
00186 pixbuf = targa_rgba + row * columns * 4;
00187 }
00188 }
00189 } else {
00190 for (j = 0; j < packetSize; j++) {
00191 switch (targa_header.pixel_size) {
00192 case 24:
00193 blue = *buf_p++;
00194 green = *buf_p++;
00195 red = *buf_p++;
00196 *pixbuf++ = red;
00197 *pixbuf++ = green;
00198 *pixbuf++ = blue;
00199 *pixbuf++ = 255;
00200 break;
00201 case 32:
00202 blue = *buf_p++;
00203 green = *buf_p++;
00204 red = *buf_p++;
00205 alphabyte = *buf_p++;
00206 *pixbuf++ = red;
00207 *pixbuf++ = green;
00208 *pixbuf++ = blue;
00209 *pixbuf++ = alphabyte;
00210 break;
00211 default:
00212 break;
00213 }
00214 column++;
00215 if (column == columns) {
00216 column = 0;
00217 if (row > 0)
00218 row--;
00219 else
00220 goto breakOut;
00221 pixbuf = targa_rgba + row * columns * 4;
00222 }
00223 }
00224 }
00225 }
00226 breakOut:;
00227 }
00228 }
00229
00230 FS_FreeFile(buffer);
00231 }
00232
00237 int TryLoadTGA (const char *path, miptex_t **mt)
00238 {
00239 byte *pic = NULL;
00240 int width, height;
00241 size_t size;
00242 byte *dest;
00243
00244 LoadTGA(path, &pic, &width, &height);
00245 if (pic == NULL)
00246 return -1;
00247
00248 size = sizeof(*mt) + width * height * 4;
00249 *mt = (miptex_t *)Mem_Alloc(size);
00250
00251 dest = (byte*)(*mt) + sizeof(*mt);
00252 memcpy(dest, pic, width * height * 4);
00253 Mem_Free(pic);
00254
00255
00256 (*mt)->width = width;
00257 (*mt)->height = height;
00258 (*mt)->offsets[0] = sizeof(*mt);
00259
00260 return 0;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269 #include <png.h>
00270
00271 typedef struct pngBuf_s {
00272 byte *buffer;
00273 size_t pos;
00274 } pngBuf_t;
00275
00276 static void PngReadFunc (png_struct *Png, png_bytep buf, png_size_t size)
00277 {
00278 pngBuf_t *PngFileBuffer = (pngBuf_t*)png_get_io_ptr(Png);
00279 memcpy(buf,PngFileBuffer->buffer + PngFileBuffer->pos, size);
00280 PngFileBuffer->pos += size;
00281 }
00282
00287 static void LoadPNG (const char *name, byte **pic, int *width, int *height)
00288 {
00289 int rowptr;
00290 int color_type, bit_depth;
00291 png_structp png_ptr;
00292 png_infop info_ptr;
00293 png_infop end_info;
00294 byte **row_pointers;
00295 byte *img;
00296 uint32_t i;
00297 pngBuf_t PngFileBuffer = {NULL, 0};
00298 png_uint_32 png_height, png_width, rowbytes;
00299 png_byte channels;
00300
00301 if (*pic != NULL)
00302 Sys_Error("possible mem leak in LoadPNG");
00303
00304
00305 FS_LoadFile(name, (byte **)&PngFileBuffer.buffer);
00306 if (!PngFileBuffer.buffer)
00307 return;
00308
00309
00310 if ((png_sig_cmp(PngFileBuffer.buffer, 0, 8)) != 0) {
00311 Com_Printf("LoadPNG: Not a PNG file: %s\n", name);
00312 FS_FreeFile(PngFileBuffer.buffer);
00313 return;
00314 }
00315
00316 PngFileBuffer.pos = 0;
00317
00318 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00319 if (!png_ptr) {
00320 Com_Printf("LoadPNG: Bad PNG file: %s\n", name);
00321 FS_FreeFile(PngFileBuffer.buffer);
00322 return;
00323 }
00324
00325 info_ptr = png_create_info_struct(png_ptr);
00326 if (!info_ptr) {
00327 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00328 Com_Printf("LoadPNG: Bad PNG file: %s\n", name);
00329 FS_FreeFile(PngFileBuffer.buffer);
00330 return;
00331 }
00332
00333 end_info = png_create_info_struct(png_ptr);
00334 if (!end_info) {
00335 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00336 Com_Printf("LoadPNG: Bad PNG file: %s\n", name);
00337 FS_FreeFile(PngFileBuffer.buffer);
00338 return;
00339 }
00340
00341
00342 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
00343 color_type = png_get_color_type(png_ptr, info_ptr);
00344
00352
00353 if (color_type == PNG_COLOR_TYPE_PALETTE)
00354 png_set_palette_to_rgb(png_ptr);
00355
00356 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
00357 png_set_expand_gray_1_2_4_to_8(png_ptr);
00358 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
00359 png_set_tRNS_to_alpha(png_ptr);
00360
00361 if (bit_depth == 16)
00362 png_set_strip_16(png_ptr);
00363 else if (bit_depth < 8)
00364 png_set_packing(png_ptr);
00365
00366 png_set_read_fn(png_ptr, (png_voidp)&PngFileBuffer, (png_rw_ptr)PngReadFunc);
00367 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
00368 row_pointers = png_get_rows(png_ptr, info_ptr);
00369 rowptr = 0;
00370
00371 png_height = png_get_image_height(png_ptr, info_ptr);
00372 png_width = png_get_image_width(png_ptr, info_ptr);
00373 img = Mem_Alloc(png_width * png_height * 4);
00374 if (pic)
00375 *pic = img;
00376
00377 channels = png_get_channels(png_ptr, info_ptr);
00378 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
00379 if (channels == 4) {
00380 for (i = 0; i < png_height; i++) {
00381 memcpy(img + rowptr, row_pointers[i], rowbytes);
00382 rowptr += rowbytes;
00383 }
00384 } else {
00385 uint32_t j;
00386
00387 memset(img, 255, png_width * png_height * 4);
00388 for (rowptr = 0, i = 0; i < png_height; i++) {
00389 for (j = 0; j < rowbytes; j += channels) {
00390 memcpy(img + rowptr, row_pointers[i] + j, channels);
00391 rowptr += 4;
00392 }
00393 }
00394 }
00395
00396 if (width)
00397 *width = (int)png_width;
00398 if (height)
00399 *height = (int)png_height;
00400
00401 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00402
00403 FS_FreeFile(PngFileBuffer.buffer);
00404 }
00405
00410 int TryLoadPNG (const char *path, miptex_t **mt)
00411 {
00412 byte *pic = NULL;
00413 int width, height;
00414 size_t size;
00415 byte *dest;
00416
00417 LoadPNG(path, &pic, &width, &height);
00418 if (pic == NULL)
00419 return -1;
00420
00421 size = sizeof(*mt) + width * height * 4;
00422 *mt = (miptex_t *)Mem_Alloc(size);
00423
00424 dest = (byte*)(*mt) + sizeof(*mt);
00425 memcpy(dest, pic, width * height * 4);
00426 Mem_Free(pic);
00427
00428
00429 (*mt)->width = width;
00430 (*mt)->height = height;
00431 (*mt)->offsets[0] = sizeof(*mt);
00432
00433 return 0;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 static void ufo_jpg_null (j_decompress_ptr cinfo)
00445 {
00446 }
00447
00448 static boolean ufo_jpg_fill_input_buffer (j_decompress_ptr cinfo)
00449 {
00450 Verb_Printf(VERB_EXTRA, "Premature end of JPEG data\n");
00451 return 1;
00452 }
00453
00454 static void ufo_jpg_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
00455 {
00456 if (cinfo->src->bytes_in_buffer < (size_t) num_bytes)
00457 Verb_Printf(VERB_EXTRA, "Premature end of JPEG data\n");
00458
00459 cinfo->src->next_input_byte += (size_t) num_bytes;
00460 cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
00461 }
00462
00463 static void ufo_jpeg_mem_src (j_decompress_ptr cinfo, byte * mem, int len)
00464 {
00465 cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr));
00466 cinfo->src->init_source = ufo_jpg_null;
00467 cinfo->src->fill_input_buffer = ufo_jpg_fill_input_buffer;
00468 cinfo->src->skip_input_data = ufo_jpg_skip_input_data;
00469 cinfo->src->resync_to_restart = jpeg_resync_to_restart;
00470 cinfo->src->term_source = ufo_jpg_null;
00471 cinfo->src->bytes_in_buffer = len;
00472 cinfo->src->next_input_byte = mem;
00473 }
00474
00480 static void LoadJPG (const char *filename, byte ** pic, int *width, int *height)
00481 {
00482 struct jpeg_decompress_struct cinfo;
00483 struct jpeg_error_mgr jerr;
00484 byte *rawdata, *rgbadata, *scanline, *p, *q;
00485 int rawsize, i;
00486
00487 if (*pic != NULL)
00488 Sys_Error("possible mem leak in LoadJPG");
00489
00490
00491 rawsize = FS_LoadFile(filename, (byte **) &rawdata);
00492 if (rawsize == -1)
00493 return;
00494
00495
00496 if (rawdata[6] != 'J' || rawdata[7] != 'F' || rawdata[8] != 'I' || rawdata[9] != 'F') {
00497 Com_Printf("Bad jpg file %s\n", filename);
00498 Mem_Free(rawdata);
00499 return;
00500 }
00501
00502
00503 cinfo.err = jpeg_std_error(&jerr);
00504 jpeg_create_decompress(&cinfo);
00505
00506
00507 ufo_jpeg_mem_src(&cinfo, rawdata, rawsize);
00508
00509
00510 jpeg_read_header(&cinfo, qtrue);
00511
00512
00513 jpeg_start_decompress(&cinfo);
00514
00515
00516 if (cinfo.output_components != 3 && cinfo.output_components != 4) {
00517 Com_Printf("Invalid JPEG colour components\n");
00518 jpeg_destroy_decompress(&cinfo);
00519 Mem_Free(rawdata);
00520 return;
00521 }
00522
00523
00524 rgbadata = Mem_Alloc(cinfo.output_width * cinfo.output_height * 4);
00525 if (!rgbadata) {
00526 Com_Printf("Insufficient RAM for JPEG buffer\n");
00527 jpeg_destroy_decompress(&cinfo);
00528 Mem_Free(rawdata);
00529 return;
00530 }
00531
00532
00533 *width = cinfo.output_width;
00534 *height = cinfo.output_height;
00535
00536
00537 scanline = Mem_Alloc(cinfo.output_width * 4);
00538 if (!scanline) {
00539 Com_Printf("Insufficient RAM for JPEG scanline buffer\n");
00540 Mem_Free(rgbadata);
00541 jpeg_destroy_decompress(&cinfo);
00542 Mem_Free(rawdata);
00543 return;
00544 }
00545
00546
00547 q = rgbadata;
00548 while (cinfo.output_scanline < cinfo.output_height) {
00549 p = scanline;
00550 jpeg_read_scanlines(&cinfo, &scanline, 1);
00551
00552 for (i = 0; i < cinfo.output_width; i++) {
00553 q[0] = p[0];
00554 q[1] = p[1];
00555 q[2] = p[2];
00556 q[3] = 255;
00557
00558 p += 3;
00559 q += 4;
00560 }
00561 }
00562
00563
00564 Mem_Free(scanline);
00565
00566
00567 jpeg_finish_decompress(&cinfo);
00568
00569
00570 jpeg_destroy_decompress(&cinfo);
00571
00572
00573 *pic = rgbadata;
00574 Mem_Free(rawdata);
00575 }
00576
00581 int TryLoadJPG (const char *path, miptex_t **mt)
00582 {
00583 byte *pic = NULL;
00584 int width, height;
00585 size_t size;
00586 byte *dest;
00587
00588 LoadJPG(path, &pic, &width, &height);
00589 if (pic == NULL)
00590 return -1;
00591
00592 size = sizeof(*mt) + width * height * 4;
00593 *mt = (miptex_t *)Mem_Alloc(size);
00594
00595 dest = (byte*)(*mt) + sizeof(*mt);
00596 memcpy(dest, pic, width * height * 4);
00597 Mem_Free(pic);
00598
00599
00600 (*mt)->width = width;
00601 (*mt)->height = height;
00602 (*mt)->offsets[0] = sizeof(*mt);
00603
00604 return 0;
00605 }