]> git.jsancho.org Git - lugaru.git/blob - Source/ImageIO.cpp
eaeef5f2751764f2c62cab33b2ffe40979b1e6fb
[lugaru.git] / Source / ImageIO.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
7 Lugaru is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 Lugaru is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /**> HEADER FILES <**/
22
23 #include <stdio.h>
24 #include <jpeglib.h>
25 #include <png.h>
26 #include <zlib.h>
27
28 #include "Game.h"
29 #include "ImageIO.h"
30
31 extern ImageRec texture;
32 extern bool visibleloading;
33
34 /* These two are needed for screenshot */
35 extern int kContextWidth;
36 extern int kContextHeight;
37
38 static bool load_png(const char * fname, ImageRec & tex);
39 static bool load_jpg(const char * fname, ImageRec & tex);
40 static bool save_screenshot_png(const char * fname);
41
42 bool upload_image(const char* fileName)
43 {
44     return load_image(fileName, texture);
45 }
46
47 bool load_image(const char *file_name, ImageRec &tex)
48 {
49     if (visibleloading)
50         Game::LoadingScreen();
51
52     if ( tex.data == NULL )
53         return false;
54
55     const char *ptr = strrchr((char *)file_name, '.');
56     if (ptr) {
57         if (strcasecmp(ptr + 1, "png") == 0)
58             return load_png(file_name, tex);
59         else if (strcasecmp(ptr + 1, "jpg") == 0)
60             return load_jpg(file_name, tex);
61     }
62
63     STUBBED("Unsupported image type");
64     return false;
65 }
66
67 bool save_screenshot(const char *file_name)
68 {
69     const char *ptr = strrchr((char *)file_name, '.');
70     if (ptr) {
71         if (strcasecmp(ptr + 1, "png") == 0)
72             return save_screenshot_png(file_name);
73     }
74
75     STUBBED("Unsupported image type");
76     return false;
77 }
78
79 struct my_error_mgr {
80     struct jpeg_error_mgr pub; /* "public" fields */
81     jmp_buf setjmp_buffer; /* for return to caller */
82 };
83 typedef struct my_error_mgr * my_error_ptr;
84
85 static void my_error_exit(j_common_ptr cinfo)
86 {
87     struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
88     longjmp(err->setjmp_buffer, 1);
89 }
90
91 /* stolen from public domain example.c code in libjpg distribution. */
92 static bool load_jpg(const char *file_name, ImageRec &tex)
93 {
94     struct jpeg_decompress_struct cinfo;
95     struct my_error_mgr jerr;
96     JSAMPROW buffer[1]; /* Output row buffer */
97     int row_stride; /* physical row width in output buffer */
98     FILE *infile = fopen(file_name, "rb");
99
100     if (infile == NULL)
101         return false;
102
103     cinfo.err = jpeg_std_error(&jerr.pub);
104     jerr.pub.error_exit = my_error_exit;
105     if (setjmp(jerr.setjmp_buffer)) {
106         jpeg_destroy_decompress(&cinfo);
107         fclose(infile);
108         return false;
109     }
110
111     jpeg_create_decompress(&cinfo);
112     jpeg_stdio_src(&cinfo, infile);
113     (void) jpeg_read_header(&cinfo, TRUE);
114
115     cinfo.out_color_space = JCS_RGB;
116     cinfo.quantize_colors = 0;
117     (void) jpeg_calc_output_dimensions(&cinfo);
118     (void) jpeg_start_decompress(&cinfo);
119
120     row_stride = cinfo.output_width * cinfo.output_components;
121     tex.sizeX = cinfo.output_width;
122     tex.sizeY = cinfo.output_height;
123     tex.bpp = 24;
124
125     while (cinfo.output_scanline < cinfo.output_height) {
126         buffer[0] = (JSAMPROW)(char *)tex.data +
127                     ((cinfo.output_height - 1) - cinfo.output_scanline) * row_stride;
128         (void) jpeg_read_scanlines(&cinfo, buffer, 1);
129     }
130
131     (void) jpeg_finish_decompress(&cinfo);
132     jpeg_destroy_decompress(&cinfo);
133     fclose(infile);
134
135     return true;
136 }
137
138 /* stolen from public domain example.c code in libpng distribution. */
139 static bool load_png(const char *file_name, ImageRec &tex)
140 {
141     bool hasalpha = false;
142     png_structp png_ptr = NULL;
143     png_infop info_ptr = NULL;
144     png_uint_32 width, height;
145     int bit_depth, color_type, interlace_type;
146     bool retval = false;
147     png_byte **row_pointers = NULL;
148     FILE *fp = fopen(file_name, "rb");
149
150     if (fp == NULL) {
151         cerr << file_name << " not found" << endl;
152         return(NULL);
153     }
154
155     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
156     if (png_ptr == NULL)
157         goto png_done;
158
159     info_ptr = png_create_info_struct(png_ptr);
160     if (info_ptr == NULL)
161         goto png_done;
162
163     if (setjmp(png_jmpbuf(png_ptr)))
164         goto png_done;
165
166     png_init_io(png_ptr, fp);
167     png_read_png(png_ptr, info_ptr,
168                  PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING,
169                  NULL);
170     png_get_IHDR(png_ptr, info_ptr, &width, &height,
171                  &bit_depth, &color_type, &interlace_type, NULL, NULL);
172
173     if (bit_depth != 8)  // transform SHOULD handle this...
174         goto png_done;
175
176     if (color_type & PNG_COLOR_MASK_PALETTE)  // !!! FIXME?
177         goto png_done;
178
179     if ((color_type & PNG_COLOR_MASK_COLOR) == 0)  // !!! FIXME?
180         goto png_done;
181
182     hasalpha = ((color_type & PNG_COLOR_MASK_ALPHA) != 0);
183     row_pointers = png_get_rows(png_ptr, info_ptr);
184     if (!row_pointers)
185         goto png_done;
186
187     if (!hasalpha) {
188         png_byte *dst = tex.data;
189         for (int i = height - 1; i >= 0; i--) {
190             png_byte *src = row_pointers[i];
191             for (unsigned j = 0; j < width; j++) {
192                 dst[0] = src[0];
193                 dst[1] = src[1];
194                 dst[2] = src[2];
195                 dst[3] = 0xFF;
196                 src += 3;
197                 dst += 4;
198             }
199         }
200     }
201
202     else {
203         png_byte *dst = tex.data;
204         int pitch = width * 4;
205         for (int i = height - 1; i >= 0; i--, dst += pitch)
206             memcpy(dst, row_pointers[i], pitch);
207     }
208
209     tex.sizeX = width;
210     tex.sizeY = height;
211     tex.bpp = 32;
212     retval = true;
213
214 png_done:
215     if (!retval) {
216         cerr << "There was a problem loading " << file_name << endl;
217     }
218     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
219     if (fp)
220         fclose(fp);
221     return (retval);
222 }
223
224 static bool save_screenshot_png(const char *file_name)
225 {
226     FILE *fp = NULL;
227     png_structp png_ptr = NULL;
228     png_infop info_ptr = NULL;
229     bool retval = false;
230
231     fp = fopen(file_name, "wb");
232     if (fp == NULL)
233         return false;
234
235     png_bytep *row_pointers = new png_bytep[kContextHeight];
236     png_bytep screenshot = new png_byte[kContextWidth * kContextHeight * 3];
237     if ((!screenshot) || (!row_pointers))
238         goto save_png_done;
239
240     glGetError();
241     glReadPixels(0, 0, kContextWidth, kContextHeight,
242                  GL_RGB, GL_UNSIGNED_BYTE, screenshot);
243     if (glGetError() != GL_NO_ERROR)
244         goto save_png_done;
245
246     for (int i = 0; i < kContextHeight; i++)
247         row_pointers[i] = screenshot + ((kContextWidth * ((kContextHeight - 1) - i)) * 3);
248
249     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
250     if (png_ptr == NULL)
251         goto save_png_done;
252
253     info_ptr = png_create_info_struct(png_ptr);
254     if (info_ptr == NULL)
255         goto save_png_done;
256
257     if (setjmp(png_jmpbuf(png_ptr)))
258         goto save_png_done;
259
260     png_init_io(png_ptr, fp);
261
262     if (setjmp(png_jmpbuf(png_ptr)))
263         goto save_png_done;
264
265     png_set_IHDR(png_ptr, info_ptr, kContextWidth, kContextHeight,
266                  8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
267                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
268
269     png_write_info(png_ptr, info_ptr);
270
271     if (setjmp(png_jmpbuf(png_ptr)))
272         goto save_png_done;
273
274     png_write_image(png_ptr, row_pointers);
275
276     if (setjmp(png_jmpbuf(png_ptr)))
277         goto save_png_done;
278
279     png_write_end(png_ptr, NULL);
280     retval = true;
281
282 save_png_done:
283     png_destroy_write_struct(&png_ptr, &info_ptr);
284     delete[] screenshot;
285     delete[] row_pointers;
286     if (fp)
287         fclose(fp);
288     if (!retval)
289         unlink(ConvertFileName(file_name));
290     return retval;
291 }