some trivial optimizations to shadowcaster
[k8-threat-experiments.git] / src / zlight.c
blob3b4303f7c6d4ef50d4db4ae395e3de2f9d3eba42
1 #include "zlight.h"
3 #include "common.h"
4 #include "zpolymod.h"
5 #include "tlevel.h"
6 #include "tgfx.h"
9 ////////////////////////////////////////////////////////////////////////////////
10 static Uint16 sqrttbl[200000];
13 /* n: [0..(1<<30-1)] */
14 static inline unsigned int isqrt0 (unsigned int n) {
15 unsigned int s, t;
16 #define ISQRT_SQRT_BIT(k) if (n >= (t = (s+(1<<(k-1)))<<(k+1))) { n -= t; s |= 1<<k; }
17 s = 0;
18 ISQRT_SQRT_BIT(14); ISQRT_SQRT_BIT(13); ISQRT_SQRT_BIT(12); ISQRT_SQRT_BIT(11); ISQRT_SQRT_BIT(10);
19 ISQRT_SQRT_BIT(9); ISQRT_SQRT_BIT(8); ISQRT_SQRT_BIT(7); ISQRT_SQRT_BIT(6); ISQRT_SQRT_BIT(5);
20 ISQRT_SQRT_BIT(4); ISQRT_SQRT_BIT(3); ISQRT_SQRT_BIT(2); ISQRT_SQRT_BIT(1);
21 if (n > s<<1) s |= 1UL;
22 #undef ISQRT_SQRT_BIT
23 return s;
27 __attribute__((constructor)) static void _ctor_sqrttbl (void) {
28 for (size_t f = 0; f < sizeof(sqrttbl)/sizeof(sqrttbl[0]); ++f) sqrttbl[f] = isqrt0(f);
32 static inline unsigned int isqrt (unsigned int n) {
33 return (n < sizeof(sqrttbl)/sizeof(sqrttbl[0]) ? sqrttbl[n] : isqrt0(n));
38 static ccBool r_lights_additive = CC_FALSE;
39 CONVAR_BOOL(r_lights_additive, r_lights_additive, 0, "additive intensity lights?")
41 static int r_lights_additive = 0;
44 ////////////////////////////////////////////////////////////////////////////////
45 void (*lb_monster_hit_by_light) (int mnum, int x, int y, int alpha);
48 ////////////////////////////////////////////////////////////////////////////////
49 /* lightbuf format (bytes):
50 * (b,g,r,a) triplets
51 * (b,g,r) are premultiplied (wow! i'm smart!)
53 static Uint32 lightbuf[MAP_RES_Y*MAP_RES_X]; /* keeps bgra values */
56 ////////////////////////////////////////////////////////////////////////////////
57 int light_dump = 0;
58 int player_light = 0; /* is this player light? player light lights monsters */
61 ////////////////////////////////////////////////////////////////////////////////
62 /* current light parameters for tracer */
63 static int z_light_mindist = 0;
64 static int lcx, lcy, lrad;
65 static Uint8 lalpha;
66 static Uint32 lbgr;
69 ////////////////////////////////////////////////////////////////////////////////
70 static inline void lb_add_rgb (int x, int y, Uint32 bgr, Uint8 alpha) {
71 Uint32 *pos = lightbuf+320*y+x, aa;
72 if (!r_lights_additive) {
73 aa = K8MAX(alpha, (pos[0]>>24));
74 } else {
75 aa = byteclamp((pos[0]>>24)+alpha);
77 // premultiply light color
78 if (bgr) {
79 Uint32 add, add_nc, cbits, cmask;
80 bgr =
81 ((((bgr&0xff00ff)*(alpha+1)+0x800080)>>8)&0xff00ff)|
82 ((((bgr&0x00ff00)*(alpha+1)+0x008000)>>8)&0x00ff00);
83 // you are not expected to understand this
84 // but if you are really curious, this is
85 // 8-bit rgb adding with clamping
86 add = (pos[0]&0xffffffu)+bgr;
87 add_nc = (pos[0]&0xffffffu)^bgr;
88 cbits = (add^add_nc)&0x01010100;
89 cmask = cbits-(cbits>>8);
90 bgr = ((add^cbits)|cmask)&0xffffffu;
91 *pos = bgr|(aa<<24);
92 } else {
93 *pos = (pos[0]&0x00ffffffu)|(aa<<24);
98 ////////////////////////////////////////////////////////////////////////////////
99 static void lb_put_light_point (int x, int y) {
100 int dst = isqrt((x-lcx)*(x-lcx)+(y-lcy)*(y-lcy));
101 if (dst >= z_light_mindist) {
102 int a = lalpha-(dst*lalpha/lrad);
103 if (a > 0 && mapbmp_orig[y][x] < 16) {
104 if (a > 255) a = 255;
105 //a = 200;
106 if (a > 128) a = 128;
107 if (player_light && monbmp[y][x]) {
108 /* player light hits some monster */
109 lb_monster_hit_by_light(monbmp[y][x]-1, x, y, a);
111 lb_add_rgb(x, y, lbgr, a);
117 ////////////////////////////////////////////////////////////////////////////////
118 static Uint8 *lightmask = NULL; /* bitmap; bit 31 == leftmost pos */
119 static int lm_wdt = 0, lm_hgt = 0;
122 static void prepare_lightmask (void) {
123 int wdt = lrad*2+1, hgt = wdt;
124 if (wdt*hgt > lm_wdt*lm_hgt) {
125 lightmask = realloc(lightmask, wdt*hgt*sizeof(lightmask[0]));
126 if (lightmask == NULL) {
127 fprintf(stderr, "ZLIGHT: out of memory for lightmask!\n");
128 abort();
131 lm_wdt = wdt;
132 lm_hgt = hgt;
133 memset(lightmask, 0, lm_wdt*lm_hgt*sizeof(lightmask[0]));
137 static inline void lb_light_plot (int x, int y) {
138 int a;
139 x -= lcx-lrad;
140 y -= lcy-lrad;
141 if (x < 0 || y < 0 || x >= lm_wdt || y >= lm_hgt) abort();
142 a = lm_wdt*y+x;
143 lightmask[a] = 1;
147 static void lb_light_hline (int x, int y, int len) {
148 int a;
149 x -= lcx-lrad;
150 y -= lcy-lrad;
151 if (x < 0 || y < 0 || x+len-1 >= lm_wdt || y >= lm_hgt) abort();
152 a = lm_wdt*y+x;
153 memset(lightmask+a, 1, len);
157 ////////////////////////////////////////////////////////////////////////////////
158 static void realize_lightmask (void) {
159 int sy = lcy-lrad;
160 for (int dy = 0; dy < lrad*2; ++dy, ++sy) {
161 int sx = lcx-lrad;
162 int a = dy*lm_wdt;
163 for (int dx = 0; dx < lrad*2; ++dx, ++a, ++sx) {
164 if (lightmask[a]) lb_put_light_point(sx, sy);
170 ////////////////////////////////////////////////////////////////////////////////
171 static int trace_point_count;
172 static struct {
173 int x;
174 int y;
175 } trace_plist[8192];
178 void t_draw_line_no_last (int x0, int y0, int x1, int y1) {
179 int dx = K8ABS(x1-x0), sx = (x0 < x1 ? 1 : -1);
180 int dy = -K8ABS(y1-y0), sy = (y0 < y1 ? 1 : -1);
181 int err = dx+dy, e2; /* error value e_xy */
182 for (;;) {
183 if (x0 == x1 && y0 == y1) break;
184 //put_pixel(x0, y0, col);
185 if (x0 >= 0 && y0 >= 0 && x0 < MAP_RES_X && y0 < MAP_RES_Y) {
186 //lb_put_light_point(x0, y0);
187 //lb_add_rgb(x0, y0, lbgr, 255);
188 lb_light_plot(x0, y0);
190 e2 = 2*err;
191 if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
192 if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
197 static void trace_start (void) {
198 trace_point_count = 0;
199 prepare_lightmask();
203 static void trace_end (void) {
204 if (trace_point_count > 1 && trace_plist[trace_point_count-1].x == trace_plist[0].x && trace_plist[trace_point_count-1].y == trace_plist[0].y) {
205 --trace_point_count;
207 if (trace_point_count > 2) {
208 int op = trace_point_count-1;
209 for (int pp = 0; pp < trace_point_count; op = pp++) {
210 t_draw_line_no_last(trace_plist[op].x, trace_plist[op].y, trace_plist[pp].x, trace_plist[pp].y);
216 static inline void trace_add_point (int x, int y) {
217 if (!trace_point_count || trace_plist[trace_point_count-1].x != x || trace_plist[trace_point_count-1].y != y) {
218 trace_plist[trace_point_count].x = x;
219 trace_plist[trace_point_count].y = y;
220 ++trace_point_count;
222 polymod_add_vertex(x, y);
226 static void trace_to_point (int x1, int y1) {
227 int x0 = lcx, y0 = lcy;
228 int dx = K8ABS(x1-x0), sx = (x0 < x1 ? 1 : -1);
229 int dy = -K8ABS(y1-y0), sy = (y0 < y1 ? 1 : -1);
230 int err = dx+dy, e2; /* error value e_xy */
231 int ox = x0, oy = y0, dst = lrad*lrad;
232 for (;;) {
233 if ((x0-lcx)*(x0-lcx)+(y0-lcy)*(y0-lcy) >= dst) {
234 trace_add_point(x0, y0);
235 break;
237 if (mapbmp_orig[y0][x0] >= 16) {
238 trace_add_point(ox, oy);
239 break;
241 ox = x0, oy = y0;
242 e2 = 2*err;
243 if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
244 if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
249 static inline double deg2rad (double angle) {
250 return angle*0.017453292519943295f; // (angle/180)*Math.PI;
254 enum {
255 EDGE_RIGHT = 0x00,
256 EDGE_BOTTOM = 0x01,
257 EDGE_LEFT = 0x02,
258 EDGE_TOP = 0x03
262 static const char *ename[4] = {"RIGHT","BOTTOM","LEFT","TOP"};
265 /* find intersection point between square (lcx-lrad,lcy-lrad)-(lcx+lrad,lcy+lrad)
266 * and ray originating from (lcx,lcy) fired at angle 'angle' degrees;
267 * also return edge code */
268 static void ray_edge_intersection (int angle, int *ix, int *iy, int *edge) {
269 int outcode, ex, ey;
270 double rad;
271 //angle = ((angle%360)+360)%360;
272 /* easy angles */
273 switch (angle) {
274 case 0: *ix = lcx+lrad; *iy = lcy; *edge = EDGE_RIGHT; return;
275 case 45: *ix = lcx+lrad; *iy = lcy+lrad; *edge = EDGE_RIGHT/*|EDGE_BOTTOM*/; return;
276 case 90: *ix = lcx; *iy = lcy+lrad; *edge = EDGE_BOTTOM; return;
277 case 135: *ix = lcx-lrad; *iy = lcy+lrad; *edge = /*EDGE_LEFT|*/EDGE_BOTTOM; return;
278 case 180: *ix = lcx-lrad; *iy = lcy; *edge = EDGE_LEFT; return;
279 case 225: *ix = lcx-lrad; *iy = lcy-lrad; *edge = EDGE_LEFT/*|EDGE_TOP*/; return;
280 case 270: *ix = lcx; *iy = lcy-lrad; *edge = EDGE_TOP; return;
281 case 315: *ix = lcx+lrad; *iy = lcy-lrad; *edge = /*EDGE_RIGHT|*/EDGE_TOP; return;
283 /* now determine outcode */
284 /* 316..359; 0..45: right side */
285 /* 46..135: bottom side */
286 /* 136..225: left side */
287 /* 226..315: top side */
288 if (angle >= 315 || angle <= 45) outcode = EDGE_RIGHT;
289 else if (angle >= 46 && angle <= 135) outcode = EDGE_BOTTOM;
290 else if (angle >= 136 && angle <= 225) outcode = EDGE_LEFT;
291 else if (angle >= 226 && angle <= 315) outcode = EDGE_TOP;
292 else abort(); /* the thing that shoild not be */
293 /* set ex and ey to reasonable big value */
294 rad = deg2rad(angle);
295 ex = lcx+cos(rad)*1000;//(lrad*2+100);
296 ey = lcy+sin(rad)*1000;//(lrad*2+100);
297 /* and find intersection point */
298 /* use formulas y = y0+slope*(x-x0), x = x0+(1/slope)*(y-y0) */
299 if (outcode == EDGE_TOP) {
300 *ix = lcx+(ex-lcx)*((lcy-lrad)-lcy)/(ey-lcy);
301 *iy = lcy-lrad;
302 } else if (outcode == EDGE_BOTTOM) {
303 *ix = lcx+(ex-lcx)*((lcy+lrad)-lcy)/(ey-lcy);
304 *iy = lcy+lrad;
305 } else if (outcode == EDGE_RIGHT) {
306 *iy = lcy+(ey-lcy)*((lcx+lrad)-lcx)/(ex-lcx);
307 *ix = lcx+lrad;
308 } else if (outcode == EDGE_LEFT) {
309 *iy = lcy+(ey-lcy)*((lcx-lrad)-lcx)/(ex-lcx);
310 *ix = lcx-lrad;
311 } else {
312 abort(); /* the thing that shoild not be */
314 *edge = outcode;
318 /******************************************************************************/
319 /* funny recursive 'shadowcasting' algo from roguebasin */
320 /******************************************************************************/
321 static inline int light_is_blocked (int x, int y) {
322 return (x < 0 || y < 0 || x >= MAP_RES_X || y >= MAP_RES_Y || mapbmp_orig[y][x] >= 16);
326 // recursive lightcasting function
327 static void light_octant (int cx, int cy, int row, double start, double end, int radius, int octant) {
328 if (start >= end) {
329 // multipliers for transforming coordinates to other octants
330 static const int mult[4][8] = {
331 {1, 0, 0,-1,-1, 0, 0, 1},
332 {0, 1,-1, 0, 0,-1, 1, 0},
333 {0, 1, 1, 0, 0,-1,-1, 0},
334 {1, 0, 0, 1,-1, 0, 0,-1},
336 int xx = mult[0][octant];
337 int xy = mult[1][octant];
338 int yx = mult[2][octant];
339 int yy = mult[3][octant];
340 int radius_sqr = radius*radius;
341 for (int j = row; j <= radius; ++j) {
342 int dx = -j-1;
343 int dy = -j, dysqr = dy*dy;
344 int blocked = 0;
345 double new_start = 666.666;
346 int x = cx+dx*xx+dy*xy;
347 int y = cy+dx*yx+dy*yy;
348 double dyp5 = dy+0.5;
349 double dym5 = dy-0.5;
350 while (dx <= 0) {
351 ++dx;
352 // translate the dx, dy coordinates into map coordinates
353 x += xx;
354 y += yx;
355 // l_slope and r_slope store the slopes of the left and right
356 // extremities of the tile we're considering
357 double l_slope = (dx-0.5)/dyp5;
358 double r_slope = (dx+0.5)/dym5;
359 if (end > l_slope) break;
360 if (start >= r_slope) {
361 // our light beam is touching this tile; light it
362 int blk = light_is_blocked(x, y);
363 if (blocked) {
364 // we're scanning a row of blocked squares
365 if (blk) {
366 new_start = r_slope;
367 } else {
368 blocked = 0;
369 start = new_start;
370 if (dx*dx+dysqr < radius_sqr) lb_light_plot(x, y);
372 } else {
373 if (blk && j < radius) {
374 // this is a blocking tile, start a child scan
375 blocked = 1;
376 light_octant(cx, cy, j+1, start, l_slope, radius, octant);
377 new_start = r_slope;
378 } else {
379 if (!blk && dx*dx+dysqr < radius_sqr) lb_light_plot(x, y);
384 // row is scanned; do next row unless last tile was blocked
385 if (blocked) break;
389 /******************************************************************************/
392 /* lcx, lcy, lrad: light parameters */
393 /* as: start angle, ae: end ange; same: do full circle */
394 static void trace_light (int as, int ae) {
396 //int ang = (int)(atan2f(ye-cy, xe-cx)*180.0f/M_PI);
397 //ang = (ang+360)%360;
398 int ang = atan2i(ye-cy, xe-cx);
400 int asx = ((as%360)+360)%360;
401 int aex = ((ae%360)+360)%360;
402 trace_start();
403 if (asx == aex) {
404 /* do full circle (square, actually) */
405 #if 0
406 /* top */
407 for (int d = -lrad; d < lrad; ++d) trace_to_point(lcx+d, lcy-lrad);
408 /* right */
409 for (int d = -lrad; d < lrad; ++d) trace_to_point(lcx+lrad, lcy+d);
410 /* bottom */
411 for (int d = lrad; d > -lrad; --d) trace_to_point(lcx+d, lcy+lrad);
412 /* left */
413 for (int d = lrad; d > -lrad; --d) trace_to_point(lcx-lrad, lcy+d);
414 #else
415 for (int oct = 0; oct < 8; ++oct) light_octant(lcx, lcy, 1, 1.0, 0.0, lrad, oct);
416 lb_light_plot(lcx, lcy);
417 #endif
418 } else {
419 /* do light sector */
420 int sx, sy, sedge;
421 int ex, ey, eedge;
422 int dir = (as < ae ? 1 : -1); /* -1: counter-clockwise; 1: clockwise */
423 /* now determine starting and ending coords */
424 ray_edge_intersection(asx, &sx, &sy, &sedge);
425 ray_edge_intersection(aex, &ex, &ey, &eedge);
426 /* now process edges */
427 if (light_dump) {
428 fprintf(stderr, "---------------------------\n(%d,%d)-(%d,%d)\n", lcx-lrad, lcy-lrad, lcx+lrad, lcy+lrad);
429 fprintf(stderr, "as=%d; asx=%d; ae=%d; aex=%d; sx=%d; sy=%d; sedge=%s; ex=%d; ey=%d; eedge=%s\n", as, asx, ae, aex, sx, sy, ename[sedge], ex, ey, ename[eedge]);
431 trace_add_point(lcx, lcy);
432 for (int f = 0; f <= 4; ++f) {
433 int delta, dx, dy, eex, eey;
434 /* determine side delta */
435 delta = (sedge == EDGE_RIGHT || sedge == EDGE_TOP ? dir : -dir);
436 switch (sedge) {
437 case EDGE_RIGHT: eex = lcx+lrad; eey = lcy+lrad*delta; dx = 0; dy = delta; break;
438 case EDGE_BOTTOM: eex = lcx+lrad*delta; eey = lcy+lrad; dx = delta; dy = 0; break;
439 case EDGE_LEFT: eex = lcx-lrad; eey = lcy+lrad*delta; dx = 0; dy = delta; break;
440 case EDGE_TOP: eex = lcx+lrad*delta; eey = lcy-lrad; dx = delta; dy = 0; break;
441 default: abort(); /* the thing that shoild not be */
443 if (light_dump) fprintf(stderr, "EDGE: %s; sx=%d; sy=%d; xs=%d; ys=%d; delta=%d; dir=%d\n", ename[sedge], sx, sy, K8SIGN(ex-sx), K8SIGN(ey-sy), delta, dir);
444 if (sedge == eedge && (f > 0 || dir == 1)) {
445 /* this is the last edge */
446 if (light_dump) fprintf(stderr, "LAST EDGE! ex=%d; ey=%d; dx=%d; dy=%d\n", ex, ey, dx, dy);
447 while (sx != ex || sy != ey) {
448 trace_to_point(sx, sy);
449 sx += dx;
450 sy += dy;
452 /* that's all, folks */
453 break;
454 } else {
455 /* this is not the last edge, trace it fully */
456 if (light_dump) fprintf(stderr, " eex=%d; eey=%d; dx=%d; dy=%d\n", eex, eey, dx, dy);
457 while (sx != eex || sy != eey) {
458 trace_to_point(sx, sy);
459 sx += dx;
460 sy += dy;
462 /* go to the next side */
463 sedge = (sedge+4+dir)&0x03;
467 trace_end();
471 ////////////////////////////////////////////////////////////////////////////////
472 void lb_reset (void) {
473 memset(lightbuf, 0, sizeof(lightbuf));
477 void lb_draw (void) {
478 const Uint8 *msrc = (void *)mapbmp;
479 const Uint32 *lbsrc = lightbuf;
480 Uint32 *dest = sdl_vscr;
481 for (size_t f = 0; f < MAP_RES_X*MAP_RES_Y; ++f) {
482 Uint32 mbgr = (palette[*msrc]&0xffffff);
483 if ((lbsrc[0]&0xff000000u) > 0) {
484 /*if (mapbmp_orig[f/SCR_WIDTH][f%SCR_WIDTH] == msrc[0])*/ {
485 // mix lights
486 Sint32 alpha = 256-(lbsrc[0]>>24);
487 if (mapbmp_orig[f/SCR_WIDTH][f%SCR_WIDTH] != msrc[0]) {
488 alpha = 256-byteclamp((lbsrc[0]>>24)+50);
490 Uint32 drb = (mbgr&0xff00ff), dg = (mbgr&0x00ff00);
491 // real pixel, do alpha
492 drb = (drb+(((-drb)*alpha+0x800080)>>8))&0xff00ff;
493 dg = (dg+(((-dg)*alpha+0x008000)>>8))&0x00ff00;
494 // lights, premultiplied
495 if (lbsrc[0]&0xffffffu) {
496 Uint32 add, add_nc, cbits, cmask, bgr = (drb|dg);
497 // you are not expected to understand this
498 // but if you are really curious, this is
499 // 8-bit rgb adding with clamping
500 add = (lbsrc[0]&0xffffffu)+bgr;
501 add_nc = (lbsrc[0]&0xffffffu)^bgr;
502 cbits = (add^add_nc)&0x01010100;
503 cmask = cbits-(cbits>>8);
504 mbgr = ((add^cbits)|cmask)&0xffffffu;
505 } else {
506 mbgr = (drb|dg);
509 } else {
510 mbgr = 0;
512 *dest = mbgr;
513 ++dest;
514 ++msrc;
515 ++lbsrc;
520 ////////////////////////////////////////////////////////////////////////////////
521 void render_warfog_sphere (int cx, int cy, int radius) {
522 for (int y = cy-radius; y <= cy+radius; ++y) {
523 for (int x = cx-radius; x <= cx+radius; ++x) {
524 if (x >= 0 && y >= 0 && x < MAP_RES_X && y < MAP_RES_Y) {
525 int dst = isqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
526 int a = 255-(dst*255/radius);
527 if (a > 0 && mapbmp_orig[y][x] >= 16) {
528 if (a > 255) a = 255;
529 lb_add_rgb(x, y, /*lbgr*/0, a);
537 ////////////////////////////////////////////////////////////////////////////////
538 /* x, y: map coordinates (in pixels) */
539 /* alpha is actually light intensity */
540 void renderlight_sector (int x, int y, int radius, int as, int ae, Uint32 rgba) {
541 //fprintf(stderr, "x=%d; y=%d; sx=%d; sy=%d\n", x, y, sx, sy);
542 if (x-radius >= MAP_RES_X || x+radius < 0 || y-radius >= MAP_RES_Y || y+radius < 0) { z_light_mindist = 0; return; }
543 if (radius < 2 /*|| fldhit1(x, y)*/ || (rgba&0xff000000u) == 0 || z_light_mindist >= radius) { z_light_mindist = 0; return; }
544 if (mapbmp_orig[y][x] >= 16) return;
545 lcx = x;
546 lcy = y;
547 lrad = radius;
548 lalpha = rgba>>24;
549 lbgr = (rgba&0xffffff);
550 polymod_start();
551 trace_light(as, ae);
552 polymod_end();
553 polymod_fill();
554 realize_lightmask();
558 ////////////////////////////////////////////////////////////////////////////////
559 typedef struct {
560 int x;
561 int y;
562 int radius;
563 int as;
564 int ae;
565 Uint32 rgba;
566 int minrad;
567 } light_info_t;
570 #define MAX_LIGHTS (4096)
572 static light_info_t lights[MAX_LIGHTS];
573 static int light_count;
574 static int level_light_count;
577 ////////////////////////////////////////////////////////////////////////////////
578 void reset_level_lights (void) {
579 level_light_count = light_count = 0;
583 void reset_lights (void) {
584 light_count = level_light_count;
588 void fix_level_lights (void) {
589 level_light_count = light_count;
593 int add_light_sector_mr (int x, int y, int radius, int as, int ae, Uint32 rgba, int minrad) {
594 if (light_count < MAX_LIGHTS && radius >= 2 && (rgba&0xff000000u) > 0 && minrad <= radius) {
595 lights[light_count].x = x;
596 lights[light_count].y = y;
597 lights[light_count].radius = radius;
598 lights[light_count].as = as;
599 lights[light_count].ae = ae;
600 lights[light_count].rgba = rgba;
601 lights[light_count].minrad = minrad;
602 return light_count++;
604 return -1;
608 int add_light_sector (int x, int y, int radius, int as, int ae, Uint32 rgba) {
609 return add_light_sector_mr(x, y, radius, as, ae, rgba, 0);
613 void render_lights (void) {
614 const light_info_t *lt = lights;
615 for (int f = light_count; f > 0; --f, ++lt) {
616 z_light_mindist = lt->minrad;
617 player_light = 0;
618 renderlight_sector(lt->x, lt->y, lt->radius, lt->as, lt->ae, lt->rgba);
623 ////////////////////////////////////////////////////////////////////////////////
624 static __attribute__((constructor)) void _ctor_polymod_init (void) {
625 //polymod_put_pixel = lb_put_light_point;
626 polymod_hline = lb_light_hline;
627 polymod_screen_width = MAP_RES_X;
628 polymod_screen_height = MAP_RES_Y;