C5_SCALE.C 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. /* Catacomb Armageddon Source Code
  2. * Copyright (C) 1993-2014 Flat Rock Software
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. // C3_SCALE.C
  19. #include "DEF.H"
  20. #pragma hdrstop
  21. //const unsigned viewheight = 144;
  22. const unsigned screenbwide = 40;
  23. const byte BACKGROUNDPIX = 5;
  24. unsigned shapesize[NUMSCALEPICS];
  25. t_compscale _seg *scaledirectory[NUMSCALEPICS];
  26. t_compshape _seg *shapedirectory[NUMSCALEPICS];
  27. memptr walldirectory[NUMSCALEWALLS];
  28. /*
  29. ===========================
  30. =
  31. = DeplanePic
  32. =
  33. = Takes a raw bit map of width bytes by height and creates a scaleable shape
  34. =
  35. = Returns the length of the shape in bytes
  36. =
  37. = Fills in spotvis (a convenient 64*64 array) with the color values
  38. =
  39. ===========================
  40. */
  41. void DeplanePic (int picnum)
  42. {
  43. byte far *plane0,far *plane1,far *plane2,far *plane3;
  44. byte by0,by1,by2,by3;
  45. unsigned x,y,b,color,shift,width,height;
  46. byte *dest;
  47. //
  48. // convert ega pixels to byte color values in a temp buffer
  49. //
  50. width = pictable[picnum-STARTPICS].width;
  51. height = pictable[picnum-STARTPICS].height;
  52. if (width>8 || height!=64)
  53. Quit ("DePlanePic: Bad size shape");
  54. memset (spotvis,BACKGROUNDPIX,sizeof(spotvis));
  55. plane0 = (byte _seg *)grsegs[picnum];
  56. plane1 = plane0 + width*height;
  57. plane2 = plane1 + width*height;
  58. plane3 = plane2 + width*height;
  59. for (y=0;y<height;y++)
  60. {
  61. dest = &spotvis[y][0];
  62. for (x=0;x<width;x++)
  63. {
  64. by0 = *plane0++;
  65. by1 = *plane1++;
  66. by2 = *plane2++;
  67. by3 = *plane3++;
  68. for (b=0;b<8;b++)
  69. {
  70. shift=8-b;
  71. color = 0;
  72. asm mov cl,[BYTE PTR shift]
  73. asm mov al,[BYTE PTR by3]
  74. asm rcr al,cl;
  75. asm rcl [BYTE PTR color],1;
  76. asm mov cl,[BYTE PTR shift]
  77. asm mov al,[BYTE PTR by2]
  78. asm rcr al,cl;
  79. asm rcl [BYTE PTR color],1;
  80. asm mov cl,[BYTE PTR shift]
  81. asm mov al,[BYTE PTR by1]
  82. asm rcr al,cl;
  83. asm rcl [BYTE PTR color],1;
  84. asm mov cl,[BYTE PTR shift]
  85. asm mov al,[BYTE PTR by0]
  86. asm rcr al,cl;
  87. asm rcl [BYTE PTR color],1;
  88. *dest++ = color;
  89. } // B
  90. } // X
  91. } // Y
  92. }
  93. /*
  94. ========================
  95. =
  96. = BuildCompScale
  97. =
  98. = Builds a compiled scaler object that will scale a 64 tall object to
  99. = the given height (centered vertically on the screen)
  100. =
  101. = height should be even
  102. =
  103. = Call with
  104. = ---------
  105. = DS:SI Source for scale
  106. = ES:DI Dest for scale
  107. =
  108. = Calling the compiled scaler only destroys AL
  109. =
  110. ========================
  111. */
  112. unsigned BuildCompScale (int height, memptr *finalspot)
  113. {
  114. t_compscale _seg *work;
  115. byte far *code;
  116. int i;
  117. long fix,step;
  118. unsigned src,totalscaled,totalsize;
  119. int startpix,endpix,toppix;
  120. MM_GetPtr (&(memptr)work,20000);
  121. step = ((long)height<<16) / 64;
  122. code = &work->code[0];
  123. toppix = (viewheight-height)/2;
  124. fix = 0;
  125. for (src=0;src<=64;src++)
  126. {
  127. startpix = fix>>16;
  128. fix += step;
  129. endpix = fix>>16;
  130. work->start[src] = startpix;
  131. if (endpix>startpix)
  132. work->width[src] = endpix-startpix;
  133. else
  134. work->width[src] = 0;
  135. //
  136. // mark the start of the code
  137. //
  138. work->codeofs[src] = FP_OFF(code);
  139. //
  140. // compile some code if the source pixel generates any screen pixels
  141. //
  142. startpix+=toppix;
  143. endpix+=toppix;
  144. if (startpix == endpix || endpix < 0 || startpix >= VIEWHEIGHT || src == 64)
  145. continue;
  146. //
  147. // mov al,[si+src]
  148. //
  149. *code++ = 0x8a;
  150. *code++ = 0x44;
  151. *code++ = src;
  152. for (;startpix<endpix;startpix++)
  153. {
  154. if (startpix >= VIEWHEIGHT)
  155. break; // off the bottom of the view area
  156. if (startpix < 0)
  157. continue; // not into the view area
  158. //
  159. // and [es:di+heightofs],al
  160. //
  161. *code++ = 0x26;
  162. *code++ = 0x20;
  163. *code++ = 0x85;
  164. *((unsigned far *)code)++ = startpix*screenbwide;
  165. }
  166. }
  167. //
  168. // retf
  169. //
  170. *code++ = 0xcb;
  171. totalsize = FP_OFF(code);
  172. MM_GetPtr (finalspot,totalsize);
  173. _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);
  174. MM_FreePtr (&(memptr)work);
  175. return totalsize;
  176. }
  177. /*
  178. ========================
  179. =
  180. = BuildCompShape
  181. =
  182. = typedef struct
  183. = {
  184. = unsigned width;
  185. = unsigned codeofs[64];
  186. = } t_compshape;
  187. =
  188. = Width is the number of compiled line draws in the shape. The shape
  189. = drawing code will assume that the midpoint of the shape is in the
  190. = middle of the width.
  191. =
  192. = The non background pixel data will start at codeofs[width], so codeofs
  193. = greater than width will be invalid.
  194. =
  195. = Each code offset will draw one vertical line of the shape, consisting
  196. = of 0 or more segments of scaled pixels.
  197. =
  198. = The scaled shapes use ss:0-4 as a scratch variable for the far call to
  199. = the compiled scaler, so zero it back out after the shape is scaled, or
  200. = a "null pointer assignment" will result upon termination.
  201. =
  202. = Setup for a call to a compiled shape
  203. = -----------------------------------
  204. = ax toast
  205. = bx toast
  206. = cx toast
  207. = dx segment of compiled shape
  208. = si toast
  209. = di byte at top of view area to draw the line in
  210. = bp 0
  211. = ss:2 and ds the segment of the compiled scaler to use
  212. = es screenseg
  213. =
  214. = Upon return, ds IS NOT SET to the data segment. Do:
  215. = mov ax,ss
  216. = mov ds,ax
  217. =
  218. =
  219. = GC_BITMASK set to the pixels to be drawn in the row of bytes under DI
  220. = GC_MODE read mode 1, write mode 2
  221. = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
  222. =
  223. =
  224. = Code generated for each segment
  225. = -------------------------------
  226. = mov bx,[(segend+1)*2]
  227. = mov cx,[bx]
  228. = mov [BYTE PTR bx],0xc8 // far return
  229. = mov ax,[segstart*2]
  230. = mov [ss:0],ax // entry point into the compiled scaler
  231. = mov ds,dx // (mov ds,cs) the data is after the compiled code
  232. = mov si,ofs data
  233. = call [bp] // scale some pixels
  234. = mov ds,[bp+2]
  235. = mov [bx],cx // un patch return
  236. =
  237. = Code generated after all segments on a line
  238. = -------------------------------------------
  239. = retf
  240. =
  241. ========================
  242. */
  243. unsigned BuildCompShape (t_compshape _seg **finalspot)
  244. {
  245. t_compshape _seg *work;
  246. byte far *code;
  247. int firstline,lastline,x,y;
  248. unsigned firstpix,lastpix,width;
  249. unsigned totalsize,pixelofs;
  250. unsigned buff;
  251. // MM_GetPtr (&(memptr)work,20000);
  252. EGAWRITEMODE(0);
  253. EGAREADMAP(0); // use ega screen memory for temp buffer
  254. EGAMAPMASK(1);
  255. buff = screenloc[1];
  256. work = (t_compshape _seg *)(0xa000+(buff+15)/16);
  257. //
  258. // find the width of the shape
  259. //
  260. firstline = -1;
  261. x=0;
  262. do
  263. {
  264. for (y=0;y<64;y++)
  265. if (spotvis[y][x] != BACKGROUNDPIX)
  266. {
  267. firstline = x;
  268. break;
  269. }
  270. if (++x == 64)
  271. Quit ("BuildCompShape: No shape data!");
  272. } while (firstline == -1);
  273. lastline = -1;
  274. x=63;
  275. do
  276. {
  277. for (y=0;y<64;y++)
  278. if (spotvis[y][x] != BACKGROUNDPIX)
  279. {
  280. lastline = x;
  281. break;
  282. }
  283. x--;
  284. } while (lastline == -1);
  285. width = lastline-firstline+1;
  286. work->width = width;
  287. code = (byte far *)&work->codeofs[width];
  288. //
  289. // copy all non background pixels to the work space
  290. //
  291. pixelofs = FP_OFF(code);
  292. for (x=firstline;x<=lastline;x++)
  293. for (y=0;y<64;y++)
  294. if (spotvis[y][x] != BACKGROUNDPIX)
  295. *code++ = spotvis[y][x];
  296. //
  297. // start compiling the vertical lines
  298. //
  299. for (x=firstline;x<=lastline;x++)
  300. {
  301. work->codeofs[x-firstline] = FP_OFF(code);
  302. y=0;
  303. do
  304. {
  305. //
  306. // scan past black background pixels
  307. //
  308. while (spotvis[y][x] == BACKGROUNDPIX && y<64)
  309. y++;
  310. if (y>63) // no more segments
  311. break;
  312. firstpix = y+1; // +1 because width is before codeofs
  313. //
  314. // scan past scalable pixels
  315. //
  316. while (spotvis[y][x] != BACKGROUNDPIX && y<64)
  317. y++;
  318. if (y>63)
  319. lastpix = 65;
  320. else
  321. lastpix = y+1; // actually one pixel past the last displayed
  322. //
  323. // compile the scale call
  324. //
  325. *code++ = 0x8b; // mov bx,[lastpix*2]
  326. *code++ = 0x1e;
  327. *((unsigned far *)code)++ = lastpix*2;
  328. *code++ = 0x8b; // mov cx,[bx]
  329. *code++ = 0x0f;
  330. *code++ = 0xc6; // move [BYTE bx],0xcb
  331. *code++ = 0x07;
  332. *code++ = 0xcb;
  333. *code++ = 0xa1; // mov ax,[firstpix*2] /*************
  334. *((unsigned far *)code)++ = firstpix*2;
  335. *code++ = 0x36; // mov [ss:0],ax
  336. *code++ = 0xa3;
  337. *code++ = 0x00;
  338. *code++ = 0x00;
  339. *code++ = 0x8e; // mov ds,dx (mov ds,cs)
  340. *code++ = 0xda;
  341. *code++ = 0xbe; // mov si,OFFSET pixelofs-firstpixel
  342. *((unsigned far *)code)++ = pixelofs-firstpix;
  343. *code++ = 0xff; // call [DWORD bp]
  344. *code++ = 0x5e;
  345. *code++ = 0x00;
  346. *code++ = 0x8e; // mov ds,[bp+2]
  347. *code++ = 0x5e;
  348. *code++ = 0x02;
  349. *code++ = 0x89; // mov [bx],cx
  350. *code++ = 0x0f;
  351. pixelofs += (lastpix-firstpix);
  352. } while (y<63);
  353. //
  354. // retf
  355. //
  356. *code++ = 0xcb;
  357. }
  358. //
  359. // copy the final shape to a properly sized buffer
  360. //
  361. totalsize = FP_OFF(code);
  362. if (totalsize >= (PAGELEN*2))
  363. Quit("BuildCompShape(): Shape is too complex!");
  364. MM_GetPtr ((memptr *)finalspot,totalsize);
  365. _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize);
  366. // MM_FreePtr (&(memptr)work);
  367. return totalsize;
  368. }
  369. /*
  370. =======================
  371. =
  372. = ScaleShape
  373. =
  374. = Draws a compiled shape at [scale] pixels high
  375. =
  376. = Setup for call
  377. = --------------
  378. = GC_MODE read mode 1, write mode 2
  379. = GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff
  380. = GC_INDEX pointing at GC_BITMASK
  381. =
  382. =======================
  383. */
  384. static long longtemp;
  385. void ScaleShape (int xcenter, t_compshape _seg *compshape, unsigned scale)
  386. {
  387. #define MAX_OBJ_SCALE (MAXSCALE)
  388. t_compscale _seg *comptable;
  389. unsigned width,scalewidth;
  390. int x,pixel,lastpixel,pixwidth,min;
  391. unsigned far *codehandle, far *widthptr;
  392. unsigned badcodeptr;
  393. int rightclip;
  394. if (!compshape)
  395. Quit ("ScaleShape: NULL compshape ptr!");
  396. scale = (scale+1)/2;
  397. if (!scale)
  398. return; // too far away
  399. if (scale>MAX_OBJ_SCALE)
  400. scale = MAX_OBJ_SCALE;
  401. comptable = scaledirectory[scale];
  402. width = compshape->width;
  403. scalewidth = comptable->start[width];
  404. pixel = xcenter - scalewidth/2;
  405. lastpixel = pixel+scalewidth-1;
  406. if (pixel >= VIEWWIDTH || lastpixel < 0)
  407. return; // totally off screen
  408. //
  409. // scan backwards from the right edge until pixels are visable
  410. // rightclip is the first NON VISABLE pixel
  411. //
  412. if (lastpixel>=VIEWWIDTH-1)
  413. rightclip = VIEWWIDTH-1;
  414. else
  415. rightclip = lastpixel;
  416. if (zbuffer[rightclip]>scale)
  417. {
  418. if (pixel>0)
  419. min = pixel;
  420. else
  421. min = 0;
  422. do
  423. {
  424. if (--rightclip < min)
  425. return; // totally covered or before 0
  426. if (zbuffer[rightclip]<=scale)
  427. break;
  428. } while (1);
  429. }
  430. rightclip++;
  431. //
  432. // scan from the left until it is on screen, leaving
  433. // [pixel],[pixwidth],[codehandle],and [widthptr] set correctly
  434. //
  435. *(((unsigned *)&longtemp)+1) = (unsigned)compshape; // seg of shape
  436. codehandle = &compshape->codeofs[0];
  437. badcodeptr = compshape->codeofs[width];
  438. widthptr = &comptable->width[0];
  439. asm mov ax,[comptable]
  440. asm mov WORD PTR [2],ax // ds:0-4 is used as a far call pointer
  441. // by the compiled shapes
  442. pixwidth = *widthptr; // scaled width of this pixel
  443. while (!pixwidth)
  444. {
  445. pixwidth = *++widthptr; // find the first visable pixel
  446. codehandle++;
  447. }
  448. if (pixel<0)
  449. {
  450. do
  451. {
  452. if (pixel+pixwidth>0)
  453. {
  454. pixwidth += pixel;
  455. pixel = 0;
  456. break;
  457. }
  458. do
  459. {
  460. pixwidth = *++widthptr;
  461. codehandle++;
  462. } while (!pixwidth);
  463. pixel+=pixwidth;
  464. } while (1);
  465. }
  466. //
  467. // scan until it is visable, leaving
  468. // [pixel],[pixwidth],[codehandle],and [widthptr] set correctly
  469. //
  470. do
  471. {
  472. if (zbuffer[pixel] <= scale)
  473. break; // start drawing here
  474. pixel++;
  475. if (!--pixwidth)
  476. {
  477. do
  478. {
  479. pixwidth = *++widthptr;
  480. codehandle++;
  481. } while (!pixwidth);
  482. }
  483. } while (1);
  484. if (pixel+pixwidth>rightclip)
  485. pixwidth = rightclip-pixel;
  486. //
  487. // draw lines
  488. //
  489. do // while (1)
  490. {
  491. //
  492. // scale a vertical segment [pixwidth] pixels wide at [pixel]
  493. //
  494. (unsigned)longtemp = *codehandle; // offset of compiled code
  495. if ((unsigned)longtemp == badcodeptr)
  496. Quit ("ScaleShape: codehandle past end!");
  497. asm mov bx,[pixel]
  498. asm mov di,bx
  499. asm shr di,1
  500. asm shr di,1
  501. asm shr di,1 // X in bytes
  502. asm add di,[bufferofs]
  503. asm and bx,7
  504. asm shl bx,1
  505. asm shl bx,1
  506. asm shl bx,1
  507. asm add bx,[pixwidth] // bx = pixel*8+pixwidth-1
  508. asm dec bx
  509. asm push bx
  510. asm mov al,BYTE PTR [bitmasks1+bx]
  511. asm mov dx,GC_INDEX+1
  512. asm out dx,al // set bit mask register
  513. asm mov es,[screenseg]
  514. asm push si
  515. asm push di
  516. asm push bp
  517. asm xor bp,bp
  518. asm mov dx,[WORD PTR longtemp+2]
  519. asm mov ds,[2]
  520. asm call ss:[DWORD PTR longtemp] // scale the line of pixels
  521. asm mov ax,ss
  522. asm mov ds,ax
  523. asm pop bp
  524. asm pop di
  525. asm pop si
  526. asm pop bx
  527. asm mov al,BYTE PTR [bitmasks2+bx]
  528. asm or al,al
  529. asm jz nosecond
  530. //
  531. // draw a second byte for vertical strips that cross two bytes
  532. //
  533. asm inc di
  534. asm mov dx,GC_INDEX+1
  535. asm out dx,al // set bit mask register
  536. asm push si
  537. asm push di
  538. asm push bp
  539. asm xor bp,bp
  540. asm mov dx,[WORD PTR longtemp+2]
  541. asm mov ds,[2]
  542. asm call ss:[DWORD PTR longtemp] // scale the line of pixels
  543. asm mov ax,ss
  544. asm mov ds,ax
  545. asm pop bp
  546. asm pop di
  547. asm pop si
  548. //
  549. // advance to the next drawn line
  550. //
  551. nosecond:;
  552. if ( (pixel+=pixwidth) == rightclip )
  553. {
  554. asm mov WORD PTR [0],0
  555. asm mov WORD PTR [2],0
  556. return; // all done!
  557. }
  558. do
  559. {
  560. pixwidth = *++widthptr;
  561. codehandle++;
  562. } while (!pixwidth);
  563. if (pixel+pixwidth > rightclip)
  564. pixwidth = rightclip-pixel;
  565. } while (1);
  566. }
  567. //
  568. // bit mask tables for drawing scaled strips up to eight pixels wide
  569. //
  570. byte bitmasks1[8][8] = {
  571. {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff},
  572. {0x40,0x60,0x70,0x78,0x7c,0x7e,0x7f,0x7f},
  573. {0x20,0x30,0x38,0x3c,0x3e,0x3f,0x3f,0x3f},
  574. {0x10,0x18,0x1c,0x1e,0x1f,0x1f,0x1f,0x1f},
  575. {0x8,0xc,0xe,0xf,0xf,0xf,0xf,0xf},
  576. {0x4,0x6,0x7,0x7,0x7,0x7,0x7,0x7},
  577. {0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3},
  578. {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1} };
  579. byte bitmasks2[8][8] = {
  580. {0,0,0,0,0,0,0,0},
  581. {0,0,0,0,0,0,0,0x80},
  582. {0,0,0,0,0,0,0x80,0xc0},
  583. {0,0,0,0,0,0x80,0xc0,0xe0},
  584. {0,0,0,0,0x80,0xc0,0xe0,0xf0},
  585. {0,0,0,0x80,0xc0,0xe0,0xf0,0xf8},
  586. {0,0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc},
  587. {0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe} };