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

Last change on this file since 56 was 56, checked in by Sam Hocevar, 11 years ago
  • Add licensing terms to most C / C++ files (Ref #5).
File size: 28.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.hpp"
15#include "image.hpp"
16#include "macs.hpp"
17#include "video.hpp"
18#include "palette.hpp"
19#include "timing.hpp"
20#include "specs.hpp"
21#include "dprint.hpp"
22#include "filter.hpp"
23#include "status.hpp"
24#include "dev.hpp"
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.hpp
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; if (rs<0) rs=0;
193    gs+=ga; if (gs>255) gs=255; if (gs<0) gs=0;
194    bs+=ba; if (bs>255) bs=255; 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 *)jmalloc(256*64,"light table");
207        white_light=white_light_initial;
208
209//      green_light=(uint8_t *)jmalloc(256*64,"green light");
210        int i = 0;
211        for( ; i < TTINTS; i++ )
212        {
213                tints[i] = (uint8_t *)jmalloc( 256, "color tint" );
214        }
215
216        char *lightpath;
217        lightpath = (char *)jmalloc( strlen( get_save_filename_prefix() ) + 9 + 1, "lightpath" );
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 *)jmalloc(256*256,"transparency table");
238//                      fp.read(trans_table,256*256);
239                }
240        }
241        delete fp;
242        fp = NULL;
243
244        if( recalc )
245        {
246                fprintf(stderr,"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 *)jmalloc(256*256,"transparency table");
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        jfree( 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 **)jmalloc(total*sizeof(light_source *),"light patches");
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 **)jrealloc(p->lights,sizeof(light_source *)*p->total,"patch_list");
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 **)jrealloc(p->lights,sizeof(light_source *)*p->total,"patch_list");
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
610/*
611#ifdef __WATCOMC__
612extern "C" {
613extern int32_t MAP_PUT(int32_t pad, int32_t screen_addr, int32_t remap, int32_t w);
614} ;
615#else*/
616
617inline void MAP_PUT(uint8_t * screen_addr, uint8_t * remap, int w)
618{
619  register int cx=w;
620  register uint8_t * di=screen_addr;
621  register uint8_t * si=remap;
622  while (cx--)
623  {
624    uint8_t x=*((uint8_t *)si+*((uint8_t *)di));
625    *((uint8_t *)(di++))=x;
626  }
627}
628
629inline void MAP_2PUT(uint8_t * in_addr, uint8_t * out_addr, uint8_t * remap, int w)
630{
631  while (w--)
632  {
633    uint8_t x=*(((uint8_t *)remap)+(*(uint8_t *)(in_addr++)));
634    *((uint8_t *)(out_addr++))=x;
635    *((uint8_t *)(out_addr++))=x;
636  }
637}
638
639/*
640#endif
641
642inline void PUT8(int32_t *addr, uint8_t *remap)
643{
644  register uint32_t in_pixels;
645  register uint32_t pixel;
646  register uint32_t out_pixels;
647  in_pixels=*addr;
648  pixel=in_pixels;
649  out_pixels=remap[(uint8_t)pixel];
650 
651  pixel=in_pixels;
652  pixel>>=8;
653  pixel=remap[(uint8_t)pixel];
654  pixel<<=8;
655  out_pixels|=pixel;
656
657  pixel=in_pixels;
658  pixel>>=16;
659  pixel=remap[(uint8_t)pixel];
660  pixel<<=16;
661  out_pixels|=pixel;
662
663  pixel=in_pixels;
664  pixel>>=24;
665  pixel=remap[(uint8_t)pixel];
666  pixel<<=24;
667  out_pixels|=pixel;
668
669  *addr=out_pixels;        // send out bus
670
671  // do next 4
672  in_pixels=addr[1];
673
674  pixel=in_pixels;
675  pixel&=0xff;
676  out_pixels=remap[pixel];
677 
678  pixel=in_pixels;
679  pixel>>=8;
680  pixel=remap[(uint8_t)pixel];
681  pixel<<=8;
682  out_pixels|=pixel;
683
684  pixel=in_pixels;
685  pixel>>=16;
686  pixel=remap[(uint8_t)pixel];
687  pixel<<=16;
688  out_pixels|=pixel;
689
690  pixel=in_pixels;
691  pixel>>=24;
692  pixel=remap[(uint8_t)pixel];
693  pixel<<=24;
694  out_pixels|=pixel; 
695  addr[1]=out_pixels;        // send out bus
696 
697}
698
699inline int32_t MAP_PUT2(int32_t dest_addr, int32_t screen_addr, int32_t remap, int32_t w)
700{ while (w--)
701  {
702    *((uint8_t *)(dest_addr))=*((uint8_t *)remap+*((uint8_t *)screen_addr));
703    screen_addr++;
704    dest_addr++;
705  }
706  return dest_addr;
707}
708
709*/
710
711uint16_t min_light_level;
712// calculate the light value for this block.  sum up all contritors
713inline int calc_light_value(light_patch *lp,   // light patch to look at
714                            int32_t sx,           // screen x & y
715                            int32_t sy)
716{
717  int lv=min_light_level,r2,light_count;
718  register int dx,dy;           // x and y distances
719
720  light_source **lon_p=lp->lights;
721
722  for (light_count=lp->total;light_count>0;light_count--)
723  {
724    light_source *fn=*lon_p;
725    register int32_t *dt=&(*lon_p)->type;
726                                     // note we are accessing structure members by bypassing the compiler
727                                     // for speed, this may not work on all compilers, but don't
728                                     // see why it shouldn't..  all members are int32_t
729   
730    if (*dt==9)                      // (dt==type),  if light is a Solid rectangle, return it value
731      return fn->inner_radius;
732    else
733    {
734      dt++;
735      dx=abs(*dt-sx); dt++;               // xdist between light and this block  (dt==x)
736      dx<<=*dt;  dt++;                    // shift makes distance further,
737                                          // making light skinner. (dt==xshift)
738
739      dy=abs(*dt-sy); dt++;                   // ydist (dt==y)
740      dy<<=*dt;  dt++;                        // (dt==yshift)
741
742      if (dx<dy)                     // calculate approximate distance
743        r2=dx+dy-(dx>>1);
744      else r2=dx+dy-(dy>>1);
745     
746      if (r2<*dt)                    // if this withing the light's outer radius?  (dt==outer_radius)
747      {         
748        int v=*dt-r2; dt++;             
749        lv+=v*(*dt)>>16;
750      }
751    }
752    lon_p++;
753  }
754
755  if (lv>63)
756    return 63;          // lighting table only has 64 (256 bytes) entries
757  else return lv;
758}
759
760
761/*#ifdef __WATCOMC__
762
763extern "C" void remap_line_asm(uint8_t *screen_line,uint8_t *light_lookup,uint8_t *remap_line,int count);
764
765#else */
766
767void remap_line_asm2(uint8_t *addr,uint8_t *light_lookup,uint8_t *remap_line,int count)
768//inline void remap_line_asm2(uint8_t *addr,uint8_t *light_lookup,uint8_t *remap_line,int count)
769{
770  while (count--)
771  {
772    uint8_t *off=light_lookup+(((int32_t)*remap_line)<<8);
773    remap_line++;
774
775    *addr=off[*addr];
776    addr[1]=off[addr[1]];
777    addr[2]=off[addr[2]];
778    addr[3]=off[addr[3]];
779    addr[4]=off[addr[4]];
780    addr[5]=off[addr[5]];
781    addr[6]=off[addr[6]];
782    addr[7]=off[addr[7]];
783    addr+=8;
784
785  }
786}
787
788//#endif
789
790
791inline void put_8line(uint8_t *in_line, uint8_t *out_line, uint8_t *remap, uint8_t *light_lookup, int count)
792{
793  uint8_t v;
794  int x;
795  for (x=0;x<count;x++)                       
796  {                                           
797    uint8_t *off=light_lookup+(((int32_t)*remap)<<8);
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    v=off[*(in_line++)];
820    *(out_line++)=v;
821    *(out_line++)=v;
822
823    v=off[*(in_line++)];
824    *(out_line++)=v;
825    *(out_line++)=v;
826
827    v=off[*(in_line++)];
828    *(out_line++)=v;
829    *(out_line++)=v;
830
831    remap++;
832  }
833}
834
835
836void light_screen(image *sc, int32_t screenx, int32_t screeny, uint8_t *light_lookup, uint16_t ambient)
837{
838  int lx_run=0,ly_run;                     // light block x & y run size in pixels ==  (1<<lx_run)
839
840  if (shutdown_lighting && !disable_autolight)
841    ambient=shutdown_lighting_value;
842
843  switch (light_detail)
844  {
845    case HIGH_DETAIL :
846    { lx_run=2; ly_run=1; } break;       // 4 x 2 patches
847    case MEDIUM_DETAIL :
848    { lx_run=3; ly_run=2; } break;       // 8 x 4 patches  (default)
849    case LOW_DETAIL :
850    { lx_run=4; ly_run=3; } break;       // 16 x 8 patches
851    case POOR_DETAIL :                   // poor detail is no lighting
852    return ;
853  }
854  if ((int)ambient+ambient_ramp<0)
855    min_light_level=0;
856  else if ((int)ambient+ambient_ramp>63)
857    min_light_level=63;
858  else min_light_level=(int)ambient+ambient_ramp;
859
860  if (ambient==63) return ;
861  short cx1,cy1,cx2,cy2;
862  sc->get_clip(cx1,cy1,cx2,cy2);
863
864  light_patch *first=make_patch_list(cx2-cx1+1,cy2-cy1+1,screenx,screeny);
865
866  int scr_w=screen->width();
867
868  int prefix_x=(screenx&7);
869  int prefix=screenx&7;
870  if (prefix)
871    prefix=8-prefix;
872  int suffix_x=cx2-cx1-(screenx&7);
873
874  int suffix=(cx2-cx1-prefix+1)&7;
875
876  int32_t remap_size=((cx2-cx1+1-prefix-suffix)>>lx_run);
877
878  uint8_t *remap_line=(uint8_t *)jmalloc(remap_size,"light remap line");
879
880  light_patch *f=first;
881  uint8_t *screen_line=screen->scan_line(cy1)+cx1;
882
883  for (int y=cy1;y<=cy2;)
884  {
885    int x,count;
886//    while (f->next && f->y2<y)
887//      f=f->next;
888    uint8_t *rem=remap_line;
889
890    int todoy=4-((screeny+y)&3);
891    if (y+todoy>cy2)
892      todoy=cy2-y+1;
893
894    int calcy=((y+screeny)&(~3))-cy1;
895   
896
897    if (suffix)
898    {
899      light_patch *lp=f;
900      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 ||
901                              lp->x1>suffix_x || lp->x2<suffix_x);lp=lp->next);
902      uint8_t * caddr=(uint8_t *)screen_line+cx2-cx1+1-suffix;
903      uint8_t *r=light_lookup+(((int32_t)calc_light_value(lp,suffix_x+screenx,calcy)<<8));
904      switch (todoy)
905      {
906        case 4 :
907        {
908          MAP_PUT(caddr,r,suffix); caddr+=scr_w;
909        }
910        case 3 :
911        { MAP_PUT(caddr,r,suffix); caddr+=scr_w;}
912        case 2 :
913        { MAP_PUT(caddr,r,suffix); caddr+=scr_w;}
914        case 1 :
915        {
916          MAP_PUT(caddr,r,suffix);
917        }
918      }
919    }
920
921    if (prefix)
922    {
923      light_patch *lp=f;
924      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 ||
925                              lp->x1>prefix_x || lp->x2<prefix_x);lp=lp->next);
926
927      uint8_t *r=light_lookup+(((int32_t)calc_light_value(lp,prefix_x+screenx,calcy)<<8));
928      uint8_t * caddr=(uint8_t *)screen_line;
929      switch (todoy)
930      {
931        case 4 :
932        {
933          MAP_PUT(caddr,r,prefix);
934          caddr+=scr_w;
935        }
936        case 3 :
937        { MAP_PUT(caddr,r,prefix); caddr+=scr_w; }
938        case 2 :
939        { MAP_PUT(caddr,r,prefix); caddr+=scr_w; }
940        case 1 :
941        { MAP_PUT(caddr,r,prefix); }
942      }
943      screen_line+=prefix;
944    }
945
946
947 
948
949    for (x=prefix,count=0;count<remap_size;count++,x+=8,rem++)   
950    {
951      light_patch *lp=f;
952      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || lp->x1>x || lp->x2<x);lp=lp->next);
953      *rem=calc_light_value(lp,x+screenx,calcy);
954    }
955
956    switch (todoy)
957    {
958      case 4 :   
959      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
960      case 3 :
961      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
962      case 2 :
963      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
964      case 1 :
965      remap_line_asm2(screen_line,light_lookup,remap_line,count);  y++; todoy--;  screen_line+=scr_w;
966    }
967
968
969    screen_line-=prefix;
970
971
972
973  }
974
975
976  while (first)
977  {
978    light_patch *p=first;
979    first=first->next;
980    delete p;
981  }
982  jfree(remap_line);
983}
984
985
986void double_light_screen(image *sc, int32_t screenx, int32_t screeny, uint8_t *light_lookup, uint16_t ambient,
987                         image *out, int32_t out_x, int32_t out_y)
988{
989  if (sc->width()*2+out_x>out->width() ||
990      sc->height()*2+out_y>out->height())
991    return ;   // screen was resized and small_render has not changed size yet
992
993
994  int lx_run=0,ly_run;                     // light block x & y run size in pixels ==  (1<<lx_run)
995  switch (light_detail)
996  {
997    case HIGH_DETAIL :
998    { lx_run=2; ly_run=1; } break;       // 4 x 2 patches
999    case MEDIUM_DETAIL :
1000    { lx_run=3; ly_run=2; } break;       // 8 x 4 patches  (default)
1001    case LOW_DETAIL :
1002    { lx_run=4; ly_run=3; } break;       // 16 x 8 patches
1003    case POOR_DETAIL :                   // poor detail is no lighting
1004    return ;
1005  }
1006  if ((int)ambient+ambient_ramp<0)
1007    min_light_level=0;
1008  else if ((int)ambient+ambient_ramp>63)
1009    min_light_level=63;
1010  else min_light_level=(int)ambient+ambient_ramp;
1011
1012  short cx1,cy1,cx2,cy2;
1013  sc->get_clip(cx1,cy1,cx2,cy2);
1014
1015
1016  if (ambient==63)      // lights off, just double the pixels
1017  {
1018    uint8_t *src=sc->scan_line(0);
1019    uint8_t *dst=out->scan_line(out_y+cy1*2)+cx1*2+out_x;
1020    int d_skip=out->width()-sc->width()*2;
1021    int x,y;
1022    uint16_t v;
1023    for (y=sc->height();y;y--)
1024    {
1025      for (x=sc->width();x;x--)
1026      {
1027        v=*(src++);
1028        *(dst++)=v;
1029        *(dst++)=v;
1030      }
1031      dst=dst+d_skip;
1032      memcpy(dst,dst-out->width(),sc->width()*2);
1033      dst+=out->width();
1034    }
1035
1036    return ;
1037  }
1038
1039  light_patch *first=make_patch_list(cx2-cx1+1,cy2-cy1+1,screenx,screeny);
1040
1041  int scr_w=sc->width();
1042  int dscr_w=out->width();
1043
1044  int prefix_x=(screenx&7);
1045  int prefix=screenx&7;
1046  if (prefix)
1047    prefix=8-prefix;
1048  int suffix_x=cx2-cx1-(screenx&7);
1049
1050  int suffix=(cx2-cx1-prefix+1)&7;
1051
1052  int32_t remap_size=((cx2-cx1+1-prefix-suffix)>>lx_run);
1053
1054  uint8_t *remap_line=(uint8_t *)jmalloc(remap_size,"light remap line");
1055
1056  light_patch *f=first;
1057  uint8_t *in_line=sc->scan_line(cy1)+cx1;
1058  uint8_t *out_line=out->scan_line(cy1*2+out_y)+cx1*2+out_x;
1059
1060
1061  for (int y=cy1;y<=cy2;)
1062  {
1063    int x,count;
1064//    while (f->next && f->y2<y)
1065//      f=f->next;
1066    uint8_t *rem=remap_line;
1067
1068    int todoy=4-((screeny+y)&3);
1069    if (y+todoy>cy2)
1070      todoy=cy2-y+1;
1071
1072    int calcy=((y+screeny)&(~3))-cy1;
1073   
1074
1075    if (suffix)
1076    {
1077      light_patch *lp=f;
1078      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 ||
1079                              lp->x1>suffix_x || lp->x2<suffix_x);lp=lp->next);
1080      uint8_t * caddr=(uint8_t *)in_line+cx2-cx1+1-suffix;
1081      uint8_t * daddr=(uint8_t *)out_line+(cx2-cx1+1-suffix)*2;
1082
1083      uint8_t *r=light_lookup+(((int32_t)calc_light_value(lp,suffix_x+screenx,calcy)<<8));
1084      switch (todoy)
1085      {
1086        case 4 :
1087        {
1088          MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w;
1089          MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w; caddr+=scr_w;
1090        }
1091        case 3 :
1092        {
1093          MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w;
1094          MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w; caddr+=scr_w;
1095        }
1096        case 2 :
1097        {
1098          MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w;
1099          MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w; caddr+=scr_w;
1100        }
1101        case 1 :
1102        {
1103          MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w;
1104          MAP_2PUT(caddr,daddr,r,suffix); daddr+=dscr_w; caddr+=scr_w;
1105        } break;
1106      }
1107    }
1108
1109    if (prefix)
1110    {
1111      light_patch *lp=f;
1112      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 ||
1113                              lp->x1>prefix_x || lp->x2<prefix_x);lp=lp->next);
1114
1115      uint8_t *r=light_lookup+(((int32_t)calc_light_value(lp,prefix_x+screenx,calcy)<<8));
1116      uint8_t * caddr=(uint8_t *)in_line;
1117      uint8_t * daddr=(uint8_t *)out_line;
1118      switch (todoy)
1119      {
1120        case 4 :
1121        {
1122          MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w;
1123          MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w; caddr+=scr_w;
1124        }
1125        case 3 :
1126        {
1127          MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w;
1128          MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w; caddr+=scr_w;
1129        }
1130        case 2 :
1131        {
1132          MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w;
1133          MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w; caddr+=scr_w;
1134        }
1135        case 1 :
1136        {
1137          MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w;
1138          MAP_2PUT(caddr,daddr,r,prefix); daddr+=dscr_w; caddr+=scr_w;
1139        } break;
1140      }
1141      in_line+=prefix;
1142      out_line+=prefix*2;
1143    }
1144
1145
1146 
1147
1148    for (x=prefix,count=0;count<remap_size;count++,x+=8,rem++)   
1149    {
1150      light_patch *lp=f;
1151      for (;(lp->y1>y-cy1 || lp->y2<y-cy1 || lp->x1>x || lp->x2<x);lp=lp->next);
1152      *rem=calc_light_value(lp,x+screenx,calcy);
1153    }
1154
1155    rem=remap_line;
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++; todoy--;
1167      if (todoy)
1168      {
1169        put_8line(in_line,out_line,rem,light_lookup,count);
1170        memcpy(out_line+dscr_w,out_line,count*16);
1171        out_line+=dscr_w;
1172        in_line+=scr_w; out_line+=dscr_w; y++; todoy--;
1173        if (todoy)
1174        {
1175          put_8line(in_line,out_line,rem,light_lookup,count);
1176          memcpy(out_line+dscr_w,out_line,count*16);
1177          out_line+=dscr_w;
1178          in_line+=scr_w; out_line+=dscr_w; y++;
1179        }
1180      }
1181    }     
1182    in_line-=prefix;
1183    out_line-=prefix*2;
1184  }
1185
1186
1187  while (first)
1188  {
1189    light_patch *p=first;
1190    first=first->next;
1191    delete p;
1192  }
1193  jfree(remap_line);
1194}
1195
1196
1197
1198
1199void add_light_spec(spec_directory *sd, char const *level_name)
1200{
1201  int32_t size=4+4;  // number of lights and minimum light levels
1202  for (light_source *f=first_light_source;f;f=f->next)
1203    size+=6*4+1;
1204  sd->add_by_hand(new spec_entry(SPEC_LIGHT_LIST,"lights",NULL,size,0)); 
1205}
1206
1207void write_lights(bFILE *fp)
1208{
1209  int t=0;
1210  light_source *f=first_light_source;
1211  for (;f;f=f->next) t++;
1212  fp->write_uint32(t);
1213  fp->write_uint32(min_light_level);
1214  for (f=first_light_source;f;f=f->next)
1215  {
1216    fp->write_uint32(f->x);
1217    fp->write_uint32(f->y);
1218    fp->write_uint32(f->xshift);
1219    fp->write_uint32(f->yshift);
1220    fp->write_uint32(f->inner_radius);
1221    fp->write_uint32(f->outer_radius);
1222    fp->write_uint8(f->type);
1223  }
1224}
1225
1226
1227void read_lights(spec_directory *sd, bFILE *fp, char const *level_name)
1228{
1229  delete_all_lights();
1230  spec_entry *se=sd->find("lights");
1231  if (se)
1232  {
1233    fp->seek(se->offset,SEEK_SET);
1234    int32_t t=fp->read_uint32();
1235    min_light_level=fp->read_uint32();
1236    light_source *last=NULL;
1237    while (t)
1238    {
1239      t--;
1240      int32_t x=fp->read_uint32();
1241      int32_t y=fp->read_uint32();
1242      int32_t xshift=fp->read_uint32();
1243      int32_t yshift=fp->read_uint32();
1244      int32_t ir=fp->read_uint32();
1245      int32_t ora=fp->read_uint32();
1246      int32_t ty=fp->read_uint8();
1247
1248      light_source *p=new light_source(ty,x,y,ir,ora,xshift,yshift,NULL);
1249     
1250      if (first_light_source)
1251        last->next=p;
1252      else first_light_source=p;
1253      last=p;
1254    }
1255  }
1256}
Note: See TracBrowser for help on using the repository browser.