rayzor

annotate src/lines.c @ 9:70e332156d02

moving along
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 10 Apr 2014 02:31:31 +0300
parents
children
rev   line source
nuclear@9 1 #include "lines.h"
nuclear@9 2
nuclear@9 3 enum {
nuclear@9 4 IN = 0,
nuclear@9 5 LEFT = 1,
nuclear@9 6 RIGHT = 2,
nuclear@9 7 TOP = 4,
nuclear@9 8 BOTTOM = 8
nuclear@9 9 };
nuclear@9 10
nuclear@9 11 static int outcode(int x, int y, int minx, int miny, int maxx, int maxy)
nuclear@9 12 {
nuclear@9 13 int code = 0;
nuclear@9 14
nuclear@9 15 if(x < minx) {
nuclear@9 16 code |= LEFT;
nuclear@9 17 } else if(x > maxx) {
nuclear@9 18 code |= RIGHT;
nuclear@9 19 }
nuclear@9 20 if(y < miny) {
nuclear@9 21 code |= TOP;
nuclear@9 22 } else if(y > maxy) {
nuclear@9 23 code |= BOTTOM;
nuclear@9 24 }
nuclear@9 25 return code;
nuclear@9 26 }
nuclear@9 27
nuclear@9 28 #define FIXMUL(a, b) (((a) * (b)) >> 8)
nuclear@9 29 #define FIXDIV(a, b) (((a) << 8) / (b))
nuclear@9 30
nuclear@9 31 #define LERP(a, b, t) ((a) + FIXMUL((b) - (a), (t)))
nuclear@9 32
nuclear@9 33 int clip_line2d(int *x0, int *y0, int *x1, int *y1, const int *vp)
nuclear@9 34 {
nuclear@9 35 int oc_out;
nuclear@9 36 int minx = vp[0];
nuclear@9 37 int miny = vp[1];
nuclear@9 38 int maxx = vp[0] + vp[2] - 1;
nuclear@9 39 int maxy = vp[1] + vp[3] - 1;
nuclear@9 40
nuclear@9 41 int oc0 = outcode(*x0, *y0, minx, miny, maxx, maxy);
nuclear@9 42 int oc1 = outcode(*x1, *y1, minx, miny, maxx, maxy);
nuclear@9 43
nuclear@9 44 int32_t fx0, fy0, fx1, fy1, fminx, fminy, fmaxx, fmaxy;
nuclear@9 45
nuclear@9 46 if(!(oc0 | oc1)) return 1; /* both points are inside */
nuclear@9 47
nuclear@9 48 fx0 = *x0 << 8;
nuclear@9 49 fy0 = *y0 << 8;
nuclear@9 50 fx1 = *x1 << 8;
nuclear@9 51 fy1 = *y1 << 8;
nuclear@9 52 fminx = minx << 8;
nuclear@9 53 fminy = miny << 8;
nuclear@9 54 fmaxx = maxx << 8;
nuclear@9 55 fmaxy = maxy << 8;
nuclear@9 56
nuclear@9 57 for(;;) {
nuclear@9 58 int32_t x, y, t;
nuclear@9 59
nuclear@9 60 if(oc0 & oc1) return 0; /* both have points with the same outbit, not visible */
nuclear@9 61 if(!(oc0 | oc1)) break; /* both points are inside */
nuclear@9 62
nuclear@9 63 oc_out = oc0 ? oc0 : oc1;
nuclear@9 64
nuclear@9 65 if(oc_out & TOP) {
nuclear@9 66 t = FIXDIV(fminy - fy0, fy1 - fy0);
nuclear@9 67 x = LERP(fx0, fx1, t);
nuclear@9 68 y = fminy;
nuclear@9 69 } else if(oc_out & BOTTOM) {
nuclear@9 70 t = FIXDIV(fmaxy - fy0, fy1 - fy0);
nuclear@9 71 x = LERP(fx0, fx1, t);
nuclear@9 72 y = fmaxy;
nuclear@9 73 } else if(oc_out & LEFT) {
nuclear@9 74 t = FIXDIV(fminx - fx0, fx1 - fx0);
nuclear@9 75 x = fminx;
nuclear@9 76 y = LERP(fy0, fy1, t);
nuclear@9 77 } else if(oc_out & RIGHT) {
nuclear@9 78 t = FIXDIV(fmaxx - fx0, fx1 - fx0);
nuclear@9 79 x = fmaxx;
nuclear@9 80 y = LERP(fy0, fy1, t);
nuclear@9 81 }
nuclear@9 82
nuclear@9 83 if(oc_out == oc0) {
nuclear@9 84 fx0 = x;
nuclear@9 85 fy0 = y;
nuclear@9 86 oc0 = outcode(fx0 >> 8, fy0 >> 8, minx, miny, maxx, maxy);
nuclear@9 87 } else {
nuclear@9 88 fx1 = x;
nuclear@9 89 fy1 = y;
nuclear@9 90 oc1 = outcode(fx1 >> 8, fy1 >> 8, minx, miny, maxx, maxy);
nuclear@9 91 }
nuclear@9 92 }
nuclear@9 93
nuclear@9 94 *x0 = fx0 >> 8;
nuclear@9 95 *y0 = fy0 >> 8;
nuclear@9 96 *x1 = fx1 >> 8;
nuclear@9 97 *y1 = fy1 >> 8;
nuclear@9 98 return 1;
nuclear@9 99 }
nuclear@9 100
nuclear@9 101 void draw_line(uint32_t *fb, int fbwidth, uint32_t col, int x0, int y0, int x1, int y1)
nuclear@9 102 {
nuclear@9 103 int i, dx, dy, x_inc, y_inc, error;
nuclear@9 104
nuclear@9 105 fb += y0 * fbwidth + x0;
nuclear@9 106
nuclear@9 107 dx = x1 - x0;
nuclear@9 108 dy = y1 - y0;
nuclear@9 109
nuclear@9 110 if(dx >= 0) {
nuclear@9 111 x_inc = 1;
nuclear@9 112 } else {
nuclear@9 113 x_inc = -1;
nuclear@9 114 dx = -dx;
nuclear@9 115 }
nuclear@9 116 if(dy >= 0) {
nuclear@9 117 y_inc = fbwidth;
nuclear@9 118 } else {
nuclear@9 119 y_inc = -fbwidth;
nuclear@9 120 dy = -dy;
nuclear@9 121 }
nuclear@9 122
nuclear@9 123 if(dx > dy) {
nuclear@9 124 error = dy * 2 - dx;
nuclear@9 125 for(i=0; i<=dx; i++) {
nuclear@9 126 *fb = col;
nuclear@9 127 if(error >= 0) {
nuclear@9 128 error -= dx * 2;
nuclear@9 129 fb += y_inc;
nuclear@9 130 }
nuclear@9 131 error += dy * 2;
nuclear@9 132 fb += x_inc;
nuclear@9 133 }
nuclear@9 134 } else {
nuclear@9 135 error = dx * 2 - dy;
nuclear@9 136 for(i=0; i<=dy; i++) {
nuclear@9 137 *fb = col;
nuclear@9 138 if(error >= 0) {
nuclear@9 139 error -= dy * 2;
nuclear@9 140 fb += x_inc;
nuclear@9 141 }
nuclear@9 142 error += dx * 2;
nuclear@9 143 fb += y_inc;
nuclear@9 144 }
nuclear@9 145 }
nuclear@9 146 }