1 /*
2  * OpenBOR - http://www.LavaLit.com
3  * -----------------------------------------------------------------------
4  * Licensed under the BSD license, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2011 OpenBOR Team
7  */
8 
9 #include <pspdisplay.h>
10 #include <stdlib.h>
11 #include <png.h>
12 #include "image.h"
13 #include "graphics.h"
14 
getNextPower2(int width)15 static int getNextPower2(int width)
16 {
17 	int b = width;
18 	int n;
19 	for(n = 0; b != 0; n++) b >>= 1;
20 	b = 1 << n;
21 	if(b == 2 * width) b >>= 1;
22 	return b;
23 }
24 
drawLine(int x0,int y0,int x1,int y1,int color,Color * destination,int width)25 static void drawLine(int x0, int y0, int x1, int y1, int color, Color* destination, int width)
26 {
27 	int dy = y1 - y0;
28 	int dx = x1 - x0;
29 	int stepx, stepy;
30 
31 	if(dy < 0)
32 	{
33 		dy = -dy;
34 		stepy = -width;
35 	}
36 	else stepy = width;
37 
38 	if(dx < 0)
39 	{
40 		dx = -dx;
41 		stepx = -1;
42 	}
43 	else stepx = 1;
44 
45 	dy <<= 1;
46 	dx <<= 1;
47 
48 	y0 *= width;
49 	y1 *= width;
50 	destination[x0+y0] = color;
51 	if(dx > dy)
52 	{
53 		int fraction = dy - (dx >> 1);
54 		while(x0 != x1)
55 		{
56 			if (fraction >= 0)
57 			{
58 				y0 += stepy;
59 				fraction -= dx;
60 			}
61 			x0 += stepx;
62 			fraction += dy;
63 			destination[x0+y0] = color;
64 		}
65 	}
66 	else
67 	{
68 		int fraction = dx - (dy >> 1);
69 		while(y0 != y1)
70 		{
71 			if(fraction >= 0)
72 			{
73 				x0 += stepx;
74 				fraction -= dy;
75 			}
76 			y0 += stepy;
77 			fraction += dx;
78 			destination[x0+y0] = color;
79 		}
80 	}
81 }
82 
user_warning_fn(png_structp png_ptr,png_const_charp warning_msg)83 void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg)
84 {
85 }
86 
loadPNGImage(const char * filename)87 Image *loadPNGImage(const char* filename)
88 {
89 	png_structp png_ptr;
90 	png_infop info_ptr;
91 	unsigned int sig_read = 0;
92 	png_uint_32 width, height;
93 	int bit_depth, color_type, interlace_type, x, y;
94 	u32* line;
95 	FILE *fp;
96 
97 	if((fp = fopen(filename, "rb")) == NULL) return NULL;
98 	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
99 	if(png_ptr == NULL)
100 	{
101 		fclose(fp);
102 		return NULL;;
103 	}
104 	png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, user_warning_fn);
105 	info_ptr = png_create_info_struct(png_ptr);
106 	if(info_ptr == NULL)
107 	{
108 		fclose(fp);
109 		png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
110 		return NULL;
111 	}
112 	if(setjmp(png_jmpbuf(png_ptr)))
113 	{
114 		fclose(fp);
115 		png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
116 		return NULL;
117 	}
118 
119 	png_init_io(png_ptr, fp);
120 	png_set_sig_bytes(png_ptr, sig_read);
121 	png_read_info(png_ptr, info_ptr);
122 	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL);
123 
124 	png_set_strip_16(png_ptr);
125 	png_set_packing(png_ptr);
126 	if(color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
127 	if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);
128 	if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
129 	png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
130 
131 	Image *image = createImage(width, height);
132 	if(image == NULL)
133 	{
134 		fclose(fp);
135 		png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
136 		return NULL;
137 	}
138 
139 	line = (u32*)malloc(width * 4);
140 	if(!line)
141 	{
142 		freeImage(image);
143 		fclose(fp);
144 		png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
145 		return NULL;
146 	}
147 	for(y=0; y<height; y++)
148 	{
149 		png_read_row(png_ptr, (u8*) line, png_bytep_NULL);
150 		for(x=0; x<width; x++)
151 		{
152 			u32 color = line[x];
153 			image->data[x + y * image->textureWidth] =  color;
154 		}
155 	}
156 	free(line);
157 	png_read_end(png_ptr, info_ptr);
158 	png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
159 	fclose(fp);
160 	return image;
161 }
162 
loadImage(const char * filename)163 Image* loadImage(const char* filename)
164 {
165 	return loadPNGImage(filename);
166 }
167 
savePNGImage(const char * filename)168 void savePNGImage(const char* filename)
169 {
170 	u32* vram32;
171 	u16* vram16;
172 	int bufferwidth;
173 	int pixelformat;
174 	int sync = 0;
175 	int i, x, y;
176 	png_structp png_ptr;
177 	png_infop info_ptr;
178 	FILE* fp;
179 	u8* line;
180 
181 	fp = fopen(filename, "wb");
182 	if(!fp) return;
183 	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
184 	if(!png_ptr) return;
185 	info_ptr = png_create_info_struct(png_ptr);
186 	if(!info_ptr)
187 	{
188 		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
189 		fclose(fp);
190 		return;
191 	}
192 	png_init_io(png_ptr, fp);
193 	png_set_IHDR(png_ptr, info_ptr, PSP_LCD_WIDTH, PSP_LCD_HEIGHT,
194 		         8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
195 		         PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
196 	png_write_info(png_ptr, info_ptr);
197 	line = (u8*)malloc(PSP_LCD_WIDTH * 3);
198 	sceDisplayWaitVblankStart();  // if framebuf was set with PSP_LCD_SETBUF_NEXTFRAME, wait until it is changed
199 	sceDisplayGetFrameBuf((void*)&vram32, &bufferwidth, &pixelformat, sync);
200 	vram16 = (u16*)vram32;
201 	for(y=0; y<PSP_LCD_HEIGHT; y++)
202 	{
203 		for(i=0, x=0; x<PSP_LCD_WIDTH; x++)
204 		{
205 			u32 color = 0;
206 			u8 r = 0, g = 0, b = 0;
207 			switch (pixelformat)
208 			{
209 				case PSP_DISPLAY_PIXEL_FORMAT_565:
210 					color = vram16[x + y * bufferwidth];
211 					r = (color & 0x1f) << 3;
212 					g = ((color >> 5) & 0x3f) << 2 ;
213 					b = ((color >> 11) & 0x1f) << 3 ;
214 					break;
215 				case PSP_DISPLAY_PIXEL_FORMAT_5551:
216 					color = vram16[x + y * bufferwidth];
217 					r = (color & 0x1f) << 3;
218 					g = ((color >> 5) & 0x1f) << 3 ;
219 					b = ((color >> 10) & 0x1f) << 3 ;
220 					break;
221 				case PSP_DISPLAY_PIXEL_FORMAT_4444:
222 					color = vram16[x + y * bufferwidth];
223 					r = (color & 0xf) << 4;
224 					g = ((color >> 4) & 0xf) << 4 ;
225 					b = ((color >> 8) & 0xf) << 4 ;
226 					break;
227 				case PSP_DISPLAY_PIXEL_FORMAT_8888:
228 					color = vram32[x + y * bufferwidth];
229 					r = color & 0xff;
230 					g = (color >> 8) & 0xff;
231 					b = (color >> 16) & 0xff;
232 					break;
233 			}
234 			line[i++] = r;
235 			line[i++] = g;
236 			line[i++] = b;
237 		}
238 		png_write_row(png_ptr, line);
239 	}
240 	free(line);
241 	line = NULL;
242 	png_write_end(png_ptr, info_ptr);
243 	png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
244 	fclose(fp);
245 }
246 
saveImage(const char * filename)247 void saveImage(const char* filename)
248 {
249 	savePNGImage(filename);
250 }
251 
createImage(int width,int height)252 Image* createImage(int width, int height)
253 {
254 	Image* image = (Image*) malloc(sizeof(Image));
255 	if(!image) return NULL;
256 	image->imageWidth = width;
257 	image->imageHeight = height;
258 	image->textureWidth = getNextPower2(width);
259 	image->textureHeight = getNextPower2(height);
260 	image->data = (Color*) memalign(16, image->textureWidth * image->textureHeight * sizeof(Color));
261 	if(!image->data)
262 	{
263 		free(image);
264 		image = NULL;
265 		return NULL;
266 	}
267 	memset(image->data, 0, image->textureWidth * image->textureHeight * sizeof(Color));
268 	return image;
269 }
270 
freeImage(Image * image)271 void freeImage(Image* image)
272 {
273 	free(image->data);
274 	image->data = NULL;
275 	free(image);
276 	image = NULL;
277 }
278 
clearImage(Image * image,Color color)279 void clearImage(Image* image, Color color)
280 {
281 	int i;
282 	int size = image->textureWidth * image->textureHeight;
283 	Color* data = image->data;
284 	for(i=0; i<size; i++, data++) *data = color;
285 }
286 
putPixelToImage(Image * image,Color color,int x,int y)287 void putPixelToImage(Image* image, Color color, int x, int y)
288 {
289 	image->data[x + y * image->textureWidth] = color;
290 }
291 
getPixelFromImage(Image * image,int x,int y)292 Color getPixelFromImage(Image* image, int x, int y)
293 {
294 	return image->data[x + y * image->textureWidth];
295 }
296 
drawLineInImage(Image * image,Color color,int x0,int y0,int x1,int y1)297 void drawLineInImage(Image* image, Color color, int x0, int y0, int x1, int y1)
298 {
299 	drawLine(x0, y0, x1, y1, color, image->data, image->textureWidth);
300 }
301 
fillImageRect(Image * image,Color color,int x0,int y0,int width,int height)302 void fillImageRect(Image* image, Color color, int x0, int y0, int width, int height)
303 {
304 	int skipX = image->textureWidth - width;
305 	int x, y;
306 	Color* data = image->data + x0 + y0 * image->textureWidth;
307 	for(y=0; y<height; y++, data+=skipX)
308 	{
309 		for(x=0; x<width; x++, data++) *data = color;
310 	}
311 }
312 
fillImageEllipse(Image * image,Color color,int x0,int y0,int width,int height,int r)313 void fillImageEllipse(Image* image, Color color, int x0, int y0, int width, int height, int r)
314 {
315 	int skipX = image->textureWidth - width;
316 	int x, y;
317 	Color* data = image->data + x0 + y0 * image->textureWidth;
318 	for(y=0; y<height; y++, data+=skipX)
319 	{
320 		for(x=0; x<width; x++, data++)
321 		{
322 			if((x < r) && (y < r)  && ((r-x)*(r-x)+(r-y)*(r-y) > r*r))
323 				continue;
324 			else if ((x < r) && (y > height-r-1)  && ((r-x)*(r-x)+(y-height+r+1)*(y-height+r+1) > r*r))
325 				continue;
326 			else if ((x > width-r-1) && (y < r)  && ((x-width+r+1)*(x-width+r+1)+(r-y)*(r-y) > r*r))
327 				continue;
328 			else if ((x > width-r-1) && (y > height-r-1)  && ((x-width+r+1)*(x-width+r+1)+(y-height+r+1)*(y-height+r+1) > r*r))
329 				continue;
330 			else
331 				*data = color;
332 		}
333 	}
334 }
335 
copyImageToImage(int sx,int sy,int width,int height,Image * source,int dx,int dy,Image * destination)336 void copyImageToImage(int sx, int sy, int width, int height, Image* source, int dx, int dy, Image* destination)
337 {
338 	Color* destinationData = &destination->data[destination->textureWidth * dy + dx];
339 	int destinationSkipX = destination->textureWidth - width;
340 	Color* sourceData = &source->data[source->textureWidth * sy + sx];
341 	int sourceSkipX = source->textureWidth - width;
342 	int x, y;
343 	for(y=0; y<height; y++, destinationData+=destinationSkipX, sourceData+=sourceSkipX)
344 	{
345 		for(x=0; x<width; x++, destinationData++, sourceData++) *destinationData = *sourceData;
346 	}
347 }
348 
drawImageBox(Image * source,Color background,Color border,int borderwidth)349 void drawImageBox(Image *source, Color background, Color border, int borderwidth)
350 {
351 	fillImageRect(source, background, 0, 0, source->imageWidth, source->imageHeight);
352 	int i, x = source->imageWidth - 1, y = source->imageHeight - 1;
353 	for(i=0; i<borderwidth; i++)
354 	{
355 	    drawLineInImage(source, border, i,         i,     x,     i);  // Top
356 		drawLineInImage(source, border, i,     y - i,     x, y - i);  // Bottom
357 		drawLineInImage(source, border, i,         i,     i,     y);  // Left
358 		drawLineInImage(source, border, x - i,     i, x - i, y - i);  // Right
359 	}
360 }