1 // vector.cpp, by iq_132. aa mods by dink
2 #include "tiles_generic.h"
3 #include "math.h"
4
5 #define TABLE_SIZE 0x10000 // excessive?
6
7 struct vector_line {
8 INT32 x;
9 INT32 y;
10 INT32 color;
11 UINT8 intensity;
12 };
13
14 static struct vector_line *vector_table;
15 struct vector_line *vector_ptr; // pointer
16 static INT32 vector_cnt;
17 static UINT32 *pBitmap = NULL;
18 static UINT32 *pPalette = NULL;
19
20 static INT32 clip_xmin, clip_xmax; // clipping for the final blit
21 static INT32 clip_ymin, clip_ymax;
22
23 static float vector_scaleX = 1.00;
24 static float vector_scaleY = 1.00;
25 static INT32 vector_scaleX_int = 0;
26 static INT32 vector_scaleY_int = 0;
27 static INT32 vector_offsetX = 0;
28 static INT32 vector_offsetY = 0;
29 static float vector_gamma_corr = 1.2;
30 static float vector_intens = 1.0;
31 static INT32 vector_antialias = 1;
32 static INT32 vector_beam = 0x0001f65e; // 16.16 beam width
33
34 #define CLAMP8(x) do { if (x > 0xff) x = 0xff; if (x < 0) x = 0; } while (0)
35
36 static UINT8 gammaLUT[256];
37 static UINT32 *cosineLUT;
38
vector_set_clip(INT32 xmin,INT32 xmax,INT32 ymin,INT32 ymax)39 void vector_set_clip(INT32 xmin, INT32 xmax, INT32 ymin, INT32 ymax)
40 {
41 clip_xmin = xmin;
42 clip_xmax = xmax;
43 clip_ymin = ymin;
44 clip_ymax = ymax;
45 }
46
vector_set_gamma(float gamma_corr)47 void vector_set_gamma(float gamma_corr)
48 {
49 for (INT32 i = 0; i < 256; i++) {
50 INT32 gamma = pow((float)i / 255.0, 1.0 / vector_gamma_corr) * (float)((1 << 8) - 1) + 0.5;
51 CLAMP8(gamma);
52 gammaLUT[i] = gamma;
53 }
54 }
55
vector_set_offsets(INT32 x,INT32 y)56 void vector_set_offsets(INT32 x, INT32 y)
57 {
58 vector_offsetX = x;
59 vector_offsetY = y;
60 }
61
vector_set_scale(INT32 x,INT32 y)62 void vector_set_scale(INT32 x, INT32 y)
63 {
64 vector_scaleX_int = x;
65 vector_scaleY_int = y;
66
67 if (x == 0 || x == -1)
68 vector_scaleX = 1.00;
69 else
70 vector_scaleX = (float)nScreenWidth / x;
71
72 if (y == 0 || y == -1)
73 vector_scaleY = 1.00;
74 else
75 vector_scaleY = (float)nScreenHeight / y;
76 }
77
vector_rescale(INT32 x,INT32 y)78 void vector_rescale(INT32 x, INT32 y)
79 {
80 if(BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL)
81 BurnDrvSetVisibleSize(y, x);
82 else
83 BurnDrvSetVisibleSize(x, y);
84 Reinitialise();
85 GenericTilesExit();
86 GenericTilesInit(); // create pTransDraw w/ new size
87 BurnFree(pBitmap);
88 pBitmap = (UINT32*)BurnMalloc(nScreenWidth * nScreenHeight * sizeof(INT32));
89
90 vector_set_clip(0, nScreenWidth, 0, nScreenHeight);
91
92 vector_set_scale(vector_scaleX_int, vector_scaleY_int);
93
94 // This is bit hacky, but thicker lines are more enjoyable at 1080p -barbudreadmon
95 vector_intens = (y == 1080 ? 2.0 : 1.0);
96 }
97
vector_add_point(INT32 x,INT32 y,INT32 color,INT32 intensity)98 void vector_add_point(INT32 x, INT32 y, INT32 color, INT32 intensity)
99 {
100 if (vector_cnt + 1 > (TABLE_SIZE - 2)) return;
101 vector_ptr->x = (vector_antialias == 0) ? (((x + 0x8000) >> 16) + vector_offsetX) : (x + (vector_offsetX << 16));
102 vector_ptr->y = (vector_antialias == 0) ? (((y + 0x8000) >> 16) + vector_offsetY) : (y + (vector_offsetY << 16));
103 vector_ptr->color = color;
104
105 intensity *= vector_intens; // intensity correction
106 CLAMP8(intensity);
107 vector_ptr->intensity = (vector_antialias == 0) ? gammaLUT[intensity] : intensity;
108
109 vector_cnt++;
110 vector_ptr++;
111 vector_ptr->color = -1; // mark it as the last one to save some cycles later...
112 }
113
vector_draw_pixel(INT32 x,INT32 y,INT32 pixel)114 static inline void vector_draw_pixel(INT32 x, INT32 y, INT32 pixel)
115 {
116 if (x >= 0 && x < nScreenWidth && y >= 0 && y < nScreenHeight)
117 {
118 INT32 coords = y * nScreenWidth + x;
119 UINT32 d = pBitmap[coords];
120 pixel = pPalette[pixel];
121
122 if (d) { // if something is already there, mix it.
123 INT32 r = ((d >> 16) & 0xff) + ((pixel >> 16) & 0xff);
124 INT32 g = ((d >> 8) & 0xff) + ((pixel >> 8) & 0xff);
125 INT32 b = (d & 0xff) + (pixel & 0xff);
126 CLAMP8(r); CLAMP8(g); CLAMP8(b);
127
128 pBitmap[coords] = (r << 16) | (g << 8) | b;
129 }
130 else
131 {
132 pBitmap[y * nScreenWidth + x] = pixel;
133 }
134 }
135 }
136
divop(INT32 dividend,INT32 divisor)137 static inline INT32 divop(INT32 dividend, INT32 divisor)
138 {
139 if (!(divisor >>= 12)) return (1 << 16); // avoid division by zero
140
141 dividend = (dividend << 4) / divisor;
142
143 if (dividend > (1 << 16)) return (1 << 16); // safety net
144 else if (dividend < -(1 << 16)) return -(1 << 16);
145
146 return dividend;
147 }
148
vec_mult(INT32 parm1,INT32 parm2)149 static inline INT32 vec_mult(INT32 parm1, INT32 parm2) // stolen from mame, we need to re-write this.
150 {
151 INT32 temp, result;
152
153 temp = abs(parm1);
154 result = (temp&0x0000ffff) * (parm2&0x0000ffff);
155 result >>= 16;
156 result += (temp&0x0000ffff) * (parm2>>16 );
157 result += (temp>>16 ) * (parm2&0x0000ffff);
158 result >>= 16;
159 result += (temp>>16 ) * (parm2>>16 );
160
161 if( parm1 < 0 )
162 return(-result);
163 else
164 return( result);
165 }
166
lineSimple(INT32 x0,INT32 y0,INT32 x1,INT32 y1,INT32 color,INT32 intensity)167 static void lineSimple(INT32 x0, INT32 y0, INT32 x1, INT32 y1, INT32 color, INT32 intensity)
168 {
169 color = color * 256 + intensity;
170 UINT32 p = pPalette[color];
171 if (p == 0) return; // safe to assume we can't draw black??
172 INT32 straight = 0;
173
174 if (x0 == x1 || y0 == y1) straight = 1;
175
176 if (vector_antialias == 0) {
177 // http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm
178
179 INT32 dx = abs(x1 - x0);
180 INT32 dy = abs(y1 - y0);
181 INT32 sx = x0 < x1 ? 1 : -1;
182 INT32 sy = y0 < y1 ? 1 : -1;
183 INT32 err = (dx>dy ? dx : -dy)/2, e2;
184
185 while (1)
186 {
187 vector_draw_pixel(x0, y0, color);
188
189 if (x0 == x1 && y0 == y1) break;
190
191 e2 = err;
192
193 if (e2 >-dx) { err -= dy; x0 += sx; }
194 if (e2 < dy) { err += dx; y0 += sy; }
195 }
196 } else {
197 // anti-aliased
198
199 INT32 dx = abs(x1 - x0);
200 INT32 dy = abs(y1 - y0);
201 INT32 width = vector_beam;
202 INT32 sx, sy, aa, yy, xx;
203 INT32 der = 0xff - intensity;
204 der = ((double)der / 1.2);
205
206 if (dx >= dy) {
207 sx = x0 <= x1 ? 1 : -1;
208 sy = divop(y1 - y0, dx);
209 if (sy < 0)
210 dy--;
211 x0 >>= 16;
212 xx = x1 >> 16;
213
214 width = vec_mult(vector_beam << 4, cosineLUT[abs(sy) >> 5]);
215 y0 -= width >> 1;
216
217 while (1) {
218 dx = width;
219 dy = y0 >> 16;
220 aa = (0xff - (0xff & (y0 >> 8))) - der;
221 CLAMP8(aa);
222 vector_draw_pixel(x0, dy++, (color & 0xff00) + gammaLUT[aa]);
223 dx -= 0x10000 - (0xffff & y0);
224 aa = ((dx >> 8) & 0xff) - der;
225 dx >>= 16;
226 while (dx--)
227 vector_draw_pixel(x0, dy++, (color & 0xff00) + gammaLUT[color & 0xff]);
228 CLAMP8(aa);
229 vector_draw_pixel(x0, dy, (color & 0xff00) + gammaLUT[aa]);
230 if (x0 == xx) break;
231 x0 += sx;
232 y0 += sy;
233 }
234 } else {
235 sy = y0 <= y1 ? 1 : -1;
236 sx = divop(x1 - x0, dy);
237 if (sx < 0)
238 dx--;
239 y0 >>= 16;
240 yy = y1 >> 16;
241
242 width = vec_mult(vector_beam << 4, cosineLUT[abs(sx) >> 5]);
243 x0 -= width >> 1;
244
245 while (1) {
246 dy = width;
247 dx = x0 >> 16;
248 aa = (0xff - (0xff & (x0 >> 8))) - der;
249 CLAMP8(aa);
250 vector_draw_pixel(dx++, y0, (color & 0xff00) + gammaLUT[aa]);
251 dy -= 0x10000 - (0xffff & x0);
252 aa = ((dy >> 8) & 0xff) - der;
253 dy >>= 16;
254 while (dy--)
255 vector_draw_pixel(dx++, y0, (color & 0xff00) + gammaLUT[color & 0xff]);
256 CLAMP8(aa);
257 vector_draw_pixel(dx, y0, (color & 0xff00) + gammaLUT[aa]);
258 if (y0 == yy) break;
259 y0 += sy;
260 x0 += sx;
261 }
262 }
263 }
264 }
265
draw_vector(UINT32 * palette)266 void draw_vector(UINT32 *palette)
267 {
268 struct vector_line *ptr = &vector_table[0];
269
270 INT32 prev_x = 0, prev_y = 0;
271
272 memset (pBitmap, 0, nScreenWidth * nScreenHeight * sizeof(INT32));
273 pBurnDrvPalette = pPalette = palette;
274
275 for (INT32 i = 0; i < vector_cnt && i < TABLE_SIZE; i++, ptr++)
276 {
277 if (ptr->color == -1) break;
278
279 INT32 curr_y = ptr->y * vector_scaleY;
280 INT32 curr_x = ptr->x * vector_scaleX;
281
282 if (ptr->intensity != 0) { // intensity 0 means turn off the beam...
283 lineSimple(curr_x, curr_y, prev_x, prev_y, ptr->color, ptr->intensity);
284 }
285
286 prev_x = curr_x;
287 prev_y = curr_y;
288 }
289
290 // copy to the screen, only draw pixels that aren't black
291 // should be safe for any bit depth with putpix
292 {
293 memset (pBurnDraw, 0, nScreenWidth * nScreenHeight * nBurnBpp);
294
295 for (INT32 y = 0; y < nScreenHeight; y++)
296 {
297 if (y < clip_ymin || y > clip_ymax) continue;
298 UINT32 idx = (y * nScreenWidth);
299
300 for (INT32 x = 0; x < nScreenWidth; x++)
301 {
302 if (x < clip_xmin || x > clip_xmax) continue;
303
304 UINT32 p = pBitmap[idx + x];
305
306 if (p) {
307 PutPix(pBurnDraw + (idx + x) * nBurnBpp, BurnHighCol((p >> 16) & 0xff, (p >> 8) & 0xff, p & 0xff, 0));
308 }
309 }
310 }
311 }
312 }
313
vector_reset()314 void vector_reset()
315 {
316 vector_cnt = 0;
317 vector_ptr = &vector_table[0];
318 vector_ptr->color = -1;
319 }
320
vector_init()321 void vector_init()
322 {
323 GenericTilesInit();
324
325 vector_set_clip(0, nScreenWidth, 0, nScreenHeight);
326
327 pBitmap = (UINT32*)BurnMalloc(nScreenWidth * nScreenHeight * sizeof(INT32));
328
329 vector_table = (struct vector_line*)BurnMalloc(TABLE_SIZE * sizeof(vector_line));
330
331 memset (vector_table, 0, TABLE_SIZE * sizeof(vector_line));
332
333 vector_set_scale(-1, -1); // default 1x
334 vector_set_offsets(0, 0);
335 vector_set_gamma(vector_gamma_corr);
336
337 cosineLUT = (UINT32*)BurnMalloc(2049 * sizeof(UINT32));
338 for (INT32 i = 0; i < 2049; i++) {
339 cosineLUT[i] = (INT32)((double)(1.0 / cos(atan((double)i / 2048.0))) * 0x10000000 + 0.5);
340 }
341
342 vector_reset();
343 }
344
vector_exit()345 void vector_exit()
346 {
347 GenericTilesExit();
348
349 if (pBitmap) {
350 BurnFree (pBitmap);
351 }
352
353 pPalette = NULL;
354
355 BurnFree (vector_table);
356 vector_ptr = NULL;
357
358 BurnFree (cosineLUT);
359 }
360
vector_scan(INT32 nAction)361 INT32 vector_scan(INT32 nAction)
362 {
363 struct BurnArea ba;
364
365 if (nAction & ACB_VOLATILE) {
366 memset(&ba, 0, sizeof(ba));
367
368 ba.Data = (UINT8*)vector_table;
369 ba.nLen = TABLE_SIZE * sizeof(vector_line);
370 ba.szName = "Vector Table";
371 BurnAcb(&ba);
372
373 SCAN_VAR(vector_cnt);
374 }
375
376 if (nAction & ACB_WRITE) {
377 vector_ptr = &vector_table[vector_cnt];
378 }
379
380 return 0;
381 }
382