1 /* Catacomb 3-D Source Code
\r
2 * Copyright (C) 1993-2014 Flat Rock Software
\r
4 * This program is free software; you can redistribute it and/or modify
\r
5 * it under the terms of the GNU General Public License as published by
\r
6 * the Free Software Foundation; either version 2 of the License, or
\r
7 * (at your option) any later version.
\r
9 * This program is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 * GNU General Public License for more details.
\r
14 * You should have received a copy of the GNU General Public License along
\r
15 * with this program; if not, write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
24 //const unsigned viewheight = 144;
\r
25 const unsigned screenbwide = 40;
\r
26 const byte BACKGROUNDPIX = 5;
\r
28 unsigned shapesize[MAXSCALE+1];
\r
29 t_compscale _seg *scaledirectory[MAXSCALE+1];
\r
30 t_compshape _seg *shapedirectory[NUMSCALEPICS];
\r
31 memptr walldirectory[NUMSCALEWALLS];
\r
34 ===========================
\r
38 = Takes a raw bit map of width bytes by height and creates a scaleable shape
\r
40 = Returns the length of the shape in bytes
\r
42 = Fills in spotvis (a convenient 64*64 array) with the color values
\r
44 ===========================
\r
47 void DeplanePic (int picnum)
\r
49 byte far *plane0,far *plane1,far *plane2,far *plane3;
\r
50 byte by0,by1,by2,by3;
\r
51 unsigned x,y,b,color,shift,width,height;
\r
55 // convert ega pixels to byte color values in a temp buffer
\r
57 width = pictable[picnum-STARTPICS].width;
\r
58 height = pictable[picnum-STARTPICS].height;
\r
60 if (width>64 || height!=64)
\r
61 Quit ("DePlanePic: Bad size shape");
\r
63 memset (spotvis,BACKGROUNDPIX,sizeof(spotvis));
\r
65 plane0 = (byte _seg *)grsegs[picnum];
\r
66 plane1 = plane0 + width*height;
\r
67 plane2 = plane1 + width*height;
\r
68 plane3 = plane2 + width*height;
\r
70 for (y=0;y<height;y++)
\r
72 dest = &spotvis[y][0];
\r
73 for (x=0;x<width;x++)
\r
85 asm mov cl,[BYTE PTR shift]
\r
86 asm mov al,[BYTE PTR by3]
\r
88 asm rcl [BYTE PTR color],1;
\r
90 asm mov cl,[BYTE PTR shift]
\r
91 asm mov al,[BYTE PTR by2]
\r
93 asm rcl [BYTE PTR color],1;
\r
95 asm mov cl,[BYTE PTR shift]
\r
96 asm mov al,[BYTE PTR by1]
\r
98 asm rcl [BYTE PTR color],1;
\r
100 asm mov cl,[BYTE PTR shift]
\r
101 asm mov al,[BYTE PTR by0]
\r
103 asm rcl [BYTE PTR color],1;
\r
115 ========================
\r
119 = Builds a compiled scaler object that will scale a 64 tall object to
\r
120 = the given height (centered vertically on the screen)
\r
122 = height should be even
\r
126 = DS:SI Source for scale
\r
127 = ES:DI Dest for scale
\r
129 = Calling the compiled scaler only destroys AL
\r
131 ========================
\r
134 unsigned BuildCompScale (int height, memptr *finalspot)
\r
136 t_compscale _seg *work;
\r
141 unsigned src,totalscaled,totalsize;
\r
142 int startpix,endpix,toppix;
\r
145 MM_GetPtr (&(memptr)work,20000);
\r
147 step = ((long)height<<16) / 64;
\r
148 code = &work->code[0];
\r
149 toppix = (viewheight-height)/2;
\r
152 for (src=0;src<=64;src++)
\r
154 startpix = fix>>16;
\r
158 work->start[src] = startpix;
\r
159 if (endpix>startpix)
\r
160 work->width[src] = endpix-startpix;
\r
162 work->width[src] = 0;
\r
165 // mark the start of the code
\r
167 work->codeofs[src] = FP_OFF(code);
\r
170 // compile some code if the source pixel generates any screen pixels
\r
175 if (startpix == endpix || endpix < 0 || startpix >= VIEWHEIGHT || src == 64)
\r
185 for (;startpix<endpix;startpix++)
\r
187 if (startpix >= VIEWHEIGHT)
\r
188 break; // off the bottom of the view area
\r
190 continue; // not into the view area
\r
193 // and [es:di+heightofs],al
\r
198 *((unsigned far *)code)++ = startpix*screenbwide;
\r
208 totalsize = FP_OFF(code);
\r
209 MM_GetPtr (finalspot,totalsize);
\r
210 _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);
\r
211 MM_FreePtr (&(memptr)work);
\r
220 ========================
\r
227 = unsigned codeofs[64];
\r
230 = Width is the number of compiled line draws in the shape. The shape
\r
231 = drawing code will assume that the midpoint of the shape is in the
\r
232 = middle of the width.
\r
234 = The non background pixel data will start at codeofs[width], so codeofs
\r
235 = greater than width will be invalid.
\r
237 = Each code offset will draw one vertical line of the shape, consisting
\r
238 = of 0 or more segments of scaled pixels.
\r
240 = The scaled shapes use ss:0-4 as a scratch variable for the far call to
\r
241 = the compiled scaler, so zero it back out after the shape is scaled, or
\r
242 = a "null pointer assignment" will result upon termination.
\r
244 = Setup for a call to a compiled shape
\r
245 = -----------------------------------
\r
249 = dx segment of compiled shape
\r
251 = di byte at top of view area to draw the line in
\r
253 = ss:2 and ds the segment of the compiled scaler to use
\r
256 = Upon return, ds IS NOT SET to the data segment. Do:
\r
261 = GC_BITMASK set to the pixels to be drawn in the row of bytes under DI
\r
262 = GC_MODE read mode 1, write mode 2
\r
263 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
\r
266 = Code generated for each segment
\r
267 = -------------------------------
\r
268 = mov bx,[(segend+1)*2]
\r
270 = mov [BYTE PTR bx],0xc8 // far return
\r
271 = mov ax,[segstart*2]
\r
272 = mov [ss:0],ax // entry point into the compiled scaler
\r
273 = mov ds,dx // (mov ds,cs) the data is after the compiled code
\r
275 = call [bp] // scale some pixels
\r
277 = mov [bx],cx // un patch return
\r
279 = Code generated after all segments on a line
\r
280 = -------------------------------------------
\r
283 ========================
\r
286 unsigned BuildCompShape (t_compshape _seg **finalspot)
\r
288 t_compshape _seg *work;
\r
290 int firstline,lastline,x,y;
\r
291 unsigned firstpix,lastpix,width;
\r
292 unsigned totalsize,pixelofs;
\r
296 // MM_GetPtr (&(memptr)work,20000);
\r
298 EGAREADMAP(0); // use ega screen memory for temp buffer
\r
300 buff = screenloc[1];
\r
301 work = (t_compshape _seg *)(0xa000+(buff+15)/16);
\r
304 // find the width of the shape
\r
311 if (spotvis[y][x] != BACKGROUNDPIX)
\r
317 Quit ("BuildCompShape: No shape data!");
\r
318 } while (firstline == -1);
\r
325 if (spotvis[y][x] != BACKGROUNDPIX)
\r
331 } while (lastline == -1);
\r
333 width = lastline-firstline+1;
\r
335 work->width = width;
\r
336 code = (byte far *)&work->codeofs[width];
\r
339 // copy all non background pixels to the work space
\r
341 pixelofs = FP_OFF(code);
\r
343 for (x=firstline;x<=lastline;x++)
\r
345 if (spotvis[y][x] != BACKGROUNDPIX)
\r
346 *code++ = spotvis[y][x];
\r
349 // start compiling the vertical lines
\r
351 for (x=firstline;x<=lastline;x++)
\r
353 work->codeofs[x-firstline] = FP_OFF(code);
\r
359 // scan past black background pixels
\r
361 while (spotvis[y][x] == BACKGROUNDPIX && y<64)
\r
364 if (y>63) // no more segments
\r
367 firstpix = y+1; // +1 because width is before codeofs
\r
370 // scan past scalable pixels
\r
372 while (spotvis[y][x] != BACKGROUNDPIX && y<64)
\r
378 lastpix = y+1; // actually one pixel past the last displayed
\r
381 // compile the scale call
\r
383 *code++ = 0x8b; // mov bx,[lastpix*2]
\r
385 *((unsigned far *)code)++ = lastpix*2;
\r
387 *code++ = 0x8b; // mov cx,[bx]
\r
390 *code++ = 0xc6; // move [BYTE bx],0xcb
\r
394 *code++ = 0xa1; // mov ax,[firstpix*2] /*************
\r
395 *((unsigned far *)code)++ = firstpix*2;
\r
397 *code++ = 0x36; // mov [ss:0],ax
\r
402 *code++ = 0x8e; // mov ds,dx (mov ds,cs)
\r
405 *code++ = 0xbe; // mov si,OFFSET pixelofs-firstpixel
\r
406 *((unsigned far *)code)++ = pixelofs-firstpix;
\r
408 *code++ = 0xff; // call [DWORD bp]
\r
412 *code++ = 0x8e; // mov ds,[bp+2]
\r
416 *code++ = 0x89; // mov [bx],cx
\r
419 pixelofs += (lastpix-firstpix);
\r
430 // copy the final shape to a properly sized buffer
\r
432 totalsize = FP_OFF(code);
\r
433 MM_GetPtr ((memptr *)finalspot,totalsize);
\r
434 _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);
\r
435 // MM_FreePtr (&(memptr)work);
\r
443 =======================
\r
447 = Draws a compiled shape at [scale] pixels high
\r
451 = GC_MODE read mode 1, write mode 2
\r
452 = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
\r
453 = GC_INDEX pointing at GC_BITMASK
\r
455 =======================
\r
458 static long longtemp;
\r
460 void ScaleShape (int xcenter, t_compshape _seg *compshape, unsigned scale)
\r
462 t_compscale _seg *comptable;
\r
463 unsigned width,scalewidth;
\r
464 int x,pixel,lastpixel,pixwidth,min;
\r
465 unsigned far *codehandle, far *widthptr;
\r
466 unsigned badcodeptr;
\r
470 Quit ("ScaleShape: NULL compshape ptr!");
\r
472 scale = (scale+1)/2;
\r
474 return; // too far away
\r
475 if (scale>MAXSCALE)
\r
477 comptable = scaledirectory[scale];
\r
479 width = compshape->width;
\r
480 scalewidth = comptable->start[width];
\r
482 pixel = xcenter - scalewidth/2;
\r
483 lastpixel = pixel+scalewidth-1;
\r
484 if (pixel >= VIEWWIDTH || lastpixel < 0)
\r
485 return; // totally off screen
\r
488 // scan backwards from the right edge until pixels are visable
\r
489 // rightclip is the first NON VISABLE pixel
\r
491 if (lastpixel>=VIEWWIDTH-1)
\r
492 rightclip = VIEWWIDTH-1;
\r
494 rightclip = lastpixel;
\r
496 if (zbuffer[rightclip]>scale)
\r
504 if (--rightclip < min)
\r
505 return; // totally covered or before 0
\r
506 if (zbuffer[rightclip]<=scale)
\r
513 // scan from the left until it is on screen, leaving
\r
514 // [pixel],[pixwidth],[codehandle],and [widthptr] set correctly
\r
516 *(((unsigned *)&longtemp)+1) = (unsigned)compshape; // seg of shape
\r
517 codehandle = &compshape->codeofs[0];
\r
518 badcodeptr = compshape->codeofs[width];
\r
519 widthptr = &comptable->width[0];
\r
520 asm mov ax,[comptable]
\r
521 asm mov WORD PTR [2],ax // ds:0-4 is used as a far call pointer
\r
522 // by the compiled shapes
\r
523 pixwidth = *widthptr; // scaled width of this pixel
\r
526 pixwidth = *++widthptr; // find the first visable pixel
\r
534 if (pixel+pixwidth>0)
\r
542 pixwidth = *++widthptr;
\r
544 } while (!pixwidth);
\r
550 // scan until it is visable, leaving
\r
551 // [pixel],[pixwidth],[codehandle],and [widthptr] set correctly
\r
555 if (zbuffer[pixel] <= scale)
\r
556 break; // start drawing here
\r
562 pixwidth = *++widthptr;
\r
564 } while (!pixwidth);
\r
568 if (pixel+pixwidth>rightclip)
\r
569 pixwidth = rightclip-pixel;
\r
576 // scale a vertical segment [pixwidth] pixels wide at [pixel]
\r
578 (unsigned)longtemp = *codehandle; // offset of compiled code
\r
579 if ((unsigned)longtemp == badcodeptr)
\r
580 Quit ("ScaleShape: codehandle past end!");
\r
586 asm shr di,1 // X in bytes
\r
587 asm add di,[bufferofs]
\r
592 asm add bx,[pixwidth] // bx = pixel*8+pixwidth-1
\r
595 asm mov al,BYTE PTR [bitmasks1+bx]
\r
596 asm mov dx,GC_INDEX+1
\r
597 asm out dx,al // set bit mask register
\r
599 asm mov es,[screenseg]
\r
604 asm mov dx,[WORD PTR longtemp+2]
\r
606 asm call ss:[DWORD PTR longtemp] // scale the line of pixels
\r
614 asm mov al,BYTE PTR [bitmasks2+bx]
\r
619 // draw a second byte for vertical strips that cross two bytes
\r
622 asm mov dx,GC_INDEX+1
\r
623 asm out dx,al // set bit mask register
\r
628 asm mov dx,[WORD PTR longtemp+2]
\r
630 asm call ss:[DWORD PTR longtemp] // scale the line of pixels
\r
639 // advance to the next drawn line
\r
642 if ( (pixel+=pixwidth) == rightclip )
\r
644 asm mov WORD PTR [0],0
\r
645 asm mov WORD PTR [2],0
\r
646 return; // all done!
\r
651 pixwidth = *++widthptr;
\r
653 } while (!pixwidth);
\r
655 if (pixel+pixwidth > rightclip)
\r
656 pixwidth = rightclip-pixel;
\r
663 // bit mask tables for drawing scaled strips up to eight pixels wide
\r
666 byte bitmasks1[8][8] = {
\r
667 {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff},
\r
668 {0x40,0x60,0x70,0x78,0x7c,0x7e,0x7f,0x7f},
\r
669 {0x20,0x30,0x38,0x3c,0x3e,0x3f,0x3f,0x3f},
\r
670 {0x10,0x18,0x1c,0x1e,0x1f,0x1f,0x1f,0x1f},
\r
671 {0x8,0xc,0xe,0xf,0xf,0xf,0xf,0xf},
\r
672 {0x4,0x6,0x7,0x7,0x7,0x7,0x7,0x7},
\r
673 {0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3},
\r
674 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1} };
\r
676 byte bitmasks2[8][8] = {
\r
678 {0,0,0,0,0,0,0,0x80},
\r
679 {0,0,0,0,0,0,0x80,0xc0},
\r
680 {0,0,0,0,0,0x80,0xc0,0xe0},
\r
681 {0,0,0,0,0x80,0xc0,0xe0,0xf0},
\r
682 {0,0,0,0x80,0xc0,0xe0,0xf0,0xf8},
\r
683 {0,0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc},
\r
684 {0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe} };
\r