source: abuse/trunk/src/light.cpp @ 489

Last change on this file since 489 was 481, checked in by Sam Hocevar, 10 years ago

Fuck the history, I'm renaming all .hpp files to .h for my own sanity.

File size: 27.8 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *
5 *  This software was released into the Public Domain. As with most public
6 *  domain software, no warranty is made or implied by Crack dot Com or
7 *  Jonathan Clark.
8 */
9
10#include "config.h"
11
12#include <stdlib.h>
13
14#include "light.h"
15#include "image.h"
16#include "macs.h"
17#include "video.h"
18#include "palette.h"
19#include "timing.h"
20#include "specs.h"
21#include "dprint.h"
22#include "filter.h"
23#include "status.h"
24#include "dev.h"
25
26light_source *first_light_source=NULL;
27uint8_t *white_light,*white_light_initial,*green_light,*trans_table;
28short ambient_ramp=0;
29short shutdown_lighting_value,shutdown_lighting=0;
30extern char disable_autolight;   // defined in dev.h
31
32int light_detail=MEDIUM_DETAIL;
33
34int32_t light_to_number(light_source *l)
35{
36
37  if (!l) return 0;
38  int x=1;
39  for (light_source *s=first_light_source;s;s=s->next,x++)
40    if (s==l) return x;
41  return 0;
42}
43
44
45light_source *number_to_light(int32_t x)
46{
47  if (x==0) return NULL;
48  x--;
49  light_source *s=first_light_source;
50  for (;x && s;x--,s=s->next);
51  return s;
52}
53
54light_source *light_source::copy()
55{
56  next=new light_source(type,x,y,inner_radius,outer_radius,xshift,yshift,next);
57  return next;
58}
59
60void delete_all_lights()
61{
62  while (first_light_source)
63  {
64    if (dev_cont)
65      dev_cont->notify_deleted_light(first_light_source);
66
67    light_source *p=first_light_source;
68    first_light_source=first_light_source->next;
69    delete p;
70  }
71}
72
73void delete_light(light_source *which)
74{
75  if (dev_cont)
76    dev_cont->notify_deleted_light(which);
77
78  if (which==first_light_source)
79  {
80    first_light_source=first_light_source->next;
81    delete which;
82  }
83  else
84  {
85    light_source *f=first_light_source;
86    for (;f->next!=which && f;f=f->next);
87    if (f)
88    {
89      f->next=which->next;
90      delete which;
91    }
92  }
93}
94
95void light_source::calc_range()
96{
97  switch (type)
98  {
99    case 0 :
100    { x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
101      x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
102    } break;
103    case 1 :
104    { x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
105      x2=x+(outer_radius>>xshift); y2=y;
106    } break;
107    case 2 :
108    { x1=x-(outer_radius>>xshift); y1=y;
109      x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
110    } break;
111    case 3 :
112    { x1=x; y1=y-(outer_radius>>yshift);
113      x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
114    } break;
115    case 4 :
116    { x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
117      x2=x; y2=y+(outer_radius>>yshift);
118    } break;
119
120
121    case 5 :
122    { x1=x; y1=y-(outer_radius>>yshift);
123      x2=x+(outer_radius>>xshift); y2=y;
124    } break;
125    case 6 :
126    { x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
127      x2=x; y2=y;
128    } break;
129    case 7 :
130    { x1=x-(outer_radius>>xshift); y1=y;
131      x2=x; y2=y+(outer_radius>>yshift);
132    } break;
133    case 8 :
134    { x1=x; y1=y;
135      x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
136    } break;
137    case 9 :
138    {
139      x1=x;
140      y1=y;
141      x2=x+xshift;
142      y2=y+yshift;
143    } break;
144
145  }
146  mul_div=(1<<16)/(outer_radius-inner_radius)*64;
147}
148
149light_source::light_source(char Type, int32_t X, int32_t Y, int32_t Inner_radius,
150               int32_t Outer_radius, int32_t Xshift,  int32_t Yshift, light_source *Next)
151{
152  type=Type;
153  x=X; y=Y;
154  inner_radius=Inner_radius;
155  outer_radius=Outer_radius;
156  next=Next;
157  known=0;
158  xshift=Xshift;
159  yshift=Yshift;
160  calc_range();
161}
162
163
164int count_lights()
165{
166  int t=0;
167  for (light_source *s=first_light_source;s;s=s->next)
168    t++;
169  return t;
170}
171
172light_source *add_light_source(char type, int32_t x, int32_t y,
173                   int32_t inner, int32_t outer, int32_t xshift, int32_t yshift)
174{
175  first_light_source=new light_source(type,x,y,inner,outer,xshift,yshift,first_light_source);
176  return first_light_source;
177}
178
179
180#define TTINTS 9
181uint8_t *tints[TTINTS];
182uint8_t bright_tint[256];
183
184void calc_tint(uint8_t *tint, int rs, int gs, int bs, int ra, int ga, int ba, palette *pal)
185{
186  palette npal;
187  memset(npal.addr(),0,256);
188  int i=0;
189  for (;i<256;i++)
190  {
191    npal.set(i,(int)rs,(int)gs,(int)bs);
192    rs+=ra; if (rs>255) rs=255; else if (rs<0) rs=0;
193    gs+=ga; if (gs>255) gs=255; else if (gs<0) gs=0;
194    bs+=ba; if (bs>255) bs=255; else if (bs<0) bs=0;
195  }
196  filter f(pal,&npal);
197  filter f2(&npal,pal);
198
199  for (i=0;i<256;i++,tint++)
200    *tint=f2.get_mapping(f.get_mapping(i));
201}
202
203
204void calc_light_table(palette *pal)
205{
206    white_light_initial=(uint8_t *)malloc(256*64);
207    white_light=white_light_initial;
208
209//    green_light=(uint8_t *)malloc(256*64);
210    int i = 0;
211    for( ; i < TTINTS; i++ )
212    {
213        tints[i] = (uint8_t *)malloc( 256 );
214    }
215
216    char *lightpath;
217    lightpath = (char *)malloc( strlen( get_save_filename_prefix() ) + 9 + 1 );
218    sprintf( lightpath, "%slight.tbl", get_save_filename_prefix() );
219
220    bFILE *fp=open_file( lightpath, "rb" );
221    int recalc = 0;
222    if( fp->open_failure() )
223    {
224        recalc = 1;
225    }
226    else
227    {
228        if (fp->read_uint16()!=calc_crc((uint8_t *)pal->addr(),768))
229            recalc=1;
230        else
231        {
232            fp->read(white_light,256*64);
233//            fp->read(green_light,256*64);
234            for (i=0;i<TTINTS;i++)
235                fp->read(tints[i],256);
236            fp->read(bright_tint,256);
237//            trans_table=(uint8_t *)malloc(256*256);
238//            fp.read(trans_table,256*256);
239        }
240    }
241    delete fp;
242    fp = NULL;
243
244    if( recalc )
245    {
246        dprintf("Palette has changed, recalculating light table...\n");
247        stat_man->push("white light",NULL);
248        int color=0;
249        for (;color<256;color++)
250        {
251            uint8_t r,g,b;
252            pal->get(color,r,g,b);
253            stat_man->update(color*100/256);
254            for (int intensity=63;intensity>=0;intensity--)
255            {
256                if (r>0 || g>0 || b>0)
257                    white_light[intensity*256+color]=pal->find_closest(r,g,b);
258                else
259                    white_light[intensity*256+color]=0;
260                if (r) r--;  if (g) g--;  if (b) b--;     
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      int r=pal->red(i)/2,g=255-pal->green(i)-30,b=pal->blue(i)*3/5+50;
310      if (g<0) g=0;
311      if (b>255) b=0;
312      *c=pal->find_closest(r,g,b);
313    }
314    for (i=0;i<256;i++)
315    {
316      int r=pal->red(i)+(255-pal->red(i))/2,
317          g=pal->green(i)+(255-pal->green(i))/2,
318          b=pal->blue(i)+(255-pal->blue(i))/2;
319      bright_tint[i]=pal->find_closest(r,g,b);
320    }
321
322    // make the colored tints
323    for (i=1;i<TTINTS-1;i++)
324    {
325      stat_man->update(i*100/(TTINTS-1));
326      calc_tint(tints[i],ti[0],ti[1],ti[2],ti[3],ti[4],ti[5],pal);
327      ti+=6;
328    }
329    stat_man->pop();
330/*    fprintf(stderr,"calculating transparency tables (256 total)\n");
331    trans_table=(uint8_t *)malloc(256*256);
332
333    uint8_t *tp=trans_table;
334    for (i=0;i<256;i++)
335    {
336      uint8_t r1,g1,b1,r2,g2,b2;
337      pal->get(i,r1,g1,b1);
338      if ((i%16)==0)
339        fprintf(stderr,"%d ",i);
340      for (int j=0;j<256;j++,tp++)
341      {
342    if (r1==0 && r2==0 && b2==0)
343      *tp=j;
344    else
345    {
346      pal->get(j,r2,g2,b2);
347      *tp=pal->find_closest((r2-r1)*3/7+r1,(g2-g1)*3/7+g1,(b2-b1)*3/7+b1);
348    }
349      }
350    }*/
351
352
353        bFILE *f = open_file( lightpath, "wb" );
354        if( f->open_failure() )
355            dprintf( "Unable to open file light.tbl for writing\n" );
356        else
357        {
358            f->write_uint16(calc_crc((uint8_t *)pal->addr(),768));
359            f->write(white_light,256*64);
360//      f->write(green_light,256*64);
361            for (int i=0;i<TTINTS;i++)
362                f->write(tints[i],256);
363            f->write(bright_tint,256);
364//    f.write(trans_table,256*256);
365        }
366        delete f;
367    }
368    free( lightpath );
369}
370
371
372light_patch *light_patch::copy(light_patch *Next)
373{
374  light_patch *p=new light_patch(x1,y1,x2,y2,Next);
375  p->total=total;
376  if (total)
377  {
378    p->lights=(light_source **)malloc(total*sizeof(light_source *));
379    memcpy(p->lights,lights,total*(sizeof(light_source *)));
380  }
381  else
382    p->lights=NULL;
383  return p;
384}
385
386#define MAX_LP 6
387
388// insert light into list make sure the are sorted by y1
389void insert_light(light_patch *&first, light_patch *l)
390{
391  if (!first)
392    first=l;
393  else if (l->y1<first->y1)
394  {
395    l->next=first;
396    first=l;
397  } else
398  {
399    light_patch *p=first;
400    for (;p->next && p->next->y1<l->y1;p=p->next);
401    l->next=p->next;
402    p->next=l;
403  }
404}
405
406void add_light(light_patch *&first, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
407                light_source *who)
408{
409  light_patch *next;
410  light_patch *p=first;
411  for (;p;p=next)
412  {
413    next=p->next;
414    // first see if light patch we are adding is enclosed entirely by another patch
415    if (x1>=p->x1 && y1>=p->y1 && x2<=p->x2 && y2<=p->y2)
416    {
417      if (p->total==MAX_LP) return ;
418
419      if (x1>p->x1)
420      {
421    light_patch *l=p->copy(NULL);
422    l->x2=x1-1;
423    insert_light(first,l);
424      }
425      if (x2<p->x2)
426      {
427    light_patch *l=p->copy(NULL);
428    l->x1=x2+1;
429    insert_light(first,l);
430      }
431      if (y1>p->y1)
432      {
433    light_patch *l=p->copy(NULL);
434    l->x1=x1;
435    l->x2=x2;
436    l->y2=y1-1;
437    insert_light(first,l);
438      }
439      if (y2<p->y2)
440      {
441    light_patch *l=p->copy(NULL);
442    l->x1=x1;
443    l->x2=x2;
444    l->y1=y2+1;
445    insert_light(first,l);
446      }
447      p->x1=x1; p->y1=y1; p->x2=x2; p->y2=y2;
448      // p has possibly changed it's y1, so we need to move it to it's correct sorted
449      // spot in the list
450      if (first==p)
451        first=first->next;
452      else
453      {
454    light_patch *q=first;
455    for (;q->next!=p;q=q->next);
456    q->next=p->next;
457      }
458      insert_light(first,p);
459
460
461      p->total++;
462      p->lights=(light_source **)realloc(p->lights,sizeof(light_source *)*p->total);
463      p->lights[p->total-1]=who;
464      return ;
465    }
466
467    // see if the patch completly covers another patch.
468    if (x1<=p->x1 && y1<=p->y1 && x2>=p->x2 && y2>=p->y2)
469    {
470      if (x1<p->x1)
471        add_light(first,x1,y1,p->x1-1,y2,who);
472      if (x2>p->x2)
473        add_light(first,p->x2+1,y1,x2,y2,who);
474      if (y1<p->y1)
475        add_light(first,p->x1,y1,p->x2,p->y1-1,who);
476      if (y2>p->y2)
477        add_light(first,p->x1,p->y2+1,p->x2,y2,who);
478      if (p->total==MAX_LP)  return ;
479      p->total++;
480      p->lights=(light_source **)realloc(p->lights,sizeof(light_source *)*p->total);
481      p->lights[p->total-1]=who;
482      return ;
483    }
484
485    // see if we intersect another rect
486    if (!(x2<p->x1 || y2<p->y1 || x1>p->x2 || y1>p->y2))
487    {
488      int ax1,ay1,ax2,ay2;
489      if (x1<p->x1)
490      {
491        add_light(first,x1,max(y1,p->y1),p->x1-1,min(y2,p->y2),who);
492    ax1=p->x1;
493      } else
494    ax1=x1;
495
496      if (x2>p->x2)
497      {
498        add_light(first,p->x2+1,max(y1,p->y1),x2,min(y2,p->y2),who);
499    ax2=p->x2;
500      }
501      else
502    ax2=x2;
503
504      if (y1<p->y1)
505      {
506        add_light(first,x1,y1,x2,p->y1-1,who);
507    ay1=p->y1;
508      } else
509    ay1=y1;
510
511      if (y2>p->y2)
512      {
513        add_light(first,x1,p->y2+1,x2,y2,who);
514    ay2=p->y2;
515      } else
516    ay2=y2;
517
518
519      add_light(first,ax1,ay1,ax2,ay2,who);
520
521      return ;
522    }
523  }
524}
525
526light_patch *find_patch(int screenx, int screeny, light_patch *list)
527{
528  for (;list;list=list->next)
529  {
530    if (screenx>=list->x1 && screenx<=list->x2 && screeny>=list->y1 && screeny<=list->y2)
531      return list;
532  }
533  return NULL;
534}
535
536/* shit
537int calc_light_value(light_patch *which, int32_t x, int32_t y)
538{
539  int lv=0;
540  int t=which->total;
541  for (register int i=t-1;i>=0;i--)
542  {
543    light_source *fn=which->lights[i];
544    if (fn->type==9)
545    {
546      lv=fn->inner_radius;
547      i=0;
548    }
549    else
550    {
551      int32_t dx=abs(fn->x-x)<<fn->xshift;
552      int32_t dy=abs(fn->y-y)<<fn->yshift;
553      int32_t  r2;
554      if (dx<dy)
555        r2=dx+dy-(dx>>1);
556      else r2=dx+dy-(dy>>1);
557
558      if (r2>=fn->inner_radius)
559      {
560    if (r2<fn->outer_radius)
561    {
562      lv+=((fn->outer_radius-r2)*fn->mul_div)>>16;
563    }
564      } else lv=63;   
565    }
566  }
567  if (lv>63) return 63;
568  else
569    return lv;
570} */
571
572
573void reduce_patches(light_patch *f)   // find constant valued patches
574{
575
576}
577
578light_patch *make_patch_list(int width, int height, int32_t screenx, int32_t screeny)
579{
580  light_patch *first=new light_patch(0,0,width-1,height-1,NULL);
581
582  for (light_source *f=first_light_source;f;f=f->next)   // determine which lights will have effect
583  {
584    int32_t x1=f->x1-screenx,y1=f->y1-screeny,
585        x2=f->x2-screenx,y2=f->y2-screeny;
586    if (x1<0) x1=0;
587    if (y1<0) y1=0;
588    if (x2>=width)  x2=width-1;
589    if (y2>=height) y2=height-1;
590
591    if (x1<=x2 && y1<=y2)
592      add_light(first,x1,y1,x2,y2,f);
593  }
594  reduce_patches(first);
595
596  return first;
597}
598
599
600void delete_patch_list(light_patch *first)
601{
602  while (first)
603  {
604    light_patch *p=first;
605    first=first->next;
606    delete p;
607  }
608}
609
610inline void MAP_PUT(uint8_t * screen_addr, uint8_t * remap, int w)
611{
612  register int cx=w;
613  register uint8_t * di=screen_addr;
614  register uint8_t * si=remap;
615  while (cx--)
616  {
617    uint8_t x=*((uint8_t *)si+*((uint8_t *)di));
618    *((uint8_t *)(di++))=x;
619  }
620}
621
622inline void MAP_2PUT(uint8_t * in_addr, uint8_t * out_addr, uint8_t * remap, int w)
623{
624  while (w--)
625  {
626    uint8_t x=*(((uint8_t *)remap)+(*(uint8_t *)(in_addr++)));
627    *((uint8_t *)(out_addr++))=x;
628    *((uint8_t *)(out_addr++))=x;
629  }
630}
631
632uint16_t min_light_level;
633// calculate the light value for this block.  sum up all contritors
634inline int calc_light_value(light_patch *lp,   // light patch to look at
635                int32_t sx,           // screen x & y
636                int32_t sy)
637{
638  int lv=min_light_level,r2,light_count;
639  register int dx,dy;           // x and y distances
640
641  light_source **lon_p=lp->lights;
642
643  for (light_count=lp->total;light_count>0;light_count--)
644  {
645    light_source *fn=*lon_p;
646    register int32_t *dt=&(*lon_p)->type;
647                                     // note we are accessing structure members by bypassing the compiler
648                                     // for speed, this may not work on all compilers, but don't
649                                     // see why it shouldn't..  all members are int32_t
650
651    if (*dt==9)                      // (dt==type),  if light is a Solid rectangle, return it value
652      return fn->inner_radius;
653    else
654    {
655      dt++;
656      dx=abs(*dt-sx); dt++;               // xdist between light and this block  (dt==x)
657      dx<<=*dt;  dt++;                    // shift makes distance further,
658                                          // making light skinner. (dt==xshift)
659
660      dy=abs(*dt-sy); dt++;                   // ydist (dt==y)
661      dy<<=*dt;  dt++;                        // (dt==yshift)
662
663      if (dx<dy)                     // calculate approximate distance
664        r2=dx+dy-(dx>>1);
665      else r2=dx+dy-(dy>>1);
666
667      if (r2<*dt)                    // if this withing the light's outer radius?  (dt==outer_radius)
668      {       
669    int v=*dt-r2; dt++;       
670    lv+=v*(*dt)>>16;
671      }
672    }
673    lon_p++;
674  }
675
676  if (lv>63)
677    return 63;          // lighting table only has 64 (256 bytes) entries
678  else return lv;
679}
680
681
682void remap_line_asm2(uint8_t *addr,uint8_t *light_lookup,uint8_t *remap_line,int count)
683//inline void remap_line_asm2(uint8_t *addr,uint8_t *light_lookup,uint8_t *remap_line,int count)
684{
685  while (count--)
686  {
687    uint8_t *off=light_lookup+(((int32_t)*remap_line)<<8);
688    remap_line++;
689
690    *addr=off[*addr];
691    addr[1]=off[addr[1]];
692    addr[2]=off[addr[2]];
693    addr[3]=off[addr[3]];
694    addr[4]=off[addr[4]];
695    addr[5]=off[addr[5]];
696    addr[6]=off[addr[6]];
697    addr[7]=off[addr[7]];
698    addr+=8;
699
700  }
701}
702
703inline void put_8line(uint8_t *in_line, uint8_t *out_line, uint8_t *remap, uint8_t *light_lookup, int count)
704{
705  uint8_t v;
706  int x;
707  for (x=0;x<count;x++)
708  {
709    uint8_t *off=light_lookup+(((int32_t)*remap)<<8);
710
711    v=off[*(in_line++)];
712    *(out_line++)=v;
713    *(out_line++)=v;
714
715    v=off[*(in_line++)];
716    *(out_line++)=v;
717    *(out_line++)=v;
718
719    v=off[*(in_line++)];
720    *(out_line++)=v;
721    *(out_line++)=v;
722
723    v=off[*(in_line++)];
724    *(out_line++)=v;
725    *(out_line++)=v;
726
727    v=off[*(in_line++)];
728    *(out_line++)=v;
729    *(out_line++)=v;
730
731    v=off[*(in_line++)];
732    *(out_line++)=v;
733    *(out_line++)=v;
734
735    v=off[*(in_line++)];
736    *(out_line++)=v;
737    *(out_line++)=v;
738
739    v=off[*(in_line++)];
740    *(out_line++)=v;
741    *(out_line++)=v;
742
743    remap++;
744  }
745}
746
747
748void light_screen(image *sc, int32_t screenx, int32_t screeny, uint8_t *light_lookup, uint16_t ambient)
749{
750  int lx_run=0,ly_run;                     // light block x & y run size in pixels ==  (1<<lx_run)
751
752  if (shutdown_lighting && !disable_autolight)
753    ambient=shutdown_lighting_value;
754
755  switch (light_detail)
756  {
757    case HIGH_DETAIL :
758    { lx_run=2; ly_run=1; } break;       // 4 x 2 patches
759    case MEDIUM_DETAIL :
760    { lx_run=3; ly_run=2; } break;       // 8 x 4 patches  (default)
761    case LOW_DETAIL :
762    { lx_run=4; ly_run=3; } break;       // 16 x 8 patches
763    case POOR_DETAIL :                   // poor detail is no lighting
764    return ;
765  }
766  if ((int)ambient+ambient_ramp<0)
767    min_light_level=0;
768  else if ((int)ambient+ambient_ramp>63)
769    min_light_level=63;
770  else min_light_level=(int)ambient+ambient_ramp;
771
772  if (ambient==63) return ;
773  short cx1,cy1,cx2,cy2;
774  sc->get_clip(cx1,cy1,cx2,cy2);
775
776  light_patch *first=make_patch_list(cx2-cx1+1,cy2-cy1+1,screenx,screeny);
777
778  int prefix_x=(screenx&7);
779  int prefix=screenx&7;
780  if (prefix)
781    prefix=8-prefix;
782  int suffix_x=cx2-cx1-(screenx&7);
783
784  int suffix=(cx2-cx1-prefix+1)&7;
785
786  int32_t remap_size=((cx2-cx1+1-prefix-suffix)>>lx_run);
787
788  uint8_t *remap_line=(uint8_t *)malloc(remap_size);
789
790  light_patch *f=first;
791
792  screen->lock();
793
794  int scr_w=screen->width();
795  uint8_t *screen_line=screen->scan_line(cy1)+cx1;
796
797  for (int y=cy1;y<=cy2;)
798  {
799    int x,count;
800//    while (f->next && f->y2<y)
801//      f=f->next;
802    uint8_t *rem=remap_line;
803
804    int todoy=4-((screeny+y)&3);
805    if (y+todoy>cy2)
806      todoy=cy2-y+1;
807
808    int calcy=((y+screeny)&(~3))-cy1;
809
810
811    if (suffix)
812    {
813      light_patch *lp=f;
814      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 ||
815                  lp->x1>suffix_x || lp->x2<suffix_x);lp=lp->next);
816      uint8_t * caddr=(uint8_t *)screen_line+cx2-cx1+1-suffix;
817      uint8_t *r=light_lookup+(((int32_t)calc_light_value(lp,suffix_x+screenx,calcy)<<8));
818      switch (todoy)
819      {
820    case 4 :
821    {
822      MAP_PUT(caddr,r,suffix); caddr+=scr_w;
823    }
824    case 3 :
825    { MAP_PUT(caddr,r,suffix); caddr+=scr_w;}
826    case 2 :
827    { MAP_PUT(caddr,r,suffix); caddr+=scr_w;}
828    case 1 :
829    {
830      MAP_PUT(caddr,r,suffix);
831    }
832      }
833    }
834
835    if (prefix)
836    {
837      light_patch *lp=f;
838      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 ||
839                  lp->x1>prefix_x || lp->x2<prefix_x);lp=lp->next);
840
841      uint8_t *r=light_lookup+(((int32_t)calc_light_value(lp,prefix_x+screenx,calcy)<<8));
842      uint8_t * caddr=(uint8_t *)screen_line;
843      switch (todoy)
844      {
845    case 4 :
846    {
847      MAP_PUT(caddr,r,prefix);
848      caddr+=scr_w;
849    }
850    case 3 :
851    { MAP_PUT(caddr,r,prefix); caddr+=scr_w; }
852    case 2 :
853    { MAP_PUT(caddr,r,prefix); caddr+=scr_w; }
854    case 1 :
855    { MAP_PUT(caddr,r,prefix); }
856      }
857      screen_line+=prefix;
858    }
859
860
861
862
863    for (x=prefix,count=0;count<remap_size;count++,x+=8,rem++)
864    {
865      light_patch *lp=f;
866      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || lp->x1>x || lp->x2<x);lp=lp->next);
867      *rem=calc_light_value(lp,x+screenx,calcy);
868    }
869
870    switch (todoy)
871    {
872      case 4 :
873      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
874      case 3 :
875      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
876      case 2 :
877      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
878      case 1 :
879      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
880    }
881
882
883    screen_line-=prefix;
884  }
885  screen->unlock();
886
887  while (first)
888  {
889    light_patch *p=first;
890    first=first->next;
891    delete p;
892  }
893  free(remap_line);
894}
895
896
897void double_light_screen(image *sc, int32_t screenx, int32_t screeny, uint8_t *light_lookup, uint16_t ambient,
898             image *out, int32_t out_x, int32_t out_y)
899{
900  if (sc->width()*2+out_x>out->width() ||
901      sc->height()*2+out_y>out->height())
902    return ;   // screen was resized and small_render has not changed size yet
903
904
905  int lx_run=0,ly_run;                     // light block x & y run size in pixels ==  (1<<lx_run)
906  switch (light_detail)
907  {
908    case HIGH_DETAIL :
909    { lx_run=2; ly_run=1; } break;       // 4 x 2 patches
910    case MEDIUM_DETAIL :
911    { lx_run=3; ly_run=2; } break;       // 8 x 4 patches  (default)
912    case LOW_DETAIL :
913    { lx_run=4; ly_run=3; } break;       // 16 x 8 patches
914    case POOR_DETAIL :                   // poor detail is no lighting
915    return ;
916  }
917  if ((int)ambient+ambient_ramp<0)
918    min_light_level=0;
919  else if ((int)ambient+ambient_ramp>63)
920    min_light_level=63;
921  else min_light_level=(int)ambient+ambient_ramp;
922
923  short cx1,cy1,cx2,cy2;
924  sc->get_clip(cx1,cy1,cx2,cy2);
925
926
927  if (ambient==63)      // lights off, just double the pixels
928  {
929    uint8_t *src=sc->scan_line(0);
930    uint8_t *dst=out->scan_line(out_y+cy1*2)+cx1*2+out_x;
931    int d_skip=out->width()-sc->width()*2;
932    int x,y;
933    uint16_t v;
934    for (y=sc->height();y;y--)
935    {
936      for (x=sc->width();x;x--)
937      {
938    v=*(src++);
939    *(dst++)=v;
940    *(dst++)=v;
941      }
942      dst=dst+d_skip;
943      memcpy(dst,dst-out->width(),sc->width()*2);
944      dst+=out->width();
945    }
946
947    return ;
948  }
949
950  light_patch *first=make_patch_list(cx2-cx1+1,cy2-cy1+1,screenx,screeny);
951
952  int scr_w=sc->width();
953  int dscr_w=out->width();
954
955  int prefix_x=(screenx&7);
956  int prefix=screenx&7;
957  if (prefix)
958    prefix=8-prefix;
959  int suffix_x=cx2-cx1-(screenx&7);
960
961  int suffix=(cx2-cx1-prefix+1)&7;
962
963  int32_t remap_size=((cx2-cx1+1-prefix-suffix)>>lx_run);
964
965  uint8_t *remap_line=(uint8_t *)malloc(remap_size);
966
967  light_patch *f=first;
968  uint8_t *in_line=sc->scan_line(cy1)+cx1;
969  uint8_t *out_line=out->scan_line(cy1*2+out_y)+cx1*2+out_x;
970
971
972  for (int y=cy1;y<=cy2;)
973  {
974    int x,count;
975//    while (f->next && f->y2<y)
976//      f=f->next;
977    uint8_t *rem=remap_line;
978
979    int todoy=4-((screeny+y)&3);
980    if (y+todoy>cy2)
981      todoy=cy2-y+1;
982
983    int calcy=((y+screeny)&(~3))-cy1;
984
985
986    if (suffix)
987    {
988      light_patch *lp=f;
989      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 ||
990                  lp->x1>suffix_x || lp->x2<suffix_x);lp=lp->next);
991      uint8_t * caddr=(uint8_t *)in_line+cx2-cx1+1-suffix;
992      uint8_t * daddr=(uint8_t *)out_line+(cx2-cx1+1-suffix)*2;
993
994      uint8_t *r=light_lookup+(((int32_t)calc_light_value(lp,suffix_x+screenx,calcy)<<8));
995      switch (todoy)
996      {
997    case 4 :
998    {
999      MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w;
1000      MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w; caddr+=scr_w;
1001    }
1002    case 3 :
1003    {
1004      MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w;
1005      MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w; caddr+=scr_w;
1006    }
1007    case 2 :
1008    {
1009      MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w;
1010      MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w; caddr+=scr_w;
1011    }
1012    case 1 :
1013    {
1014      MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w;
1015      MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w; caddr+=scr_w;
1016    } break;
1017      }
1018    }
1019
1020    if (prefix)
1021    {
1022      light_patch *lp=f;
1023      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 ||
1024                  lp->x1>prefix_x || lp->x2<prefix_x);lp=lp->next);
1025
1026      uint8_t *r=light_lookup+(((int32_t)calc_light_value(lp,prefix_x+screenx,calcy)<<8));
1027      uint8_t * caddr=(uint8_t *)in_line;
1028      uint8_t * daddr=(uint8_t *)out_line;
1029      switch (todoy)
1030      {
1031    case 4 :
1032    {
1033      MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w;
1034      MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w; caddr+=scr_w;
1035    }
1036    case 3 :
1037    {
1038      MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w;
1039      MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w; caddr+=scr_w;
1040    }
1041    case 2 :
1042    {
1043      MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w;
1044      MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w; caddr+=scr_w;
1045    }
1046    case 1 :
1047    {
1048      MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w;
1049      MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w; caddr+=scr_w;
1050    } break;
1051      }
1052      in_line+=prefix;
1053      out_line+=prefix*2;
1054    }
1055
1056
1057
1058
1059    for (x=prefix,count=0;count<remap_size;count++,x+=8,rem++)
1060    {
1061      light_patch *lp=f;
1062      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || lp->x1>x || lp->x2<x);lp=lp->next);
1063      *rem=calc_light_value(lp,x+screenx,calcy);
1064    }
1065
1066    rem=remap_line;
1067
1068    put_8line(in_line,out_line,rem,light_lookup,count);
1069    memcpy(out_line+dscr_w,out_line,count*16);
1070    out_line+=dscr_w;
1071    in_line+=scr_w; out_line+=dscr_w; y++; todoy--;
1072    if (todoy)
1073    {
1074      put_8line(in_line,out_line,rem,light_lookup,count);
1075      memcpy(out_line+dscr_w,out_line,count*16);
1076      out_line+=dscr_w;
1077      in_line+=scr_w; out_line+=dscr_w; y++; todoy--;
1078      if (todoy)
1079      {
1080    put_8line(in_line,out_line,rem,light_lookup,count);
1081    memcpy(out_line+dscr_w,out_line,count*16);
1082    out_line+=dscr_w;
1083    in_line+=scr_w; out_line+=dscr_w; y++; todoy--;
1084    if (todoy)
1085    {
1086      put_8line(in_line,out_line,rem,light_lookup,count);
1087      memcpy(out_line+dscr_w,out_line,count*16);
1088      out_line+=dscr_w;
1089      in_line+=scr_w; out_line+=dscr_w; y++;
1090    }
1091      }
1092    }
1093    in_line-=prefix;
1094    out_line-=prefix*2;
1095  }
1096
1097
1098  while (first)
1099  {
1100    light_patch *p=first;
1101    first=first->next;
1102    delete p;
1103  }
1104  free(remap_line);
1105}
1106
1107
1108
1109
1110void add_light_spec(spec_directory *sd, char const *level_name)
1111{
1112  int32_t size=4+4;  // number of lights and minimum light levels
1113  for (light_source *f=first_light_source;f;f=f->next)
1114    size+=6*4+1;
1115  sd->add_by_hand(new spec_entry(SPEC_LIGHT_LIST,"lights",NULL,size,0));
1116}
1117
1118void write_lights(bFILE *fp)
1119{
1120  int t=0;
1121  light_source *f=first_light_source;
1122  for (;f;f=f->next) t++;
1123  fp->write_uint32(t);
1124  fp->write_uint32(min_light_level);
1125  for (f=first_light_source;f;f=f->next)
1126  {
1127    fp->write_uint32(f->x);
1128    fp->write_uint32(f->y);
1129    fp->write_uint32(f->xshift);
1130    fp->write_uint32(f->yshift);
1131    fp->write_uint32(f->inner_radius);
1132    fp->write_uint32(f->outer_radius);
1133    fp->write_uint8(f->type);
1134  }
1135}
1136
1137
1138void read_lights(spec_directory *sd, bFILE *fp, char const *level_name)
1139{
1140  delete_all_lights();
1141  spec_entry *se=sd->find("lights");
1142  if (se)
1143  {
1144    fp->seek(se->offset,SEEK_SET);
1145    int32_t t=fp->read_uint32();
1146    min_light_level=fp->read_uint32();
1147    light_source *last=NULL;
1148    while (t)
1149    {
1150      t--;
1151      int32_t x=fp->read_uint32();
1152      int32_t y=fp->read_uint32();
1153      int32_t xshift=fp->read_uint32();
1154      int32_t yshift=fp->read_uint32();
1155      int32_t ir=fp->read_uint32();
1156      int32_t ora=fp->read_uint32();
1157      int32_t ty=fp->read_uint8();
1158
1159      light_source *p=new light_source(ty,x,y,ir,ora,xshift,yshift,NULL);
1160
1161      if (first_light_source)
1162        last->next=p;
1163      else first_light_source=p;
1164      last=p;
1165    }
1166  }
1167}
Note: See TracBrowser for help on using the repository browser.