Suggestion from "mgh".
[open-ps2-loader.git] / src / textures.c
blob125d2dfe397f9939193880852872b4aabcb38a23
1 #include "include/usbld.h"
2 #include "include/textures.h"
3 #include "include/util.h"
4 #include "include/ioman.h"
5 #include <libjpg.h>
6 #include <png.h>
8 extern void *load0_png;
9 extern void *load1_png;
10 extern void *load2_png;
11 extern void *load3_png;
12 extern void *load4_png;
13 extern void *load5_png;
14 extern void *load6_png;
15 extern void *load7_png;
16 extern void *usb_png;
17 extern void *hdd_png;
18 extern void *eth_png;
19 extern void *app_png;
21 extern void *cross_png;
22 extern void *triangle_png;
23 extern void *circle_png;
24 extern void *square_png;
25 extern void *select_png;
26 extern void *start_png;
27 extern void *left_png;
28 extern void *right_png;
29 extern void *up_png;
30 extern void *down_png;
31 extern void *L1_png;
32 extern void *L2_png;
33 extern void *R1_png;
34 extern void *R2_png;
36 extern void *logo_png;
38 // Not related to screen size, just to limit at some point
39 static int maxWidth = 640;
40 static int maxHeight = 512;
42 typedef struct {
43 int id;
44 char* name;
45 void** texture;
46 } texture_t;
48 static texture_t internalDefault[TEXTURES_COUNT] = {
49 { LOAD0_ICON, "load0", &load0_png },
50 { LOAD1_ICON, "load1", &load1_png },
51 { LOAD2_ICON, "load2", &load2_png },
52 { LOAD3_ICON, "load3", &load3_png },
53 { LOAD4_ICON, "load4", &load4_png },
54 { LOAD5_ICON, "load5", &load5_png },
55 { LOAD6_ICON, "load6", &load6_png },
56 { LOAD7_ICON, "load7", &load7_png },
57 { USB_ICON, "usb", &usb_png },
58 { HDD_ICON, "hdd", &hdd_png },
59 { ETH_ICON, "eth", &eth_png },
60 { APP_ICON, "app", &app_png },
61 { LEFT_ICON, "left", &left_png },
62 { RIGHT_ICON, "right", &right_png },
63 { UP_ICON, "up", &up_png },
64 { DOWN_ICON, "down", &down_png },
65 { CROSS_ICON, "cross", &cross_png },
66 { TRIANGLE_ICON, "triangle", &triangle_png },
67 { CIRCLE_ICON, "circle", &circle_png },
68 { SQUARE_ICON, "square", &square_png },
69 { SELECT_ICON, "select", &select_png },
70 { START_ICON, "start", &start_png },
71 { L1_ICON, "L1", &L1_png },
72 { L2_ICON, "L2", &L2_png },
73 { R1_ICON, "R1", &R1_png },
74 { R2_ICON, "R2", &R2_png },
75 { LOGO_PICTURE, "logo", &logo_png },
78 static void texUpdate(GSTEXTURE* texture, int width, int height) {
79 texture->Width = width;
80 texture->Height = height;
83 void texPrepare(GSTEXTURE* texture, short psm) {
84 texture->PSM = psm;
85 texture->ClutPSM = 0;
86 texture->Filter = GS_FILTER_LINEAR;
87 texture->Mem = NULL;
88 texture->Vram = 0;
89 texture->VramClut = 0;
90 texture->Clut = NULL;
91 //gsKit_setup_tbw(texture); already done in gsKit_texture_upload
94 int texDiscoverLoad(GSTEXTURE* texture, char* path, int texId, short psm) {
95 int rc = texPngLoad(texture, path, texId, psm);
97 if (rc < 0) {
98 init_scr();
99 scr_clear();
100 scr_printf("PNG EXIT CODE: %d\n", rc);
101 sleep(20);
104 if (rc >= 0)
105 return 0;
106 else if (psm == GS_PSM_CT24)
107 return texJpgLoad(texture, path, texId, psm);
108 return ERR_BAD_FILE;
112 /// PNG SUPPORT ///////////////////////////////////////////////////////////////////////////////////////
115 static int texPngEnd(png_structp pngPtr, png_infop infoPtr, FILE* file, int status) {
116 if (file != NULL)
117 fclose(file);
119 if (infoPtr != NULL)
120 png_destroy_read_struct(&pngPtr, &infoPtr, (png_infopp) NULL);
122 return status;
125 static void texPngReadFunction(png_structp pngPtr, png_bytep data, png_size_t length)
127 FILE* File = (FILE*) pngPtr->io_ptr;
128 if(fread(data, length, 1, File) <= 0)
130 png_error(pngPtr, "Error reading via fread\n");
131 return;
135 static void texPngReadMemFunction(png_structp pngPtr, png_bytep data, png_size_t length)
137 u8* memBuffer = (u8*) pngPtr->io_ptr;
138 memcpy(data, memBuffer, length);
139 pngPtr->io_ptr = memBuffer + length;
143 static void texPngReadPixels24(GSTEXTURE* texture, png_bytep* rowPointers) {
144 struct pixel3 { unsigned char r,g,b; };
145 struct pixel3 *Pixels = (struct pixel3 *) texture->Mem;
147 int i, j, k = 0;
148 for (i = 0; i < texture->Height; i++) {
149 for (j = 0; j < texture->Width; j++) {
150 memcpy(&Pixels[k++], &rowPointers[i][4 * j], 3);
155 static void texPngReadPixels32(GSTEXTURE* texture, png_bytep* rowPointers) {
156 struct pixel { unsigned char r,g,b,a; };
157 struct pixel *Pixels = (struct pixel *) texture->Mem;
159 int i, j, k = 0;
160 for (i = 0; i < texture->Height; i++) {
161 for (j = 0; j < texture->Width; j++) {
162 memcpy(&Pixels[k], &rowPointers[i][4 * j], 3);
163 Pixels[k++].a = rowPointers[i][4 * j + 3] >> 1;
168 static void texPngReadData(GSTEXTURE* texture, png_structp pngPtr, png_infop infoPtr,
169 void (*texPngReadPixels)(GSTEXTURE* texture, png_bytep *rowPointers)) {
170 int row, rowBytes = png_get_rowbytes(pngPtr, infoPtr);
171 size_t size = gsKit_texture_size_ee(texture->Width, texture->Height, texture->PSM);
172 texture->Mem = memalign(128, size);
174 // failed allocation
175 if (!texture->Mem) {
176 LOG("TEXTURES PngReadData: Failed to allocate %d bytes\n", size);
177 return;
180 png_bytep *rowPointers = calloc(texture->Height, sizeof(png_bytep));
181 for (row = 0; row < texture->Height; row++) {
182 rowPointers[row] = malloc(rowBytes);
184 png_read_image(pngPtr, rowPointers);
186 texPngReadPixels(texture, rowPointers);
188 for (row = 0; row < texture->Height; row++)
189 free(rowPointers[row]);
191 free(rowPointers);
193 png_read_end(pngPtr, NULL);
196 int texPngLoad(GSTEXTURE* texture, char* path, int texId, short psm) {
197 texPrepare(texture, psm);
198 png_structp pngPtr = NULL;
199 png_infop infoPtr = NULL;
200 png_voidp readData = NULL;
201 png_rw_ptr readFunction = NULL;
202 FILE* file = NULL;
204 if (path) {
205 char filePath[255];
206 if (texId != -1)
207 snprintf(filePath, 255, "%s%s.png", path, internalDefault[texId].name);
208 else
209 snprintf(filePath, 255, "%s.png", path);
211 file = fopen(filePath, "r");
212 if (file == NULL)
213 return ERR_BAD_FILE;
215 readData = file;
216 readFunction = &texPngReadFunction;
218 else {
219 readData = internalDefault[texId].texture;
220 if (!readData)
221 return ERR_BAD_FILE;
223 readFunction = &texPngReadMemFunction;
226 pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL);
227 if(!pngPtr)
228 return texPngEnd(pngPtr, infoPtr, file, ERR_READ_STRUCT);
230 infoPtr = png_create_info_struct(pngPtr);
231 if(!infoPtr)
232 return texPngEnd(pngPtr, infoPtr, file, ERR_INFO_STRUCT);
234 if(setjmp(pngPtr->jmpbuf))
235 return texPngEnd(pngPtr, infoPtr, file, ERR_SET_JMP);
237 png_set_read_fn(pngPtr, readData, readFunction);
238 unsigned int sigRead = 0;
239 png_set_sig_bytes(pngPtr, sigRead);
240 png_read_info(pngPtr, infoPtr);
242 png_uint_32 pngWidth, pngHeight;
243 int bitDepth, colorType, interlaceType;
244 png_get_IHDR(pngPtr, infoPtr, &pngWidth, &pngHeight, &bitDepth, &colorType, &interlaceType, NULL, NULL);
245 if (pngWidth > maxWidth || pngHeight > maxHeight)
246 return texPngEnd(pngPtr, infoPtr, file, ERR_BAD_DIMENSION);
247 texUpdate(texture, pngWidth, pngHeight);
249 void (*texPngReadPixels)(GSTEXTURE* texture, png_bytep *rowPointers);
250 if(pngPtr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
252 // if PNG have alpha, then it fits for every case (even if we only wanted RGB)
253 texture->PSM = GS_PSM_CT32;
254 texPngReadPixels = &texPngReadPixels32;
256 else if(pngPtr->color_type == PNG_COLOR_TYPE_RGB)
258 if (psm != GS_PSM_CT24)
259 return texPngEnd(pngPtr, infoPtr, file, ERR_MISSING_ALPHA);
261 texPngReadPixels = &texPngReadPixels24;
263 else
264 return texPngEnd(pngPtr, infoPtr, file, ERR_BAD_DEPTH);
266 png_set_strip_16(pngPtr);
268 if (colorType == PNG_COLOR_TYPE_PALETTE)
269 png_set_expand(pngPtr);
271 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)
272 png_set_expand(pngPtr);
274 if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS))
275 png_set_tRNS_to_alpha(pngPtr);
277 png_set_filler(pngPtr, 0xff, PNG_FILLER_AFTER);
278 png_read_update_info(pngPtr, infoPtr);
279 texPngReadData(texture, pngPtr, infoPtr, texPngReadPixels);
281 return texPngEnd(pngPtr, infoPtr, file, 0);
285 /// JPG SUPPORT ///////////////////////////////////////////////////////////////////////////////////////
288 int texJpgLoad(GSTEXTURE* texture, char* path, int texId, short psm) {
289 texPrepare(texture, GS_PSM_CT24);
290 int result = ERR_BAD_FILE;
291 jpgData *jpg = NULL;
292 char filePath[255];
294 if (texId != -1)
295 snprintf(filePath, 255, "%s%s.jpg", path, internalDefault[texId].name);
296 else
297 snprintf(filePath, 255, "%s.jpg", path);
298 FILE* file = fopen(filePath, "r");
299 if (file) {
300 jpg = jpgOpenFILE(file, JPG_NORMAL);
301 if (jpg != NULL) {
302 if (jpg->width > maxWidth || jpg->height > maxHeight)
303 return ERR_BAD_DIMENSION;
305 size_t size = gsKit_texture_size_ee(jpg->width, jpg->height, psm);
306 texture->Mem = memalign(128, size);
308 // failed allocation
309 if (!texture->Mem) {
310 LOG("TEXTURES JpgLoad: Failed to allocate %d bytes\n", size);
311 } else {
312 // okay
313 texUpdate(texture, jpg->width, jpg->height);
315 jpgReadImage(jpg, (void*) texture->Mem);
316 result = 0;
321 if (jpg)
322 jpgClose(jpg);
324 if (file)
325 fclose(file);
327 return result;