some meshgen and map rendering updates
[voxelands-alt.git] / src / graphics / image.c
blobff75180af74d0004f0eb5e5f45e86082d91e3836
1 /************************************************************************
2 * image.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "common.h"
21 #include "graphics.h"
22 #include "file.h"
24 #include <string.h>
26 static uint32_t merge_colours(uint32_t btm, uint32_t top)
28 fcolour_t f;
29 fcolour_t t;
30 fcolour_t r;
32 f.r = (float)RED(top);
33 f.g = (float)GREEN(top);
34 f.b = (float)BLUE(top);
35 f.a = (float)ALPHA(top);
36 f.a /= 255.0;
37 t.r = (float)RED(btm);
38 t.g = (float)GREEN(btm);
39 t.b = (float)BLUE(btm);
40 t.a = (float)ALPHA(btm);
41 t.a /= 255.0;
43 if (ALPHA(btm) == 0)
44 return top;
45 if (ALPHA(top) == 0)
46 return btm;
48 r.r = f.r * (1.0 - t.a) + (f.r * f.a + t.r * (1.0 - f.a)) * t.a;
49 r.g = f.g * (1.0 - t.a) + (f.g * f.a + t.g * (1.0 - f.a)) * t.a;
50 r.b = f.b * (1.0 - t.a) + (f.b * f.a + t.b * (1.0 - f.a)) * t.a;
51 if (t.a == 1.0) {
52 r.a = 255.0;
53 }else{
54 r.a = t.a * f.a * 255.0;
57 return C2P(r);
60 static uint32_t colourise(uint32_t btm, uint32_t top)
62 fcolour_t f;
63 fcolour_t t;
64 fcolour_t r;
66 f.r = (float)RED(top);
67 f.g = (float)GREEN(top);
68 f.b = (float)BLUE(top);
69 f.a = (float)ALPHA(top);
70 f.a /= 255.0;
71 t.r = (float)RED(btm);
72 t.g = (float)GREEN(btm);
73 t.b = (float)BLUE(btm);
74 t.a = (float)ALPHA(btm);
75 t.a /= 255.0;
77 if (ALPHA(btm) == 0 || ALPHA(top) == 0)
78 return btm;
80 r.r = f.r * (1.0 - t.a) + (f.r * f.a + t.r * (1.0 - f.a)) * t.a;
81 r.g = f.g * (1.0 - t.a) + (f.g * f.a + t.g * (1.0 - f.a)) * t.a;
82 r.b = f.b * (1.0 - t.a) + (f.b * f.a + t.b * (1.0 - f.a)) * t.a;
83 r.a = (float)ALPHA(btm);
85 return C2P(r);
88 /* load an image to pixel data */
89 image_t *image_load(char* type, char* file)
91 /* storage space for the image */
92 file_t* f = NULL;
93 image_t* image = NULL;
95 /* load the file data */
96 f = file_load(type,file);
98 if (!f)
99 return NULL;
101 /* and make in image out of it */
102 image = image_load_frommem(f);
104 file_free(f);
106 return image;
109 /* load an image to pixel data from memory */
110 image_t *image_load_frommem(file_t *f)
112 image_t* image = malloc(sizeof(image_t));
113 if (!image)
114 return NULL;
116 image->pixels = NULL;
117 image->w = 0;
118 image->h = 0;
120 /* bmp image */
121 if (image_is_bmp(f)) {
122 if (image_load_bmp(f,image)) {
123 vlprintf(CN_ERROR, "Image Not Loaded: %s",f->name);
124 free(image);
125 image = NULL;
127 /* png image */
128 }else if (image_is_png(f)) {
129 if (image_load_png(f,image)) {
130 vlprintf(CN_ERROR, "Image Not Loaded: %s",f->name);
131 free(image);
132 image = NULL;
134 /* tga image */
135 }else if (image_is_tga(f)) {
136 if (image_load_tga(f,image)) {
137 vlprintf(CN_ERROR, "Image Not Loaded: %s",f->name);
138 free(image);
139 image = NULL;
141 /* unsupported image */
142 }else{
143 vlprintf(CN_ERROR, "Unsupported Image: %s",f->name);
144 free(image);
145 image = NULL;
148 return image;
151 /* load an image to pixel data from a section of the screen */
152 image_t *image_load_fromscreen(int x, int y, int w, int h, int alpha)
154 int size;
155 image_t *image = malloc(sizeof(image_t));
156 if (!image)
157 return NULL;
159 size = w*h*4;
161 image->pixels = malloc(size);
162 image->w = w;
163 image->h = h;
165 /* if keeping alpha, just grab rgba */
166 if (alpha) {
167 glReadPixels(x,(wm_data.size.height-y)-h,w,h,GL_RGBA,GL_UNSIGNED_BYTE,image->pixels);
168 /* otherwise grab rgb, then reformat with alpha */
169 }else{
170 int i;
171 int o;
172 image_t img;
173 img.w = w;
174 img.h = h;
175 img.pixels = malloc(size);
177 glReadPixels(x,h,w,(wm_data.size.height-y)-h,GL_RGB,GL_UNSIGNED_BYTE,img.pixels);
179 for (i=0,o=0; o<size;) {
180 image->pixels[o++] = 0xFF;
181 image->pixels[o++] = img.pixels[i++];
182 image->pixels[o++] = img.pixels[i++];
183 image->pixels[o++] = img.pixels[i++];
186 free(img.pixels);
189 return image;
192 /* create an image from rgba values */
193 image_t *image_rgba(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
195 char n[100];
196 image_t *img;
197 int size;
198 int i;
200 snprintf(n,100,"rgba-%u-%u-%u-%u-%d-%d",(uint32_t)r,(uint32_t)g,(uint32_t)b,(uint32_t)a,x,y);
202 img = malloc(sizeof(image_t));
203 if (!img)
204 return NULL;
206 img->w = x;
207 img->h = y;
209 size = x*y*4;
211 img->pixels = malloc(sizeof(uint8_t)*size);
212 if (!img->pixels) {
213 free(img);
214 return NULL;
217 i = 0;
218 while (i<size) {
219 img->pixels[i++] = r;
220 img->pixels[i++] = g;
221 img->pixels[i++] = b;
222 img->pixels[i++] = a;
225 return img;
228 /* create a copy of an image */
229 image_t *image_copy(image_t *img)
231 int ds;
232 image_t *p = malloc(sizeof(image_t));
233 if (!p)
234 return NULL;
236 p->w = img->w;
237 p->h = img->h;
239 ds = p->w*p->h*4;
240 p->pixels = malloc(sizeof(unsigned char)*ds);
241 if (!p->pixels) {
242 free(p);
243 return NULL;
246 memcpy(p->pixels,img->pixels,ds);
248 return p;
251 /* clear an image - set all pixels black */
252 void image_clear(image_t *img)
254 int i;
255 int s;
256 uint32_t c = 0xFF000000;
257 if (!img)
258 return;
259 s = img->w*img->h;
260 for (i=0; i<s; i++) {
261 SETPXI(img,i,c);
265 /* draw an open rectangle of colour onto an image */
266 void image_draw_rect(image_t *img, colour_t *c, int width, rect_t *area)
268 rect_t p;
269 rect_t f;
270 rect_t t;
271 int w;
272 if (!img)
273 return;
274 if (area) {
275 p = *area;
276 if (p.x < 0) {
277 p.w += p.x;
278 p.x = 0;
280 if (p.y < 0) {
281 p.h += p.y;
282 p.y = 0;
284 if (p.x+p.w > img->w)
285 p.w = img->w-p.x;
286 if (p.y+p.h > img->h)
287 p.h = img->h-p.y;
288 }else{
289 p.x = 0;
290 p.y = 0;
291 p.w = img->w;
292 p.h = img->h;
294 w = (width/2);
295 p.w += p.x;
296 p.h += p.y;
297 f.x = p.x+w;
298 f.y = p.y;
299 t.x = p.w+w;
300 t.y = p.y;
301 image_draw_line(img,c,width,&f,&t);
302 f.x = p.w;
303 f.y = p.y+w;
304 t.x = p.w;
305 t.y = p.h+w;
306 image_draw_line(img,c,width,&f,&t);
307 f.x = p.x-(width-w);
308 f.y = p.h;
309 t.x = p.w-(width-w);
310 t.y = p.h;
311 image_draw_line(img,c,width,&f,&t);
312 f.x = p.x;
313 f.y = p.y-(width-w);
314 t.x = p.x;
315 t.y = p.h-(width-w);
316 image_draw_line(img,c,width,&f,&t);
319 /* draw a line of colour onto an image */
320 void image_draw_line(image_t *img, colour_t *c, int width, rect_t *from, rect_t *to)
322 int i;
323 int dx;
324 int dy;
325 int sdx;
326 int sdy;
327 int dxabs;
328 int dyabs;
329 int x;
330 int y;
331 int px;
332 int py;
333 int w;
334 uint32_t clr;
335 uint32_t tclr;
336 if (!img || !from || !to)
337 return;
339 clr = C2P(*c);
341 dx=to->x-from->x; /* the horizontal distance of the line */
342 dy=to->y-from->y; /* the vertical distance of the line */
343 dxabs=abs(dx);
344 dyabs=abs(dy);
345 sdx=SGN(dx);
346 sdy=SGN(dy);
347 x=dyabs>>1;
348 y=dxabs>>1;
349 px=from->x;
350 py=from->y;
352 width /= 2;
354 if (dxabs>=dyabs) { /* the line is more horizontal than vertical */
355 for (i=0;i<dxabs;i++) {
356 y+=dyabs;
357 if (y>=dxabs) {
358 y-=dxabs;
359 py+=sdy;
361 px+=sdx;
362 if (px >= img->w || px < 0)
363 continue;
364 for (w=py-width; w<=py+width; w++) {
365 if (w >= img->h || w < 0)
366 continue;
367 tclr = GETPX(img,px,w);
368 tclr = merge_colours(tclr,clr);
369 SETPX(img,px,w,tclr);
372 }else{ /* the line is more vertical than horizontal */
373 for (i=0;i<dyabs;i++) {
374 x+=dxabs;
375 if (x>=dyabs) {
376 x-=dyabs;
377 px+=sdx;
379 py+=sdy;
380 if (py >= img->h || py < 0)
381 continue;
382 for (w=px-width; w<=px+width; w++) {
383 if (w >= img->w || w < 0)
384 continue;
385 tclr = GETPX(img,w,py);
386 tclr = merge_colours(tclr,clr);
387 SETPX(img,w,py,tclr);
393 /* draw a rectangle of colour onto an image */
394 void image_fill_rect(image_t *img, colour_t *c, rect_t *area)
396 int x;
397 int y;
398 rect_t p;
399 uint32_t clr;
400 if (!img)
401 return;
402 if (area) {
403 p = *area;
404 if (p.x < 0) {
405 p.w += p.x;
406 p.x = 0;
408 if (p.y < 0) {
409 p.h += p.y;
410 p.y = 0;
412 if (p.x+p.w > img->w)
413 p.w = img->w-p.x;
414 if (p.y+p.h > img->h)
415 p.h = img->h-p.y;
416 }else{
417 p.x = 0;
418 p.y = 0;
419 p.w = img->w;
420 p.h = img->h;
422 p.w += p.x;
423 p.h += p.y;
424 clr = C2P(*c);
425 for (y=p.y; y<p.h; y++) {
426 for (x=p.x; x<p.w; x++) {
427 SETPX(img,x,y,clr);
432 /* copy pixels from one image to another */
433 void image_copy_area(image_t *dest, image_t *src, rect_t *to, rect_t *from)
435 int x;
436 int y;
437 int fx;
438 int fy;
439 rect_t t;
440 rect_t f;
441 uint32_t clr;
442 if (!src)
443 return;
444 if (!dest)
445 return;
446 if (from) {
447 f = *from;
448 if (f.x < 0) {
449 f.w += f.x;
450 f.x = 0;
452 if (f.y < 0) {
453 f.h += f.y;
454 f.y = 0;
456 if (f.x+f.w > src->w)
457 f.w = src->w-f.x;
458 if (f.y+f.h > src->h)
459 f.h = src->h-f.y;
460 }else{
461 f.x = 0;
462 f.y = 0;
463 f.w = src->w;
464 f.h = src->h;
466 if (to) {
467 t = *to;
468 if (t.x < 0) {
469 t.w += t.x;
470 t.x = 0;
472 if (t.y < 0) {
473 t.h += t.y;
474 t.y = 0;
476 if (t.x+t.w > dest->w)
477 t.w = dest->w-t.x;
478 if (t.y+t.h > dest->h)
479 t.h = dest->h-t.y;
480 }else{
481 t.x = 0;
482 t.y = 0;
483 t.w = dest->w;
484 t.h = dest->h;
486 if (t.w != f.w) {
487 x = t.w;
488 if (x > f.w)
489 x = f.w;
490 t.w = x;
491 f.w = x;
493 if (t.h != f.h) {
494 y = t.h;
495 if (y > f.h)
496 y = f.h;
497 t.h = y;
498 f.h = y;
500 t.w += t.x;
501 t.h += t.y;
502 f.w += f.x;
503 f.h += f.y;
504 for (y=t.y,fy=f.y; y<t.h; y++,fy++) {
505 for (x=t.x,fx=f.x; x<t.w; x++,fx++) {
506 clr = GETPX(src,fx,fy);
507 SETPX(dest,x,y,clr);
512 /* blit one image over another */
513 void image_blit(image_t *dest, image_t *src, rect_t *to, rect_t *from)
515 int x;
516 int y;
517 int fx;
518 int fy;
519 rect_t t;
520 rect_t f;
521 uint32_t fclr;
522 uint32_t tclr;
523 if (!src)
524 return;
525 if (!dest)
526 return;
527 if (from) {
528 f = *from;
529 if (f.x < 0) {
530 f.w += f.x;
531 f.x = 0;
533 if (f.y < 0) {
534 f.h += f.y;
535 f.y = 0;
537 if (f.x+f.w > src->w)
538 f.w = src->w-f.x;
539 if (f.y+f.h > src->h)
540 f.h = src->h-f.y;
541 }else{
542 f.x = 0;
543 f.y = 0;
544 f.w = src->w;
545 f.h = src->h;
547 if (to) {
548 t = *to;
549 if (t.x < 0) {
550 t.w += t.x;
551 t.x = 0;
553 if (t.y < 0) {
554 t.h += t.y;
555 t.y = 0;
557 if (t.x+t.w > dest->w)
558 t.w = dest->w-t.x;
559 if (t.y+t.h > dest->h)
560 t.h = dest->h-t.y;
561 }else{
562 t.x = 0;
563 t.y = 0;
564 t.w = dest->w;
565 t.h = dest->h;
567 if (t.w != f.w) {
568 x = t.w;
569 if (x > f.w)
570 x = f.w;
571 t.w = x;
572 f.w = x;
574 if (t.h != f.h) {
575 y = t.h;
576 if (y > f.h)
577 y = f.h;
578 t.h = y;
579 f.h = y;
581 t.w += t.x;
582 t.h += t.y;
583 f.w += f.x;
584 f.h += f.y;
585 for (y=t.y,fy=f.y; y<t.h; y++,fy++) {
586 for (x=t.x,fx=f.x; x<t.w; x++,fx++) {
587 fclr = GETPX(src,fx,fy);
588 tclr = GETPX(dest,x,y);
589 tclr = merge_colours(tclr,fclr);
590 SETPX(dest,x,y,tclr);
595 /* colourise an image */
596 void image_colourise(image_t *img, colour_t *c, rect_t *area)
598 int x;
599 int y;
600 rect_t t;
601 uint32_t fclr;
602 uint32_t tclr;
603 if (!img)
604 return;
605 if (area) {
606 t = *area;
607 if (t.x < 0) {
608 t.w += t.x;
609 t.x = 0;
611 if (t.y < 0) {
612 t.h += t.y;
613 t.y = 0;
615 if (t.x+t.w > img->w)
616 t.w = img->w-t.x;
617 if (t.y+t.h > img->h)
618 t.h = img->h-t.y;
619 }else{
620 t.x = 0;
621 t.y = 0;
622 t.w = img->w;
623 t.h = img->h;
625 t.w += t.x;
626 t.h += t.y;
627 for (y=t.y; y<t.h; y++) {
628 for (x=t.x; x<t.w; x++) {
629 fclr = C2P(*c);
630 tclr = GETPX(img,x,y);
631 tclr = colourise(tclr,fclr);
632 SETPX(img,x,y,tclr);