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

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

style: remove trailing spaces, fix copyright statements.

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