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

Last change on this file since 528 was 524, checked in by Sam Hocevar, 11 years ago

core: Get rid of mostly useless headers, move endianness handling to
common.h (and rewrite functions so that they do not need the SDL headers)
and move a few functions out of sdlport's video.cpp. These functions
were in the original video.cpp (which reappears) and shouldn't be part
of the SDL port.

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