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