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

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