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

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