3dgfx code, untested
[metatoy] / src / gfxutil.c
1 #include <string.h>
2 #include <assert.h>
3 #include "game.h"
4 #include "gfxutil.h"
5 #include "3dgfx/3dgfx.h"
6
7 enum {
8         IN              = 0,
9         LEFT    = 1,
10         RIGHT   = 2,
11         TOP             = 4,
12         BOTTOM  = 8
13 };
14
15 static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax)
16 {
17         int code = 0;
18
19         if(x < xmin) {
20                 code |= LEFT;
21         } else if(x > xmax) {
22                 code |= RIGHT;
23         }
24         if(y < ymin) {
25                 code |= TOP;
26         } else if(y > ymax) {
27                 code |= BOTTOM;
28         }
29         return code;
30 }
31
32 #define FIXMUL(a, b)    (((a) * (b)) >> 8)
33 #define FIXDIV(a, b)    (((a) << 8) / (b))
34
35 #define LERP(a, b, t)   ((a) + FIXMUL((b) - (a), (t)))
36
37 int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax)
38 {
39         int oc_out;
40
41         int oc0 = outcode(*x0, *y0, xmin, ymin, xmax, ymax);
42         int oc1 = outcode(*x1, *y1, xmin, ymin, xmax, ymax);
43
44         long fx0, fy0, fx1, fy1, fxmin, fymin, fxmax, fymax;
45
46         if(!(oc0 | oc1)) return 1;      /* both points are inside */
47
48         fx0 = *x0 << 8;
49         fy0 = *y0 << 8;
50         fx1 = *x1 << 8;
51         fy1 = *y1 << 8;
52         fxmin = xmin << 8;
53         fymin = ymin << 8;
54         fxmax = xmax << 8;
55         fymax = ymax << 8;
56
57         for(;;) {
58                 long x, y, t;
59
60                 if(oc0 & oc1) return 0;         /* both have points with the same outbit, not visible */
61                 if(!(oc0 | oc1)) break;         /* both points are inside */
62
63                 oc_out = oc0 ? oc0 : oc1;
64
65                 if(oc_out & TOP) {
66                         t = FIXDIV(fymin - fy0, fy1 - fy0);
67                         x = LERP(fx0, fx1, t);
68                         y = fymin;
69                 } else if(oc_out & BOTTOM) {
70                         t = FIXDIV(fymax - fy0, fy1 - fy0);
71                         x = LERP(fx0, fx1, t);
72                         y = fymax;
73                 } else if(oc_out & LEFT) {
74                         t = FIXDIV(fxmin - fx0, fx1 - fx0);
75                         x = fxmin;
76                         y = LERP(fy0, fy1, t);
77                 } else /*if(oc_out & RIGHT)*/ {
78                         t = FIXDIV(fxmax - fx0, fx1 - fx0);
79                         x = fxmax;
80                         y = LERP(fy0, fy1, t);
81                 }
82
83                 if(oc_out == oc0) {
84                         fx0 = x;
85                         fy0 = y;
86                         oc0 = outcode(fx0 >> 8, fy0 >> 8, xmin, ymin, xmax, ymax);
87                 } else {
88                         fx1 = x;
89                         fy1 = y;
90                         oc1 = outcode(fx1 >> 8, fy1 >> 8, xmin, ymin, xmax, ymax);
91                 }
92         }
93
94         *x0 = fx0 >> 8;
95         *y0 = fy0 >> 8;
96         *x1 = fx1 >> 8;
97         *y1 = fy1 >> 8;
98         return 1;
99 }
100
101 void draw_line(int x0, int y0, int x1, int y1, unsigned char color)
102 {
103         int i, dx, dy, x_inc, y_inc, error;
104         unsigned char *fb = framebuf;
105
106         fb += y0 * FB_WIDTH + x0;
107
108         dx = x1 - x0;
109         dy = y1 - y0;
110
111         if(dx >= 0) {
112                 x_inc = 1;
113         } else {
114                 x_inc = -1;
115                 dx = -dx;
116         }
117         if(dy >= 0) {
118                 y_inc = FB_WIDTH;
119         } else {
120                 y_inc = -FB_WIDTH;
121                 dy = -dy;
122         }
123
124         if(dx > dy) {
125                 error = dy * 2 - dx;
126                 for(i=0; i<=dx; i++) {
127                         *fb = color;
128                         if(error >= 0) {
129                                 error -= dx * 2;
130                                 fb += y_inc;
131                         }
132                         error += dy * 2;
133                         fb += x_inc;
134                 }
135         } else {
136                 error = dx * 2 - dy;
137                 for(i=0; i<=dy; i++) {
138                         *fb = color;
139                         if(error >= 0) {
140                                 error -= dy * 2;
141                                 fb += x_inc;
142                         }
143                         error += dx * 2;
144                         fb += y_inc;
145                 }
146         }
147 }
148
149 void draw_billboard(float x, float y, float z, float size, int lum, int a)
150 {
151         float m[16];
152         size *= 0.5f;
153
154         g3d_matrix_mode(G3D_MODELVIEW);
155         g3d_push_matrix();
156
157         g3d_translate(x, y, z);
158
159         g3d_get_matrix(G3D_MODELVIEW, m);
160         /* make the upper 3x3 part of the matrix identity */
161         m[0] = m[5] = m[10] = 1.0f;
162         m[1] = m[2] = m[3] = m[4] = m[6] = m[7] = m[8] = m[9] = 0.0f;
163         g3d_load_matrix(m);
164
165         g3d_begin(G3D_QUADS);
166         g3d_color2b(lum, a);
167         g3d_texcoord(0, 0);
168         g3d_vertex(-size, -size, 0);
169         g3d_texcoord(1, 0);
170         g3d_vertex(size, -size, 0);
171         g3d_texcoord(1, 1);
172         g3d_vertex(size, size, 0);
173         g3d_texcoord(0, 1);
174         g3d_vertex(-size, size, 0);
175         g3d_end();
176
177         g3d_pop_matrix();
178 }