1 /*
2 * OpenBOR - http://www.LavaLit.com
3 * -----------------------------------------------------------------------
4 * All rights reserved, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2011 OpenBOR Team
7 */
8
9 // Primitive drawing functions. Should really be done in ASM...
10 // Last update: 24-jun-2002
11
12 #include "types.h"
13
14 #ifndef NULL
15 #define NULL ((void*)0)
16 #endif
17
18
19 #define abso(x) (x<0?-x:x)
20
21
22 // Not a particularly fast line function, but it works, and clips!
line(int sx,int sy,int ex,int ey,int colour,s_screen * screen,int alpha)23 void line(int sx, int sy, int ex, int ey, int colour, s_screen *screen, int alpha){
24
25 int diffx, diffy;
26 int absdiffx, absdiffy;
27 int xdir, ydir;
28 int thres;
29 int d;
30 unsigned char *lut;
31
32 // Some off-screen lines may slip through this test!
33 if(sx<0 && ex<0) return;
34 if(sy<0 && ey<0) return;
35 if(sx>=screen->width && ex>=screen->width) return;
36 if(sy>=screen->height && ey>=screen->height) return;
37
38
39 // Check clipping and calculate new coords if necessary
40
41 diffx = ex - sx;
42 diffy = ey - sy;
43
44 if(sx<0){
45 sy -= (sx*diffy/diffx);
46 sx = 0;
47 }
48 if(sy<0){
49 sx -= (sy*diffx/diffy);
50 sy = 0;
51 }
52 if(sx>=screen->width){
53 sy -= ((sx-screen->width)*diffy/diffx);
54 sx = screen->width-1;
55 }
56 if(sy>=screen->height){
57 sx -= ((sy-screen->height)*diffx/diffy);
58 sy = screen->height-1;
59 }
60
61 if(ex<0){
62 ey -= (ex*diffy/diffx);
63 ex = 0;
64 }
65 if(ey<0){
66 ex -= (ey*diffx/diffy);
67 ey = 0;
68 }
69 if(ex>=screen->width){
70 ey -= ((ex-screen->width)*diffy/diffx);
71 ex = screen->width-1;
72 }
73 if(ey>=screen->height){
74 ex -= ((ey-screen->height)*diffx/diffy);
75 ey = screen->height-1;
76 }
77
78
79 // Second test: the lines that passed test 1 won't pass this time!
80 if(sx<0 || ex<0) return;
81 if(sy<0 || ey<0) return;
82 if(sx>=screen->width || ex>=screen->width) return;
83 if(sy>=screen->height || ey>=screen->height) return;
84
85
86 // Recalculate directions
87 diffx = ex - sx;
88 diffy = ey - sy;
89
90 absdiffx = abso(diffx);
91 absdiffy = abso(diffy);
92
93 sy *= screen->width;
94 ey *= screen->width;
95
96 lut = alpha>0?blendtables[alpha-1]:NULL;
97
98 if(lut) lut += (colour<<8);
99
100 if(absdiffx > absdiffy){
101 // Draw a flat line
102 thres = absdiffx >> 1;
103 xdir = 1;
104 if(diffx<0) xdir = -xdir;
105 ydir = screen->width;
106 if(diffy<0) ydir = -ydir;
107 while(sx!=ex){
108 d = sx+sy;
109 screen->data[d] = (lut && screen->data[d])?(lut[screen->data[d]]):colour;
110 sx += xdir;
111 if((thres-=absdiffy) <= 0){
112 sy += ydir;
113 thres += absdiffx;
114 }
115 }
116 d = ex+ey;
117 screen->data[d] = (lut && screen->data[d])?(lut[screen->data[d]]):colour;
118 return;
119 }
120
121 // Draw a high line
122 thres = absdiffy >> 1;
123 xdir = 1;
124 if(diffx<0) xdir = -1;
125 ydir = screen->width;
126 if(diffy<0) ydir = -ydir;
127 while(sy!=ey){
128 d = sx+sy;
129 screen->data[d] = (lut && screen->data[d])?(lut[screen->data[d]]):colour;;
130 sy += ydir;
131 if((thres-=absdiffx) <= 0){
132 sx += xdir;
133 thres += absdiffy;
134 }
135 }
136 d = ex+ey;
137 screen->data[d] = (lut && screen->data[d])?(lut[screen->data[d]]):colour;
138 }
139
140
141
142
143
drawbox(int x,int y,int width,int height,int colour,s_screen * screen,int alpha)144 void drawbox(int x, int y, int width, int height, int colour, s_screen *screen, int alpha)
145 {
146 unsigned char *cp;
147 unsigned char *lut;
148
149 if(width<=0) return;
150 if(height<=0) return;
151 if(screen==NULL) return;
152
153 if(x<0){
154 if((width+=x)<=0) return;
155 x = 0;
156 }
157 else if(x>=screen->width) return;
158 if(y<0){
159 if((height+=y)<=0) return;
160 y = 0;
161 }
162 else if(y>=screen->height) return;
163 if(x+width>screen->width) width = screen->width-x;
164 if(y+height>screen->height) height = screen->height-y;
165
166 cp = (unsigned char*)screen->data + y*screen->width + x;
167 lut = alpha>0?blendtables[alpha-1]:NULL;
168 if(lut) lut += (colour<<8);
169 while(--height>=0){
170 for(x=0;x<width;x++){
171 *cp = (lut&&*cp)?(lut[((int)(*cp)) & 0xFF]):colour;
172 ++cp;
173 }
174 cp += screen->width - width;
175 }
176 }
177
178
179
180 // Putpixel used by circle function
putpixel(unsigned x,unsigned y,int colour,s_screen * screen,int alpha)181 void putpixel(unsigned x, unsigned y, int colour, s_screen *screen, int alpha){
182 int pixind;
183 unsigned char *lut;
184 if(x>screen->width || y>screen->height) return;
185 pixind = x+y*screen->width;
186 lut = alpha>0?blendtables[alpha-1]:NULL;
187 if(lut) lut += (colour<<8);
188 screen->data[pixind] = (lut&&screen->data[pixind])?(lut[(int)(screen->data[pixind]) & 0xFF]):colour;
189 }
190
191
192
193
194 // Code to draw a circle.
195 // I ripped this, not sure how it works...
196 // It seems it devides the circle into 8 parts, which are drawn
197 // simultaneously.
198 // Not much optimization, though, since every pixel is clipped
199 // separately.
200
circle(int x,int y,int rad,int col,s_screen * screen,int alpha)201 void circle(int x, int y, int rad, int col, s_screen *screen, int alpha){
202 int cx = 0; // 'Circle X'
203 int cy = rad; // 'Circle Y'
204 int df = 1 - rad;
205 int d_e = 3;
206 int d_se = -2 * rad + 5;
207
208 do{
209 putpixel(x+cx, y+cy, col, screen, alpha);
210 if(cx) putpixel(x-cx, y+cy, col, screen, alpha);
211 if(cy) putpixel(x+cx, y-cy, col, screen, alpha);
212 if(cx && cy) putpixel(x-cx, y-cy, col, screen, alpha);
213
214 if(cx != cy){
215 putpixel(x+cy, y+cx, col, screen, alpha);
216 if(cx) putpixel(x+cy, y-cx, col, screen, alpha);
217 if(cy) putpixel(x-cy, y+cx, col, screen, alpha);
218 if(cx && cy) putpixel(x-cy, y-cx, col, screen, alpha);
219 }
220
221 if(df<0){
222 df += d_e;
223 d_e += 2;
224 d_se += 2;
225 }
226 else{
227 df += d_se;
228 d_e += 2;
229 d_se += 4;
230 --cy;
231 }
232 ++cx;
233 }while(cx<=cy);
234 }
235
236
237
238
239
240
241
242
243