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

Last change on this file since 512 was 512, checked in by Sam Hocevar, 7 years ago

imlib: use vec2i for image::size and unroll all necessary changes
everywhere else in the code.

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