source: abuse/tags/pd/abuse/src/light.c @ 49

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