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

Last change on this file since 665 was 665, checked in by Sam Hocevar, 9 years ago

imlib: refactor GetClip?, SetClip? etc. to use vec2i.

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