1 /* Copyright (C) 2010-2020 The RetroArch team
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (image_texture.c).
5 * ---------------------------------------------------------------------------------------
7 * Permission is hereby granted, free of charge,
8 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 #include <formats/image.h>
30 #include <file/nbio.h>
31 #include <string/stdstring.h>
33 enum image_type_enum image_texture_get_type(const char *path)
35 /* We are comparing against a fixed list of file
36 * extensions, the longest (jpeg) being 4 characters
37 * in length. We therefore only need to extract the first
38 * 5 characters from the extension of the input path
39 * to correctly validate a match */
40 const char *ext = NULL;
45 if (string_is_empty(path))
46 return IMAGE_TYPE_NONE;
48 /* Get file extension */
49 ext = strrchr(path, '.');
51 if (!ext || (*(++ext) == '\0'))
52 return IMAGE_TYPE_NONE;
54 /* Copy and convert to lower case */
55 strlcpy(ext_lower, ext, sizeof(ext_lower));
56 string_to_lower(ext_lower);
59 if (string_is_equal(ext_lower, "png"))
60 return IMAGE_TYPE_PNG;
63 if (string_is_equal(ext_lower, "jpg") ||
64 string_is_equal(ext_lower, "jpeg"))
65 return IMAGE_TYPE_JPEG;
68 if (string_is_equal(ext_lower, "bmp"))
69 return IMAGE_TYPE_BMP;
72 if (string_is_equal(ext_lower, "tga"))
73 return IMAGE_TYPE_TGA;
76 return IMAGE_TYPE_NONE;
79 bool image_texture_set_color_shifts(
80 unsigned *r_shift, unsigned *g_shift, unsigned *b_shift,
82 struct texture_image *out_img
90 if (out_img->supports_rgba)
100 bool image_texture_color_convert(unsigned r_shift,
101 unsigned g_shift, unsigned b_shift, unsigned a_shift,
102 struct texture_image *out_img)
104 /* This is quite uncommon. */
105 if (a_shift != 24 || r_shift != 16 || g_shift != 8 || b_shift != 0)
108 uint32_t num_pixels = out_img->width * out_img->height;
109 uint32_t *pixels = (uint32_t*)out_img->pixels;
111 for (i = 0; i < num_pixels; i++)
113 uint32_t col = pixels[i];
114 uint8_t a = (uint8_t)(col >> 24);
115 uint8_t r = (uint8_t)(col >> 16);
116 uint8_t g = (uint8_t)(col >> 8);
117 uint8_t b = (uint8_t)(col >> 0);
118 /* Explicitly cast these to uint32_t to prevent
119 * ASAN runtime error: left shift of 255 by 24 places
120 * cannot be represented in type 'int' */
121 pixels[i] = ((uint32_t)a << a_shift) |
122 ((uint32_t)r << r_shift) |
123 ((uint32_t)g << g_shift) |
124 ((uint32_t)b << b_shift);
135 #define GX_BLIT_LINE_32(off) \
138 const uint16_t *tmp_src = src; \
139 uint16_t *tmp_dst = dst; \
140 for (x = 0; x < width2 >> 3; x++, tmp_src += 8, tmp_dst += 32) \
142 tmp_dst[ 0 + off] = tmp_src[0]; \
143 tmp_dst[ 16 + off] = tmp_src[1]; \
144 tmp_dst[ 1 + off] = tmp_src[2]; \
145 tmp_dst[ 17 + off] = tmp_src[3]; \
146 tmp_dst[ 2 + off] = tmp_src[4]; \
147 tmp_dst[ 18 + off] = tmp_src[5]; \
148 tmp_dst[ 3 + off] = tmp_src[6]; \
149 tmp_dst[ 19 + off] = tmp_src[7]; \
154 static bool image_texture_internal_gx_convert_texture32(
155 struct texture_image *image)
157 unsigned tmp_pitch, width2, i;
158 const uint16_t *src = NULL;
159 uint16_t *dst = NULL;
160 /* Memory allocation in libogc is extremely primitive so try
161 * to avoid gaps in memory when converting by copying over to
162 * a temporary buffer first, then converting over into
163 * main buffer again. */
164 void *tmp = malloc(image->width
165 * image->height * sizeof(uint32_t));
170 memcpy(tmp, image->pixels, image->width
171 * image->height * sizeof(uint32_t));
172 tmp_pitch = (image->width * sizeof(uint32_t)) >> 1;
176 width2 = image->width << 1;
177 src = (uint16_t*)tmp;
178 dst = (uint16_t*)image->pixels;
180 for (i = 0; i < image->height; i += 4, dst += 4 * width2)
193 static bool image_texture_load_internal(
194 enum image_type_enum type,
197 struct texture_image *out_img,
198 unsigned a_shift, unsigned r_shift,
199 unsigned g_shift, unsigned b_shift)
202 bool success = false;
203 void *img = image_transfer_new(type);
208 image_transfer_set_buffer_ptr(img, type, (uint8_t*)ptr, len);
210 if (!image_transfer_start(img, type))
213 while (image_transfer_iterate(img, type));
215 if (!image_transfer_is_valid(img, type))
220 ret = image_transfer_process(img, type,
221 (uint32_t**)&out_img->pixels, len, &out_img->width,
223 } while (ret == IMAGE_PROCESS_NEXT);
225 if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
228 image_texture_color_convert(r_shift, g_shift, b_shift,
232 if (!image_texture_internal_gx_convert_texture32(out_img))
234 image_texture_free(out_img);
243 image_transfer_free(img, type);
248 void image_texture_free(struct texture_image *img)
260 bool image_texture_load_buffer(struct texture_image *out_img,
261 enum image_type_enum type, void *buffer, size_t buffer_len)
263 unsigned r_shift, g_shift, b_shift, a_shift;
264 image_texture_set_color_shifts(&r_shift, &g_shift, &b_shift,
267 if (type != IMAGE_TYPE_NONE)
269 if (image_texture_load_internal(
270 type, buffer, buffer_len, out_img,
271 a_shift, r_shift, g_shift, b_shift))
277 out_img->supports_rgba = false;
278 out_img->pixels = NULL;
285 bool image_texture_load(struct texture_image *out_img,
288 unsigned r_shift, g_shift, b_shift, a_shift;
290 struct nbio_t *handle = NULL;
292 enum image_type_enum type = image_texture_get_type(path);
294 image_texture_set_color_shifts(&r_shift, &g_shift, &b_shift,
297 if (type != IMAGE_TYPE_NONE)
299 handle = (struct nbio_t*)nbio_open(path, NBIO_READ);
302 nbio_begin_read(handle);
304 while (!nbio_iterate(handle));
306 ptr = nbio_get_ptr(handle, &file_len);
311 if (image_texture_load_internal(
313 ptr, file_len, out_img,
314 a_shift, r_shift, g_shift, b_shift))
319 out_img->supports_rgba = false;
320 out_img->pixels = NULL;