ce6f781997-10-27Mirar (Pontus Hagland) /* $Id: blit.c,v 1.16 1997/10/27 22:41:16 mirar Exp $ */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include "global.h"
b9284c1997-04-09Mirar (Pontus Hagland) /* **! module Image
4ce7411997-05-29Mirar (Pontus Hagland) **! note
ce6f781997-10-27Mirar (Pontus Hagland) **! $Id: blit.c,v 1.16 1997/10/27 22:41:16 mirar Exp $
b9284c1997-04-09Mirar (Pontus Hagland) **! class image */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include <math.h> #include <ctype.h> #include "stralloc.h" #include "global.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #include "object.h" #include "constants.h" #include "interpret.h" #include "svalue.h" #include "array.h" #include "error.h" #include "threads.h" #include "image.h" extern struct program *image_program; #define THIS ((struct image *)(fp->current_storage)) #define THISOBJ (fp->current_object)
c378911997-03-20Mirar (Pontus Hagland) #define absdiff(a,b) ((a)<(b)?((b)-(a)):((a)-(b)))
ab6aec1997-02-11Fredrik Hübinette (Hubbe) #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)<(b)?(b):(a)) #if 0 #include <sys/resource.h> #define CHRONO(X) chrono(X) static void chrono(char *x) { struct rusage r; static struct rusage rold; getrusage(RUSAGE_SELF,&r); fprintf(stderr,"%s: %ld.%06ld - %ld.%06ld\n",x, r.ru_utime.tv_sec,r.ru_utime.tv_usec, ((r.ru_utime.tv_usec-rold.ru_utime.tv_usec<0)?-1:0) +r.ru_utime.tv_sec-rold.ru_utime.tv_sec, ((r.ru_utime.tv_usec-rold.ru_utime.tv_usec<0)?1000000:0) + r.ru_utime.tv_usec-rold.ru_utime.tv_usec ); rold=r; } #else #define CHRONO(X) #endif /***************** internals ***********************************/ #define testrange(x) max(min((x),255),0) #define apply_alpha(x,y,alpha) \ ((unsigned char)((y*(255L-(alpha))+x*(alpha))/255L)) #define set_rgb_group_alpha(dest,src,alpha) \ (((dest).r=apply_alpha((dest).r,(src).r,alpha)), \ ((dest).g=apply_alpha((dest).g,(src).g,alpha)), \ ((dest).b=apply_alpha((dest).b,(src).b,alpha))) #define pixel(_img,x,y) ((_img)->img[(x)+(y)*(_img)->xsize]) #define setpixel(x,y) \ (THIS->alpha? \ set_rgb_group_alpha(THIS->img[(x)+(y)*THIS->xsize],THIS->rgb,THIS->alpha): \ ((pixel(THIS,x,y)=THIS->rgb),0)) #define setpixel_test(x,y) \ (((x)<0||(y)<0||(x)>=THIS->xsize||(y)>=THIS->ysize)? \ 0:(setpixel(x,y),0)) static INLINE void getrgb(struct image *img, INT32 args_start,INT32 args,char *name) { INT32 i; if (args-args_start<3) return; for (i=0; i<3; i++) if (sp[-args+i+args_start].type!=T_INT) error("Illegal r,g,b argument to %s\n",name); img->rgb.r=(unsigned char)sp[-args+args_start].u.integer; img->rgb.g=(unsigned char)sp[1-args+args_start].u.integer; img->rgb.b=(unsigned char)sp[2-args+args_start].u.integer; if (args-args_start>=4) if (sp[3-args+args_start].type!=T_INT) error("Illegal alpha argument to %s\n",name); else img->alpha=sp[3-args+args_start].u.integer; else img->alpha=0; } /*** end internals ***/ void img_clear(rgb_group *dest,rgb_group rgb,INT32 size) { THREADS_ALLOW(); while (size--) *(dest++)=rgb; THREADS_DISALLOW(); } void img_box_nocheck(INT32 x1,INT32 y1,INT32 x2,INT32 y2) { INT32 x,mod; rgb_group *foo,*end,rgb; struct image *this; this=THIS; THREADS_ALLOW(); mod=this->xsize-(x2-x1)-1; foo=this->img+x1+y1*this->xsize; end=this->img+x1+y2*this->xsize; rgb=this->rgb; if (!this->alpha) for (; foo<=end; foo+=mod) for (x=x1; x<=x2; x++) *(foo++)=rgb; else for (; foo<=end; foo+=mod) for (x=x1; x<=x2; x++,foo++) set_rgb_group_alpha(*foo,rgb,this->alpha); THREADS_DISALLOW(); } void img_blit(rgb_group *dest,rgb_group *src,INT32 width, INT32 lines,INT32 moddest,INT32 modsrc) {
1f99241997-09-06Per Hedbor  if(width <= 0 || lines <= 0) return;
ab6aec1997-02-11Fredrik Hübinette (Hubbe) CHRONO("image_blit begin"); THREADS_ALLOW(); while (lines--) { MEMCPY(dest,src,sizeof(rgb_group)*width); dest+=moddest; src+=modsrc; } THREADS_DISALLOW(); CHRONO("image_blit end"); } void img_crop(struct image *dest, struct image *img, INT32 x1,INT32 y1, INT32 x2,INT32 y2) { rgb_group *new; INT32 xp,yp,xs,ys; if (dest->img) { free(dest->img); dest->img=NULL; } if (x1>x2) x1^=x2,x2^=x1,x1^=x2; if (y1>y2) y1^=y2,y2^=y1,y1^=y2; if (x1==0 && y1==0 && img->xsize-1==x2 && img->ysize-1==y2) { *dest=*img; new=malloc( (x2-x1+1)*(y2-y1+1)*sizeof(rgb_group) + 1); if (!new) error("Out of memory.\n"); THREADS_ALLOW(); MEMCPY(new,img->img,(x2-x1+1)*(y2-y1+1)*sizeof(rgb_group)); THREADS_DISALLOW(); dest->img=new; return; } new=malloc( (x2-x1+1)*(y2-y1+1)*sizeof(rgb_group) +1); if (!new) error("Out of memory.\n"); img_clear(new,THIS->rgb,(x2-x1+1)*(y2-y1+1)); dest->xsize=x2-x1+1; dest->ysize=y2-y1+1; xp=max(0,-x1); yp=max(0,-y1); xs=max(0,x1); ys=max(0,y1); if (x1<0) x1=0; else if (x1>=img->xsize) x1=img->xsize-1; if (y1<0) y1=0; else if (y1>=img->ysize) y1=img->ysize-1; if (x2<0) x2=0; else if (x2>=img->xsize) x2=img->xsize-1; if (y2<0) y2=0; else if (y2>=img->ysize) y2=img->ysize-1; img_blit(new+xp+yp*dest->xsize, img->img+xs+(img->xsize)*ys, x2-x1+1, y2-y1+1, dest->xsize, img->xsize); dest->img=new; } void img_clone(struct image *newimg,struct image *img) { if (newimg->img) free(newimg->img); newimg->img=malloc(sizeof(rgb_group)*img->xsize*img->ysize +1); if (!newimg->img) error("Out of memory!\n"); THREADS_ALLOW(); MEMCPY(newimg->img,img->img,sizeof(rgb_group)*img->xsize*img->ysize); THREADS_DISALLOW(); newimg->xsize=img->xsize; newimg->ysize=img->ysize; newimg->rgb=img->rgb; }
64f1361997-03-25Mirar (Pontus Hagland) /* **! method object paste(object image) **! method object paste(object image,int x,int y) **! Pastes a given image over the current image. **! **! returns the object called **!
f311411997-04-18Mirar (Pontus Hagland) **! arg object image
64f1361997-03-25Mirar (Pontus Hagland) **! image to paste
f311411997-04-18Mirar (Pontus Hagland) **! arg int x **! arg int y
64f1361997-03-25Mirar (Pontus Hagland) **! where to paste the image; default is 0,0 **! **! see also: paste_mask, paste_alpha, paste_alpha_color */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void image_paste(INT32 args) { struct image *img; INT32 x1,y1,x2,y2,blitwidth,blitheight; if (args<1 || sp[-args].type!=T_OBJECT || !sp[-args].u.object || sp[-args].u.object->prog!=image_program) error("illegal argument 1 to image->paste()\n"); if (!THIS->img) return; img=(struct image*)sp[-args].u.object->storage; if (!img) return; if (args>=3) { if (sp[1-args].type!=T_INT || sp[2-args].type!=T_INT) error("illegal arguments to image->paste()\n"); x1=sp[1-args].u.integer; y1=sp[2-args].u.integer; } else x1=y1=0;
f729e81997-09-01Per Hedbor  if(x1 >= THIS->xsize || y1 >= THIS->ysize) /* Per */ { pop_n_elems(args); THISOBJ->refs++; push_object(THISOBJ); return; }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  x2=x1+img->xsize-1; y2=y1+img->ysize-1;
f729e81997-09-01Per Hedbor  if(x2 < 0 || y2 < 0) /* Per */ { pop_n_elems(args); THISOBJ->refs++; push_object(THISOBJ); return; }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  blitwidth=min(x2,THIS->xsize-1)-max(x1,0)+1; blitheight=min(y2,THIS->ysize-1)-max(y1,0)+1;
f729e81997-09-01Per Hedbor 
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  img_blit(THIS->img+max(0,x1)+(THIS->xsize)*max(0,y1), img->img+max(0,-x1)+(x2-x1+1)*max(0,-y1), blitwidth, blitheight, THIS->xsize, img->xsize); pop_n_elems(args); THISOBJ->refs++; push_object(THISOBJ); }
64f1361997-03-25Mirar (Pontus Hagland) /* **! method object paste_alpha(object image,int alpha) **! method object paste_alpha(object image,int alpha,int x,int y) **! Pastes a given image over the current image, with **! the specified alpha channel value. **! **! An alpha channel value of 0 leaves nothing of the original **! image in the paste area, 255 is meaningless and makes the **! given image invisible. **! **! returns the object called **!
f311411997-04-18Mirar (Pontus Hagland) **! arg object image
64f1361997-03-25Mirar (Pontus Hagland) **! image to paste
f311411997-04-18Mirar (Pontus Hagland) **! arg int alpha
64f1361997-03-25Mirar (Pontus Hagland) **! alpha channel value
f311411997-04-18Mirar (Pontus Hagland) **! arg int x **! arg int y
64f1361997-03-25Mirar (Pontus Hagland) **! where to paste the image; default is 0,0 **! **! see also: paste_mask, paste, paste_alpha_color */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void image_paste_alpha(INT32 args) { struct image *img; INT32 x1,y1,x,y; if (args<2 || sp[-args].type!=T_OBJECT || !sp[-args].u.object || sp[-args].u.object->prog!=image_program || sp[1-args].type!=T_INT) error("illegal arguments to image->paste_alpha()\n"); if (!THIS->img) return; img=(struct image*)sp[-args].u.object->storage; if (!img) return; THIS->alpha=(unsigned char)(sp[1-args].u.integer); if (args>=4) { if (sp[2-args].type!=T_INT || sp[3-args].type!=T_INT) error("illegal arguments to image->paste_alpha()\n"); x1=sp[2-args].u.integer; y1=sp[3-args].u.integer; } else x1=y1=0;
f729e81997-09-01Per Hedbor  if(x1 >= THIS->xsize || y1 >= THIS->ysize) /* Per */ { pop_n_elems(args); THISOBJ->refs++; push_object(THISOBJ); return; }
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
f729e81997-09-01Per Hedbor /* tråda här nåndag.. Ok /Per */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
f729e81997-09-01Per Hedbor  { rgb_group *source = img->img; struct image *this = THIS; int xs = this->xsize, ix, mx=img->xsize, my=img->ysize, x; int ys = this->ysize, iy, y; THREADS_ALLOW(); for (iy=0; iy<my; iy++) for (ix=0; ix<mx; ix++) { x = ix + x1; y = iy + y1; if(x>=0 && y>=0 && x<xs && y<ys) if(this->alpha) set_rgb_group_alpha(this->img[x+y*xs],*(source),this->alpha); else this->img[x+y*xs]=*(source); source++; } THREADS_DISALLOW(); }
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  pop_n_elems(args); THISOBJ->refs++; push_object(THISOBJ); }
64f1361997-03-25Mirar (Pontus Hagland) /* **! method object paste_mask(object image,object mask) **! method object paste_mask(object image,object mask,int x,int y) **! Pastes a given image over the current image, **! using the given mask as opaque channel. **! **! A pixel value of 255 makes the result become a pixel **! from the given image, 0 doesn't change anything. **! **! The masks red, green and blue values are used separately. **! **! returns the object called **!
f311411997-04-18Mirar (Pontus Hagland) **! arg object image
64f1361997-03-25Mirar (Pontus Hagland) **! image to paste
f311411997-04-18Mirar (Pontus Hagland) **! arg object mask
64f1361997-03-25Mirar (Pontus Hagland) **! mask image
f311411997-04-18Mirar (Pontus Hagland) **! arg int x **! arg int y
64f1361997-03-25Mirar (Pontus Hagland) **! where to paste the image; default is 0,0 **! **! see also: paste, paste_alpha, paste_alpha_color */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void image_paste_mask(INT32 args) { struct image *img,*mask; INT32 x1,y1,x,y,x2,y2,smod,dmod,mmod; rgb_group *s,*d,*m; float q; CHRONO("image_paste_mask init"); if (args<2) error("illegal number of arguments to image->paste_mask()\n"); if (sp[-args].type!=T_OBJECT || !sp[-args].u.object || sp[-args].u.object->prog!=image_program) error("illegal argument 1 to image->paste_mask()\n"); if (sp[1-args].type!=T_OBJECT || !sp[1-args].u.object || sp[1-args].u.object->prog!=image_program) error("illegal argument 2 to image->paste_mask()\n"); if (!THIS->img) return; img=(struct image*)sp[-args].u.object->storage; mask=(struct image*)sp[1-args].u.object->storage; if ((!img)||(!img->img)) error("argument 1 has no image\n"); if ((!mask)||(!mask->img)) error("argument 2 (alpha) has no image\n"); if (args>=4) { if (sp[2-args].type!=T_INT || sp[3-args].type!=T_INT) error("illegal coordinate arguments to image->paste_mask()\n"); x1=sp[2-args].u.integer; y1=sp[3-args].u.integer; } else x1=y1=0; x2=min(THIS->xsize-x1,min(img->xsize,mask->xsize)); y2=min(THIS->ysize-y1,min(img->ysize,mask->ysize)); CHRONO("image_paste_mask begin"); s=img->img+max(0,-x1)+max(0,-y1)*img->xsize; m=mask->img+max(0,-x1)+max(0,-y1)*mask->xsize; d=THIS->img+max(0,-x1)+x1+(y1+max(0,-y1))*THIS->xsize; x=max(0,-x1); smod=img->xsize-(x2-x); mmod=mask->xsize-(x2-x); dmod=THIS->xsize-(x2-x); q=1.0/255; THREADS_ALLOW(); for (y=max(0,-y1); y<y2; y++) { for (x=max(0,-x1); x<x2; x++) { if (m->r==255) d->r=s->r;
64f1361997-03-25Mirar (Pontus Hagland)  else if (m->r==0) {}
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  else d->r=(unsigned char)(((d->r*(255-m->r))+(s->r*m->r))*q); if (m->g==255) d->g=s->g;
64f1361997-03-25Mirar (Pontus Hagland)  else if (m->g==0) {}
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  else d->g=(unsigned char)(((d->g*(255-m->g))+(s->g*m->g))*q); if (m->b==255) d->b=s->b;
64f1361997-03-25Mirar (Pontus Hagland)  else if (m->b==0) {}
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  else d->b=(unsigned char)(((d->b*(255-m->b))+(s->b*m->b))*q); s++; m++; d++; } s+=smod; m+=mmod; d+=dmod; } THREADS_DISALLOW(); CHRONO("image_paste_mask end"); pop_n_elems(args); THISOBJ->refs++; push_object(THISOBJ); }
64f1361997-03-25Mirar (Pontus Hagland) /* **! method object paste_alpha_color(object mask) **! method object paste_alpha_color(object mask,int x,int y) **! method object paste_alpha_color(object mask,int r,int g,int b) **! method object paste_alpha_color(object mask,int r,int g,int b,int x,int y) **! Pastes a given color over the current image, **! using the given mask as opaque channel. **! **! A pixel value of 255 makes the result become the color given, **! 0 doesn't change anything. **! **! The masks red, green and blue values are used separately. **! If no color are given, the current is used. **! **! returns the object called **!
f311411997-04-18Mirar (Pontus Hagland) **! arg object mask
64f1361997-03-25Mirar (Pontus Hagland) **! mask image
f311411997-04-18Mirar (Pontus Hagland) **! arg int r **! arg int g **! arg int b
64f1361997-03-25Mirar (Pontus Hagland) **! what color to paint with; default is current
f311411997-04-18Mirar (Pontus Hagland) **! arg int x **! arg int y
64f1361997-03-25Mirar (Pontus Hagland) **! where to paste the image; default is 0,0 **! **! see also: paste_mask, paste_alpha, paste_alpha_color */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) void image_paste_alpha_color(INT32 args) {
bb001b1997-10-12Mirar (Pontus Hagland)  struct image *mask;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  INT32 x1,y1,x,y,x2,y2; rgb_group rgb,*d,*m; INT32 mmod,dmod; float q; if (args!=1 && args!=4 && args!=6 && args!=3) error("illegal number of arguments to image->paste_alpha_color()\n"); if (sp[-args].type!=T_OBJECT || !sp[-args].u.object || sp[-args].u.object->prog!=image_program) error("illegal argument 1 to image->paste_alpha_color()\n"); if (!THIS->img) return; if (args==6 || args==4) /* colors at arg 2..4 */ getrgb(THIS,1,args,"image->paste_alpha_color()\n"); if (args==3) /* coords at 2..3 */ { if (sp[1-args].type!=T_INT || sp[2-args].type!=T_INT) error("illegal coordinate arguments to image->paste_alpha_color()\n"); x1=sp[1-args].u.integer; y1=sp[2-args].u.integer; } else if (args==6) /* at 5..6 */ { if (sp[4-args].type!=T_INT || sp[5-args].type!=T_INT) error("illegal coordinate arguments to image->paste_alpha_color()\n"); x1=sp[4-args].u.integer; y1=sp[5-args].u.integer; } else x1=y1=0; mask=(struct image*)sp[-args].u.object->storage;
a2d8a71997-09-10Henrik Grubbström (Grubba)  if (!mask||!mask->img) error("argument 1 (alpha) has no image\n");
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  x2=min(THIS->xsize-x1,mask->xsize); y2=min(THIS->ysize-y1,mask->ysize); CHRONO("image_paste_alpha_color begin"); m=mask->img+max(0,-x1)+max(0,-y1)*mask->xsize; d=THIS->img+max(0,-x1)+x1+(y1+max(0,-y1))*THIS->xsize; x=max(0,-x1); mmod=mask->xsize-(x2-x); dmod=THIS->xsize-(x2-x); q=1.0/255; rgb=THIS->rgb; THREADS_ALLOW(); for (y=max(0,-y1); y<y2; y++) { for (x=max(0,-x1); x<x2; x++) { if (m->r==255) d->r=rgb.r; else if (m->r==0) ; else d->r=(unsigned char)(((d->r*(255-m->r))+(rgb.r*m->r))*q); if (m->g==255) d->g=rgb.g; else if (m->g==0) ; else d->g=(unsigned char)(((d->g*(255-m->g))+(rgb.g*m->g))*q); if (m->b==255) d->b=rgb.b; else if (m->b==0) ; else d->b=(unsigned char)(((d->b*(255-m->b))+(rgb.b*m->b))*q); m++; d++; } m+=mmod; d+=dmod; } THREADS_DISALLOW(); CHRONO("image_paste_alpha_color end"); pop_n_elems(args); THISOBJ->refs++; push_object(THISOBJ); } void img_box(INT32 x1,INT32 y1,INT32 x2,INT32 y2) { if (x1>x2) x1^=x2,x2^=x1,x1^=x2; if (y1>y2) y1^=y2,y2^=y1,y1^=y2;
eca7571997-09-19Henrik Grubbström (Grubba)  if (x2 >= THIS->xsize) x2 = THIS->xsize-1; if (y2 >= THIS->ysize) y2 = THIS->ysize-1;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  if (x2<0||y2<0||x1>=THIS->xsize||y1>=THIS->ysize) return;
eca7571997-09-19Henrik Grubbström (Grubba)  if (x1<0) x1 = 0; if (y1<0) y1 = 0;
ab6aec1997-02-11Fredrik Hübinette (Hubbe)  img_box_nocheck(max(x1,0),max(y1,0),min(x2,THIS->xsize-1),min(y2,THIS->ysize-1)); }
64f1361997-03-25Mirar (Pontus Hagland) /*
e3cb4b1997-04-03Mirar (Pontus Hagland) **! method object add_layers(array(int|object)) layer0,...) **! method object add_layers(int x1,int y1,int x2,int y2,array(int|object)) layer0,...)
64f1361997-03-25Mirar (Pontus Hagland) **! Using the called object as base, adds layers using masks, **! opaque channel values and special methods. **! **! The destination image can also be cropped, thus **! speeding up the process. **! **! Each array in the layers array is one of: **! <pre> **! ({object image,object|int mask}) **! ({object image,object|int mask,int opaque_value}) **! ({object image,object|int mask,int opaque_value,int method}) **! </pre> **! Given 0 as mask means the image is totally opaque. **! **! Default opaque value is 255, only using the mask. **! **! Methods for now are: **! <pre> **! 0 no operation (just paste with mask, default) **! 1 maximum (`|) **! 2 minimum (`&) **! 3 multiply (`*) **! 4 add (`+) **! 5 diff (`-) **! </pre> **! The layer image and the current source are calculated **! through the given method and then pasted using the mask **! and the opaque channel value. **! **! All given images must be the same size. **! **! returns a new image object **!
e3cb4b1997-04-03Mirar (Pontus Hagland) **! arg array(int|object) layer0
64f1361997-03-25Mirar (Pontus Hagland) **! image to paste
e3cb4b1997-04-03Mirar (Pontus Hagland) **! arg int x1 **! arg int y1 **! arg int x2 **! arg int y2 **! rectangle for cropping
64f1361997-03-25Mirar (Pontus Hagland) **! **! see also: paste_mask, paste_alpha, paste_alpha_color, `|, `&, `*, `+, `- */
ab6aec1997-02-11Fredrik Hübinette (Hubbe) 
c378911997-03-20Mirar (Pontus Hagland) void image_add_layers(INT32 args) /* [x1,y1,x2,y2],
64f1361997-03-25Mirar (Pontus Hagland) ({object image,object mask|0,[int alpha_value,[int method]]}), ({object image,object mask|0,[int alpha_value,[int method]]}),
c378911997-03-20Mirar (Pontus Hagland) ... :object */ { struct img_layer { rgb_group *s; rgb_group *m;
64f1361997-03-25Mirar (Pontus Hagland)  int opaque;
c378911997-03-20Mirar (Pontus Hagland)  enum layer_method method; } *layer; float q2=1/(255.0*255.0); float q=1/(255.0); rgb_group *s; rgb_group *d; struct object *o;
64f1361997-03-25Mirar (Pontus Hagland)  int allopaque255=1,allmask=1,allnop=1;
c378911997-03-20Mirar (Pontus Hagland)  int i,j,l,mod,layers; int x1,y1,x2,y2; if (!THIS->img) error("No image."); s=THIS->img; if (args>=4 && sp[-args].type==T_INT && sp[1-args].type==T_INT && sp[2-args].type==T_INT && sp[3-args].type==T_INT) { x1=sp[-args].u.integer; y1=sp[1-args].u.integer; x2=sp[2-args].u.integer; y2=sp[3-args].u.integer;
84a15c1997-03-23Mirar (Pontus Hagland)  if (x2<x1) x2^=x1,x1^=x2,x2^=x1; if (y2<y1) y2^=y1,y1^=y2,y2^=y1;
c378911997-03-20Mirar (Pontus Hagland)  if (x2>THIS->xsize-1 || y2>THIS->ysize-1 || x1<0 || y1<0) error("Illegal coordinates to image->add_layers()\n"); layers=args-4; } else { x1=0; y1=0; x2=THIS->xsize-1; y2=THIS->ysize-1; layers=args; } layer=(struct img_layer*)xalloc(sizeof(struct img_layer)*layers); for (j=0,i=layers; i>0; i--,j++) { struct array *a; struct image *img; if (sp[-i].type!=T_ARRAY) { free(layer); error("Illegal argument(s) to image->add_layers()\n"); } a=sp[-i].u.array; if (a->size<2) { free(layer); error("Illegal size of array argument to image->add_layers()\n"); } if (a->item[0].type!=T_OBJECT || !a->item[0].u.object || a->item[0].u.object->prog!=image_program) { free(layer);
e3cb4b1997-04-03Mirar (Pontus Hagland)  error("Illegal array contents, layer %d (argument %d) (wrong or no image) to image->add_layers()\n",layers-i,args-i+1);
c378911997-03-20Mirar (Pontus Hagland)  } img=(struct image*)a->item[0].u.object->storage; if (!img->img || img->xsize != THIS->xsize || img->ysize != THIS->ysize) { free(layer);
e3cb4b1997-04-03Mirar (Pontus Hagland)  error("Illegal array contents, layer %d (argument %d) (no image or wrong image size) to image->add_layers()\n",layers-i,args-i+1);
c378911997-03-20Mirar (Pontus Hagland)  } layer[j].s=img->img; if (a->item[1].type==T_INT && a->item[1].u.integer==0) { layer[j].m=NULL; } else { if (a->item[1].type!=T_OBJECT || !a->item[1].u.object || a->item[1].u.object->prog!=image_program) { free(layer);
e3cb4b1997-04-03Mirar (Pontus Hagland)  error("Illegal array contents, layer %d (argument %d) (wrong or no image for mask) to image->add_layers()\n",layers-i,args-i+1);
c378911997-03-20Mirar (Pontus Hagland)  } img=(struct image*)a->item[1].u.object->storage; if (!img->img || img->xsize != THIS->xsize || img->ysize != THIS->ysize) { free(layer);
e3cb4b1997-04-03Mirar (Pontus Hagland)  error("Illegal array contents, layer %d (argument %d) (no mask or wrong mask size) to image->add_layers()\n",layers-i,args-i+1);
c378911997-03-20Mirar (Pontus Hagland)  } layer[j].m=img->img; } if (a->size>=3) { if (a->item[2].type!=T_INT) { free(layer);
e3cb4b1997-04-03Mirar (Pontus Hagland)  error("Illegal array contents, layer %d (argument %d) (illegal opaque) to image->add_layers()\n",layers-i,args-i+1);
c378911997-03-20Mirar (Pontus Hagland)  }
64f1361997-03-25Mirar (Pontus Hagland)  layer[j].opaque=a->item[2].u.integer;
c378911997-03-20Mirar (Pontus Hagland)  } else
64f1361997-03-25Mirar (Pontus Hagland)  layer[j].opaque=255;
c378911997-03-20Mirar (Pontus Hagland)  if (a->size>=4) { if (a->item[3].type!=T_INT) { free(layer);
e3cb4b1997-04-03Mirar (Pontus Hagland)  error("Illegal array contents, layer %d (argument %d) (illegal method) to image->add_layers()\n",layers-i,args-i+1);
c378911997-03-20Mirar (Pontus Hagland)  } layer[j].method=a->item[3].u.integer; } else layer[j].method=LAYER_NOP; } push_int(1+x2-x1); push_int(1+y2-y1); o=clone_object(image_program,2); d=((struct image*)(o->storage))->img; mod=THIS->xsize-(x2-x1+1); s+=x1+THIS->xsize*y1; for (i=0; i<layers; i++) { layer[i].s+=x1+THIS->xsize*y1; if (layer[i].m) layer[i].m+=x1+THIS->xsize*y1; else allmask=0;
64f1361997-03-25Mirar (Pontus Hagland)  if (layer[i].opaque!=255) allopaque255=0;
c378911997-03-20Mirar (Pontus Hagland)  if (layer[i].method!=LAYER_NOP) allnop=0; }
64f1361997-03-25Mirar (Pontus Hagland)  if (allmask && allopaque255 && allnop)
c378911997-03-20Mirar (Pontus Hagland)  { #define ALL_IS_NOP #define ALL_HAVE_MASK
64f1361997-03-25Mirar (Pontus Hagland) #define ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland) #include "blit_layer_include.h" #undef ALL_IS_NOP #undef ALL_HAVE_MASK
64f1361997-03-25Mirar (Pontus Hagland) #undef ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland)  }
64f1361997-03-25Mirar (Pontus Hagland)  else if (allopaque255 && allnop)
c378911997-03-20Mirar (Pontus Hagland)  { #define ALL_IS_NOP
64f1361997-03-25Mirar (Pontus Hagland) #define ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland) #include "blit_layer_include.h" #undef ALL_IS_NOP
64f1361997-03-25Mirar (Pontus Hagland) #undef ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland)  } else if (allmask && allnop) { #define ALL_HAVE_MASK
64f1361997-03-25Mirar (Pontus Hagland) #define ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland) #include "blit_layer_include.h" #undef ALL_HAVE_MASK
64f1361997-03-25Mirar (Pontus Hagland) #undef ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland)  } else if (allnop) { #define ALL_IS_NOP #include "blit_layer_include.h" #undef ALL_IS_NOP }
64f1361997-03-25Mirar (Pontus Hagland)  else if (allmask && allopaque255)
c378911997-03-20Mirar (Pontus Hagland)  { #define ALL_HAVE_MASK
64f1361997-03-25Mirar (Pontus Hagland) #define ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland) #include "blit_layer_include.h" #undef ALL_HAVE_MASK
64f1361997-03-25Mirar (Pontus Hagland) #undef ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland)  }
64f1361997-03-25Mirar (Pontus Hagland)  else if (allopaque255)
c378911997-03-20Mirar (Pontus Hagland)  {
64f1361997-03-25Mirar (Pontus Hagland) #define ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland) #include "blit_layer_include.h"
64f1361997-03-25Mirar (Pontus Hagland) #undef ALL_HAVE_OPAQUE
c378911997-03-20Mirar (Pontus Hagland)  } else if (allmask) { #define ALL_HAVE_MASK #include "blit_layer_include.h" #undef ALL_HAVE_MASK } else { #include "blit_layer_include.h" }
e3cb4b1997-04-03Mirar (Pontus Hagland)  pop_n_elems(args);
c378911997-03-20Mirar (Pontus Hagland)  free(layer); push_object(o); }