OpenTTD
splash.cpp
Go to the documentation of this file.
1 /* $Id: splash.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD 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, version 2.
6  * OpenTTD 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.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #include "../../stdafx.h"
13 #include "../../openttd.h"
14 #include "../../debug.h"
15 #include "../../gfx_func.h"
16 #include "../../fileio_func.h"
17 #include "../../blitter/factory.hpp"
18 #include "../../core/mem_func.hpp"
19 
20 #include "splash.h"
21 
22 #ifdef WITH_PNG
23 
24 #include <png.h>
25 
26 #include "../../safeguards.h"
27 
34 static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message)
35 {
36  DEBUG(misc, 0, "[libpng] error: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
37  longjmp(png_jmpbuf(png_ptr), 1);
38 }
39 
46 static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
47 {
48  DEBUG(misc, 1, "[libpng] warning: %s - %s", message, (char *)png_get_error_ptr(png_ptr));
49 }
50 
55 {
56  FILE *f = FioFOpenFile(SPLASH_IMAGE_FILE, "r", BASESET_DIR);
57  if (f == NULL) return;
58 
59  png_byte header[8];
60  fread(header, sizeof(png_byte), 8, f);
61  if (png_sig_cmp(header, 0, 8) != 0) {
62  fclose(f);
63  return;
64  }
65 
66  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, png_my_error, png_my_warning);
67 
68  if (png_ptr == NULL) {
69  fclose(f);
70  return;
71  }
72 
73  png_infop info_ptr = png_create_info_struct(png_ptr);
74  if (info_ptr == NULL) {
75  png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
76  fclose(f);
77  return;
78  }
79 
80  png_infop end_info = png_create_info_struct(png_ptr);
81  if (end_info == NULL) {
82  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
83  fclose(f);
84  return;
85  }
86 
87  if (setjmp(png_jmpbuf(png_ptr))) {
88  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
89  fclose(f);
90  return;
91  }
92 
93  png_init_io(png_ptr, f);
94  png_set_sig_bytes(png_ptr, 8);
95 
96  png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
97 
98  uint width = png_get_image_width(png_ptr, info_ptr);
99  uint height = png_get_image_height(png_ptr, info_ptr);
100  uint bit_depth = png_get_bit_depth(png_ptr, info_ptr);
101  uint color_type = png_get_color_type(png_ptr, info_ptr);
102 
103  if (color_type != PNG_COLOR_TYPE_PALETTE || bit_depth != 8) {
104  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
105  fclose(f);
106  return;
107  }
108 
109  if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
110  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
111  fclose(f);
112  return;
113  }
114 
115  png_colorp palette;
116  int num_palette;
117  png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
118 
119  png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr);
120 
121  if (width > (uint) _screen.width) width = _screen.width;
122  if (height > (uint) _screen.height) height = _screen.height;
123 
124  uint xoff = (_screen.width - width) / 2;
125  uint yoff = (_screen.height - height) / 2;
126 
128  case 8: {
129  uint8 *dst_ptr = (uint8 *)_screen.dst_ptr;
130  /* Initialize buffer */
131  MemSetT(dst_ptr, 0xff, _screen.pitch * _screen.height);
132 
133  for (uint y = 0; y < height; y++) {
134  uint8 *src = row_pointers[y];
135  uint8 *dst = dst_ptr + (yoff + y) * _screen.pitch + xoff;
136 
137  memcpy(dst, src, width);
138  }
139 
140  for (int i = 0; i < num_palette; i++) {
141  _cur_palette.palette[i].a = i == 0 ? 0 : 0xff;
142  _cur_palette.palette[i].r = palette[i].red;
143  _cur_palette.palette[i].g = palette[i].green;
144  _cur_palette.palette[i].b = palette[i].blue;
145  }
146 
147  _cur_palette.palette[0xff].a = 0xff;
148  _cur_palette.palette[0xff].r = 0;
149  _cur_palette.palette[0xff].g = 0;
150  _cur_palette.palette[0xff].b = 0;
151 
154  break;
155  }
156  case 32: {
157  uint32 *dst_ptr = (uint32 *)_screen.dst_ptr;
158  /* Initialize buffer */
159  MemSetT(dst_ptr, 0, _screen.pitch * _screen.height);
160 
161  for (uint y = 0; y < height; y++) {
162  uint8 *src = row_pointers[y];
163  uint32 *dst = dst_ptr + (yoff + y) * _screen.pitch + xoff;
164 
165  for (uint x = 0; x < width; x++) {
166  dst[x] = palette[src[x]].blue | (palette[src[x]].green << 8) | (palette[src[x]].red << 16) | 0xff000000;
167  }
168  }
169  break;
170  }
171  }
172 
173  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
174  fclose(f);
175  return;
176 }
177 
178 
179 
180 #else /* WITH_PNG */
181 
185 void DisplaySplashImage() {}
186 
187 #endif /* WITH_PNG */