source: abuse/branches/lol/src/light.cpp @ 732

Last change on this file since 732 was 732, checked in by Sam Hocevar, 8 years ago

build: SDL2 compilation fixes.

File size: 20.9 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *  Copyright (c) 2005-2013 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This software was released into the Public Domain. As with most public
7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
9 */
10
11#if HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <stdlib.h>
16
17#include "common.h"
18
19#include "imlib/image.h"
20#include "imlib/video.h"
21#include "imlib/palette.h"
22#include "imlib/specs.h"
23#include "imlib/dprint.h"
24#include "imlib/filter.h"
25#include "imlib/status.h"
26
27#include "light.h"
28#include "dev.h"
29
30LightSource *first_light_source=NULL;
31uint8_t *white_light,*white_light_initial,*green_light,*trans_table;
32short ambient_ramp=0;
33short shutdown_lighting_value,shutdown_lighting=0;
34extern char disable_autolight;   // defined in dev.h
35
36int light_detail=MEDIUM_DETAIL;
37
38int32_t light_to_number(LightSource *l)
39{
40    if (l)
41    {
42        int x = 1;
43        for (LightSource *s = first_light_source; s; s = s->m_next, x++)
44            if (s == l)
45                return x;
46    }
47    return 0;
48}
49
50
51LightSource *number_to_light(int32_t x)
52{
53  if (x==0) return NULL;
54  x--;
55  LightSource *s=first_light_source;
56  for (; x && s; x--,s=s->m_next)
57    ;
58  return s;
59}
60
61LightSource *LightSource::Copy()
62{
63    m_next = new LightSource(m_type, m_pos, m_inner_radius,
64                             m_outer_radius, m_shift, m_next);
65    return m_next;
66}
67
68void delete_all_lights()
69{
70  while (first_light_source)
71  {
72    if (dev_cont)
73      dev_cont->notify_deleted_light(first_light_source);
74
75    LightSource *p=first_light_source;
76    first_light_source=first_light_source->m_next;
77    delete p;
78  }
79}
80
81void delete_light(LightSource *which)
82{
83  if (dev_cont)
84    dev_cont->notify_deleted_light(which);
85
86  if (which==first_light_source)
87  {
88    first_light_source=first_light_source->m_next;
89    delete which;
90  }
91  else
92  {
93    LightSource *f=first_light_source;
94    for (; f->m_next!=which && f; f=f->m_next)
95      ;
96    if (f)
97    {
98      f->m_next=which->m_next;
99      delete which;
100    }
101  }
102}
103
104void LightSource::CalcRange()
105{
106    ivec2 delta = ivec2(m_outer_radius >> m_shift.x,
107                        m_outer_radius >> m_shift.y);
108    switch (m_type)
109    {
110    case 0:
111        m_p1 = m_pos - delta;
112        m_p2 = m_pos + delta;
113        break;
114    case 1:
115        m_p1 = m_pos - delta;
116        m_p2 = m_pos + ivec2(delta.x, 0);
117        break;
118    case 2:
119        m_p1 = m_pos - ivec2(delta.x, 0);
120        m_p2 = m_pos + delta;
121        break;
122    case 3:
123        m_p1 = m_pos - ivec2(0, delta.y);
124        m_p2 = m_pos + delta;
125        break;
126    case 4:
127        m_p1 = m_pos - delta;
128        m_p2 = m_pos + ivec2(0, delta.y);
129        break;
130    case 5:
131        m_p1 = m_pos - ivec2(0, delta.y);
132        m_p2 = m_pos + ivec2(delta.x, 0);
133        break;
134    case 6:
135        m_p1 = m_pos - delta;
136        m_p2 = m_pos;
137        break;
138    case 7:
139        m_p1 = m_pos - ivec2(delta.x, 0);
140        m_p2 = m_pos + ivec2(0, delta.y);
141        break;
142    case 8:
143        m_p1 = m_pos;
144        m_p2 = m_pos + delta;
145        break;
146    case 9:
147        m_p1 = m_pos;
148        m_p2 = m_pos + m_shift;
149        break;
150    }
151    mul_div = (1 << 16) / (m_outer_radius - m_inner_radius) * 64;
152}
153
154LightSource::LightSource(char Type, ivec2 pos, int32_t inner_radius,
155               int32_t outer_radius, ivec2 shift, LightSource *next)
156{
157    m_type = Type;
158    m_pos = pos;
159    m_inner_radius = inner_radius;
160    m_outer_radius = outer_radius;
161    m_next = next;
162    known = 0;
163    m_shift = shift;
164
165    CalcRange();
166}
167
168
169int count_lights()
170{
171  int t=0;
172  for (LightSource *s=first_light_source; s; s=s->m_next)
173    t++;
174  return t;
175}
176
177LightSource *AddLightSource(char type, ivec2 pos,
178                            int32_t inner, int32_t outer, ivec2 shift)
179{
180    first_light_source = new LightSource(type, pos, inner, outer,
181                                         shift, first_light_source);
182    return first_light_source;
183}
184
185
186#define TTINTS 9
187uint8_t *tints[TTINTS];
188uint8_t bright_tint[256];
189
190void calc_tint(uint8_t *tint, u8vec3 s, u8vec3 a, Palette *pal)
191{
192  Palette npal;
193  for (int i = 0; i < 256; i++)
194  {
195    npal.SetColor(i, s);
196    s = (u8vec3)clamp((ivec3)s + (ivec3)a, 0, 255);
197  }
198  Filter f(pal, &npal);
199  Filter f2(&npal, pal);
200
201  for (int i = 0; i < 256; i++, tint++)
202    *tint = f2.GetMapping(f.GetMapping(i));
203}
204
205
206void calc_light_table(Palette *pal)
207{
208    white_light_initial=(uint8_t *)malloc(256*64);
209    white_light=white_light_initial;
210
211//    green_light=(uint8_t *)malloc(256*64);
212    int i = 0;
213    for( ; i < TTINTS; i++ )
214    {
215        tints[i] = (uint8_t *)malloc( 256 );
216    }
217
218    char *lightpath;
219    lightpath = (char *)malloc( strlen( get_save_filename_prefix() ) + 9 + 1 );
220    sprintf( lightpath, "%slight.tbl", get_save_filename_prefix() );
221
222    bFILE *fp=open_file( lightpath, "rb" );
223    int recalc = 0;
224    if( fp->open_failure() )
225    {
226        recalc = 1;
227    }
228    else
229    {
230        if (fp->read_uint16() != Crc::FromData((uint8_t *)pal->Data(), 768))
231            recalc=1;
232        else
233        {
234            fp->read(white_light,256*64);
235//            fp->read(green_light,256*64);
236            for (i=0; i<TTINTS; i++)
237                fp->read(tints[i],256);
238            fp->read(bright_tint,256);
239//            trans_table=(uint8_t *)malloc(256*256);
240//            fp.read(trans_table,256*256);
241        }
242    }
243    delete fp;
244    fp = NULL;
245
246    if( recalc )
247    {
248        dprintf("Palette has changed, recalculating light table...\n");
249        stat_man->push("white light",NULL);
250        for (int color = 0; color < 256; color++)
251        {
252            u8vec3 rgb = pal->GetColor(color);
253            stat_man->update(color * 100 / 256);
254            for (int intensity = 63; intensity >= 0; intensity--)
255            {
256                if (rgb != u8vec3::zero)
257                    white_light[intensity*256+color] = pal->FindClosest(rgb);
258                else
259                    white_light[intensity*256+color]=0;
260                rgb = max(rgb, u8vec3(1)) - u8vec3(1);
261            }
262        }
263        stat_man->pop();
264
265/*    stat_man->push("green light",NULL);
266    for (color=0; color<256; color++)
267    {
268      stat_man->update(color*100/256);
269      uint8_t r,g,b;
270      pal->get(color,b,r,g);
271      r=r*3/5; b=b*3/5; g+=7; if (g>255) g=255;
272
273      for (int intensity=63; intensity>=0; intensity--)
274      {
275    if (r>0 || g>0 || b>0)
276          green_light[intensity*256+color]=pal->find_closest(r,g,b);
277    else
278          green_light[intensity*256+color]=0;
279    if (r) r--;
280    if ((intensity&1)==1)
281      if (g) g--;
282    if (b) b--;
283      }
284    }
285    stat_man->pop(); */
286
287    stat_man->push("tints",NULL);
288    uint8_t t[TTINTS*6]={ 0,0,0,0,0,0, // normal
289                   0,0,0,1,0,0,     // red
290           0,0,0,1,1,0,     // yellow
291           0,0,0,1,0,1,     // purple
292           0,0,0,1,1,1,     // gray
293           0,0,0,0,1,0,     // green
294           0,0,0,0,0,1,     // blue
295           0,0,0,0,1,1,     // cyan
296
297
298
299
300
301
302           0,0,0,0,0,0   // reverse green  (night vision effect)
303         } ;
304    uint8_t *ti=t+6;
305    uint8_t *c;
306    for (i=0,c=tints[0]; i<256; i++,c++) *c=i;  // make the normal tint (maps everthing to itself)
307    for (i=0,c=tints[TTINTS-1]; i<256; i++,c++)  // reverse green
308    {
309      ivec3 rgb = (ivec3)pal->GetColor(i);
310      rgb = clamp(ivec3(rgb.r / 2, 255 - rgb.g - 30, rgb.b * 3 / 5 + 50), 0, 255);
311      *c = pal->FindClosest(u8vec3(rgb));
312    }
313    for (i=0; i<256; i++)
314    {
315      u8vec3 rgb = pal->GetColor(i) + (u8vec3(255) - pal->GetColor(i)) / (uint8_t)2;
316      bright_tint[i] = pal->FindClosest(rgb);
317    }
318
319    // make the colored tints
320    for (i=1; i<TTINTS-1; i++)
321    {
322      stat_man->update(i*100/(TTINTS-1));
323      calc_tint(tints[i], u8vec3(ti[0], ti[1], ti[2]),
324                          u8vec3(ti[3], ti[4], ti[5]), pal);
325      ti += 6;
326    }
327    stat_man->pop();
328/*    fprintf(stderr,"calculating transparency tables (256 total)\n");
329    trans_table=(uint8_t *)malloc(256*256);
330
331    uint8_t *tp=trans_table;
332    for (i=0; i<256; i++)
333    {
334      uint8_t r1,g1,b1,r2,g2,b2;
335      pal->get(i,r1,g1,b1);
336      if ((i%16)==0)
337        fprintf(stderr,"%d ",i);
338      for (int j=0; j<256; j++,tp++)
339      {
340    if (r1==0 && r2==0 && b2==0)
341      *tp=j;
342    else
343    {
344      pal->get(j,r2,g2,b2);
345      *tp=pal->find_closest((r2-r1)*3/7+r1,(g2-g1)*3/7+g1,(b2-b1)*3/7+b1);
346    }
347      }
348    }*/
349
350
351        bFILE *f = open_file( lightpath, "wb" );
352        if( f->open_failure() )
353            dprintf( "Unable to open file light.tbl for writing\n" );
354        else
355        {
356            f->write_uint16(Crc::FromData(pal->Data(), 768));
357            f->write(white_light, 256 * 64);
358//      f->write(green_light,256*64);
359            for (int i=0; i<TTINTS; i++)
360                f->write(tints[i],256);
361            f->write(bright_tint,256);
362//    f.write(trans_table,256*256);
363        }
364        delete f;
365    }
366    free( lightpath );
367}
368
369
370LightPatch *LightPatch::Copy(LightPatch *next)
371{
372    LightPatch *p = new LightPatch(m_p1, m_p2, next);
373    p->m_lights = m_lights;
374    return p;
375}
376
377#define MAX_LP 6
378
379// insert light into list make sure the are sorted by y1
380void InsertLight(LightPatch *&first, LightPatch *l)
381{
382    if (!first)
383        first = l;
384    else if (l->m_p1.y < first->m_p1.y)
385    {
386        l->m_next = first;
387        first = l;
388    }
389    else
390    {
391        LightPatch *p = first;
392        for (; p->m_next && p->m_next->m_p1.y < l->m_p1.y; p = p->m_next)
393            ;
394        l->m_next = p->m_next;
395        p->m_next = l;
396    }
397}
398
399void AddLight(LightPatch *&first, ivec2 p1, ivec2 p2, LightSource *who)
400{
401    for (LightPatch *p = first, *next; p; p = next)
402    {
403        next = p->m_next;
404
405        // first see if light patch we are adding is enclosed entirely
406        // by another patch
407        if (p1.x >= p->m_p1.x && p1.y >= p->m_p1.y
408             && p2.x <= p->m_p2.x && p2.y <= p->m_p2.y)
409        {
410            if (p->m_lights.Count() == MAX_LP)
411                return;
412
413            if (p1.x > p->m_p1.x)
414            {
415                LightPatch *l = p->Copy(nullptr);
416                l->m_p2.x = p1.x - 1;
417                InsertLight(first, l);
418            }
419            if (p2.x < p->m_p2.x)
420            {
421                LightPatch *l = p->Copy(nullptr);
422                l->m_p1.x = p2.x + 1;
423                InsertLight(first, l);
424            }
425            if (p1.y>p->m_p1.y)
426            {
427                LightPatch *l = p->Copy(nullptr);
428                l->m_p1.x = p1.x;
429                l->m_p2.x = p2.x;
430                l->m_p2.y = p1.y - 1;
431                InsertLight(first, l);
432            }
433            if (p2.y<p->m_p2.y)
434            {
435                LightPatch *l = p->Copy(nullptr);
436                l->m_p1.x = p1.x;
437                l->m_p2.x = p2.x;
438                l->m_p1.y = p2.y + 1;
439                InsertLight(first, l);
440            }
441            p->m_p1 = p1;
442            p->m_p2 = p2;
443            // p has possibly changed its p1.y, so we need to move it to
444            // its correct sorted spot in the list
445            if (first == p)
446                first = first->m_next;
447            else
448            {
449                LightPatch *q = first;
450                for (; q->m_next!=p; q=q->m_next)
451                    ;
452                q->m_next=p->m_next;
453            }
454            InsertLight(first, p);
455
456            p->m_lights.Push(who);
457            return;
458        }
459
460        // see if the patch completly covers another patch.
461        if (p1 <= p->m_p1 && p2 >= p->m_p2)
462        {
463            if (p1.x < p->m_p1.x)
464                AddLight(first, p1, ivec2(p->m_p1.x - 1, p2.y), who);
465            if (p2.x > p->m_p2.x)
466                AddLight(first, ivec2(p->m_p2.x + 1, p1.y), p2, who);
467            if (p1.y < p->m_p1.y)
468                AddLight(first, ivec2(p->m_p1.x, p1.y), ivec2(p->m_p2.x, p->m_p1.y - 1), who);
469            if (p2.y > p->m_p2.y)
470                AddLight(first, ivec2(p->m_p1.x, p->m_p2.y + 1), ivec2(p->m_p2.x, p2.y), who);
471
472            if (p->m_lights.Count() < MAX_LP)
473                p->m_lights.Push(who);
474
475            return;
476        }
477
478        // see if we intersect another rect
479        if (p2 >= p->m_p1 && p1 <= p->m_p2)
480        {
481            ivec2 ap1 = lol::max(p1, p->m_p1),
482                  ap2 = lol::min(p2, p->m_p2);
483
484            if (p1.x < p->m_p1.x)
485                AddLight(first, ivec2(p1.x, ap1.y), ivec2(p->m_p1.x - 1, ap2.y), who);
486
487            if (p2.x > p->m_p2.x)
488                AddLight(first, ivec2(p->m_p2.x + 1, ap1.y), ivec2(p2.x, ap2.y), who);
489
490            if (p1.y < p->m_p1.y)
491                AddLight(first, p1, ivec2(p2.x, p->m_p1.y - 1), who);
492
493            if (p2.y > p->m_p2.y)
494                AddLight(first, ivec2(p1.x, p->m_p2.y + 1), p2, who);
495
496            AddLight(first, ap1, ap2, who);
497            return;
498        }
499    }
500}
501
502LightPatch *MakePatchList(ivec2 size, ivec2 screen)
503{
504    LightPatch *first = new LightPatch(ivec2::zero, size - ivec2(1), nullptr);
505
506    // determine which lights will have effect
507    for (LightSource *f = first_light_source; f; f = f->m_next)
508    {
509        ivec2 p1 = lol::max(f->m_p1 - screen, ivec2::zero);
510        ivec2 p2 = lol::min(f->m_p2 - screen, size - ivec2(1));
511
512        if (p1.x <= p2.x && p1.y <= p2.y)
513            AddLight(first, p1, p2, f);
514    }
515
516    return first;
517}
518
519inline void MAP_PUT(uint8_t * screen_addr, uint8_t * remap, int w)
520{
521  register int cx=w;
522  register uint8_t * di=screen_addr;
523  register uint8_t * si=remap;
524  while (cx--)
525  {
526    uint8_t x=*((uint8_t *)si+*((uint8_t *)di));
527    *((uint8_t *)(di++))=x;
528  }
529}
530
531uint16_t min_light_level;
532
533// calculate the light value for this block.  sum up all contritors
534static inline int CalcLightValue(LightPatch *lp, ivec2 screen)
535{
536    int lv = min_light_level;
537
538    for (int i = 0; i < lp->m_lights.Count(); ++i)
539    {
540        LightSource *l = lp->m_lights[i];
541
542        if (l->m_type == 9) // if light is a Solid rectangle, return its value
543            return l->m_inner_radius;
544
545        // xdist between light and this block; shift makes distance further, making light skinner.
546        int dx = lol::abs(l->m_pos.x - screen.x) << l->m_shift.x;
547        int dy = lol::abs(l->m_pos.y - screen.y) << l->m_shift.y;
548
549        // calculate approximate distance
550        int r2 = dx + dy - (lol::min(dx, dy) >> 1);
551
552        if (r2 < l->m_outer_radius) // if this within the light's outer radius?
553        {
554            int v = l->m_outer_radius - r2;
555            lv += v * l->mul_div >> 16;
556        }
557    }
558
559    return lol::min(lv, 63); // lighting table only has 64 (256 bytes) entries
560}
561
562
563void remap_line_asm2(uint8_t *addr,uint8_t *light_lookup,uint8_t *remap_line,int count)
564//inline void remap_line_asm2(uint8_t *addr,uint8_t *light_lookup,uint8_t *remap_line,int count)
565{
566  while (count--)
567  {
568    uint8_t *off=light_lookup+(((int32_t)*remap_line)<<8);
569    remap_line++;
570
571    *addr=off[*addr];
572    addr[1]=off[addr[1]];
573    addr[2]=off[addr[2]];
574    addr[3]=off[addr[3]];
575    addr[4]=off[addr[4]];
576    addr[5]=off[addr[5]];
577    addr[6]=off[addr[6]];
578    addr[7]=off[addr[7]];
579    addr+=8;
580
581  }
582}
583
584inline void put_8line(uint8_t *in_line, uint8_t *out_line, uint8_t *remap, uint8_t *light_lookup, int count)
585{
586  uint8_t v;
587  int x;
588  for (x=0; x<count; x++)
589  {
590    uint8_t *off=light_lookup+(((int32_t)*remap)<<8);
591
592    v=off[*(in_line++)];
593    *(out_line++)=v;
594    *(out_line++)=v;
595
596    v=off[*(in_line++)];
597    *(out_line++)=v;
598    *(out_line++)=v;
599
600    v=off[*(in_line++)];
601    *(out_line++)=v;
602    *(out_line++)=v;
603
604    v=off[*(in_line++)];
605    *(out_line++)=v;
606    *(out_line++)=v;
607
608    v=off[*(in_line++)];
609    *(out_line++)=v;
610    *(out_line++)=v;
611
612    v=off[*(in_line++)];
613    *(out_line++)=v;
614    *(out_line++)=v;
615
616    v=off[*(in_line++)];
617    *(out_line++)=v;
618    *(out_line++)=v;
619
620    v=off[*(in_line++)];
621    *(out_line++)=v;
622    *(out_line++)=v;
623
624    remap++;
625  }
626}
627
628
629void light_screen(AImage *sc, int32_t screenx, int32_t screeny, uint8_t *light_lookup, uint16_t ambient)
630{
631  int lx_run=0,ly_run;                     // light block x & y run size in pixels ==  (1<<lx_run)
632
633  if (shutdown_lighting && !disable_autolight)
634    ambient=shutdown_lighting_value;
635
636  switch (light_detail)
637  {
638    case HIGH_DETAIL :
639    { lx_run=2; ly_run=1; } break;       // 4 x 2 patches
640    case MEDIUM_DETAIL :
641    { lx_run=3; ly_run=2; } break;       // 8 x 4 patches  (default)
642    case LOW_DETAIL :
643    { lx_run=4; ly_run=3; } break;       // 16 x 8 patches
644    case POOR_DETAIL :                   // poor detail is no lighting
645    return ;
646  }
647  if ((int)ambient+ambient_ramp<0)
648    min_light_level=0;
649  else if ((int)ambient+ambient_ramp>63)
650    min_light_level=63;
651  else min_light_level=(int)ambient+ambient_ramp;
652
653  if (ambient==63) return ;
654  ivec2 caa, cbb;
655  sc->GetClip(caa, cbb);
656
657  LightPatch *first = MakePatchList(cbb - caa, ivec2(screenx, screeny));
658
659  int prefix_x=(screenx&7);
660  int prefix=screenx&7;
661  if (prefix)
662    prefix=8-prefix;
663  int suffix_x = cbb.x - 1 - caa.x - (screenx & 7);
664
665  int suffix = (cbb.x - caa.x - prefix) & 7;
666
667  int32_t remap_size=((cbb.x - caa.x - prefix - suffix)>>lx_run);
668
669  uint8_t *remap_line=(uint8_t *)malloc(remap_size);
670
671  LightPatch *f=first;
672
673  int scr_w=main_screen->Size().x;
674  uint8_t *screen_line=main_screen->scan_line(caa.y)+caa.x;
675
676  for (int y = caa.y; y < cbb.y; )
677  {
678    int x,count;
679//    while (f->m_next && f->m_p2.y<y)
680//      f=f->m_next;
681    uint8_t *rem=remap_line;
682
683    int todoy=4-((screeny+y)&3);
684    if (y + todoy >= cbb.y)
685      todoy = cbb.y - y;
686
687    int calcy=((y+screeny)&(~3))-caa.y;
688
689
690    if (suffix)
691    {
692      LightPatch *lp=f;
693      for (; (lp->m_p1.y>y-caa.y || lp->m_p2.y<y-caa.y ||
694                  lp->m_p1.x>suffix_x || lp->m_p2.x<suffix_x); lp=lp->m_next)
695          ;
696      uint8_t * caddr=(uint8_t *)screen_line + cbb.x - caa.x - suffix;
697      uint8_t *r=light_lookup+(((int32_t)CalcLightValue(lp, ivec2(suffix_x + screenx, calcy)) << 8));
698      switch (todoy)
699      {
700    case 4 :
701    {
702      MAP_PUT(caddr,r,suffix); caddr+=scr_w;
703    }
704    case 3 :
705    { MAP_PUT(caddr,r,suffix); caddr+=scr_w; }
706    case 2 :
707    { MAP_PUT(caddr,r,suffix); caddr+=scr_w; }
708    case 1 :
709    {
710      MAP_PUT(caddr,r,suffix);
711    }
712      }
713    }
714
715    if (prefix)
716    {
717      LightPatch *lp=f;
718      for (; (lp->m_p1.y>y-caa.y || lp->m_p2.y<y-caa.y ||
719                  lp->m_p1.x>prefix_x || lp->m_p2.x<prefix_x); lp=lp->m_next);
720
721      uint8_t *r=light_lookup+(((int32_t)CalcLightValue(lp, ivec2(prefix_x + screenx, calcy)) << 8));
722      uint8_t * caddr=(uint8_t *)screen_line;
723      switch (todoy)
724      {
725    case 4 :
726    {
727      MAP_PUT(caddr,r,prefix);
728      caddr+=scr_w;
729    }
730    case 3 :
731    { MAP_PUT(caddr,r,prefix); caddr+=scr_w; }
732    case 2 :
733    { MAP_PUT(caddr,r,prefix); caddr+=scr_w; }
734    case 1 :
735    { MAP_PUT(caddr,r,prefix); }
736      }
737      screen_line+=prefix;
738    }
739
740
741
742
743    for (x=prefix,count=0; count<remap_size; count++,x+=8,rem++)
744    {
745      LightPatch *lp=f;
746      for (; (lp->m_p1.y>y-caa.y || lp->m_p2.y<y-caa.y || lp->m_p1.x>x || lp->m_p2.x<x); lp=lp->m_next)
747        ;
748      *rem = CalcLightValue(lp, ivec2(x + screenx, calcy));
749    }
750
751    switch (todoy)
752    {
753      case 4 :
754      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
755      case 3 :
756      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
757      case 2 :
758      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
759      case 1 :
760      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
761    }
762
763
764    screen_line-=prefix;
765  }
766
767  while (first)
768  {
769    LightPatch *p=first;
770    first=first->m_next;
771    delete p;
772  }
773  free(remap_line);
774}
775
776void add_light_spec(SpecDir *sd, char const *level_name)
777{
778  int32_t size=4+4;  // number of lights and minimum light levels
779  for (LightSource *f=first_light_source; f; f=f->m_next)
780    size+=6*4+1;
781  sd->add_by_hand(new SpecEntry(SPEC_LIGHT_LIST,"lights",NULL,size,0));
782}
783
784void write_lights(bFILE *fp)
785{
786  int t=0;
787  LightSource *f=first_light_source;
788  for (; f; f=f->m_next) t++;
789  fp->write_uint32(t);
790  fp->write_uint32(min_light_level);
791  for (f = first_light_source; f; f = f->m_next)
792  {
793    fp->write_uint32(f->m_pos.x);
794    fp->write_uint32(f->m_pos.y);
795    fp->write_uint32(f->m_shift.x);
796    fp->write_uint32(f->m_shift.y);
797    fp->write_uint32(f->m_inner_radius);
798    fp->write_uint32(f->m_outer_radius);
799    fp->write_uint8(f->m_type);
800  }
801}
802
803
804void read_lights(SpecDir *sd, bFILE *fp, char const *level_name)
805{
806  delete_all_lights();
807  SpecEntry *se=sd->find("lights");
808  if (se)
809  {
810    fp->seek(se->offset,SEEK_SET);
811    int32_t t=fp->read_uint32();
812    min_light_level=fp->read_uint32();
813    LightSource *last=NULL;
814    while (t)
815    {
816      t--;
817      ivec2 pos, shift;
818      pos.x = fp->read_uint32();
819      pos.y = fp->read_uint32();
820      shift.x = fp->read_uint32();
821      shift.y = fp->read_uint32();
822      int32_t ir=fp->read_uint32();
823      int32_t ora=fp->read_uint32();
824      int32_t ty=fp->read_uint8();
825
826      LightSource *p = new LightSource(ty, pos, ir, ora, shift, nullptr);
827
828      if (first_light_source)
829        last->m_next = p;
830      else
831        first_light_source = p;
832      last = p;
833    }
834  }
835}
Note: See TracBrowser for help on using the repository browser.