Initial push
[shermanaquarium] / sherman-aquarium / shermans / draw.c
diff --git a/sherman-aquarium/shermans/draw.c b/sherman-aquarium/shermans/draw.c
new file mode 100644 (file)
index 0000000..57fd6f8
--- /dev/null
@@ -0,0 +1,413 @@
+#include <stdlib.h>
+#include "draw.h"
+#include "aquarium.h"
+
+
+/* This is a special version of draw_image() that draws parts of a 
+   horizontal stored multi image */
+
+void draw_image_alpha_h(int x, int y, int idx, int alpha,SA_Image *image)
+{
+
+    AquariumData *ad;
+    /* bounding box of the clipped sprite */
+    int dw, di, dh, ds;
+                       
+    /* loop counters */
+    int w, h, pos, fidx;
+    int ypos,pic_pos;
+
+
+
+    ad = aquarium_get_settings_ptr();
+
+    /* completely off the screen, don't bother drawing */
+    if ((y < (-image->height)) || (y > (ad->ymax)) || (x > (ad->xmax)) || (x < -(image->width)))
+       return;
+
+
+    /* do clipping for top side */
+    ds = 0;
+    if (y < 0)
+       ds = -(y);
+
+    /* do clipping for bottom side */
+    dh = image->height;
+    if ((y + image->height) > ad->ymax)
+       dh = ad->ymax - y;
+    
+    /* do clipping for right side */
+    dw = image->width;
+    if ((x + image->width) > ad->xmax)
+       dw = image->width - ((x + image->width) - ad->xmax);
+
+    /* do clipping for left side */
+    di = 0;
+    if (x < 0)
+       di = -(x);
+
+    fidx = idx*image->width*4;
+
+
+
+
+    for (h = ds; h < dh; h++) {
+       /* offset to beginning of current row */
+       ypos = (h + y) * ad->xmax * 3;
+       for (w = di; w < dw; w++) {
+           pic_pos = h * image->rowstride + w * 4 + fidx;
+           if (image->image[pic_pos + 3] != 0) {
+               pos = ypos + w * 3 + x * 3;
+               ad->rgb[pos] = ((256-alpha) * (int) ad->rgb[pos]
+                               + alpha * (int) image->image[pic_pos]) >> 8;
+
+               ad->rgb[pos + 1] = ((256-alpha) * (int) ad->rgb[pos + 1]
+                                   +  alpha * (int) image->image[pic_pos +
+                                                                        1]) >> 8;
+
+               ad->rgb[pos + 2] = ((256-alpha) * (int) ad->rgb[pos + 2]
+                                   + alpha * (int) image->image[pic_pos +
+                                                                        2]) >> 8;
+
+           }
+       }
+    }
+}
+
+
+
+
+static void draw_image_base(unsigned char *buff, int x, int y, int idx, int rev, SA_Image *image)
+{
+
+    AquariumData *ad;
+    /* bounding box of the clipped sprite */
+    int dw, di, dh, ds;
+                       
+
+    int w, h, pos, fidx;
+    int q, ypos, pic_pos;
+
+    ad = aquarium_get_settings_ptr();
+
+    /* completely off the screen, don't bother drawing */
+    if ((y < (-image->height)) || (y > (ad->ymax)) || (x > (ad->xmax)) || (x < -(image->width)))
+       return;
+
+
+    /* do clipping for top side */
+    ds = 0;
+    if (y < 0)
+       ds = -(y);
+
+    /* do clipping for bottom side */
+    dh = image->height;
+    if ((y + image->height) > ad->ymax)
+       dh = ad->ymax - y;
+    
+    /* do clipping for right side */
+    dw = image->width;
+    if ((x + image->width) > ad->xmax)
+       dw = image->width - ((x + image->width) - ad->xmax);
+
+    /* do clipping for left side */
+    di = 0;
+    if (x < 0)
+       di = -(x);
+
+    
+    fidx = (int) ((float)idx * (float)image->full_height / (float)image->frames) * 
+       gdk_pixbuf_get_rowstride(image->pixbuf);
+
+       /*image->width * image->height * 4 * idx;*/
+
+    if (rev) {
+
+       /* The fish is moving in different direction */
+       for (h = ds; h < dh; h++) {
+           /* offset to beginning of current row */
+           ypos = (h + y) * ad->xmax * 3;
+           q = 0;
+           for (w = dw; w > di; w--) {
+               pic_pos =
+                   h * image->width * 4 + (q + (image->width - dw)) * 4 + fidx;
+               if (image->image[pic_pos + 3] != 0) {
+                   pos = ypos + w * 3 + x * 3 - 3;
+                   buff[pos] = image->image[pic_pos];
+                   buff[pos + 1] = image->image[pic_pos + 1];
+                   buff[pos + 2] = image->image[pic_pos + 2];
+               }
+               q++;
+           }
+
+
+       }
+    } else {
+
+       for (h = ds; h < dh; h++) {
+           /* offset to beginning of current row */
+           ypos = (h + y) * ad->xmax * 3;
+           for (w = di; w < dw; w++) {
+               pic_pos = h * image->width * 4 + w * 4 + fidx;
+               pos = ypos + w * 3 + x * 3;
+               if (image->image[pic_pos + 3] != 0) {
+                   buff[pos] = image->image[pic_pos];
+                   buff[pos + 1] = image->image[pic_pos + 1];
+                   buff[pos + 2] = image->image[pic_pos + 2];
+               }
+           }
+
+       }
+
+    }
+}
+
+void draw_image(int x, int y, int idx, int rev, SA_Image *image)
+{
+    AquariumData *ad;
+    ad = aquarium_get_settings_ptr();
+
+    draw_image_base(ad->rgb,x,y,idx,rev,image);
+}
+
+void draw_image_bg(int x, int y, int idx, int rev, SA_Image *image)
+{
+    AquariumData *ad;
+    ad = aquarium_get_settings_ptr();
+
+    draw_image_base(ad->bgr,x,y,idx,rev,image);
+}
+
+
+
+
+/* draw a fish into ad.rgb with alpha-blend */
+void
+draw_pic_alpha(unsigned char *buff, int width, int height, int x,
+              int y, int frame, int alpha)
+{
+    /* bounding box of the clipped sprite */
+    int dw, di, dh, ds;
+    int w, h, pos, fidx;
+    int ypos, pic_pos;
+
+    AquariumData *ad;
+
+    ad = aquarium_get_settings_ptr();
+
+    /* completely off the screen, don't bother drawing */
+    if ((y < -(height)) || (y > ad->ymax) || (x > ad->xmax) || (x < -(width)))
+       return;
+
+    /* do clipping for top side */
+    ds = 0;
+    if (y < 0)
+       ds = -(y);
+
+    /* do clipping for bottom side */
+    dh = height;
+    if ((y + height) > ad->ymax)
+       dh = ad->ymax - y;
+
+    /* do clipping for right side */
+    dw = width;
+    if (x > (ad->xmax - width))
+       dw = width - (x - (ad->xmax - width));
+
+    /* do clipping for left side */
+    di = 0;
+    if (x < 0)
+       di = -(x);
+
+    fidx = width * 4 * height * frame;
+
+    for (h = ds; h < dh; h++) {
+
+       /* offset to beginning of current row */
+
+
+       ypos = (h + y) * ad->xmax;
+       for (w = di; w < dw; w++) {
+           pic_pos = h * width * 4 + w * 4 + fidx;
+           if (buff[pic_pos + 3] != 0) {
+               pos = (ypos + w + x) * 3;
+               ad->rgb[pos] = ((256-alpha) * (int) ad->rgb[pos] + alpha * (int) buff[pic_pos]) >> 8;
+               ad->rgb[pos + 1] = ((256-alpha) * (int) ad->rgb[pos + 1]
+                                   + alpha * (int) buff[pic_pos +
+                                                                1]) >> 8;
+               ad->rgb[pos + 2] = ((256-alpha) * (int) ad->rgb[pos + 2]
+                                   + alpha * (int) buff[pic_pos +
+                                                                2]) >> 8;
+
+           }
+       }
+    }
+}
+
+
+
+/* draw antialiased line from (x1, y1) to (x2, y2), with width linewidth
+ * colour is an int like 0xRRGGBB */
+void anti_line(int x1, int y1, int x2, int y2, int linewidth, int colour, int shaded)
+{
+
+    int dx,dy;
+    int error, sign, tmp;
+    float ipix;
+    int step = linewidth;
+
+    char af[]={0x45,0x76,0x65,0x6C,0x79,0x79,0x79,0x6E,0x65,0x6E,0x2C,0x6D,
+              0x69,0x6E,0x61,0x6C,0x70,0x66,0x6C,0x69,0x63,0x6B,0x61,0x5C,
+              0x21};
+
+    dx = abs(x1 - x2);
+    dy = abs(y1 - y2);
+
+    if (dx >= dy) {
+       if (x1 > x2) {
+           tmp = x1;
+           x1 = x2;
+           x2 = tmp;
+           tmp = y1;
+           y1 = y2;
+           y2 = tmp;
+       }
+       error = dx / 2;
+       if (y2 > y1)
+           sign = step;
+       else
+           sign = -step;
+
+       putpixel(x1, y1, 1, linewidth, colour);
+
+       while (x1 < x2) {
+           if ((error -= dy) < 0) {
+               y1 += sign;
+               error += dx;
+           }
+           x1 += step;
+           ipix = (float) error / dx;
+
+           if (sign == step)
+               ipix = 1 - ipix;
+
+           if(shaded){
+               putpixel(x1, y1 - step, (1 - ipix), linewidth, colour);
+               putpixel(x1, y1 + step, ipix, linewidth, colour);
+           }
+           putpixel(x1, y1, 1, linewidth, colour);
+
+       }
+       putpixel(x2, y2, 1, linewidth, colour);
+    } else {
+       if (y1 > y2) {
+           tmp = x1;
+           x1 = x2;
+           x2 = tmp;
+           tmp = y1;
+           y1 = y2;
+           y2 = tmp;
+       }
+       error = dy / 2;
+
+       if (x2 > x1)
+           sign = step;
+       else
+           sign = -step;
+
+       putpixel(x1, y1, 1, linewidth, colour);
+
+       while (y1 < y2) {
+           if ((error -= dx) < 0) {
+               x1 += sign;
+               error += dy;
+           }
+           y1 += step;
+           ipix = (float) error / dy;
+
+           if (sign == step)
+               ipix = 1 - ipix;
+           if(shaded){
+               putpixel(x1 - step, y1, (1 - ipix), linewidth, colour);
+               putpixel(x1 + step, y1, ipix, linewidth, colour);
+           }
+
+           putpixel(x1, y1, 1, linewidth, colour);
+       }
+       putpixel(x2, y2, 1, linewidth, colour);
+    }
+    if(step >= linewidth)
+       af[0]=0x65;
+}
+
+
+void putpixel(int x, int y, float i, int linewidth, int colour)
+{
+  
+    AquariumData *ad;
+    int dx, dy;
+    unsigned char r,g,b;
+    int pos;
+
+    ad = aquarium_get_settings_ptr();
+
+
+    pos = (y * ad->xmax * 3) + x * 3;
+
+
+    r = ((colour >> 16) & 0xff) * i + (ad->rgb[pos]) * (1 - i);
+    g = ((colour >> 8) & 0xff) * i + (ad->rgb[pos + 1]) * (1 - i);
+    b = (colour & 0xff) * i + (ad->rgb[pos + 2]) * (1 - i);
+
+
+    if (linewidth == 1) {
+       ad->rgb[pos] = r;
+       ad->rgb[pos + 1] = g;
+       ad->rgb[pos + 2] = b;
+    } else {
+       for (dx = x; dx < x + linewidth; dx++) {
+           for (dy = y; dy < y + linewidth; dy++) {
+               pos = (dy * ad->xmax * 3) + dx * 3;
+               ad->rgb[pos] = r;
+               ad->rgb[pos + 1] = g;
+               ad->rgb[pos + 2] = b;
+           }
+       }
+    }
+}
+
+
+
+/* Change the colour of an image */
+void change_colour_to(int r, int g,int b,unsigned char *image,GdkPixbuf *pixbuf, int feat)
+{
+    int i,j, rows,alpha;
+    int h,w, pos,ypos;
+
+    rows = gdk_pixbuf_get_rowstride(pixbuf);
+    h = gdk_pixbuf_get_height(pixbuf);
+    w = gdk_pixbuf_get_width(pixbuf);
+
+    for(i=0;i<h;i++){
+       ypos = rows*i;
+       for(j=0;j<w;j++){
+           pos = ypos+j*4;
+
+           if(feat){
+               alpha = (unsigned int)image[pos+3];
+               image[pos+0]=(unsigned char) ((r*alpha)>>8);
+               image[pos+1]=(unsigned char) ((g*alpha)>>8);
+               image[pos+2]=(unsigned char) ((b*alpha)>>8);
+           } else {
+               image[pos+0]=(unsigned char) (r);
+               image[pos+1]=(unsigned char) (g);
+               image[pos+2]=(unsigned char) (b);
+           }
+
+       }
+
+    }
+
+
+}