Advertisement
bildramer

voxlap.c

Oct 3rd, 2011
540
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 371.01 KB | None | 0 0
  1. #include <math.h>
  2. #include <stdio.h>
  3. #define VOXLAP5
  4. #include "voxlap5.h"
  5.  
  6. //VOXLAP engine by Ken Silverman (http://advsys.net/ken)
  7.  
  8. #define USEZBUFFER 1
  9.  
  10. #define PREC (256*4096)
  11. #define CMPPREC (256*4096)
  12. #define FPREC (256*4096)
  13. #define USEV5ASM 1
  14. #define SCISDIST 1.0
  15. #define GOLDRAT 0.3819660112501052 //Golden Ratio: 1 - 1/((sqrt(5)+1)/2)
  16. #define ESTNORMRAD 2 //Specially optimized for 2: DON'T CHANGE unless testing!
  17.  
  18. #ifdef _WIN32
  19. #define WIN32_LEAN_AND_MEAN
  20. #include <windows.h>
  21. #else
  22. #include <stdarg.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <conio.h>
  26. #include <dos.h>
  27. #define MAX_PATH 260
  28. #endif
  29. #include <stdlib.h>
  30.  
  31. extern char keystatus[256];
  32. extern void readkeyboard ();
  33. extern void breath ();
  34. extern long startdirectdraw (long *, long *, long *, long *);
  35. extern void stopdirectdraw ();
  36. extern void nextpage ();
  37. extern void evilquit (const char *);
  38.  
  39. #define VOXSIZ VSID*VSID*64
  40. #ifdef __cplusplus
  41. extern "C" {
  42. #endif
  43. char *sptr[(VSID*VSID*4)/3];
  44. #ifdef __cplusplus
  45. }
  46. #endif
  47. static long *vbuf = 0, *vbit = 0, vbiti;
  48.     //WARNING: loaddta uses last 2MB of vbuf; vbuf:[VOXSIZ>>2], vbit:[VOXSIZ>>7]
  49.     //WARNING: loadpng uses last 4MB of vbuf; vbuf:[VOXSIZ>>2], vbit:[VOXSIZ>>7]
  50.  
  51. //                     ΪΔΔΔΔΔΔΔΔΒΔΔΔΔΔΔΔΔΒΔΔΔΔΔΔΔΔΒΔΔΔΔΔΔΔΔΏ
  52. //        vbuf format: ³   0:   ³   1:   ³   2:   ³   3:   ³
  53. //ΪΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΕΔΔΔΔΔΔΔΔΕΔΔΔΔΔΔΔΔΕΔΔΔΔΔΔΔΔΕΔΔΔΔΔΔΔΔ΄
  54. //³      First header: ³ nextptr³   z1   ³   z1c  ³  dummy ³
  55. //³           Color 1: ³    b   ³    g   ³    r   ³ intens ³
  56. //³           Color 2: ³    b   ³    g   ³    r   ³ intens ³
  57. //³             ...    ³    b   ³    g   ³    r   ³ intens ³
  58. //³           Color n: ³    b   ³    g   ³    r   ³ intens ³
  59. //³ Additional header: ³ nextptr³   z1   ³   z1c  ³   z0   ³
  60. //ΐΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΔΑΔΔΔΔΔΔΔΔΑΔΔΔΔΔΔΔΔΑΔΔΔΔΔΔΔΔΑΔΔΔΔΔΔΔΔΩ
  61. //  nextptr: add this # <<2 to index to get to next header (0 if none)
  62. //       z1: z floor (top of floor color list)
  63. //      z1c: z bottom of floor color list MINUS 1! - needed to calculate
  64. //             slab size with slng() and used as a separator for fcol/ccol
  65. //       z0: z ceiling (bottom of ceiling color list)
  66.  
  67.     //Memory management variables:
  68. #define MAXCSIZ 1028
  69. char tbuf[MAXCSIZ];
  70. long tbuf2[MAXZDIM*3];
  71. long templongbuf[MAXZDIM];
  72.  
  73. long cputype = 0; //bit25=1: SSE, bits30&31=1,1:3DNow!+
  74.  
  75. static char nullst = 0; //nullst always NULL string
  76.  
  77. #define SETSPHMAXRAD 256
  78. static double logint[SETSPHMAXRAD];
  79. static float tempfloatbuf[SETSPHMAXRAD];
  80. static long factr[SETSPHMAXRAD][2];
  81.  
  82. #pragma pack(push,1)
  83.     //Rendering variables:
  84. #if (USEZBUFFER == 0)
  85. typedef struct { long col; } castdat;
  86. #else
  87. typedef struct { long col, dist; } castdat;
  88. #endif
  89. typedef struct { castdat *i0, *i1; long z0, z1, cx0, cy0, cx1, cy1; } cftype;
  90. typedef struct { unsigned short x, y; } uspoint2d;
  91. typedef struct { long x, y; } lpoint2d;
  92. typedef struct { float x, y; } point2d;
  93. #pragma pack(pop)
  94.  
  95. #if USEV5ASM
  96. #ifndef __cplusplus
  97.     extern void *cfasm;
  98.     extern castdat skycast;
  99. #else
  100.     extern "C" void *cfasm;
  101.     extern "C" castdat skycast;
  102. #endif
  103.     #define cf ((cftype *)&cfasm)
  104. #else
  105.     cftype cf[256];
  106. #endif
  107.  
  108.     //Screen related variables:
  109. static long xres, yres, bytesperline, frameplace, xres4;
  110. long ylookup[MAXYDIM+1];
  111.  
  112. static lpoint3d glipos;
  113. static point3d gipos, gistr, gihei, gifor;
  114. static point3d gixs, giys, gizs, giadd;
  115. static float gihx, gihy, gihz, gposxfrac[2], gposyfrac[2], grd;
  116. static long gposz, giforzsgn, gstartz0, gstartz1, gixyi[2];
  117. static char *gstartv;
  118.  
  119. long backtag, backedup = -1, bacx0, bacy0, bacx1, bacy1;
  120. char *bacsptr[262144];
  121.  
  122.     //Flash variables
  123. #define LOGFLASHVANG 9
  124. static lpoint2d gfc[(1<<LOGFLASHVANG)*8];
  125. static long gfclookup[8] = {4,7,2,5,0,3,6,1}, flashcnt = 0;
  126. __int64 flashbrival;
  127.  
  128.     //Norm flash variables
  129. #define GSIZ 512  //NOTE: GSIZ should be 1<<x, and must be <= 65536
  130. static long bbuf[GSIZ][GSIZ>>5], p2c[32], p2m[32];      //bbuf: 2.0K
  131. static uspoint2d ffx[((GSIZ>>1)+2)*(GSIZ>>1)], *ffxptr; // ffx:16.5K
  132. static long xbsox = -17, xbsoy, xbsof;
  133. static __int64 xbsbuf[25*5+1]; //need few bits before&after for protection
  134.  
  135.     //Look tables for expandbitstack256:
  136. static long xbsceil[32], xbsflor[32];
  137.  
  138.     //float detection & falling code variables...
  139.     //WARNING: VLSTSIZ,FSTKSIZ,FLCHKSIZ can all have bounds errors! :(
  140. #define VLSTSIZ 65536 //Theoretically should be at least: VOXSIZ\8
  141. #define LOGHASHEAD 12
  142. #define FSTKSIZ 8192
  143. typedef struct { long v, b; } vlstyp;
  144. vlstyp vlst[VLSTSIZ];
  145. long hhead[1<<LOGHASHEAD], vlstcnt = 0x7fffffff;
  146. lpoint3d fstk[FSTKSIZ]; //Note .z is actually used as a pointer, not z!
  147. #define FLCHKSIZ 4096
  148. lpoint3d flchk[FLCHKSIZ]; long flchkcnt = 0;
  149.  
  150.     //Opticast global variables:
  151.     //radar: 320x200 requires  419560*2 bytes (area * 6.56*2)
  152.     //radar: 400x300 requires  751836*2 bytes (area * 6.27*2)
  153.     //radar: 640x480 requires 1917568*2 bytes (area * 6.24*2)
  154. #define SCPITCH 256
  155. long *radar = 0, *radarmem = 0;
  156. #if (USEZBUFFER == 1)
  157. static long *zbuffermem = 0, zbuffersiz = 0;
  158. #endif
  159. static castdat *angstart[MAXXDIM*4], *gscanptr;
  160. #define CMPRECIPSIZ MAXXDIM+32
  161. static float cmprecip[CMPRECIPSIZ], wx0, wy0, wx1, wy1;
  162. static long iwx0, iwy0, iwx1, iwy1;
  163. static point3d gcorn[4];
  164.          point3d ginor[4]; //Should be static, but... necessary for stupid pingball hack :/
  165. static long lastx[max(MAXYDIM,VSID)], uurendmem[MAXXDIM*2+8], *uurend;
  166.  
  167. void mat0(point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *);
  168. void mat1(point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *);
  169. void mat2(point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *, point3d *);
  170.  
  171.     //Parallaxing sky variables:
  172. static long skypic = 0, nskypic = 0, skybpl, skyysiz, skycurlng, skycurdir;
  173. static float skylngmul;
  174. static point2d *skylng = 0;
  175.  
  176. #ifdef __cplusplus
  177. extern "C" {
  178. #endif
  179.  
  180.     //Parallaxing sky variables (accessed by assembly code)
  181. long skyoff = 0, skyxsiz, *skylat = 0;
  182.  
  183. __int64 gi, gcsub[8] =
  184. {
  185.     0xff00ff00ff00ff,0xff00ff00ff00ff,0xff00ff00ff00ff,0xff00ff00ff00ff,
  186.     0xff00ff00ff00ff,0xff00ff00ff00ff,0xff00ff00ff00ff,0xff00ff00ff00ff
  187. };
  188. long gylookup[512+36], gmipnum = 0; //256+4+128+4+64+4+...
  189. long gpz[2], gdz[2], gxmip, gxmax, gixy[2], gpixy;
  190. static long gmaxscandist;
  191.  
  192. //long reax, rebx, recx, redx, resi, redi, rebp, resp, remm[16];
  193. void v5_asm_dep_unlock();
  194. void grouscanasm (long);
  195. #if (USEZBUFFER == 1)
  196. long zbufoff;
  197. #endif
  198. #ifdef __cplusplus
  199. }
  200. #endif
  201. #define gi0 (((long *)&gi)[0])
  202. #define gi1 (((long *)&gi)[1])
  203.  
  204. #ifdef _MSC_VER
  205.  
  206. #pragma warning(disable:4799) //I know how to use EMMS
  207.  
  208. static _inline void fcossin (float a, float *c, float *s)
  209. {
  210.     _asm
  211.     {
  212.         fld a
  213.         fsincos
  214.         mov eax, c
  215.         fstp dword ptr [eax]
  216.         mov eax, s
  217.         fstp dword ptr [eax]
  218.     }
  219. }
  220.  
  221. static _inline void dcossin (double a, double *c, double *s)
  222. {
  223.     _asm
  224.     {
  225.         fld a
  226.         fsincos
  227.         mov eax, c
  228.         fstp qword ptr [eax]
  229.         mov eax, s
  230.         fstp qword ptr [eax]
  231.     }
  232. }
  233.  
  234. static _inline void ftol (float f, long *a)
  235. {
  236.     _asm
  237.     {
  238.         mov eax, a
  239.         fld f
  240.         fistp dword ptr [eax]
  241.     }
  242. }
  243.  
  244. static _inline void dtol (double d, long *a)
  245. {
  246.     _asm
  247.     {
  248.         mov eax, a
  249.         fld qword ptr d
  250.         fistp dword ptr [eax]
  251.     }
  252. }
  253.  
  254.     //WARNING: This ASM code requires >= PPRO
  255. static _inline double dbound (double d, double dmin, double dmax)
  256. {
  257.     _asm
  258.     {
  259.         fld dmin
  260.         fld d
  261.         fucomi st, st(1)   ;if (d < dmin)
  262.         fcmovb st, st(1)   ;    d = dmin;
  263.         fld dmax
  264.         fxch st(1)
  265.         fucomi st, st(1)   ;if (d > dmax)
  266.         fcmovnb st, st(1)  ;    d = dmax;
  267.         fstp d
  268.         fucompp
  269.     }
  270.     return(d);
  271. }
  272.  
  273. static _inline long mulshr16 (long a, long d)
  274. {
  275.     _asm
  276.     {
  277.         mov eax, a
  278.         mov edx, d
  279.         imul edx
  280.         shrd eax, edx, 16
  281.     }
  282. }
  283.  
  284. static _inline __int64 mul64 (long a, long d)
  285. {
  286.     _asm
  287.     {
  288.         mov eax, a
  289.         imul d
  290.     }
  291. }
  292.  
  293. static _inline long shldiv16 (long a, long b)
  294. {
  295.     _asm
  296.     {
  297.         mov eax, a
  298.         mov edx, eax
  299.         shl eax, 16
  300.         sar edx, 16
  301.         idiv b
  302.     }
  303. }
  304.  
  305. static _inline long isshldiv16safe (long a, long b)
  306. {
  307.     _asm
  308.     {
  309.         mov edx, a
  310.         test edx, edx
  311.         js short skipneg0
  312.         neg edx
  313. skipneg0:
  314.         sar edx, 14
  315.  
  316.         mov eax, b
  317.         test eax, eax
  318.         js short skipneg1
  319.         neg eax
  320. skipneg1:
  321.             ;abs((a<<16)/b) < (1<<30) ;1 extra for good luck!
  322.             ;-abs(a)>>14 > -abs(b)    ;use -abs because safe for 0x80000000
  323.             ;eax-edx < 0
  324.         sub eax, edx
  325.         shr eax, 31
  326.     }
  327. }
  328.  
  329. static _inline long umulshr32 (long a, long d)
  330. {
  331.     _asm
  332.     {
  333.         mov eax, a
  334.         mul d
  335.         mov eax, edx
  336.     }
  337. }
  338.  
  339. static _inline long scale (long a, long d, long c)
  340. {
  341.     _asm
  342.     {
  343.         mov eax, a
  344.         imul d
  345.         idiv c
  346.     }
  347. }
  348.  
  349. static _inline long dmulrethigh (long b, long c, long a, long d)
  350. {
  351.     _asm
  352.     {
  353.         mov eax, a
  354.         imul d
  355.         mov ecx, eax
  356.         push edx
  357.         mov eax, b
  358.         imul c
  359.         sub eax, ecx
  360.         pop ecx
  361.         sbb edx, ecx
  362.         mov eax, edx
  363.     }
  364. }
  365.  
  366. static _inline void copybuf (void *s, void *d, long c)
  367. {
  368.     _asm
  369.     {
  370.         push esi
  371.         push edi
  372.         mov esi, s
  373.         mov edi, d
  374.         mov ecx, c
  375.         rep movsd
  376.         pop edi
  377.         pop esi
  378.     }
  379. }
  380.  
  381. static _inline void clearbuf (void *d, long c, long a)
  382. {
  383.     _asm
  384.     {
  385.         push edi
  386.         mov edi, d
  387.         mov ecx, c
  388.         mov eax, a
  389.         rep stosd
  390.         pop edi
  391.     }
  392. }
  393.  
  394. #else
  395. #pragma message ("Compiler says it isn't Visual C.")
  396. #endif
  397.  
  398.     //if (a < 0) return(0); else if (a > b) return(b); else return(a);
  399. static _inline long lbound0 (long a, long b) //b MUST be >= 0
  400. {
  401.     if ((unsigned long)a <= b) return(a);
  402.     return((~(a>>31))&b);
  403. }
  404.  
  405.     //if (a < b) return(b); else if (a > c) return(c); else return(a);
  406. static _inline long lbound (long a, long b, long c) //c MUST be >= b
  407. {
  408.     c -= b;
  409.     if ((unsigned long)(a-b) <= c) return(a);
  410.     return((((b-a)>>31)&c) + b);
  411. }
  412.  
  413. #define LSINSIZ 8 //Must be >= 2!
  414. static point2d usintab[(1<<LSINSIZ)+(1<<(LSINSIZ-2))];
  415. static void ucossininit ()
  416. {
  417.     long i, j;
  418.     double a, ai, s, si, m;
  419.  
  420.     j = 0; usintab[0].y = 0.0;
  421.     i = (1<<LSINSIZ)-1;
  422.     ai = PI*(-2)/((float)(1<<LSINSIZ)); a = ((float)(-i))*ai;
  423.     ai *= .5; m = sin(ai)*2; s = sin(a); si = cos(a+ai)*m; m = -m*m;
  424.     for(;i>=0;i--)
  425.     {
  426.         usintab[i].y = s; s += si; si += s*m; //MUCH faster than next line :)
  427.         //usintab[i].y = sin(i*PI*2/((float)(1<<LSINSIZ)));
  428.         usintab[i].x = (usintab[j].y-usintab[i].y)/((float)(1<<(32-LSINSIZ)));
  429.         j = i;
  430.     }
  431.     for(i=(1<<(LSINSIZ-2))-1;i>=0;i--) usintab[i+(1<<LSINSIZ)] = usintab[i];
  432. }
  433.  
  434.     //Calculates cos & sin of 32-bit unsigned long angle in ~15 clock cycles
  435.     //  Accuracy is approximately +/-.0001
  436. static _inline void ucossin (unsigned long a, float *cosin)
  437. {
  438.     float f = ((float)(a&((1<<(32-LSINSIZ))-1))); a >>= (32-LSINSIZ);
  439.     cosin[0] = usintab[a+(1<<(LSINSIZ-2))].x*f+usintab[a+(1<<(LSINSIZ-2))].y;
  440.     cosin[1] = usintab[a                 ].x*f+usintab[a                 ].y;
  441. }
  442.  
  443. static const long font4x6[] = //256 DOS chars, from Ken's Build SMALLFNT
  444. {
  445.     0x000000,0x6f9f60,0x69f960,0xaffe40,0x4efe40,0x6ff6f0,0x66f6f0,0x000000,
  446.     0xeeaee0,0x000000,0x000000,0x000000,0x000000,0x000000,0x7755c0,0x96f690,
  447.     0x8cec80,0x26e620,0x4e4e40,0xaaa0a0,0x7dd550,0x7ca6c0,0x000ee0,0x4e4ee0,
  448.     0x4e4440,0x444e40,0x02f200,0x04f400,0x000000,0x000000,0x000000,0x000000,
  449.     0x000000,0x444040,0xaa0000,0xafafa0,0x6c46c0,0xa248a0,0x4a4ce0,0x240000,
  450.     0x488840,0x422240,0x0a4a00,0x04e400,0x000224,0x00e000,0x000040,0x224480,
  451.     0xeaaae0,0x444440,0xe2e8e0,0xe2e2e0,0xaae220,0xe8e2e0,0xe8eae0,0xe22220,
  452.     0xeaeae0,0xeae220,0x040400,0x040480,0x248420,0x0e0e00,0x842480,0xc24040,
  453.     0xeaece0,0x4aeaa0,0xcacac0,0x688860,0xcaaac0,0xe8c8e0,0xe8c880,0xe8aae0,
  454.     0xaaeaa0,0xe444e0,0xe22a60,0xaacaa0,0x8888e0,0xaeeaa0,0xaeeea0,0xeaaae0,
  455.     0xeae880,0xeaae60,0xeacaa0,0xe8e2e0,0xe44440,0xaaaae0,0xaaa440,0xaaeea0,
  456.     0xaa4aa0,0xaae440,0xe248e0,0xc888c0,0x844220,0x622260,0x4a0000,0x0000e0,
  457.     0x420000,0x006a60,0x88eae0,0x00e8e0,0x22eae0,0x006e60,0x24e440,0x06a62c,
  458.     0x88eaa0,0x040440,0x040448,0x88aca0,0x444440,0x08eee0,0x00caa0,0x00eae0,
  459.     0x00eae8,0x00eae2,0x00e880,0x0064c0,0x04e440,0x00aa60,0x00aa40,0x00eee0,
  460.     0x00a4a0,0x00aa6c,0x00c460,0x648460,0x440440,0xc424c0,0x6c0000,0x04ae00,
  461.     0x68886c,0xa0aa60,0x606e60,0xe06a60,0xa06a60,0xc06a60,0x046a60,0x00e8e4,
  462.     0xe06e60,0xa06e60,0xc06e60,0x0a0440,0x0e0440,0x0c0440,0xa4aea0,0x404ea0,
  463.     0x60ece0,0x007a70,0x7afab0,0xe0eae0,0xa0eae0,0xc0eae0,0xe0aa60,0xc0aa60,
  464.     0xa0aa6c,0xa0eae0,0xa0aae0,0x4e8e40,0x65c4f0,0xa4ee40,0xcafab0,0x64e4c0,
  465.     0x606a60,0x060440,0x60eae0,0x60aa60,0xc0caa0,0xe0aea0,0x6a60e0,0xeae0e0,
  466.     0x404860,0x007400,0x00c400,0x8a4e60,0x8a6e20,0x404440,0x05a500,0x0a5a00,
  467.     0x282828,0x5a5a5a,0xd7d7d7,0x444444,0x44c444,0x44cc44,0x66e666,0x00e666,
  468.     0x00cc44,0x66ee66,0x666666,0x00ee66,0x66ee00,0x66e000,0x44cc00,0x00c444,
  469.     0x447000,0x44f000,0x00f444,0x447444,0x00f000,0x44f444,0x447744,0x667666,
  470.     0x667700,0x007766,0x66ff00,0x00ff66,0x667766,0x00ff00,0x66ff66,0x44ff00,
  471.     0x66f000,0x00ff44,0x00f666,0x667000,0x447700,0x007744,0x007666,0x66f666,
  472.     0x44ff44,0x44c000,0x007444,0xffffff,0x000fff,0xcccccc,0x333333,0xfff000,
  473.     0x00dad0,0xcacac8,0xea8880,0x00f660,0xe848e0,0x007a40,0x0aac80,0x05a220,
  474.     0xe4a4e0,0x4aea40,0x6996f0,0x646ae0,0x06f600,0x16f680,0x68c860,0x4aaaa0,
  475.     0xe0e0e0,0x4e40e0,0x4240e0,0x4840e0,0x4a8880,0x222a40,0x40e040,0x06ec00,
  476.     0xeae000,0x0cc000,0x00c000,0x644c40,0xcaa000,0xc4e000,0x0eee00,0x000000,
  477. };
  478.  
  479. void print4x6 (long x, long y, long fcol, long bcol, const char *fmt, ...)
  480. {
  481.     va_list arglist;
  482.     char st[280], *c;
  483.     long i, j;
  484.  
  485.     if (!fmt) return;
  486.     va_start(arglist,fmt);
  487.     vsprintf(st,fmt,arglist);
  488.     va_end(arglist);
  489.  
  490.     y = y*bytesperline+(x<<2)+frameplace;
  491.     if (bcol < 0)
  492.     {
  493.         for(j=20;j>=0;y+=bytesperline,j-=4)
  494.             for(c=st,x=y;*c;c++,x+=16)
  495.             {
  496.                 i = (font4x6[*c]>>j);
  497.                 if (i&8) *(long *)(x   ) = fcol;
  498.                 if (i&4) *(long *)(x+ 4) = fcol;
  499.                 if (i&2) *(long *)(x+ 8) = fcol;
  500.                 if (i&1) *(long *)(x+12) = fcol;
  501.                 if ((*c) == 9) x += 32;
  502.             }
  503.         return;
  504.     }
  505.     fcol -= bcol;
  506.     for(j=20;j>=0;y+=bytesperline,j-=4)
  507.         for(c=st,x=y;*c;c++,x+=16)
  508.         {
  509.             i = (font4x6[*c]>>j);
  510.             *(long *)(x   ) = (((i<<28)>>31)&fcol)+bcol;
  511.             *(long *)(x+ 4) = (((i<<29)>>31)&fcol)+bcol;
  512.             *(long *)(x+ 8) = (((i<<30)>>31)&fcol)+bcol;
  513.             *(long *)(x+12) = (((i<<31)>>31)&fcol)+bcol;
  514.             if ((*c) == 9) { for(i=16;i<48;i+=4) *(long *)(x+i) = bcol; x += 32; }
  515.         }
  516. }
  517.  
  518.     //NOTE: font is stored vertically first! (like .ART files)
  519. static const __int64 font6x8[] = //256 DOS chars, from: DOSAPP.FON (tab blank)
  520. {
  521.     0x3E00000000000000,0x6F6B3E003E455145,0x1C3E7C3E1C003E6B,0x3000183C7E3C1800,
  522.     0x7E5C180030367F36,0x000018180000185C,0x0000FFFFE7E7FFFF,0xDBDBC3FF00000000,
  523.     0x0E364A483000FFC3,0x6000062979290600,0x0A7E600004023F70,0x2A1C361C2A003F35,
  524.     0x0800081C3E7F0000,0x7F361400007F3E1C,0x005F005F00001436,0x22007F017F090600,
  525.     0x606060002259554D,0x14B6FFB614000060,0x100004067F060400,0x3E08080010307F30,
  526.     0x08083E1C0800081C,0x0800404040407800,0x3F3C3000083E083E,0x030F3F0F0300303C,
  527.     0x0000000000000000,0x0003070000065F06,0x247E247E24000307,0x630000126A2B2400,
  528.     0x5649360063640813,0x0000030700005020,0x00000000413E0000,0x1C3E080000003E41,
  529.     0x08083E080800083E,0x0800000060E00000,0x6060000008080808,0x0204081020000000,
  530.     0x00003E4549513E00,0x4951620000407F42,0x3649494922004649,0x2F00107F12141800,
  531.     0x494A3C0031494949,0x0305097101003049,0x0600364949493600,0x6C6C00001E294949,
  532.     0x00006CEC00000000,0x2400004122140800,0x2241000024242424,0x0609590102000814,
  533.     0x7E001E555D413E00,0x49497F007E111111,0x224141413E003649,0x7F003E4141417F00,
  534.     0x09097F0041494949,0x7A4949413E000109,0x00007F0808087F00,0x4040300000417F41,
  535.     0x412214087F003F40,0x7F00404040407F00,0x04027F007F020402,0x3E4141413E007F08,
  536.     0x3E00060909097F00,0x09097F005E215141,0x3249494926006619,0x3F0001017F010100,
  537.     0x40201F003F404040,0x3F403C403F001F20,0x0700631408146300,0x4549710007087008,
  538.     0x0041417F00000043,0x0000201008040200,0x01020400007F4141,0x8080808080800402,
  539.     0x2000000007030000,0x44447F0078545454,0x2844444438003844,0x38007F4444443800,
  540.     0x097E080008545454,0x7CA4A4A418000009,0x0000007804047F00,0x8480400000407D00,
  541.     0x004428107F00007D,0x7C0000407F000000,0x04047C0078041804,0x3844444438000078,
  542.     0x380038444444FC00,0x44784400FC444444,0x2054545408000804,0x3C000024443E0400,
  543.     0x40201C00007C2040,0x3C6030603C001C20,0x9C00006C10106C00,0x54546400003C60A0,
  544.     0x0041413E0800004C,0x0000000077000000,0x02010200083E4141,0x3C2623263C000001,
  545.     0x3D001221E1A11E00,0x54543800007D2040,0x7855555520000955,0x2000785554552000,
  546.     0x5557200078545555,0x1422E2A21C007857,0x3800085555553800,0x5555380008555455,
  547.     0x00417C0100000854,0x0000004279020000,0x2429700000407C01,0x782F252F78007029,
  548.     0x3400455554547C00,0x7F097E0058547C54,0x0039454538004949,0x3900003944453800,
  549.     0x21413C0000384445,0x007C20413D00007D,0x3D00003D60A19C00,0x40413C00003D4242,
  550.     0x002466241800003D,0x29006249493E4800,0x16097F00292A7C2A,0x02097E8840001078,
  551.     0x0000785555542000,0x4544380000417D00,0x007D21403C000039,0x7A0000710A097A00,
  552.     0x5555080000792211,0x004E51514E005E55,0x3C0020404D483000,0x0404040404040404,
  553.     0x506A4C0817001C04,0x0000782A34081700,0x0014080000307D30,0x0814000814001408,
  554.     0x55AA114411441144,0xEEBBEEBB55AA55AA,0x0000FF000000EEBB,0x0A0A0000FF080808,
  555.     0xFF00FF080000FF0A,0x0000F808F8080000,0xFB0A0000FE0A0A0A,0xFF00FF000000FF00,
  556.     0x0000FE02FA0A0000,0x0F0800000F080B0A,0x0F0A0A0A00000F08,0x0000F80808080000,
  557.     0x080808080F000000,0xF808080808080F08,0x0808FF0000000808,0x0808080808080808,
  558.     0xFF0000000808FF08,0x0808FF00FF000A0A,0xFE000A0A0B080F00,0x0B080B0A0A0AFA02,
  559.     0x0A0AFA02FA0A0A0A,0x0A0A0A0AFB00FF00,0xFB00FB0A0A0A0A0A,0x0A0A0B0A0A0A0A0A,
  560.     0x0A0A08080F080F08,0xF808F8080A0AFA0A,0x08080F080F000808,0x00000A0A0F000000,
  561.     0xF808F8000A0AFE00,0x0808FF00FF080808,0x08080A0AFB0A0A0A,0xF800000000000F08,
  562.     0xFFFFFFFFFFFF0808,0xFFFFF0F0F0F0F0F0,0xFF000000000000FF,0x0F0F0F0F0F0FFFFF,
  563.     0xFE00241824241800,0x01017F0000344A4A,0x027E027E02000003,0x1800006349556300,
  564.     0x2020FC00041C2424,0x000478040800001C,0x3E00085577550800,0x02724C00003E4949,
  565.     0x0030595522004C72,0x1800182418241800,0x2A2A1C0018247E24,0x003C02023C00002A,
  566.     0x0000002A2A2A2A00,0x4A4A510000242E24,0x00514A4A44000044,0x20000402FC000000,
  567.     0x2A08080000003F40,0x0012241224000808,0x0000000609090600,0x0008000000001818,
  568.     0x02023E4030000000,0x0900000E010E0100,0x3C3C3C0000000A0D,0x000000000000003C,
  569. };
  570.  
  571. void print6x8 (long x, long y, long fcol, long bcol, const char *fmt, ...)
  572. {
  573.     va_list arglist;
  574.     char st[280], *c, *v;
  575.     long i, j;
  576.  
  577.     if (!fmt) return;
  578.     va_start(arglist,fmt);
  579.     vsprintf(st,fmt,arglist);
  580.     va_end(arglist);
  581.  
  582.     y = y*bytesperline+(x<<2)+frameplace;
  583.     if (bcol < 0)
  584.     {
  585.         for(j=1;j<256;y+=bytesperline,j<<=1)
  586.             for(c=st,x=y;*c;c++,x+=24)
  587.             {
  588.                 v = (char *)(((long)font6x8) + ((long)c[0])*6);
  589.                 if (v[0]&j) *(long *)(x   ) = fcol;
  590.                 if (v[1]&j) *(long *)(x+ 4) = fcol;
  591.                 if (v[2]&j) *(long *)(x+ 8) = fcol;
  592.                 if (v[3]&j) *(long *)(x+12) = fcol;
  593.                 if (v[4]&j) *(long *)(x+16) = fcol;
  594.                 if (v[5]&j) *(long *)(x+20) = fcol;
  595.                 if ((*c) == 9) x += ((2*6)<<2);
  596.             }
  597.         return;
  598.     }
  599.     fcol -= bcol;
  600.     for(j=1;j<256;y+=bytesperline,j<<=1)
  601.         for(c=st,x=y;*c;c++,x+=24)
  602.         {
  603.             v = (char *)(((long)font6x8) + ((long)c[0])*6);
  604.             *(long *)(x   ) = (((-(v[0]&j))>>31)&fcol)+bcol;
  605.             *(long *)(x+ 4) = (((-(v[1]&j))>>31)&fcol)+bcol;
  606.             *(long *)(x+ 8) = (((-(v[2]&j))>>31)&fcol)+bcol;
  607.             *(long *)(x+12) = (((-(v[3]&j))>>31)&fcol)+bcol;
  608.             *(long *)(x+16) = (((-(v[4]&j))>>31)&fcol)+bcol;
  609.             *(long *)(x+20) = (((-(v[5]&j))>>31)&fcol)+bcol;
  610.             if ((*c) == 9) { for(i=24;i<72;i+=4) *(long *)(x+i) = bcol; x += ((2*6)<<2); }
  611.         }
  612. }
  613.  
  614. static long gkrand = 0;
  615. long colorjit (long i, long jitamount)
  616. {
  617.     gkrand = (gkrand*27584621)+1;
  618.     return((gkrand&jitamount)^i);
  619. }
  620.  
  621. long lightvox (long i)
  622. {
  623.     long r, g, b;
  624.  
  625.     b = ((unsigned long)i>>24);
  626.     r = min((((i>>16)&255)*b)>>7,255);
  627.     g = min((((i>>8 )&255)*b)>>7,255);
  628.     b = min((((i    )&255)*b)>>7,255);
  629.     return((r<<16)+(g<<8)+b);
  630. }
  631.  
  632.     //Note: ebx = 512 is no change
  633.     //If PENTIUM III:1.Replace punpcklwd&punpckldq with: pshufw mm1, mm1, 0
  634.     //               2.Use pmulhuw, shift by 8 & mul by 256
  635.     //  :(  Can't mix with floating point
  636. //#pragma aux colormul =
  637. //   "movd mm0, eax"
  638. //   "pxor mm1, mm1"
  639. //   "punpcklbw mm0, mm1"
  640. //   "psllw mm0, 7"
  641. //   "movd mm1, ebx"
  642. //   "punpcklwd mm1, mm1"
  643. //   "punpckldq mm1, mm1"
  644. //   "pmulhw mm0, mm1"
  645. //   "packsswb mm0, mm0"
  646. //   "movd eax, mm0"
  647. //   parm [eax][ebx]
  648. //   modify exact [eax]
  649. //   value [eax]
  650.  
  651. long colormul (long i, long mulup8)
  652. {
  653.     long r, g, b;
  654.  
  655.     r = ((((i>>16)&255)*mulup8)>>8); if (r > 255) r = 255;
  656.     g = ((((i>>8 )&255)*mulup8)>>8); if (g > 255) g = 255;
  657.     b = ((((i    )&255)*mulup8)>>8); if (b > 255) b = 255;
  658.     return((i&0xff000000)+(r<<16)+(g<<8)+b);
  659. }
  660.  
  661. long curcolfunc (lpoint3d *p) { return(vx5.curcol); }
  662.  
  663. long floorcolfunc (lpoint3d *p)
  664. {
  665.     char *v;
  666.     for(v=sptr[p->y*VSID+p->x];(p->z>v[2]) && (v[0]);v+=v[0]*4);
  667.     return(*(long *)&v[4]);
  668. }
  669.  
  670. long jitcolfunc (lpoint3d *p) { return(colorjit(vx5.curcol,vx5.amount)); }
  671.  
  672. static long manycolukup[64] =
  673. {
  674.       0,  1,  2,  5, 10, 15, 21, 29, 37, 47, 57, 67, 79, 90,103,115,
  675.     127,140,152,165,176,188,198,208,218,226,234,240,245,250,253,254,
  676.     255,254,253,250,245,240,234,226,218,208,198,188,176,165,152,140,
  677.     128,115,103, 90, 79, 67, 57, 47, 37, 29, 21, 15, 10,  5,  2,  1
  678. };
  679. long manycolfunc (lpoint3d *p)
  680. {
  681.     return((manycolukup[p->x&63]<<16)+(manycolukup[p->y&63]<<8)+manycolukup[p->z&63]+0x80000000);
  682. }
  683.  
  684. long sphcolfunc (lpoint3d *p)
  685. {
  686.     long i;
  687.     ftol(sin((p->x+p->y+p->z-vx5.cen)*vx5.daf)*-96,&i);
  688.     return(((i+128)<<24)|(vx5.curcol&0xffffff));
  689. }
  690.  
  691. #define WOODXSIZ 46
  692. #define WOODYSIZ 24
  693. #define WOODZSIZ 24
  694. static float wx[256], wy[256], wz[256], vx[256], vy[256], vz[256];
  695. long woodcolfunc (lpoint3d *p)
  696. {
  697.     float col, u, a, f, dx, dy, dz;
  698.     long i, c, xof, yof, tx, ty, xoff;
  699.  
  700.     if (*(long *)&wx[0] == 0)
  701.     {
  702.         for(i=0;i<256;i++)
  703.         {
  704.             wx[i] = WOODXSIZ * ((float)rand()/32768.0f-.5f) * .5f;
  705.             wy[i] = WOODXSIZ * ((float)rand()/32768.0f-.5f) * .5f;
  706.             wz[i] = WOODXSIZ * ((float)rand()/32768.0f-.5f) * .5f;
  707.  
  708.                 //UNIFORM spherical randomization (see spherand.c)
  709.             dz = 1.0f-(float)rand()/32768.0f*.04f;
  710.             a = (float)rand()/32768.0f*PI*2.0f; fcossin(a,&dx,&dy);
  711.             f = sqrt(1.0f-dz*dz); dx *= f; dy *= f;
  712.                 //??z: rings,  ?z?: vertical,  z??: horizontal (nice)
  713.             vx[i] = dz; vy[i] = fabs(dy); vz[i] = dx;
  714.         }
  715.     }
  716.  
  717.         //(tx&,ty&) = top-left corner of current panel
  718.     ty = p->y - (p->y%WOODYSIZ);
  719.     xoff = ((ty/WOODYSIZ)*(ty/WOODYSIZ)*51721 + (p->z/WOODZSIZ)*357) % WOODXSIZ;
  720.     tx = ((p->x+xoff) - (p->x+xoff)%WOODXSIZ) - xoff;
  721.  
  722.     xof = p->x - (tx + (WOODXSIZ>>1));
  723.     yof = p->y - (ty + (WOODYSIZ>>1));
  724.  
  725.     c = ((((tx*429 + 4695) ^ (ty*341 + 4355) ^ 13643) * 2797) & 255);
  726.     dx = xof - wx[c];
  727.     dy = yof - wy[c];
  728.     dz = (p->z%WOODZSIZ) - wz[c];
  729.  
  730.         //u = distance to center of randomly oriented cylinder
  731.     u = vx[c]*dx + vy[c]*dy + vz[c]*dz;
  732.     u = sqrt(dx*dx + dy*dy + dz*dz - u*u);
  733.  
  734.         //ring randomness
  735.     u += sin((float)xof*.12 + (float)yof*.15) * .5;
  736.     u *= (sin(u)*.05 + 1);
  737.  
  738.         //Ring function: smooth saw-tooth wave
  739.     col = sin(u*2)*24;
  740.     col *= pow(1.f-vx[c],.3f);
  741.  
  742.         //Thin shaded borders
  743.     if ((p->x-tx == 0) || (p->y-ty == 0)) col -= 5;
  744.     if ((p->x-tx == WOODXSIZ-1) || (p->y-ty == WOODYSIZ-1)) col -= 3;
  745.  
  746.     //f = col+c*.12+72; i = ftolp3(&f);
  747.       ftol(col+c*.12f+72.0f,&i);
  748.  
  749.     return(colormul(vx5.curcol,i<<1));
  750. }
  751.  
  752. long gxsizcache = 0, gysizcache = 0;
  753. long pngcolfunc (lpoint3d *p)
  754. {
  755.     long x, y, z, u, v;
  756.     float fx, fy, fz, rx, ry, rz;
  757.  
  758.     if (!vx5.pic) return(vx5.curcol);
  759.     switch(vx5.picmode)
  760.     {
  761.         case 0:
  762.             x = p->x-vx5.pico.x; y = p->y-vx5.pico.y; z = p->z-vx5.pico.z;
  763.             u = (((x&vx5.picu.x) + (y&vx5.picu.y) + (z&vx5.picu.z))^vx5.xoru);
  764.             v = (((x&vx5.picv.x) + (y&vx5.picv.y) + (z&vx5.picv.z))^vx5.xorv);
  765.             break;
  766.         case 1: case 2:
  767.             fx = (float)p->x-vx5.fpico.x;
  768.             fy = (float)p->y-vx5.fpico.y;
  769.             fz = (float)p->z-vx5.fpico.z;
  770.             rx = vx5.fpicu.x*fx + vx5.fpicu.y*fy + vx5.fpicu.z*fz;
  771.             ry = vx5.fpicv.x*fx + vx5.fpicv.y*fy + vx5.fpicv.z*fz;
  772.             rz = vx5.fpicw.x*fx + vx5.fpicw.y*fy + vx5.fpicw.z*fz;
  773.             ftol(atan2(ry,rx)*vx5.xoru/(PI*2),&u);
  774.             if (vx5.picmode == 1) ftol(rz,&v);
  775.             else ftol((atan2(rz,sqrt(rx*rx+ry*ry))/PI+.5)*vx5.ysiz,&v);
  776.             break;
  777.         default: //case 3:
  778.             fx = (float)p->x-vx5.fpico.x;
  779.             fy = (float)p->y-vx5.fpico.y;
  780.             fz = (float)p->z-vx5.fpico.z;
  781.             ftol(vx5.fpicu.x*fx + vx5.fpicu.y*fy + vx5.fpicu.z*fz,&u);
  782.             ftol(vx5.fpicv.x*fx + vx5.fpicv.y*fy + vx5.fpicv.z*fz,&v);
  783.             break;
  784.     }
  785.     if ((unsigned long)(u-gxsizcache) >= (unsigned long)vx5.xsiz)
  786.         if (u < 0) gxsizcache = u-(u+1)%vx5.xsiz-vx5.xsiz+1; else gxsizcache = u-(u%vx5.xsiz);
  787.     if ((unsigned long)(v-gysizcache) >= (unsigned long)vx5.ysiz)
  788.         if (v < 0) gysizcache = v-(v+1)%vx5.ysiz-vx5.ysiz+1; else gysizcache = v-(v%vx5.ysiz);
  789.     return((vx5.pic[(v-gysizcache)*(vx5.bpl>>2)+(u-gxsizcache)]&0xffffff)|0x80000000);
  790. }
  791.  
  792.     //Special case for SETSEC & SETCEI bumpmapping (vx5.picmode == 3)
  793.     //no safety checks, returns alpha as signed char in range: (-128 to 127)
  794. long hpngcolfunc (point3d *p)
  795. {
  796.     long u, v;
  797.     float fx, fy, fz;
  798.  
  799.     fx = p->x-vx5.fpico.x;
  800.     fy = p->y-vx5.fpico.y;
  801.     fz = p->z-vx5.fpico.z;
  802.     ftol(vx5.fpicu.x*fx + vx5.fpicu.y*fy + vx5.fpicu.z*fz,&u);
  803.     ftol(vx5.fpicv.x*fx + vx5.fpicv.y*fy + vx5.fpicv.z*fz,&v);
  804.  
  805.     if ((unsigned long)(u-gxsizcache) >= (unsigned long)vx5.xsiz)
  806.         if (u < 0) gxsizcache = u-(u+1)%vx5.xsiz-vx5.xsiz+1; else gxsizcache = u-(u%vx5.xsiz);
  807.     if ((unsigned long)(v-gysizcache) >= (unsigned long)vx5.ysiz)
  808.         if (v < 0) gysizcache = v-(v+1)%vx5.ysiz-vx5.ysiz+1; else gysizcache = v-(v%vx5.ysiz);
  809.     return(vx5.pic[(v-gysizcache)*(vx5.bpl>>2)+(u-gxsizcache)]>>24);
  810. }
  811.  
  812. static long slng (const char *s)
  813. {
  814.     const char *v;
  815.  
  816.     for(v=s;v[0];v+=v[0]*4);
  817.     return((long)v-(long)s+(v[2]-v[1]+1)*4+4);
  818. }
  819.  
  820. void voxdealloc (const char *v)
  821. {
  822.     long i, j;
  823.     i = (((long)v-(long)vbuf)>>2); j = (slng(v)>>2)+i;
  824. #if 0
  825.     while (i < j) { vbit[i>>5] &= ~(1<<i); i++; }
  826. #else
  827.     if (!((j^i)&~31))
  828.         vbit[i>>5] &= ~(p2m[j&31]^p2m[i&31]);
  829.     else
  830.     {
  831.         vbit[i>>5] &=   p2m[i&31];  i >>= 5;
  832.         vbit[j>>5] &= (~p2m[j&31]); j >>= 5;
  833.         for(j--;j>i;j--) vbit[j] = 0;
  834.     }
  835. #endif
  836. }
  837.  
  838.     //Note: danum MUST be a multiple of 4!
  839. char *voxalloc (long danum)
  840. {
  841.     long i, badcnt, p0, p1, vend;
  842.  
  843.     badcnt = 0; danum >>= 2; vend = (VOXSIZ>>2)-danum;
  844.     do
  845.     {
  846.         for(;vbiti<vend;vbiti+=danum)
  847.         {
  848.             if (vbit[vbiti>>5]&(1<<vbiti)) continue;
  849.             for(p0=vbiti;(!(vbit[(p0-1)>>5]&(1<<(p0-1))));p0--);
  850.             for(p1=p0+danum-1;p1>vbiti;p1--)
  851.                 if (vbit[p1>>5]&(1<<p1)) goto allocnothere;
  852.  
  853.             vbiti = p0+danum;
  854.             for(i=p0;i<vbiti;i++) vbit[i>>5] |= (1<<i);
  855.             return((char *)(&vbuf[p0]));
  856. allocnothere:;
  857.         }
  858.         vbiti = 0; badcnt++;
  859.     } while (badcnt < 2);
  860.     evilquit("voxalloc: vbuf full"); return(0);
  861. }
  862.  
  863. long isvoxelsolid (long x, long y, long z)
  864. {
  865.     char *v;
  866.  
  867.     if ((unsigned long)(x|y) >= VSID) return(0);
  868.     v = sptr[y*VSID+x];
  869.     while (1)
  870.     {
  871.         if (z < v[1]) return(0);
  872.         if (!v[0]) return(1);
  873.         v += v[0]*4;
  874.         if (z < v[3]) return(1);
  875.     }
  876. }
  877.  
  878.     //Returns 1 if any voxels in range (x,y,z0) to (x,y,z1-1) are solid, else 0
  879. long anyvoxelsolid (long x, long y, long z0, long z1)
  880. {
  881.     char *v;
  882.  
  883.         //         v1.....v3   v1.....v3    v1.......................>
  884.         //                z0.........z1
  885.     if ((unsigned long)(x|y) >= VSID) return(0);
  886.     v = sptr[y*VSID+x];
  887.     while (1)
  888.     {
  889.         if (z1 <= v[1]) return(0);
  890.         if (!v[0]) return(1);
  891.         v += v[0]*4;
  892.         if (z0 < v[3]) return(1);
  893.     }
  894. }
  895.  
  896.     //Returns 1 if any voxels in range (x,y,z0) to (x,y,z1-1) are empty, else 0
  897. long anyvoxelempty (long x, long y, long z0, long z1)
  898. {
  899.     char *v;
  900.  
  901.         //         v1.....v3   v1.....v3    v1.......................>
  902.         //                z0.........z1
  903.     if ((unsigned long)(x|y) >= VSID) return(1);
  904.     v = sptr[y*VSID+x];
  905.     while (1)
  906.     {
  907.         if (z0 < v[1]) return(1);
  908.         if (!v[0]) return(0);
  909.         v += v[0]*4;
  910.         if (z1 <= v[3]) return(0);
  911.     }
  912. }
  913.  
  914.     //Returns z of first solid voxel under (x,y,z). Returns z if in solid.
  915. long getfloorz (long x, long y, long z)
  916. {
  917.     char *v;
  918.  
  919.     if ((unsigned long)(x|y) >= VSID) return(z);
  920.     v = sptr[y*VSID+x];
  921.     while (1)
  922.     {
  923.         if (z <= v[1]) return(v[1]);
  924.         if (!v[0]) break;
  925.         v += v[0]*4;
  926.         if (z < v[3]) break;
  927.     }
  928.     return(z);
  929. }
  930.  
  931.     //Returns:
  932.     //   0: air
  933.     //   1: unexposed solid
  934.     //else: address to color in vbuf (this can never be 0 or 1)
  935. long getcube (long x, long y, long z)
  936. {
  937.     long ceilnum;
  938.     char *v;
  939.  
  940.     if ((unsigned long)(x|y) >= VSID) return(0);
  941.     v = sptr[y*VSID+x];
  942.     while (1)
  943.     {
  944.         if (z <= v[2])
  945.         {
  946.             if (z < v[1]) return(0);
  947.             return((long)&v[(z-v[1])*4+4]);
  948.         }
  949.         ceilnum = v[2]-v[1]-v[0]+2;
  950.  
  951.         if (!v[0]) return(1);
  952.         v += v[0]*4;
  953.  
  954.         if (z < v[3])
  955.         {
  956.             if (z-v[3] < ceilnum) return(1);
  957.             return((long)&v[(z-v[3])*4]);
  958.         }
  959.     }
  960. }
  961.  
  962.     // Inputs: uind[MAXZDIM]: uncompressed 32-bit color buffer (-1: air)
  963.     //         nind?[MAXZDIM]: neighbor buf:
  964.     //            -2: unexposed solid
  965.     //            -1: air
  966.     //    0-16777215: exposed solid (color)
  967.     //         px,py: parameters for setting unexposed voxel colors
  968.     //Outputs: cbuf[MAXCSIZ]: compressed output buffer
  969.     //Returns: n: length of compressed buffer (in bytes)
  970. long compilestack (long *uind, long *n0, long *n1, long *n2, long *n3, char *cbuf, long px, long py)
  971. {
  972.     long oz, onext, n, cp2, cp1, cp0, rp1, rp0;
  973.     lpoint3d p;
  974.  
  975.     p.x = px; p.y = py;
  976.  
  977.         //Do top slab (sky)
  978.     oz = -1;
  979.     p.z = -1; while (uind[p.z+1] == -1) p.z++;
  980.     onext = 0;
  981.     cbuf[1] = p.z+1;
  982.     cbuf[2] = p.z+1;
  983.     cbuf[3] = 0;  //Top z0 (filler, not used yet)
  984.     n = 4;
  985.     cp1 = 1; cp0 = 0;
  986.     rp1 = -1; rp0 = -1;
  987.  
  988.     do
  989.     {
  990.             //cp2 = state at p.z-1 (0 = air, 1 = next2air, 2 = solid)
  991.             //cp1 = state at p.z   (0 = air, 1 = next2air, 2 = solid)
  992.             //cp0 = state at p.z+1 (0 = air, 1 = next2air, 2 = solid)
  993.         cp2 = cp1; cp1 = cp0; cp0 = 2;
  994.         if (p.z < MAXZDIM-2)  //Bottom must be solid!
  995.         {
  996.             if (uind[p.z+1] == -1)
  997.                 cp0 = 0;
  998.             else if ((n0[p.z+1] == -1) || (n1[p.z+1] == -1) ||
  999.                         (n2[p.z+1] == -1) || (n3[p.z+1] == -1))
  1000.                 cp0 = 1;
  1001.         }
  1002.  
  1003.             //Add slab
  1004.         if (cp1 != rp0)
  1005.         {
  1006.             if ((!cp1) && (rp0 > 0)) { oz = p.z; }
  1007.             else if ((rp0 < cp1) && (rp0 < rp1))
  1008.             {
  1009.                 if (oz < 0) oz = p.z;
  1010.                 cbuf[onext] = ((n-onext)>>2); onext = n;
  1011.                 cbuf[n+1] = p.z;
  1012.                 cbuf[n+2] = p.z-1;
  1013.                 cbuf[n+3] = oz;
  1014.                 n += 4; oz = -1;
  1015.             }
  1016.             rp1 = rp0; rp0 = cp1;
  1017.         }
  1018.  
  1019.             //Add color
  1020.         if ((cp1 == 1) || ((cp1 == 2) && ((!cp0) || (!cp2))))
  1021.         {
  1022.             if (cbuf[onext+2] == p.z-1) cbuf[onext+2] = p.z;
  1023.             if (uind[p.z] == -2) *(long *)&cbuf[n] = vx5.colfunc(&p);
  1024.                                  else *(long *)&cbuf[n] = uind[p.z];
  1025.             n += 4;
  1026.         }
  1027.  
  1028.         p.z++;
  1029.     } while (p.z < MAXZDIM);
  1030.     cbuf[onext] = 0;
  1031.     return(n);
  1032. }
  1033.  
  1034. #ifdef _MSC_VER
  1035.  
  1036. static _inline void expandbit256 (void *s, void *d)
  1037. {
  1038.     _asm
  1039.     {
  1040.         push esi
  1041.         push edi
  1042.         mov esi, s
  1043.         mov edi, d
  1044.         mov ecx, 32   ;current bit index
  1045.         xor edx, edx  ;value of current 32-bit bits
  1046.         jmp short in2it
  1047. begit:lea esi, [esi+eax*4]
  1048.         movzx eax, byte ptr [esi+3]
  1049.         sub eax, ecx              ;xor mask [eax] for ceiling begins
  1050.         jl short xskpc
  1051. xdoc: mov [edi], edx
  1052.         add edi, 4
  1053.         mov edx, -1
  1054.         add ecx, 32
  1055.         sub eax, 32
  1056.         jge short xdoc
  1057. xskpc:and edx, xbsceil[eax*4+128] ;~(-1<<eax); xor mask [eax] for ceiling ends
  1058. in2it:movzx eax, byte ptr [esi+1]
  1059.         sub eax, ecx              ;xor mask [eax] for floor begins
  1060.         jl short xskpf
  1061. xdof: mov [edi], edx
  1062.         add edi, 4
  1063.         xor edx, edx
  1064.         add ecx, 32
  1065.         sub eax, 32
  1066.         jge short xdof
  1067. xskpf:or edx, xbsflor[eax*4+128] ;(-1<<eax); xor mask [eax] for floor ends
  1068.         movzx eax, byte ptr [esi]
  1069.         test eax, eax
  1070.         jnz short begit
  1071.         sub ecx, 256              ;finish writing buffer to [edi]
  1072.         jg short xskpe
  1073. xdoe: mov [edi], edx
  1074.         add edi, 4
  1075.         mov edx, -1
  1076.         add ecx, 32
  1077.         jle short xdoe
  1078. xskpe:pop edi
  1079.         pop esi
  1080.     }
  1081. }
  1082.  
  1083. #endif
  1084.  
  1085. void expandbitstack (long x, long y, __int64 *bind)
  1086. {
  1087.     if ((x|y)&(~(VSID-1))) { clearbuf((void *)bind,8,0L); return; }
  1088.     expandbit256(sptr[y*VSID+x],(void *)bind);
  1089. }
  1090.  
  1091. void expandstack (long x, long y, long *uind)
  1092. {
  1093.     long z, topz;
  1094.     char *v, *v2;
  1095.  
  1096.     if ((x|y)&(~(VSID-1))) { clearbuf((void *)uind,MAXZDIM,0); return; }
  1097.  
  1098.         //Expands compiled voxel info to 32-bit uind[?]
  1099.     v = sptr[y*VSID+x]; z = 0;
  1100.     while (1)
  1101.     {
  1102.         while (z < v[1]) { uind[z] = -1; z++; }
  1103.         while (z <= v[2]) { uind[z] = (*(long *)&v[(z-v[1])*4+4]); z++; }
  1104.         v2 = &v[(v[2]-v[1]+1)*4+4];
  1105.  
  1106.         if (!v[0]) break;
  1107.         v += v[0]*4;
  1108.  
  1109.         topz = v[3]+(((long)v2-(long)v)>>2);
  1110.         while (z < topz) { uind[z] = -2; z++; }
  1111.         while (z < v[3]) { uind[z] = *(long *)v2; z++; v2 += 4; }
  1112.     }
  1113.     while (z < MAXZDIM) { uind[z] = -2; z++; }
  1114. }
  1115.  
  1116. void gline (long leng, float x0, float y0, float x1, float y1)
  1117. {
  1118.     unsigned __int64 q;
  1119.     float f, f1, f2, vd0, vd1, vz0, vx1, vy1, vz1;
  1120.     long j;
  1121.     cftype *c;
  1122. #if (USEV5ASM == 0)
  1123.     long gx, ogx, gy, ixy, col, dax, day;
  1124.     cftype *c2, *ce;
  1125.     char *v;
  1126. #endif
  1127.  
  1128.     vd0 = x0*gistr.x + y0*gihei.x + gcorn[0].x;
  1129.     vd1 = x0*gistr.y + y0*gihei.y + gcorn[0].y;
  1130.     vz0 = x0*gistr.z + y0*gihei.z + gcorn[0].z;
  1131.     vx1 = x1*gistr.x + y1*gihei.x + gcorn[0].x;
  1132.     vy1 = x1*gistr.y + y1*gihei.y + gcorn[0].y;
  1133.     vz1 = x1*gistr.z + y1*gihei.z + gcorn[0].z;
  1134.  
  1135.     f = sqrt(vx1*vx1 + vy1*vy1);
  1136.     f1 = f / vx1;
  1137.     f2 = f / vy1;
  1138.     if (fabs(vx1) > fabs(vy1)) vd0 = vd0*f1; else vd0 = vd1*f2;
  1139.     if (*(long *)&vd0 < 0) vd0 = 0; //vd0 MUST NOT be negative: bad for asm
  1140.     vd1 = f;
  1141.     ftol(fabs(f1)*PREC,&gdz[0]);
  1142.     ftol(fabs(f2)*PREC,&gdz[1]);
  1143.  
  1144.     gixy[0] = (((*(signed long *)&vx1)>>31)<<3)+4; //=sgn(vx1)*4
  1145.     gixy[1] = gixyi[(*(unsigned long *)&vy1)>>31]; //=sgn(vy1)*4*VSID
  1146.     if (gdz[0] <= 0) { gpz[0] = 0x7fffffff; gdz[0] = 0; } //Hack for divide overflow
  1147.     else ftol(gposxfrac[(*(unsigned long *)&vx1)>>31]*(float)gdz[0],&gpz[0]);
  1148.     if (gdz[1] <= 0) { gpz[1] = 0x7fffffff; gdz[1] = 0; } //Hack for divide overflow
  1149.     else ftol(gposyfrac[(*(unsigned long *)&vy1)>>31]*(float)gdz[1],&gpz[1]);
  1150.  
  1151.     c = &cf[128];
  1152.     c->i0 = gscanptr; c->i1 = &gscanptr[leng];
  1153.     c->z0 = gstartz0; c->z1 = gstartz1;
  1154.     if (giforzsgn < 0)
  1155.     {
  1156.         ftol((vd1-vd0)*cmprecip[leng],&gi0); ftol(vd0*CMPPREC,&c->cx0);
  1157.         ftol((vz1-vz0)*cmprecip[leng],&gi1); ftol(vz0*CMPPREC,&c->cy0);
  1158.     }
  1159.     else
  1160.     {
  1161.         ftol((vd0-vd1)*cmprecip[leng],&gi0); ftol(vd1*CMPPREC,&c->cx0);
  1162.         ftol((vz0-vz1)*cmprecip[leng],&gi1); ftol(vz1*CMPPREC,&c->cy0);
  1163.     }
  1164.     c->cx1 = leng*gi0 + c->cx0;
  1165.     c->cy1 = leng*gi1 + c->cy0;
  1166.  
  1167.     gxmax = gmaxscandist;
  1168.  
  1169.         //Hack for early-out case when looking up towards sky
  1170. #if 0  //DOESN'T WORK WITH LOWER MIPS!
  1171.     if (c->cy1 < 0)
  1172.         if (gposz > 0)
  1173.         {
  1174.             if (dmulrethigh(-gposz,c->cx1,c->cy1,gxmax) >= 0)
  1175.             {
  1176.                 j = scale(-gposz,c->cx1,c->cy1)+PREC; //+PREC for good luck
  1177.                 if ((unsigned long)j < (unsigned long)gxmax) gxmax = j;
  1178.             }
  1179.         } else gxmax = 0;
  1180. #endif
  1181.  
  1182.         //Clip borders safely (MUST use integers!) - don't wrap around
  1183. #if ((USEZBUFFER == 1) && (USEV5ASM != 0))
  1184.     skycast.dist = gxmax;
  1185. #endif
  1186.     if (gixy[0] < 0) j = glipos.x; else j = VSID-1-glipos.x;
  1187.     q = mul64(gdz[0],j); q += (unsigned __int64)gpz[0];
  1188.     if (q < (unsigned __int64)gxmax)
  1189.     {
  1190.         gxmax = (long)q;
  1191. #if ((USEZBUFFER == 1) && (USEV5ASM != 0))
  1192.         skycast.dist = 0x7fffffff;
  1193. #endif
  1194.     }
  1195.     if (gixy[1] < 0) j = glipos.y; else j = VSID-1-glipos.y;
  1196.     q = mul64(gdz[1],j); q += (unsigned __int64)gpz[1];
  1197.     if (q < (unsigned __int64)gxmax)
  1198.     {
  1199.         gxmax = (long)q;
  1200. #if ((USEZBUFFER == 1) && (USEV5ASM != 0))
  1201.         skycast.dist = 0x7fffffff;
  1202. #endif
  1203.     }
  1204.  
  1205.     if (vx5.sideshademode)
  1206.     {
  1207.         gcsub[0] = gcsub[(((unsigned long)gixy[0])>>31)+4];
  1208.         gcsub[1] = gcsub[(((unsigned long)gixy[1])>>31)+6];
  1209.     }
  1210.  
  1211. #if USEV5ASM
  1212.     if (nskypic)
  1213.     {
  1214.         if (skycurlng < 0)
  1215.         {
  1216.             ftol((atan2(vy1,vx1)+PI)*skylngmul-.5,&skycurlng);
  1217.             if ((unsigned long)skycurlng >= skyysiz)
  1218.                 skycurlng = ((skyysiz-1)&(j>>31));
  1219.         }
  1220.         else if (skycurdir < 0)
  1221.         {
  1222.             j = skycurlng+1; if (j >= skyysiz) j = 0;
  1223.             while (skylng[j].x*vy1 > skylng[j].y*vx1)
  1224.                 { skycurlng = j++; if (j >= skyysiz) j = 0; }
  1225.         }
  1226.         else
  1227.         {
  1228.             while (skylng[skycurlng].x*vy1 < skylng[skycurlng].y*vx1)
  1229.                 { skycurlng--; if (skycurlng < 0) skycurlng = skyysiz-1; }
  1230.         }
  1231.         skyoff = skycurlng*skybpl + nskypic;
  1232.     }
  1233.  
  1234.     //resp = 0;
  1235.     grouscanasm((long)gstartv);
  1236.     //if (resp)
  1237.     //{
  1238.     //   static char tempbuf[2048], tempbuf2[256];
  1239.     //   sprintf(tempbuf,"eax:%08x\tmm0:%08x%08x\nebx:%08x\tmm1:%08x%08x\necx:%08x\tmm2:%08x%08x\nedx:%08x\tmm3:%08x%08x\nesi:%08x\tmm4:%08x%08x\nedi:%08x\tmm5:%08x%08x\nebp:%08x\tmm6:%08x%08x\nesp:%08x\tmm7:%08x%08x\n",
  1240.     //      reax,remm[ 1],remm[ 0], rebx,remm[ 3],remm[ 2],
  1241.     //      recx,remm[ 5],remm[ 4], redx,remm[ 7],remm[ 6],
  1242.     //      resi,remm[ 9],remm[ 8], redi,remm[11],remm[10],
  1243.     //      rebp,remm[13],remm[12], resp,remm[15],remm[14]);
  1244.     //
  1245.     //   for(j=0;j<3;j++)
  1246.     //   {
  1247.     //      sprintf(tempbuf2,"%d i0:%d i1:%d z0:%ld z1:%ld cx0:%08x cy0:%08x cx1:%08x cy1:%08x\n",
  1248.     //         j,(long)cf[j].i0-(long)gscanptr,(long)cf[j].i1-(long)gscanptr,cf[j].z0,cf[j].z1,cf[j].cx0,cf[j].cy0,cf[j].cx1,cf[j].cy1);
  1249.     //      strcat(tempbuf,tempbuf2);
  1250.     //   }
  1251.     //   evilquit(tempbuf);
  1252.     //}
  1253. #else
  1254. //------------------------------------------------------------------------
  1255.     ce = c; v = gstartv;
  1256.     j = (((unsigned long)(gpz[1]-gpz[0]))>>31);
  1257.     gx = gpz[j];
  1258.     ixy = gpixy;
  1259.     if (v == (char *)*(long *)gpixy) goto drawflor; goto drawceil;
  1260.  
  1261.     while (1)
  1262.     {
  1263.  
  1264. drawfwall:;
  1265.         if (v[1] != c->z1)
  1266.         {
  1267.             if (v[1] > c->z1) c->z1 = v[1];
  1268.             else { do
  1269.             {
  1270.                 c->z1--; col = *(long *)&v[(c->z1-v[1])*4+4];
  1271.                 while (dmulrethigh(gylookup[c->z1],c->cx1,c->cy1,ogx) < 0)
  1272.                 {
  1273.                     c->i1->col = col; c->i1--; if (c->i0 > c->i1) goto deletez;
  1274.                     c->cx1 -= gi0; c->cy1 -= gi1;
  1275.                 }
  1276.             } while (v[1] != c->z1); }
  1277.         }
  1278.  
  1279.         if (v == (char *)*(long *)ixy) goto drawflor;
  1280.  
  1281. //drawcwall:;
  1282.         if (v[3] != c->z0)
  1283.         {
  1284.             if (v[3] < c->z0) c->z0 = v[3];
  1285.             else { do
  1286.             {
  1287.                 c->z0++; col = *(long *)&v[(c->z0-v[3])*4-4];
  1288.                 while (dmulrethigh(gylookup[c->z0],c->cx0,c->cy0,ogx) >= 0)
  1289.                 {
  1290.                     c->i0->col = col; c->i0++; if (c->i0 > c->i1) goto deletez;
  1291.                     c->cx0 += gi0; c->cy0 += gi1;
  1292.                 }
  1293.             } while (v[3] != c->z0); }
  1294.         }
  1295.  
  1296. drawceil:;
  1297.         while (dmulrethigh(gylookup[c->z0],c->cx0,c->cy0,gx) >= 0)
  1298.         {
  1299.             c->i0->col = (*(long *)&v[-4]); c->i0++; if (c->i0 > c->i1) goto deletez;
  1300.             c->cx0 += gi0; c->cy0 += gi1;
  1301.         }
  1302.  
  1303. drawflor:;
  1304.         while (dmulrethigh(gylookup[c->z1],c->cx1,c->cy1,gx) < 0)
  1305.         {
  1306.             c->i1->col = *(long *)&v[4]; c->i1--; if (c->i0 > c->i1) goto deletez;
  1307.             c->cx1 -= gi0; c->cy1 -= gi1;
  1308.         }
  1309.  
  1310. afterdelete:;
  1311.         c--;
  1312.         if (c < &cf[128])
  1313.         {
  1314.             ixy += gixy[j];
  1315.             gpz[j] += gdz[j];
  1316.             j = (((unsigned long)(gpz[1]-gpz[0]))>>31);
  1317.             ogx = gx; gx = gpz[j];
  1318.  
  1319.             if (gx > gxmax) break;
  1320.             v = (char *)*(long *)ixy; c = ce;
  1321.         }
  1322.             //Find highest intersecting vbuf slab
  1323.         while (1)
  1324.         {
  1325.             if (!v[0]) goto drawfwall;
  1326.             if (dmulrethigh(gylookup[v[2]+1],c->cx0,c->cy0,ogx) >= 0) break;
  1327.             v += v[0]*4;
  1328.         }
  1329.             //If next slab ALSO intersects, split cf!
  1330.         gy = gylookup[v[v[0]*4+3]];
  1331.         if (dmulrethigh(gy,c->cx1,c->cy1,ogx) < 0)
  1332.         {
  1333.             col = (long)c->i1; dax = c->cx1; day = c->cy1;
  1334.             while (dmulrethigh(gylookup[v[2]+1],dax,day,ogx) < 0)
  1335.                 { col -= sizeof(castdat); dax -= gi0; day -= gi1; }
  1336.             ce++; if (ce >= &cf[192]) return; //Give it max=64 entries like ASM
  1337.             for(c2=ce;c2>c;c2--) c2[0] = c2[-1];
  1338.             c[1].i1 = (castdat *)col; c->i0 = ((castdat *)col)+1;
  1339.             c[1].cx1 = dax; c->cx0 = dax+gi0;
  1340.             c[1].cy1 = day; c->cy0 = day+gi1;
  1341.             c[1].z1 = c->z0 = v[v[0]*4+3];
  1342.             c++;
  1343.         }
  1344.     }
  1345. //------------------------------------------------------------------------
  1346.  
  1347.     for(c=ce;c>=&cf[128];c--)
  1348.         while (c->i0 <= c->i1) { c->i0->col = 0; c->i0++; }
  1349.     return;
  1350.  
  1351. deletez:;
  1352.     ce--; if (ce < &cf[128]) return;
  1353.     for(c2=c;c2<=ce;c2++) c2[0] = c2[1];
  1354.     goto afterdelete;
  1355. #endif
  1356. }
  1357.  
  1358. #ifdef _MSC_VER
  1359.  
  1360. static _inline void mmxcoloradd (long *a)
  1361. {
  1362.     _asm
  1363.     {
  1364.         mov eax, a
  1365.         movd mm0, [eax]
  1366.         paddusb mm0, flashbrival
  1367.         movd [eax], mm0
  1368.     }
  1369. }
  1370.  
  1371. static _inline void mmxcolorsub (long *a)
  1372. {
  1373.     _asm
  1374.     {
  1375.         mov eax, a
  1376.         movd mm0, [eax]
  1377.         psubusb mm0, flashbrival
  1378.         movd [eax], mm0
  1379.     }
  1380. }
  1381.  
  1382. #endif
  1383.  
  1384. static _inline void addusb (char *a, long b)
  1385. {
  1386.     (*a) += b; if ((*a) < b) (*a) = 255;
  1387. }
  1388.  
  1389.     // (cone diameter vs. % 3D angular area) or: (a vs. 2/(1-cos(a*.5*PI/180)))
  1390.     // ΪΔΔΔΔΔΔΔΔΔΔΔΔΔΒΔΔΔΔΔΔΔΔΔΔΔΒΔΔΔΔΔΔΔΔΔΔΔΒΔΔΔΔΔΔΔΔΔΔΒΔΔΔΔΔΔΔΔΔΔΔΒΔΔΔΔΔΔΔΔΔΏ
  1391.     // ³  0: inf     ³ 25: 84.37 ³ 50: 21.35 ³ 75: 9.68 ³ 100: 5.60 ³ 180: 2  ³
  1392.     // ³  5: 2101.33 ³ 30: 58.70 ³ 55: 17.70 ³ 80: 8.55 ³ 105: 5.11 ³ 360: 1  ³
  1393.     // ³ 10:  525.58 ³ 35: 43.21 ³ 60: 14.93 ³ 85: 7.61 ³ 110: 4.69 ΓΔΔΔΔΔΔΔΔΔΩ
  1394.     // ³ 15:  233.78 ³ 40: 33.16 ³ 65: 12.77 ³ 90: 6.83 ³ 115: 4.32 ³
  1395.     // ³ 20:  131.65 ³ 45: 26.27 ³ 70: 11.06 ³ 95: 6.17 ³ 120: 4    ³
  1396.     // ΐΔΔΔΔΔΔΔΔΔΔΔΔΔΑΔΔΔΔΔΔΔΔΔΔΔΑΔΔΔΔΔΔΔΔΔΔΔΑΔΔΔΔΔΔΔΔΔΔΑΔΔΔΔΔΔΔΔΔΔΔΩ
  1397. void setflash (float px, float py, float pz, long flashradius, long numang, long intens)
  1398. {
  1399.     unsigned __int64 q;
  1400.     float vx, vy;
  1401.     long i, j, gx, ogx, ixy, col, angoff;
  1402.     long ipx, ipy, ipz, sz0, sz1;
  1403.     cftype *c, *c2, *ce;
  1404.     char *v, *vs;
  1405.  
  1406.     ipx = (long)px; ipy = (long)py; ipz = (long)pz;
  1407.     vx5.minx = ipx-flashradius; vx5.maxx = ipx+flashradius+1;
  1408.     vx5.miny = ipy-flashradius; vx5.maxy = ipy+flashradius+1;
  1409.     vx5.minz = ipz-flashradius; vx5.maxz = ipz+flashradius+1;
  1410.  
  1411.     if (flashradius > 2047) flashradius = 2047;
  1412.     flashradius *= FPREC;
  1413.  
  1414.     flashbrival = (intens<<24);
  1415.     angoff = ((0x52741630>>(flashcnt<<2))&15); flashcnt++;
  1416.  
  1417.     gposxfrac[1] = px - (float)(ipx); gposxfrac[0] = 1 - gposxfrac[1];
  1418.     gposyfrac[1] = py - (float)(ipy); gposyfrac[0] = 1 - gposyfrac[1];
  1419.     gpixy = (long)&sptr[ipy*VSID + ipx];
  1420.     ftol(pz*FPREC-.5f,&gposz);
  1421.     for(gylookup[0]=-gposz,i=1;i<260;i++) gylookup[i] = gylookup[i-1]+FPREC;
  1422.  
  1423.     vs = (char *)*(long *)gpixy;
  1424.     if (ipz >= vs[1])
  1425.     {
  1426.         do
  1427.         {
  1428.             if (!vs[0]) return;
  1429.             vs += vs[0]*4;
  1430.         } while (ipz >= vs[1]);
  1431.         if (ipz < vs[3]) return;
  1432.         sz0 = vs[3];
  1433.     } else sz0 = 0;
  1434.     sz1 = vs[1];
  1435.  
  1436.     for(i=0;i<numang;i++)
  1437.     {
  1438.         _asm emms
  1439.  
  1440.         fcossin(((float)i+(float)angoff*.125f)*PI*2.0f/(float)numang,&vx,&vy);
  1441.  
  1442.         ftol(FPREC/fabs(vx),&gdz[0]);
  1443.         ftol(FPREC/fabs(vy),&gdz[1]);
  1444.  
  1445.         gixy[0] = (((*(signed long *)&vx)>>31) & (     -8)) +      4;
  1446.         gixy[1] = (((*(signed long *)&vy)>>31) & (VSID*-8)) + VSID*4;
  1447.         if (gdz[0] < 0) { gpz[0] = 0x7fffffff; gdz[0] = 0; } //Hack for divide overflow
  1448.         else ftol(gposxfrac[(*(unsigned long *)&vx)>>31]*(float)gdz[0],&gpz[0]);
  1449.         if (gdz[1] < 0) { gpz[1] = 0x7fffffff; gdz[1] = 0; } //Hack for divide overflow
  1450.         else ftol(gposyfrac[(*(unsigned long *)&vy)>>31]*(float)gdz[1],&gpz[1]);
  1451.  
  1452.         c = ce = &cf[128];
  1453.         v = vs; c->z0 = sz0; c->z1 = sz1;
  1454.             //Note!  These substitions are used in flashscan:
  1455.             //   c->i0 in flashscan is now: c->cx0
  1456.             //   c->i1 in flashscan is now: c->cx1
  1457.         c->cx0 = (((i+flashcnt+rand())&7)<<LOGFLASHVANG);
  1458.         c->cx1 = c->cx0+(1<<LOGFLASHVANG)-1;
  1459.  
  1460.         gxmax = flashradius;
  1461.  
  1462.             //Clip borders safely (MUST use integers!) - don't wrap around
  1463.         if (gixy[0] < 0) j = ipx; else j = VSID-1-ipx;
  1464.         q = mul64(gdz[0],j); q += (unsigned __int64)gpz[0];
  1465.         if (q < (unsigned __int64)gxmax) gxmax = (long)q;
  1466.         if (gixy[1] < 0) j = ipy; else j = VSID-1-ipy;
  1467.         q = mul64(gdz[1],j); q += (unsigned __int64)gpz[1];
  1468.         if (q < (unsigned __int64)gxmax) gxmax = (long)q;
  1469.  
  1470.     //------------------------------------------------------------------------
  1471.         j = (((unsigned long)(gpz[1]-gpz[0]))>>31);
  1472.         gx = gpz[j];
  1473.         ixy = gpixy;
  1474.         if (v == (char *)*(long *)gpixy) goto fdrawflor; goto fdrawceil;
  1475.  
  1476.         while (1)
  1477.         {
  1478.  
  1479. fdrawfwall:;
  1480.             if (v[1] != c->z1)
  1481.             {
  1482.                 if (v[1] > c->z1) c->z1 = v[1];
  1483.                 else { do
  1484.                 {
  1485.                     c->z1--; col = (long)&v[(c->z1-v[1])*4+4];
  1486.                     while (dmulrethigh(gylookup[c->z1],gfc[c->cx1].x,gfc[c->cx1].y,ogx) < 0)
  1487.                     {
  1488.                         mmxcoloradd((long *)col); c->cx1--;
  1489.                         if (c->cx0 > c->cx1) goto fdeletez;
  1490.                     }
  1491.                 } while (v[1] != c->z1); }
  1492.             }
  1493.  
  1494.             if (v == (char *)*(long *)ixy) goto fdrawflor;
  1495.  
  1496. //fdrawcwall:;
  1497.             if (v[3] != c->z0)
  1498.             {
  1499.                 if (v[3] < c->z0) c->z0 = v[3];
  1500.                 else { do
  1501.                 {
  1502.                     c->z0++; col = (long)&v[(c->z0-v[3])*4-4];
  1503.                     while (dmulrethigh(gylookup[c->z0],gfc[c->cx0].x,gfc[c->cx0].y,ogx) >= 0)
  1504.                     {
  1505.                         mmxcoloradd((long *)col); c->cx0++;
  1506.                         if (c->cx0 > c->cx1) goto fdeletez;
  1507.                     }
  1508.                 } while (v[3] != c->z0); }
  1509.             }
  1510.  
  1511. fdrawceil:;
  1512.             while (dmulrethigh(gylookup[c->z0],gfc[c->cx0].x,gfc[c->cx0].y,gx) >= 0)
  1513.             {
  1514.                 mmxcoloradd((long *)&v[-4]); c->cx0++;
  1515.                 if (c->cx0 > c->cx1) goto fdeletez;
  1516.             }
  1517.  
  1518. fdrawflor:;
  1519.             while (dmulrethigh(gylookup[c->z1],gfc[c->cx1].x,gfc[c->cx1].y,gx) < 0)
  1520.             {
  1521.                 mmxcoloradd((long *)&v[4]); c->cx1--;
  1522.                 if (c->cx0 > c->cx1) goto fdeletez;
  1523.             }
  1524.  
  1525. fafterdelete:;
  1526.             c--;
  1527.             if (c < &cf[128])
  1528.             {
  1529.                 ixy += gixy[j];
  1530.                 gpz[j] += gdz[j];
  1531.                 j = (((unsigned long)(gpz[1]-gpz[0]))>>31);
  1532.                 ogx = gx; gx = gpz[j];
  1533.  
  1534.                 if (gx > gxmax) break;
  1535.                 v = (char *)*(long *)ixy; c = ce;
  1536.             }
  1537.                 //Find highest intersecting vbuf slab
  1538.             while (1)
  1539.             {
  1540.                 if (!v[0]) goto fdrawfwall;
  1541.                 if (dmulrethigh(gylookup[v[2]+1],gfc[c->cx0].x,gfc[c->cx0].y,ogx) >= 0) break;
  1542.                 v += v[0]*4;
  1543.             }
  1544.                 //If next slab ALSO intersects, split cf!
  1545.             if (dmulrethigh(gylookup[v[v[0]*4+3]],gfc[c->cx1].x,gfc[c->cx1].y,ogx) < 0)
  1546.             {
  1547.                 col = c->cx1;
  1548.                 while (dmulrethigh(gylookup[v[2]+1],gfc[col].x,gfc[col].y,ogx) < 0)
  1549.                     col--;
  1550.                 ce++; if (ce >= &cf[192]) break; //Give it max=64 entries like ASM
  1551.                 for(c2=ce;c2>c;c2--) c2[0] = c2[-1];
  1552.                 c[1].cx1 = col; c->cx0 = col+1;
  1553.                 c[1].z1 = c->z0 = v[v[0]*4+3];
  1554.                 c++;
  1555.             }
  1556.         }
  1557. fcontinue:;
  1558.     }
  1559.  
  1560.     _asm emms
  1561.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,0);
  1562.     return;
  1563.  
  1564. fdeletez:;
  1565.     ce--; if (ce < &cf[128]) goto fcontinue;
  1566.     for(c2=c;c2<=ce;c2++) c2[0] = c2[1];
  1567.     goto fafterdelete;
  1568. }
  1569.  
  1570. #if (ESTNORMRAD == 2)
  1571. static signed char bitnum[32] =
  1572. {
  1573.     0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
  1574.     1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5
  1575. };
  1576. //static long bitsum[32] =
  1577. //{
  1578. //   0,-2,-1,-3, 0,-2,-1,-3, 1,-1, 0,-2, 1,-1, 0,-2,
  1579. //   2, 0, 1,-1, 2, 0, 1,-1, 3, 1, 2, 0, 3, 1, 2, 0
  1580. //};
  1581. static long bitsnum[32] =
  1582. {
  1583.     0        ,1-(2<<16),1-(1<<16),2-(3<<16),
  1584.     1        ,2-(2<<16),2-(1<<16),3-(3<<16),
  1585.     1+(1<<16),2-(1<<16),2        ,3-(2<<16),
  1586.     2+(1<<16),3-(1<<16),3        ,4-(2<<16),
  1587.     1+(2<<16),2        ,2+(1<<16),3-(1<<16),
  1588.     2+(2<<16),3        ,3+(1<<16),4-(1<<16),
  1589.     2+(3<<16),3+(1<<16),3+(2<<16),4,
  1590.     3+(3<<16),4+(1<<16),4+(2<<16),5
  1591. };
  1592. static float fsqrecip[5860]; //75*75 + 15*15 + 3*3 = 5859 is max value (5*5*5 box)
  1593. #endif
  1594.  
  1595. void estnorm (long x, long y, long z, point3d *fp)
  1596. {
  1597.     lpoint3d n;
  1598.     long *lptr, xx, yy, zz, b[5], i, j, k;
  1599.     float f;
  1600.  
  1601.     n.x = 0; n.y = 0; n.z = 0;
  1602.  
  1603. #if (ESTNORMRAD == 2)
  1604.     if (labs(x-xbsox) + labs(y-xbsoy) > 1)
  1605.     {
  1606.             //x,y not close enough to cache: calls expandbitstack 25 times :(
  1607.         xbsox = x; xbsoy = y; xbsof = 24*5;
  1608.         lptr = (long *)(&xbsbuf[24*5+1]);
  1609.         for(yy=-2;yy<=2;yy++)
  1610.             for(xx=-2;xx<=2;xx++,lptr-=10)
  1611.                 expandbitstack(x+xx,y+yy,(__int64 *)lptr);
  1612.     }
  1613.     else if (x != xbsox)
  1614.     {
  1615.             //shift xbsbuf cache left/right: calls expandbitstack 5 times :)
  1616.         if (x < xbsox) { xx = -2; xbsof -= 24*5; lptr = (long *)(&xbsbuf[xbsof+1]); }
  1617.                      else { xx = 2; lptr = (long *)(&xbsbuf[xbsof-5*5+1]); xbsof -= 1*5; }
  1618.         xbsox = x; if (xbsof < 0) xbsof += 25*5;
  1619.         for(yy=-2;yy<=2;yy++)
  1620.         {
  1621.             if (lptr < (long *)&xbsbuf[1]) lptr += 25*10;
  1622.             expandbitstack(x+xx,y+yy,(__int64 *)lptr);
  1623.             lptr -= 5*10;
  1624.         }
  1625.     }
  1626.     else if (y != xbsoy)
  1627.     {
  1628.             //shift xbsbuf cache up/down: calls expandbitstack 5 times :)
  1629.         if (y < xbsoy) { yy = -2; xbsof -= 20*5; lptr = (long *)(&xbsbuf[xbsof+1]); }
  1630.                      else { yy = 2; lptr = (long *)(&xbsbuf[xbsof+1]); xbsof -= 5*5; }
  1631.         xbsoy = y; if (xbsof < 0) xbsof += 25*5;
  1632.         for(xx=-2;xx<=2;xx++)
  1633.         {
  1634.             if (lptr < (long *)&xbsbuf[1]) lptr += 25*10;
  1635.             expandbitstack(x+xx,y+yy,(__int64 *)lptr);
  1636.             lptr -= 1*10;
  1637.         }
  1638.     }
  1639.  
  1640.     z -= 2;
  1641.     if ((z&31) <= 27) //2 <= (z&31) <= 29
  1642.         { lptr = (long *)((long)(&xbsbuf[xbsof+1]) + ((z&~31)>>3)); z &= 31; }
  1643.     else
  1644.         { lptr = (long *)((long)(&xbsbuf[xbsof+1]) + (z>>3)); z &= 7; }
  1645.  
  1646.     for(yy=-2;yy<=2;yy++)
  1647.     {
  1648.         if (lptr >= (long *)&xbsbuf[1+10*5])
  1649.         {
  1650.             b[0] = ((lptr[  0]>>z)&31); b[1] = ((lptr[-10]>>z)&31);
  1651.             b[2] = ((lptr[-20]>>z)&31); b[3] = ((lptr[-30]>>z)&31);
  1652.             b[4] = ((lptr[-40]>>z)&31); lptr -= 50;
  1653.         }
  1654.         else
  1655.         {
  1656.             b[0] = ((lptr[0]>>z)&31); lptr -= 10; if (lptr < (long *)&xbsbuf[1]) lptr += 25*10;
  1657.             b[1] = ((lptr[0]>>z)&31); lptr -= 10; if (lptr < (long *)&xbsbuf[1]) lptr += 25*10;
  1658.             b[2] = ((lptr[0]>>z)&31); lptr -= 10; if (lptr < (long *)&xbsbuf[1]) lptr += 25*10;
  1659.             b[3] = ((lptr[0]>>z)&31); lptr -= 10; if (lptr < (long *)&xbsbuf[1]) lptr += 25*10;
  1660.             b[4] = ((lptr[0]>>z)&31); lptr -= 10; if (lptr < (long *)&xbsbuf[1]) lptr += 25*10;
  1661.         }
  1662.  
  1663.             //Make filter spherical
  1664.         //if (yy&1) { b[0] &= 0xe; b[4] &= 0xe; }
  1665.         //else if (yy) { b[0] &= 0x4; b[1] &= 0xe; b[3] &= 0xe; b[4] &= 0x4; }
  1666.  
  1667.         n.x += ((bitnum[b[4]]-bitnum[b[0]])<<1)+bitnum[b[3]]-bitnum[b[1]];
  1668.         j = bitsnum[b[0]]+bitsnum[b[1]]+bitsnum[b[2]]+bitsnum[b[3]]+bitsnum[b[4]];
  1669.         n.z += j; n.y += (*(signed short *)&j)*yy;
  1670.     }
  1671.     n.z >>= 16;
  1672. #else
  1673.     for(yy=-ESTNORMRAD;yy<=ESTNORMRAD;yy++)
  1674.         for(xx=-ESTNORMRAD;xx<=ESTNORMRAD;xx++)
  1675.             for(zz=-ESTNORMRAD;zz<=ESTNORMRAD;zz++)
  1676.                 if (isvoxelsolid(x+xx,y+yy,z+zz))
  1677.                     { n.x += xx; n.y += yy; n.z += zz; }
  1678. #endif
  1679.  
  1680. #if 1
  1681.     f = fsqrecip[n.x*n.x + n.y*n.y + n.z*n.z];
  1682.     fp->x = ((float)n.x)*f; fp->y = ((float)n.y)*f; fp->z = ((float)n.z)*f;
  1683. #else
  1684.  
  1685.         //f = 1.0 / sqrt((double)(n.x*n.x + n.y*n.y + n.z*n.z));
  1686.         //fp->x = f*(float)n.x; fp->y = f*(float)n.y; fp->z = f*(float)n.z;
  1687.     zz = n.x*n.x + n.y*n.y + n.z*n.z;
  1688.     if (cputype&(1<<25))
  1689.     {
  1690.         _asm
  1691.         {
  1692.             cvtsi2ss xmm0, zz
  1693.             rsqrtss xmm0, xmm0
  1694.             ;movss f, xmm0
  1695.  
  1696.                 ;fp->x = f*(float)n.x; fp->y = f*(float)n.y; fp->z = f*(float)n.z;
  1697.             cvtsi2ss xmm1, n.z
  1698.             shufps xmm0, xmm0, 0
  1699.             mov eax, fp
  1700.             movlhps xmm1, xmm1
  1701.             cvtpi2ps xmm1, n
  1702.             mulps xmm0, xmm1
  1703.             movlps [eax], xmm0
  1704.             movhlps xmm0, xmm0
  1705.             movss [eax+8], xmm0
  1706.         }
  1707.     }
  1708.     else
  1709.     {
  1710.         _asm
  1711.         {
  1712.             pi2fd mm0, zz       ;mm0:     0          zz
  1713.             pfrsqrt mm0, mm0    ;mm0: 1/sqrt(zz) 1/sqrt(zz)
  1714.             pi2fd mm1, n.x      ;mm1:     0         n.x
  1715.             pi2fd mm2, n.y      ;mm2:     0         n.y
  1716.             punpckldq mm1, mm2  ;mm1:    n.y        n.x
  1717.             pi2fd mm2, n.z      ;mm2:     0         n.z
  1718.             pfmul mm1, mm0      ;mm1:n.y/sqrt(zz) n.x/sqrt(zz)
  1719.             pfmul mm2, mm0      ;mm2:     0       n.z/sqrt(zz)
  1720.             mov eax, fp
  1721.             movq [eax], mm1
  1722.             movd [eax+8], mm2
  1723.             femms
  1724.         }
  1725.     }
  1726. #endif
  1727. }
  1728.  
  1729. static long vspan (long x, long y0, long y1)
  1730. {
  1731.     long y, yy, *bbufx;
  1732.  
  1733.     y = (y0>>5); bbufx = &bbuf[x][0];
  1734.     if ((y1>>5) == y)
  1735.     {
  1736.         yy = bbufx[y]; bbufx[y] &= ~(p2m[y1&31]^p2m[y0&31]);
  1737.         return(bbufx[y] ^ yy);
  1738.     }
  1739.  
  1740.     if (!(bbufx[y]&(~p2m[y0&31])))
  1741.         if (!(bbufx[y1>>5]&p2m[y1&31]))
  1742.         {
  1743.             for(yy=(y1>>5)-1;yy>y;yy--)
  1744.                 if (bbufx[yy]) goto vspan_skip;
  1745.             return(0);
  1746.         }
  1747. vspan_skip:;
  1748.     bbufx[y] &= p2m[y0&31];
  1749.     bbufx[y1>>5] &= (~p2m[y1&31]);
  1750.     for(yy=(y1>>5)-1;yy>y;yy--) bbufx[yy] = 0;
  1751.     return(1);
  1752. }
  1753.  
  1754. static long docube (long x, long y, long z)
  1755. {
  1756.     long x0, y0, x1, y1, g;
  1757.  
  1758.     ffxptr = &ffx[(z+1)*z-1];
  1759.     x0 = (long)ffxptr[x].x; x1 = (long)ffxptr[x].y;
  1760.     y0 = (long)ffxptr[y].x; y1 = (long)ffxptr[y].y;
  1761.     for(g=0;x0<x1;x0++) g |= vspan(x0,y0,y1);
  1762.     return(g);
  1763. }
  1764.  
  1765. void setnormflash (float px, float py, float pz, long flashradius, long intens)
  1766. {
  1767.     point3d fp;
  1768.     float f, fintens;
  1769.     long i, j, k, l, m, x, y, z, xx, yy, xi, yi, xe, ye, ipx, ipy, ipz;
  1770.     long ceilnum, sq;
  1771.     char *v;
  1772.  
  1773.     ipx = (long)px; ipy = (long)py; ipz = (long)pz;
  1774.     vx5.minx = ipx-flashradius+1; vx5.maxx = ipx+flashradius;
  1775.     vx5.miny = ipy-flashradius+1; vx5.maxy = ipy+flashradius;
  1776.     vx5.minz = ipz-flashradius+1; vx5.maxz = ipz+flashradius;
  1777.  
  1778.     if (isvoxelsolid(ipx,ipy,ipz)) return;
  1779.  
  1780.     fintens = intens;
  1781.     if (flashradius > (GSIZ>>1)) flashradius = (GSIZ>>1);
  1782.  
  1783.     xbsox = -17;
  1784.  
  1785.         //       ΪΔ 7ΔΏ
  1786.         //      11  . 8
  1787.         //  ΪΔ11ΔΕΔ 4ΔΕΔ 8ΔΒΔ 7ΔΏ
  1788.         //  3 |  0  + 1  | 2  + 3
  1789.         //  ΐΔ10ΔΕΔ 5ΔΕΔ 9ΔΑΔ 6ΔΩ
  1790.         //      10  . 9
  1791.         //       ΐΔ 6ΔΩ
  1792.  
  1793.         //Do left&right faces of the cube
  1794.     for(j=1;j>=0;j--)
  1795.     {
  1796.         clearbuf((void *)bbuf,GSIZ*(GSIZ>>5),0xffffffff);
  1797.         for(y=1;y<flashradius;y++)
  1798.         {
  1799.             if (j) yy = ipy-y; else yy = ipy+y;
  1800.             for(xi=1,xe=y+1;xi>=-1;xi-=2,xe=-xe)
  1801.                 for(x=(xi>>1);x!=xe;x+=xi)
  1802.                 {
  1803.                     xx = ipx+x;
  1804.                     if ((unsigned long)(xx|yy) >= VSID) continue;
  1805.                     v = sptr[yy*VSID+xx]; i = 0; sq = x*x+y*y;
  1806.                     while (1)
  1807.                     {
  1808.                         for(z=v[1];z<=v[2];z++)
  1809.                         {
  1810.                             if (z-ipz < 0) { tbuf2[i] = z-ipz; tbuf2[i+1] = (long)&v[(z-v[1])*4+4]; i += 2; }
  1811.                             else
  1812.                             {
  1813.                                 //if (z-ipz < -y) continue; //TEMP HACK!!!
  1814.                                 if (z-ipz > y) goto normflash_exwhile1;
  1815.                                 if (!docube(x,z-ipz,y)) continue;
  1816.                                 estnorm(xx,yy,z,&fp); if (j) fp.y = -fp.y;
  1817.                                 f = fp.x*x + fp.y*y + fp.z*(z-ipz);
  1818.                                 if (*(long *)&f > 0) addusb(&v[(z-v[1])*4+7],f*fintens/((z-ipz)*(z-ipz)+sq));
  1819.                             }
  1820.                         }
  1821.                         if (!v[0]) break;
  1822.                         ceilnum = v[2]-v[1]-v[0]+2; v += v[0]*4;
  1823.                         for(z=v[3]+ceilnum;z<v[3];z++)
  1824.                         {
  1825.                             if (z < ipz) { tbuf2[i] = z-ipz; tbuf2[i+1] = (long)&v[(z-v[3])*4]; i += 2; }
  1826.                             else
  1827.                             {
  1828.                                 //if (z-ipz < -y) continue; //TEMP HACK!!!
  1829.                                 if (z-ipz > y) goto normflash_exwhile1;
  1830.                                 if (!docube(x,z-ipz,y)) continue;
  1831.                                 estnorm(xx,yy,z,&fp); if (j) fp.y = -fp.y;
  1832.                                 f = fp.x*x + fp.y*y + fp.z*(z-ipz);
  1833.                                 if (*(long *)&f > 0) addusb(&v[(z-v[3])*4+3],f*fintens/((z-ipz)*(z-ipz)+sq));
  1834.                             }
  1835.                         }
  1836.                     }
  1837. normflash_exwhile1:;
  1838.                     while (i > 0)
  1839.                     {
  1840.                         i -= 2; if (tbuf2[i] < -y) break;
  1841.                         if (!docube(x,tbuf2[i],y)) continue;
  1842.                         estnorm(xx,yy,tbuf2[i]+ipz,&fp); if (j) fp.y = -fp.y;
  1843.                         f = fp.x*x + fp.y*y + fp.z*tbuf2[i];
  1844.                         if (*(long *)&f > 0) addusb(&((char *)tbuf2[i+1])[3],f*fintens/(tbuf2[i]*tbuf2[i]+sq));
  1845.                     }
  1846.                 }
  1847.         }
  1848.     }
  1849.  
  1850.         //Do up&down faces of the cube
  1851.     for(j=1;j>=0;j--)
  1852.     {
  1853.         clearbuf((void *)bbuf,GSIZ*(GSIZ>>5),0xffffffff);
  1854.         for(y=1;y<flashradius;y++)
  1855.         {
  1856.             if (j) xx = ipx-y; else xx = ipx+y;
  1857.             for(xi=1,xe=y+1;xi>=-1;xi-=2,xe=-xe)
  1858.                 for(x=(xi>>1);x!=xe;x+=xi)
  1859.                 {
  1860.                     yy = ipy+x;
  1861.                     if ((unsigned long)(xx|yy) >= VSID) continue;
  1862.                     v = sptr[yy*VSID+xx]; i = 0; sq = x*x+y*y; m = x+xi-xe;
  1863.                     while (1)
  1864.                     {
  1865.                         for(z=v[1];z<=v[2];z++)
  1866.                         {
  1867.                             if (z-ipz < 0) { tbuf2[i] = z-ipz; tbuf2[i+1] = (long)&v[(z-v[1])*4+4]; i += 2; }
  1868.                             else
  1869.                             {
  1870.                                 //if (z-ipz < -y) continue; //TEMP HACK!!!
  1871.                                 if (z-ipz > y) goto normflash_exwhile2;
  1872.                                 if ((!docube(x,z-ipz,y)) || (!m)) continue;
  1873.                                 estnorm(xx,yy,z,&fp); if (j) fp.x = -fp.x;
  1874.                                 f = fp.x*y + fp.y*x + fp.z*(z-ipz);
  1875.                                 if (*(long *)&f > 0) addusb(&v[(z-v[1])*4+7],f*fintens/((z-ipz)*(z-ipz)+sq));
  1876.                             }
  1877.                         }
  1878.                         if (!v[0]) break;
  1879.                         ceilnum = v[2]-v[1]-v[0]+2; v += v[0]*4;
  1880.                         for(z=v[3]+ceilnum;z<v[3];z++)
  1881.                         {
  1882.                             if (z < ipz) { tbuf2[i] = z-ipz; tbuf2[i+1] = (long)&v[(z-v[3])*4]; i += 2; }
  1883.                             else
  1884.                             {
  1885.                                 //if (z-ipz < -y) continue; //TEMP HACK!!!
  1886.                                 if (z-ipz > y) goto normflash_exwhile2;
  1887.                                 if ((!docube(x,z-ipz,y)) || (!m)) continue;
  1888.                                 estnorm(xx,yy,z,&fp); if (j) fp.x = -fp.x;
  1889.                                 f = fp.x*y + fp.y*x + fp.z*(z-ipz);
  1890.                                 if (*(long *)&f > 0) addusb(&v[(z-v[3])*4+3],f*fintens/((z-ipz)*(z-ipz)+sq));
  1891.                             }
  1892.                         }
  1893.                     }
  1894. normflash_exwhile2:;
  1895.                     while (i > 0)
  1896.                     {
  1897.                         i -= 2; if (tbuf2[i] < -y) break;
  1898.                         if ((!docube(x,tbuf2[i],y)) || (!m)) continue;
  1899.                         estnorm(xx,yy,tbuf2[i]+ipz,&fp); if (j) fp.x = -fp.x;
  1900.                         f = fp.x*y + fp.y*x + fp.z*tbuf2[i];
  1901.                         if (*(long *)&f > 0) addusb(&((char *)tbuf2[i+1])[3],f*fintens/(tbuf2[i]*tbuf2[i]+sq));
  1902.                     }
  1903.                 }
  1904.         }
  1905.     }
  1906.  
  1907.         //Do the bottom face of the cube
  1908.     clearbuf((void *)bbuf,GSIZ*(GSIZ>>5),0xffffffff);
  1909.     for(yi=1,ye=flashradius+1;yi>=-1;yi-=2,ye=-ye)
  1910.         for(y=(yi>>1);y!=ye;y+=yi)
  1911.             for(xi=1,xe=flashradius+1;xi>=-1;xi-=2,xe=-xe)
  1912.                 for(x=(xi>>1);x!=xe;x+=xi)
  1913.                 {
  1914.                     xx = ipx+x; yy = ipy+y;
  1915.                     if ((unsigned long)(xx|yy) >= VSID) goto normflash_exwhile3;
  1916.                     k = max(labs(x),labs(y));
  1917.  
  1918.                     v = sptr[yy*VSID+xx]; sq = x*x+y*y;
  1919.                     while (1)
  1920.                     {
  1921.                         for(z=v[1];z<=v[2];z++)
  1922.                         {
  1923.                             if (z-ipz < k) continue;
  1924.                             if (z-ipz >= flashradius) goto normflash_exwhile3;
  1925.                             if ((!docube(x,y,z-ipz)) || (z-ipz == k)) continue;
  1926.                             estnorm(xx,yy,z,&fp);
  1927.                             f = fp.x*x + fp.y*y + fp.z*(z-ipz);
  1928.                             if (*(long *)&f > 0) addusb(&v[(z-v[1])*4+7],f*fintens/((z-ipz)*(z-ipz)+sq));
  1929.                         }
  1930.                         if (!v[0]) break;
  1931.                         ceilnum = v[2]-v[1]-v[0]+2; v += v[0]*4;
  1932.                         for(z=v[3]+ceilnum;z<v[3];z++)
  1933.                         {
  1934.                             if (z-ipz < k) continue;
  1935.                             if (z-ipz >= flashradius) goto normflash_exwhile3;
  1936.                             if ((!docube(x,y,z-ipz)) || (z-ipz <= k)) continue;
  1937.                             estnorm(xx,yy,z,&fp);
  1938.                             f = fp.x*x + fp.y*y + fp.z*(z-ipz);
  1939.                             if (*(long *)&f > 0) addusb(&v[(z-v[3])*4+3],f*fintens/((z-ipz)*(z-ipz)+sq));
  1940.                         }
  1941.                     }
  1942. normflash_exwhile3:;
  1943.                 }
  1944.  
  1945.  
  1946.         //Do the top face of the cube
  1947.     clearbuf((void *)bbuf,GSIZ*(GSIZ>>5),0xffffffff);
  1948.     for(yi=1,ye=flashradius+1;yi>=-1;yi-=2,ye=-ye)
  1949.         for(y=(yi>>1);y!=ye;y+=yi)
  1950.             for(xi=1,xe=flashradius+1;xi>=-1;xi-=2,xe=-xe)
  1951.                 for(x=(xi>>1);x!=xe;x+=xi)
  1952.                 {
  1953.                     xx = ipx+x; yy = ipy+y;
  1954.                     if ((unsigned long)(xx|yy) >= VSID) goto normflash_exwhile4;
  1955.                     k = max(labs(x),labs(y)); m = ((x+xi != xe) && (y+yi != ye));
  1956.  
  1957.                     v = sptr[yy*VSID+xx]; i = 0; sq = x*x+y*y;
  1958.                     while (1)
  1959.                     {
  1960.                         for(z=v[1];z<=v[2];z++)
  1961.                         {
  1962.                             if (ipz-z >= flashradius) continue;
  1963.                             if (ipz-z < k) goto normflash_exwhile4;
  1964.                             tbuf2[i] = ipz-z; tbuf2[i+1] = (long)&v[(z-v[1])*4+4]; i += 2;
  1965.                         }
  1966.                         if (!v[0]) break;
  1967.                         ceilnum = v[2]-v[1]-v[0]+2; v += v[0]*4;
  1968.                         for(z=v[3]+ceilnum;z<v[3];z++)
  1969.                         {
  1970.                             if (ipz-z >= flashradius) continue;
  1971.                             if (ipz-z < k) goto normflash_exwhile4;
  1972.                             tbuf2[i] = ipz-z; tbuf2[i+1] = (long)&v[(z-v[3])*4]; i += 2;
  1973.                         }
  1974.                     }
  1975. normflash_exwhile4:;
  1976.                     while (i > 0)
  1977.                     {
  1978.                         i -= 2;
  1979.                         if ((!docube(x,y,tbuf2[i])) || (tbuf2[i] <= k)) continue;
  1980.                         estnorm(xx,yy,ipz-tbuf2[i],&fp);
  1981.                         f = fp.x*x + fp.y*y - fp.z*tbuf2[i];
  1982.                         if (*(long *)&f > 0) addusb(&((char *)tbuf2[i+1])[3],f*fintens/(tbuf2[i]*tbuf2[i]+sq));
  1983.                     }
  1984.                 }
  1985.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,0);
  1986. }
  1987.  
  1988. void hline (float x0, float y0, float x1, float y1, long *ix0, long *ix1)
  1989. {
  1990.     float dyx;
  1991.  
  1992.     dyx = (y1-y0) * grd; //grd = 1/(x1-x0)
  1993.  
  1994.           if (y0 < wy0) ftol((wy0-y0)/dyx+x0,ix0);
  1995.     else if (y0 > wy1) ftol((wy1-y0)/dyx+x0,ix0);
  1996.     else ftol(x0,ix0);
  1997.           if (y1 < wy0) ftol((wy0-y0)/dyx+x0,ix1);
  1998.     else if (y1 > wy1) ftol((wy1-y0)/dyx+x0,ix1);
  1999.     else ftol(x1,ix1);
  2000.     if ((*ix0) < iwx0) (*ix0) = iwx0;
  2001.     if ((*ix0) > iwx1) (*ix0) = iwx1; //(*ix1) = min(max(*ix1,wx0),wx1);
  2002.     gline(labs((*ix1)-(*ix0)),(float)(*ix0),((*ix0)-x1)*dyx + y1,
  2003.                                       (float)(*ix1),((*ix1)-x1)*dyx + y1);
  2004. }
  2005.  
  2006. void vline (float x0, float y0, float x1, float y1, long *iy0, long *iy1)
  2007. {
  2008.     float dxy;
  2009.  
  2010.     dxy = (x1-x0) * grd; //grd = 1/(y1-y0)
  2011.  
  2012.           if (x0 < wx0) ftol((wx0-x0)/dxy+y0,iy0);
  2013.     else if (x0 > wx1) ftol((wx1-x0)/dxy+y0,iy0);
  2014.     else ftol(y0,iy0);
  2015.           if (x1 < wx0) ftol((wx0-x0)/dxy+y0,iy1);
  2016.     else if (x1 > wx1) ftol((wx1-x0)/dxy+y0,iy1);
  2017.     else ftol(y1,iy1);
  2018.     if ((*iy0) < iwy0) (*iy0) = iwy0;
  2019.     if ((*iy0) > iwy1) (*iy0) = iwy1;
  2020.     gline(labs((*iy1)-(*iy0)),((*iy0)-y1)*dxy + x1,(float)(*iy0),
  2021.                                       ((*iy1)-y1)*dxy + x1,(float)(*iy1));
  2022. }
  2023.  
  2024. static float optistrx, optistry, optiheix, optiheiy, optiaddx, optiaddy;
  2025.  
  2026. static __int64 foglut[2048], fogcol;
  2027. static long ofogdist = -1;
  2028.  
  2029. #ifdef _MSC_VER
  2030.  
  2031. #ifdef __cplusplus
  2032. extern "C" {
  2033. #endif
  2034. extern void *opti4asm;
  2035. #define opti4 ((point4d *)&opti4asm)
  2036. #ifdef __cplusplus
  2037. }
  2038. #endif
  2039.  
  2040. void (*hrend)(long,long,long,long,long,long);
  2041. void (*vrend)(long,long,long,long,long);
  2042.  
  2043. #if (USEZBUFFER != 1)
  2044. void hrendnoz (long sx, long sy, long p1, long plc, long incr, long j)
  2045. {
  2046.     sy = ylookup[sy]+frameplace; p1 = sy+(p1<<2); sy += (sx<<2);
  2047.     do
  2048.     {
  2049.         *(long *)sy = angstart[plc>>16][j].col;
  2050.         plc += incr; sy += 4;
  2051.     } while (sy != p1);
  2052. }
  2053.  
  2054. void vrendnoz (long sx, long sy, long p1, long iplc, long iinc)
  2055. {
  2056.     sy = ylookup[sy]+(sx<<2)+frameplace;
  2057.     for(;sx<p1;sx++)
  2058.     {
  2059.         *(long *)sy = angstart[uurend[sx]>>16][iplc].col;
  2060.         uurend[sx] += uurend[sx+MAXXDIM]; sy += 4; iplc += iinc;
  2061.     }
  2062. }
  2063.  
  2064. #else
  2065.  
  2066. #if 0
  2067.     //Example C code
  2068. void hrendz (long sx, long sy, long p1, long plc, long incr, long j)
  2069. {
  2070.     long p0, i; float dirx, diry;
  2071.     p0 = ylookup[sy]+(sx<<2)+frameplace;
  2072.     p1 = ylookup[sy]+(p1<<2)+frameplace;
  2073.     dirx = optistrx*(float)sx + optiheix*(float)sy + optiaddx;
  2074.     diry = optistry*(float)sx + optiheiy*(float)sy + optiaddy;
  2075.     i = zbufoff;
  2076.     do
  2077.     {
  2078.         *(long *)p0 = angstart[plc>>16][j].col;
  2079.         *(float *)(p0+i) = (float)angstart[plc>>16][j].dist/sqrt(dirx*dirx+diry*diry);
  2080.         dirx += optistrx; diry += optistry; plc += incr; p0 += 4;
  2081.     } while (p0 != p1);
  2082. }
  2083.  
  2084.     //Example C code
  2085. void vrendz (long sx, long sy, long p1, long iplc, long iinc)
  2086. {
  2087.     float dirx, diry; long i, p0;
  2088.     p0 = ylookup[sy]+(sx<<2)+frameplace;
  2089.     p1 = ylookup[sy]+(p1<<2)+frameplace;
  2090.     dirx = optistrx*(float)sx + optiheix*(float)sy + optiaddx;
  2091.     diry = optistry*(float)sx + optiheiy*(float)sy + optiaddy;
  2092.     i = zbufoff;
  2093.     while (p0 < p1)
  2094.     {
  2095.         *(long *)p0 = angstart[uurend[sx]>>16][iplc].col;
  2096.         *(float *)(p0+i) = (float)angstart[uurend[sx]>>16][iplc].dist/sqrt(dirx*dirx+diry*diry);
  2097.         dirx += optistrx; diry += optistry; uurend[sx] += uurend[sx+MAXXDIM]; p0 += 4; iplc += iinc; sx++;
  2098.     }
  2099. }
  2100.  
  2101.     //Example C code
  2102. void hrendzfog (long sx, long sy, long p1, long plc, long incr, long j)
  2103. {
  2104.     long p0, i, k, l; float dirx, diry;
  2105.     p0 = ylookup[sy]+(sx<<2)+frameplace;
  2106.     p1 = ylookup[sy]+(p1<<2)+frameplace;
  2107.     dirx = optistrx*(float)sx + optiheix*(float)sy + optiaddx;
  2108.     diry = optistry*(float)sx + optiheiy*(float)sy + optiaddy;
  2109.     i = zbufoff;
  2110.     do
  2111.     {
  2112.         k = angstart[plc>>16][j].col;
  2113.         l = angstart[plc>>16][j].dist;
  2114.         l = (foglut[l>>20]&32767);
  2115.         *(long *)p0 = ((((( vx5.fogcol     &255)-( k     &255))*l)>>15)    ) +
  2116.                           ((((((vx5.fogcol>> 8)&255)-((k>> 8)&255))*l)>>15)<< 8) +
  2117.                           ((((((vx5.fogcol>>16)&255)-((k>>16)&255))*l)>>15)<<16)+k;
  2118.         *(float *)(p0+i) = (float)angstart[plc>>16][j].dist/sqrt(dirx*dirx+diry*diry);
  2119.         dirx += optistrx; diry += optistry; plc += incr; p0 += 4;
  2120.     } while (p0 != p1);
  2121. }
  2122.  
  2123.     //Example C code
  2124. void vrendzfog (long sx, long sy, long p1, long iplc, long iinc)
  2125. {
  2126.     float dirx, diry; long i, k, l, p0;
  2127.     p0 = ylookup[sy]+(sx<<2)+frameplace;
  2128.     p1 = ylookup[sy]+(p1<<2)+frameplace;
  2129.     dirx = optistrx*(float)sx + optiheix*(float)sy + optiaddx;
  2130.     diry = optistry*(float)sx + optiheiy*(float)sy + optiaddy;
  2131.     i = zbufoff;
  2132.     while (p0 < p1)
  2133.     {
  2134.         k = angstart[uurend[sx]>>16][iplc].col;
  2135.         l = angstart[uurend[sx]>>16][iplc].dist;
  2136.         l = (foglut[l>>20]&32767);
  2137.         *(long *)p0 = ((((( vx5.fogcol     &255)-( k     &255))*l)>>15)    ) +
  2138.                           ((((((vx5.fogcol>> 8)&255)-((k>> 8)&255))*l)>>15)<< 8) +
  2139.                           ((((((vx5.fogcol>>16)&255)-((k>>16)&255))*l)>>15)<<16)+k;
  2140.         *(float *)(p0+i) = (float)angstart[uurend[sx]>>16][iplc].dist/sqrt(dirx*dirx+diry*diry);
  2141.         dirx += optistrx; diry += optistry; uurend[sx] += uurend[sx+MAXXDIM]; p0 += 4; iplc += iinc; sx++;
  2142.     }
  2143. }
  2144.  
  2145. #endif
  2146.  
  2147. void hrendzsse (long sx, long sy, long p1, long plc, long incr, long j)
  2148. {
  2149.     _asm
  2150.     {
  2151.         push esi
  2152.         push edi
  2153. beghasm_p3:
  2154.         mov eax, sx
  2155.         mov ecx, sy
  2156.         mov esi, p1
  2157.         mov edx, ylookup[ecx*4]
  2158.         add edx, frameplace
  2159.         lea edi, [edx+eax*4]
  2160.         lea esi, [edx+esi*4]
  2161.  
  2162.         and eax, 0xfffffffc
  2163.         cvtsi2ss xmm0, eax
  2164.         cvtsi2ss xmm4, ecx
  2165.         movss xmm1, xmm0
  2166.         movss xmm5, xmm4
  2167.         mulss xmm0, optistrx
  2168.         mulss xmm1, optistry
  2169.         mulss xmm4, optiheix
  2170.         mulss xmm5, optiheiy
  2171.         addss xmm0, optiaddx
  2172.         addss xmm1, optiaddy
  2173.         addss xmm0, xmm4
  2174.         addss xmm1, xmm5
  2175.  
  2176.         mov ecx, zbufoff
  2177.         mov edx, j
  2178.         movd mm6, plc
  2179.         movd mm7, incr
  2180.  
  2181.         shufps xmm0, xmm0, 0
  2182.         shufps xmm1, xmm1, 0
  2183.         movaps xmm2, opti4asm[2*16]
  2184.         movaps xmm3, opti4asm[3*16]
  2185.         addps xmm0, opti4asm[0*16]
  2186.         addps xmm1, opti4asm[1*16]
  2187.             ;xmm0 =  xmm0      ^2 +  xmm1      ^2        (p)
  2188.             ;xmm2 = (xmm0+xmm2)^2 + (xmm1+xmm3)^2 - xmm0 (v)
  2189.             ;xmm1 = ...                                  (a)
  2190.         addps xmm2, xmm0  ;This block converts inner loop...
  2191.         addps xmm3, xmm1  ;from: 1 / sqrt(x*x + y*y), x += xi, y += yi;
  2192.         mulps xmm0, xmm0  ;  to: 1 / sqrt(p), p += v, v += a;
  2193.         mulps xmm1, xmm1
  2194.         mulps xmm2, xmm2
  2195.         mulps xmm3, xmm3
  2196.         addps xmm0, xmm1
  2197.         movaps xmm1, opti4asm[4*16]
  2198.         addps xmm2, xmm3
  2199.         subps xmm2, xmm0
  2200.  
  2201.             ;Do first 0-3 pixels to align unrolled loop of 4
  2202.         test edi, 15
  2203.         jz short skip1ha
  2204.  
  2205.         test edi, 8
  2206.         jz short skipshufa
  2207.         shufps xmm0, xmm0, 0x4e ;rotate right by 2
  2208. skipshufa:
  2209.         test edi, 4
  2210.         jz short skipshufb
  2211.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2212. skipshufb:
  2213.  
  2214. beg1ha:
  2215.         pextrw eax, mm6, 1
  2216.         paddd mm6, mm7
  2217.         mov eax, angstart[eax*4]
  2218.         movd mm0, [eax+edx*8]
  2219.         movd [edi], mm0
  2220.         cvtsi2ss xmm7, [eax+edx*8+4]
  2221.         rsqrtss xmm3, xmm0
  2222.         mulss xmm7, xmm3
  2223.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2224.         movss [edi+ecx], xmm7
  2225.         add edi, 4
  2226.         cmp edi, esi
  2227.         jz short endh
  2228.         test edi, 15
  2229.         jnz short beg1ha
  2230.  
  2231.         addps xmm0, xmm2
  2232.         addps xmm2, xmm1
  2233. skip1ha:
  2234.         lea eax, [edi+16]      ;these 3 lines re-ordered
  2235.         cmp eax, esi
  2236.         ja short skip4h
  2237.  
  2238.         movq mm0, mm6          ;mm0: 0,plc
  2239.         paddd mm0, mm7         ;mm0: 0,plc+inc
  2240.         punpckldq mm7, mm7     ;mm7: inc,inc
  2241.         punpckldq mm6, mm0     ;mm6: plc+inc,plc
  2242.         paddd mm7, mm7         ;mm7: inc+inc,inc+inc
  2243.  
  2244.         sub esi, 16
  2245.  
  2246.          ;eax: temp   ³ mm0:  z0 argb0   argb1 argb0 ³ xmm0: plc3 plc2 plc1 plc0
  2247.          ;ebx:  -     ³ mm1:  z1 argb1               ³ xmm1: acc3 acc2 acc1 acc0
  2248.          ;ecx:zbufoff ³ mm2:  z2 argb2   argb3 argb2 ³ xmm2: inc3 inc2 inc1 inc0
  2249.          ;edx:  j     ³ mm3:  z3 argb3               ³ xmm3:  r3   r2   r1   r0
  2250.          ;esi:  -     ³ mm4:              z1    z0   ³ xmm4:            z3   z2
  2251.          ;edi:scroff  ³ mm5:              z3    z2   ³ xmm5:
  2252.          ;ebp:  -     ³ mm6: plc1 plc0               ³ xmm6:
  2253. beg4h: ;esp:  -     ³ mm7: inc1 inc0               ³ xmm7:  z3   z2   z1   z0
  2254.         pextrw eax, mm6, 1
  2255.         mov eax, angstart[eax*4]
  2256.         movq mm0, [eax+edx*8]
  2257.         pextrw eax, mm6, 3
  2258.         mov eax, angstart[eax*4]
  2259.         movq mm1, [eax+edx*8]
  2260.         paddd mm6, mm7
  2261.         pextrw eax, mm6, 1
  2262.         mov eax, angstart[eax*4]
  2263.         movq mm2, [eax+edx*8]
  2264.         pextrw eax, mm6, 3
  2265.         mov eax, angstart[eax*4]
  2266.         movq mm3, [eax+edx*8]
  2267.         paddd mm6, mm7
  2268.  
  2269.         movq mm4, mm0
  2270.         movq mm5, mm2
  2271.         punpckldq mm0, mm1
  2272.         punpckldq mm2, mm3
  2273.         movntq [edi], mm0
  2274.         movntq [edi+8], mm2
  2275.  
  2276.         punpckhdq mm4, mm1
  2277.         punpckhdq mm5, mm3
  2278.         cvtpi2ps xmm7, mm4
  2279.         cvtpi2ps xmm4, mm5
  2280.         rsqrtps xmm3, xmm0
  2281.         movlhps xmm7, xmm4
  2282.         mulps xmm7, xmm3
  2283.         movntps [edi+ecx], xmm7
  2284.         addps xmm0, xmm2
  2285.         addps xmm2, xmm1
  2286.  
  2287.         add edi, 16
  2288.         cmp edi, esi
  2289.         jbe short beg4h
  2290.         add esi, 16
  2291.         cmp edi, esi
  2292.         jae endh
  2293.  
  2294.         psrad mm7, 1    ;Restore mm7 from incr*2 to just incr for single loop
  2295. skip4h:
  2296. beg1h:
  2297.         pextrw eax, mm6, 1
  2298.         paddd mm6, mm7
  2299.         mov eax, angstart[eax*4]
  2300.         movd mm0, [eax+edx*8]
  2301.         movd [edi], mm0
  2302.         cvtsi2ss xmm7, [eax+edx*8+4]
  2303.         rsqrtss xmm3, xmm0
  2304.         mulss xmm7, xmm3
  2305.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2306.         movss [edi+ecx], xmm7
  2307.         add edi, 4
  2308.         cmp edi, esi
  2309.         jb short beg1h
  2310. endh: pop edi
  2311.         pop esi
  2312.     }
  2313. }
  2314.  
  2315. void hrendzfogsse (long sx, long sy, long p1, long plc, long incr, long j)
  2316. {
  2317.     static __int64 mm7bak;
  2318.     _asm
  2319.     {
  2320.         push esi
  2321.         push edi
  2322. beghasm_p3:
  2323.         mov eax, sx
  2324.         mov ecx, sy
  2325.         mov esi, p1
  2326.         mov edx, ylookup[ecx*4]
  2327.         add edx, frameplace
  2328.         lea edi, [edx+eax*4]
  2329.         lea esi, [edx+esi*4]
  2330.  
  2331.         and eax, 0xfffffffc
  2332.         cvtsi2ss xmm0, eax
  2333.         cvtsi2ss xmm4, ecx
  2334.         movss xmm1, xmm0
  2335.         movss xmm5, xmm4
  2336.         mulss xmm0, optistrx
  2337.         mulss xmm1, optistry
  2338.         mulss xmm4, optiheix
  2339.         mulss xmm5, optiheiy
  2340.         addss xmm0, optiaddx
  2341.         addss xmm1, optiaddy
  2342.         addss xmm0, xmm4
  2343.         addss xmm1, xmm5
  2344.  
  2345.         mov ecx, zbufoff
  2346.         mov edx, j
  2347.         movd mm6, plc
  2348.         movd mm7, incr
  2349.  
  2350.         shufps xmm0, xmm0, 0
  2351.         shufps xmm1, xmm1, 0
  2352.         movaps xmm2, opti4asm[2*16]
  2353.         movaps xmm3, opti4asm[3*16]
  2354.         addps xmm0, opti4asm[0*16]
  2355.         addps xmm1, opti4asm[1*16]
  2356.             ;xmm0 =  xmm0      ^2 +  xmm1      ^2        (p)
  2357.             ;xmm2 = (xmm0+xmm2)^2 + (xmm1+xmm3)^2 - xmm0 (v)
  2358.             ;xmm1 = ...                                  (a)
  2359.         addps xmm2, xmm0  ;This block converts inner loop...
  2360.         addps xmm3, xmm1  ;from: 1 / sqrt(x*x + y*y), x += xi, y += yi;
  2361.         mulps xmm0, xmm0  ;  to: 1 / sqrt(p), p += v, v += a;
  2362.         mulps xmm1, xmm1
  2363.         mulps xmm2, xmm2
  2364.         mulps xmm3, xmm3
  2365.         addps xmm0, xmm1
  2366.         movaps xmm1, opti4asm[4*16]
  2367.         addps xmm2, xmm3
  2368.         subps xmm2, xmm0
  2369.  
  2370.             ;Do first 0-3 pixels to align unrolled loop of 4
  2371.         test edi, 15
  2372.         jz short skip1ha
  2373.  
  2374.         test edi, 8
  2375.         jz short skipshufa
  2376.         shufps xmm0, xmm0, 0x4e ;rotate right by 2
  2377. skipshufa:
  2378.         test edi, 4
  2379.         jz short skipshufb
  2380.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2381. skipshufb:
  2382.  
  2383. beg1ha:
  2384.         pextrw eax, mm6, 1
  2385.         paddd mm6, mm7
  2386.         mov eax, angstart[eax*4]
  2387.  
  2388.             ;Z
  2389.         cvtsi2ss xmm7, [eax+edx*8+4]
  2390.         rsqrtss xmm3, xmm0
  2391.         mulss xmm7, xmm3
  2392.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2393.         movss [edi+ecx], xmm7
  2394.  
  2395.             ;Col
  2396.         punpcklbw mm0, [eax+edx*8]
  2397.         psrlw mm0, 8
  2398.         movq mm1, fogcol
  2399.         psubw mm1, mm0
  2400.         paddw mm1, mm1
  2401.         mov eax, [eax+edx*8+4]
  2402.         shr eax, 16+4
  2403.         pmulhw mm1, foglut[eax*8]
  2404.         paddw mm0, mm1
  2405.         packuswb mm0, mm1
  2406.         movd [edi], mm0
  2407.  
  2408.         add edi, 4
  2409.         cmp edi, esi
  2410.         jz short endh
  2411.         test edi, 15
  2412.         jnz short beg1ha
  2413.  
  2414.         addps xmm0, xmm2
  2415.         addps xmm2, xmm1
  2416. skip1ha:
  2417.         lea eax, [edi+16]      ;these 3 lines re-ordered
  2418.         cmp eax, esi
  2419.         ja short skip4h
  2420.  
  2421.         movq mm0, mm6          ;mm0: 0,plc
  2422.         paddd mm0, mm7         ;mm0: 0,plc+inc
  2423.         punpckldq mm7, mm7     ;mm7: inc,inc
  2424.         punpckldq mm6, mm0     ;mm6: plc+inc,plc
  2425.         paddd mm7, mm7         ;mm7: inc+inc,inc+inc
  2426.  
  2427.         sub esi, 16
  2428.  
  2429.          ;eax: temp   ³ mm0:  z0 argb0   argb1 argb0 ³ xmm0: plc3 plc2 plc1 plc0
  2430.          ;ebx:  -     ³ mm1:  z1 argb1               ³ xmm1: acc3 acc2 acc1 acc0
  2431.          ;ecx:zbufoff ³ mm2:  z2 argb2   argb3 argb2 ³ xmm2: inc3 inc2 inc1 inc0
  2432.          ;edx:  j     ³ mm3:  z3 argb3               ³ xmm3:  r3   r2   r1   r0
  2433.          ;esi:  -     ³ mm4:              z1    z0   ³ xmm4:            z3   z2
  2434.          ;edi:scroff  ³ mm5:              z3    z2   ³ xmm5:
  2435.          ;ebp:  -     ³ mm6: plc1 plc0               ³ xmm6:
  2436.          ;esp:  -     ³ mm7: inc1 inc0               ³ xmm7:  z3   z2   z1   z0
  2437.  
  2438.         movq mm7bak, mm7
  2439. beg4h:pextrw eax, mm6, 1
  2440.         mov eax, angstart[eax*4]
  2441.         movq mm4, [eax+edx*8]
  2442.         pextrw eax, mm6, 3
  2443.         mov eax, angstart[eax*4]
  2444.         movq mm1, [eax+edx*8]
  2445.         paddd mm6, mm7bak
  2446.         pextrw eax, mm6, 1
  2447.         mov eax, angstart[eax*4]
  2448.         movq mm5, [eax+edx*8]
  2449.         pextrw eax, mm6, 3
  2450.         mov eax, angstart[eax*4]
  2451.         movq mm3, [eax+edx*8]
  2452.         paddd mm6, mm7bak
  2453.  
  2454.         movq mm0, mm4
  2455.         movq mm2, mm5
  2456.  
  2457.             ;Do Z
  2458.         punpckhdq mm4, mm1
  2459.         punpckhdq mm5, mm3
  2460.         cvtpi2ps xmm7, mm4
  2461.         cvtpi2ps xmm4, mm5
  2462.         rsqrtps xmm3, xmm0
  2463.         movlhps xmm7, xmm4
  2464.         mulps xmm7, xmm3
  2465.         movntps [edi+ecx], xmm7
  2466.         addps xmm0, xmm2
  2467.         addps xmm2, xmm1
  2468.  
  2469.             ;Do colors
  2470.             ;mm4:dist1 dist0
  2471.             ;mm5:dist3 dist2
  2472.         pxor mm7, mm7
  2473.         punpcklbw mm0, mm7
  2474.         punpcklbw mm1, mm7
  2475.         punpcklbw mm2, mm7
  2476.         punpcklbw mm3, mm7
  2477.  
  2478.         movq mm7, fogcol
  2479.         psubw mm7, mm0
  2480.         paddw mm7, mm7
  2481.         pextrw eax, mm4, 1
  2482.         shr eax, 4
  2483.         pmulhw mm7, foglut[eax*8]
  2484.         paddw mm0, mm7
  2485.  
  2486.         movq mm7, fogcol
  2487.         psubw mm7, mm1
  2488.         paddw mm7, mm7
  2489.         pextrw eax, mm4, 3
  2490.         shr eax, 4
  2491.         pmulhw mm7, foglut[eax*8]
  2492.         paddw mm1, mm7
  2493.  
  2494.         movq mm7, fogcol
  2495.         psubw mm7, mm2
  2496.         paddw mm7, mm7
  2497.         pextrw eax, mm5, 1
  2498.         shr eax, 4
  2499.         pmulhw mm7, foglut[eax*8]
  2500.         paddw mm2, mm7
  2501.  
  2502.         movq mm7, fogcol
  2503.         psubw mm7, mm3
  2504.         paddw mm7, mm7
  2505.         pextrw eax, mm5, 3
  2506.         shr eax, 4
  2507.         pmulhw mm7, foglut[eax*8]
  2508.         paddw mm3, mm7
  2509.  
  2510.         packuswb mm0, mm1
  2511.         packuswb mm2, mm3
  2512.         movntq [edi], mm0
  2513.         movntq [edi+8], mm2
  2514.  
  2515.         add edi, 16
  2516.         cmp edi, esi
  2517.         jbe short beg4h
  2518.         add esi, 16
  2519.         cmp edi, esi
  2520.         jae endh
  2521.  
  2522.         movq mm7, mm7bak
  2523.         psrad mm7, 1    ;Restore mm7 from incr*2 to just incr for single loop
  2524. skip4h:
  2525. beg1h:
  2526.         pextrw eax, mm6, 1
  2527.         paddd mm6, mm7
  2528.         mov eax, angstart[eax*4]
  2529.  
  2530.             ;Z
  2531.         cvtsi2ss xmm7, [eax+edx*8+4]
  2532.         rsqrtss xmm3, xmm0
  2533.         mulss xmm7, xmm3
  2534.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2535.         movss [edi+ecx], xmm7
  2536.  
  2537.             ;Col
  2538.         punpcklbw mm0, [eax+edx*8]
  2539.         psrlw mm0, 8
  2540.         movq mm1, fogcol
  2541.         psubw mm1, mm0
  2542.         paddw mm1, mm1
  2543.         mov eax, [eax+edx*8+4]
  2544.         shr eax, 16+4
  2545.         pmulhw mm1, foglut[eax*8]
  2546.         paddw mm0, mm1
  2547.         packuswb mm0, mm1
  2548.         movd [edi], mm0
  2549.  
  2550.         add edi, 4
  2551.         cmp edi, esi
  2552.         jb short beg1h
  2553. endh: pop edi
  2554.         pop esi
  2555.     }
  2556. }
  2557.  
  2558. void hrendz3dn (long sx, long sy, long p1, long plc, long incr, long j)
  2559. {
  2560.     _asm
  2561.     {
  2562.         push esi
  2563.         push edi
  2564.         mov eax, sy
  2565.         mov eax, ylookup[eax*4]
  2566.         add eax, frameplace
  2567.         mov esi, p1
  2568.         lea esi, [eax+esi*4]    ;esi = p1
  2569.         mov edi, sx
  2570.         lea edi, [eax+edi*4]    ;edi = p0
  2571.  
  2572.         movd mm0, sx
  2573.         punpckldq mm0, sy
  2574.         pi2fd mm0, mm0          ;mm0: (float)sy (float)sx
  2575.         pshufw mm2, mm0, 0xee   ;mm2: (float)sy (float)sy
  2576.         punpckldq mm0, mm0      ;mm0: (float)sx (float)sx
  2577.         movd mm1, optistrx
  2578.         punpckldq mm1, optistry
  2579.         pfmul mm0, mm1          ;mm0: (float)sx*optistry (float)sx*optistrx
  2580.         movd mm3, optiheix
  2581.         punpckldq mm3, optiheiy
  2582.         pfmul mm2, mm3          ;mm2: (float)sy*optiheiy (float)sy*optiheix
  2583.         pfadd mm0, mm2
  2584.         movd mm3, optiaddx
  2585.         punpckldq mm3, optiaddy ;mm3: optiaddy optiaddx
  2586.         pfadd mm0, mm3          ;mm0: diry diry
  2587.  
  2588.         movd mm6, plc
  2589.         movd mm7, incr
  2590.         mov ecx, zbufoff
  2591.         mov edx, j
  2592.  
  2593. beg:  pextrw eax, mm6, 1
  2594.         mov eax, angstart[eax*4]
  2595.         movq mm2, [eax+edx*8]   ;mm2:      dist       col
  2596.         pshufw mm3, mm2, 0xee   ;mm3:         ?      dist
  2597.         pi2fd mm3, mm3          ;mm3:         ?   (f)dist
  2598.         movq mm4, mm0           ;mm4:      diry      dirx
  2599.         pfmul mm4, mm4          ;mm4:    diry^2    dirx^2
  2600.         pfadd mm0, mm1          ;mm0: dirx+optx diry+opty (unrelated)
  2601.         pfacc mm4, mm4          ;mm4: (x^2+y^2)   x^2+y^2
  2602.         pfrsqrt mm4, mm4        ;mm4: 1/sqrt(*) 1/sqrt(*)
  2603.         pfmul mm3, mm4          ;mm3:         0    zvalue
  2604.         paddd mm6, mm7          ;mm6:            plc+incr (unrelated)
  2605.         movd [edi], mm2
  2606.         movd [edi+ecx], mm3
  2607.         add edi, 4
  2608.         cmp edi, esi
  2609.         jb short beg
  2610.         pop edi
  2611.         pop esi
  2612.     }
  2613. }
  2614.  
  2615. void hrendzfog3dn (long sx, long sy, long p1, long plc, long incr, long j)
  2616. {
  2617.     _asm
  2618.     {
  2619.         push esi
  2620.         push edi
  2621.         mov eax, sy
  2622.         mov eax, ylookup[eax*4]
  2623.         add eax, frameplace
  2624.         mov esi, p1
  2625.         lea esi, [eax+esi*4]    ;esi = p1
  2626.         mov edi, sx
  2627.         lea edi, [eax+edi*4]    ;edi = p0
  2628.  
  2629.         movd mm0, sx
  2630.         punpckldq mm0, sy
  2631.         pi2fd mm0, mm0          ;mm0: (float)sy (float)sx
  2632.         pshufw mm2, mm0, 0xee   ;mm2: (float)sy (float)sy
  2633.         punpckldq mm0, mm0      ;mm0: (float)sx (float)sx
  2634.         movd mm1, optistrx
  2635.         punpckldq mm1, optistry
  2636.         pfmul mm0, mm1          ;mm0: (float)sx*optistry (float)sx*optistrx
  2637.         movd mm3, optiheix
  2638.         punpckldq mm3, optiheiy
  2639.         pfmul mm2, mm3          ;mm2: (float)sy*optiheiy (float)sy*optiheix
  2640.         pfadd mm0, mm2
  2641.         movd mm3, optiaddx
  2642.         punpckldq mm3, optiaddy ;mm3: optiaddy optiaddx
  2643.         pfadd mm0, mm3          ;mm0: diry diry
  2644.  
  2645.         pxor mm5, mm5
  2646.  
  2647.         movd mm6, plc
  2648.         movd mm7, incr
  2649.         mov ecx, zbufoff
  2650.         mov edx, j
  2651.  
  2652. beg:  pextrw eax, mm6, 1
  2653.         mov eax, angstart[eax*4]
  2654.         movq mm2, [eax+edx*8]   ;mm2:      dist       col
  2655.         pshufw mm3, mm2, 0xee   ;mm3:         ?      dist
  2656.         pi2fd mm3, mm3          ;mm3:         ?   (f)dist
  2657.         movq mm4, mm0           ;mm4:      diry      dirx
  2658.         pfmul mm4, mm4          ;mm4:    diry^2    dirx^2
  2659.         pfadd mm0, mm1          ;mm0: dirx+optx diry+opty (unrelated)
  2660.         pfacc mm4, mm4          ;mm4: (x^2+y^2)   x^2+y^2
  2661.         pfrsqrt mm4, mm4        ;mm4: 1/sqrt(*) 1/sqrt(*)
  2662.         pfmul mm3, mm4          ;mm3:         0    zvalue
  2663.         paddd mm6, mm7          ;mm6:            plc+incr (unrelated)
  2664.  
  2665.             ;Extra calculations for fog
  2666.         pextrw eax, mm2, 3
  2667.         punpcklbw mm2, mm5
  2668.         movq mm4, fogcol
  2669.         psubw mm4, mm2
  2670.         paddw mm4, mm4
  2671.         shr eax, 4
  2672.         pmulhw mm4, foglut[eax*8]
  2673.         paddw mm2, mm4
  2674.         packuswb mm2, mm4
  2675.  
  2676.         movd [edi], mm2
  2677.         movd [edi+ecx], mm3
  2678.         add edi, 4
  2679.         cmp edi, esi
  2680.         jb short beg
  2681.         pop edi
  2682.         pop esi
  2683.     }
  2684. }
  2685.  
  2686. void vrendzsse (long sx, long sy, long p1, long iplc, long iinc)
  2687. {
  2688.     _asm
  2689.     {
  2690.         push ebx
  2691.         push esi
  2692.         push edi
  2693. begvasm_p3:
  2694.         mov esi, sx
  2695.         mov eax, sy
  2696.         mov edx, p1
  2697.         mov ecx, ylookup[eax*4]
  2698.         add ecx, frameplace
  2699.         lea edx, [ecx+edx*4]
  2700.         lea edi, [ecx+esi*4]
  2701.  
  2702.         mov ecx, esi
  2703.         and ecx, 0xfffffffc
  2704.         cvtsi2ss xmm0, ecx
  2705.         cvtsi2ss xmm4, eax
  2706.         movss xmm1, xmm0
  2707.         movss xmm5, xmm4
  2708.         mulss xmm0, optistrx
  2709.         mulss xmm1, optistry
  2710.         mulss xmm4, optiheix
  2711.         mulss xmm5, optiheiy
  2712.         addss xmm0, optiaddx
  2713.         addss xmm1, optiaddy
  2714.         addss xmm0, xmm4
  2715.         addss xmm1, xmm5
  2716.  
  2717.         shufps xmm0, xmm0, 0
  2718.         shufps xmm1, xmm1, 0
  2719.         movaps xmm2, opti4asm[2*16]
  2720.         movaps xmm3, opti4asm[3*16]
  2721.         addps xmm0, opti4asm[0*16]
  2722.         addps xmm1, opti4asm[1*16]
  2723.             ;xmm0 =  xmm0      ^2 +  xmm1      ^2        (p)
  2724.             ;xmm2 = (xmm0+xmm2)^2 + (xmm1+xmm3)^2 - xmm0 (v)
  2725.             ;xmm1 = ...                                  (a)
  2726.         addps xmm2, xmm0  ;This block converts inner loop...
  2727.         addps xmm3, xmm1  ;from: 1 / sqrt(x*x + y*y), x += xi, y += yi;
  2728.         mulps xmm0, xmm0  ;  to: 1 / sqrt(p), p += v, v += a;
  2729.         mulps xmm1, xmm1
  2730.         mulps xmm2, xmm2
  2731.         mulps xmm3, xmm3
  2732.         addps xmm0, xmm1
  2733.         movaps xmm1, opti4asm[4*16]
  2734.         addps xmm2, xmm3
  2735.         subps xmm2, xmm0
  2736.  
  2737.         mov p1, edx
  2738.         mov ecx, zbufoff
  2739.         shl esi, 2
  2740.         add esi, uurend
  2741.         mov ebx, iplc
  2742.  
  2743.         cmp edi, edx
  2744.         jae short endv
  2745.  
  2746.             ;Do first 0-3 pixels to align unrolled loop of 4
  2747.         test edi, 15
  2748.         jz short skip1va
  2749.  
  2750.         test edi, 8
  2751.         jz short skipshufc
  2752.         shufps xmm0, xmm0, 0x4e ;rotate right by 2
  2753. skipshufc:
  2754.         test edi, 4
  2755.         jz short skipshufd
  2756.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2757. skipshufd:
  2758.  
  2759. beg1va:
  2760.         mov edx, [esi]
  2761.         mov eax, [esi+MAXXDIM*4]
  2762.         add eax, edx
  2763.         sar edx, 16
  2764.         mov edx, angstart[edx*4]
  2765.         mov [esi], eax
  2766.         mov eax, [edx+ebx*8]
  2767.         mov [edi], eax
  2768.         cvtsi2ss xmm7, [edx+ebx*8+4]
  2769.         rsqrtss xmm3, xmm0
  2770.         mulss xmm7, xmm3
  2771.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2772.         movss [edi+ecx], xmm7
  2773.         add ebx, iinc
  2774.         add esi, 4
  2775.         add edi, 4
  2776.         cmp edi, p1
  2777.         jz short endv
  2778.         test edi, 15
  2779.         jnz short beg1va
  2780.  
  2781.         addps xmm0, xmm2
  2782.         addps xmm2, xmm1
  2783. skip1va:
  2784.         lea edx, [edi+16]
  2785.         cmp edx, p1
  2786.         ja short prebeg1v
  2787.  
  2788.         cmp iinc, 0
  2789.         jl short beg4vn
  2790.  
  2791. beg4vp:
  2792.         movq mm6, [esi]
  2793.         movq mm7, [esi+8]
  2794.         pextrw eax, mm6, 1
  2795.         pextrw edx, mm6, 3
  2796.         paddd mm6, [esi+MAXXDIM*4]
  2797.         mov eax, angstart[eax*4]
  2798.         mov edx, angstart[edx*4]
  2799.         movq mm0, [eax+ebx*8]
  2800.         movq mm1, [edx+ebx*8+8]
  2801.         pextrw eax, mm7, 1
  2802.         pextrw edx, mm7, 3
  2803.         paddd mm7, [esi+8+MAXXDIM*4]
  2804.         mov eax, angstart[eax*4]
  2805.         mov edx, angstart[edx*4]
  2806.         movq mm2, [eax+ebx*8+16]
  2807.         movq mm3, [edx+ebx*8+24]
  2808.         add ebx, 4
  2809.  
  2810.         movq mm4, mm0
  2811.         movq mm5, mm2
  2812.         punpckldq mm0, mm1
  2813.         punpckldq mm2, mm3
  2814.         movntq [edi], mm0
  2815.         movntq [edi+8], mm2
  2816.  
  2817.         punpckhdq mm4, mm1
  2818.         punpckhdq mm5, mm3
  2819.         cvtpi2ps xmm7, mm4
  2820.         cvtpi2ps xmm4, mm5
  2821.         rsqrtps xmm3, xmm0
  2822.         movlhps xmm7, xmm4
  2823.         mulps xmm7, xmm3
  2824.         movntps [edi+ecx], xmm7
  2825.         addps xmm0, xmm2
  2826.         addps xmm2, xmm1
  2827.  
  2828.         movq [esi], mm6
  2829.         movq [esi+8], mm7
  2830.  
  2831.         add esi, 16
  2832.         add edi, 16
  2833.         lea edx, [edi+16]
  2834.         cmp edx, p1
  2835.         jbe short beg4vp
  2836.         cmp edi, p1
  2837.         jae short endv
  2838.         jmp short prebeg1v
  2839.  
  2840. beg4vn:
  2841.         movq mm6, [esi]
  2842.         movq mm7, [esi+8]
  2843.         pextrw eax, mm6, 1
  2844.         pextrw edx, mm6, 3
  2845.         paddd mm6, [esi+MAXXDIM*4]
  2846.         mov eax, angstart[eax*4]
  2847.         mov edx, angstart[edx*4]
  2848.         movq mm0, [eax+ebx*8]
  2849.         movq mm1, [edx+ebx*8-8]
  2850.         pextrw eax, mm7, 1
  2851.         pextrw edx, mm7, 3
  2852.         paddd mm7, [esi+8+MAXXDIM*4]
  2853.         mov eax, angstart[eax*4]
  2854.         mov edx, angstart[edx*4]
  2855.         movq mm2, [eax+ebx*8-16]
  2856.         movq mm3, [edx+ebx*8-24]
  2857.         sub ebx, 4
  2858.  
  2859.         movq mm4, mm0
  2860.         movq mm5, mm2
  2861.         punpckldq mm0, mm1
  2862.         punpckldq mm2, mm3
  2863.         movntq [edi], mm0
  2864.         movntq [edi+8], mm2
  2865.  
  2866.         punpckhdq mm4, mm1
  2867.         punpckhdq mm5, mm3
  2868.         cvtpi2ps xmm7, mm4
  2869.         cvtpi2ps xmm4, mm5
  2870.         rsqrtps xmm3, xmm0
  2871.         movlhps xmm7, xmm4
  2872.         mulps xmm7, xmm3
  2873.         movntps [edi+ecx], xmm7
  2874.         addps xmm0, xmm2
  2875.         addps xmm2, xmm1
  2876.  
  2877.         movq [esi], mm6
  2878.         movq [esi+8], mm7
  2879.  
  2880.         add esi, 16
  2881.         add edi, 16
  2882.         lea edx, [edi+16]
  2883.         cmp edx, p1
  2884.         jbe short beg4vn
  2885.         cmp edi, p1
  2886.         jae short endv
  2887.  
  2888. prebeg1v:
  2889. beg1v:
  2890.         mov edx, [esi]
  2891.         mov eax, [esi+MAXXDIM*4]
  2892.         add eax, edx
  2893.         sar edx, 16
  2894.         mov edx, angstart[edx*4]
  2895.         mov [esi], eax
  2896.         mov eax, [edx+ebx*8]
  2897.         mov [edi], eax
  2898.         cvtsi2ss xmm7, [edx+ebx*8+4]
  2899.         rsqrtss xmm3, xmm0
  2900.         mulss xmm7, xmm3
  2901.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2902.         movss [edi+ecx], xmm7
  2903.         add ebx, iinc
  2904.         add esi, 4
  2905.         add edi, 4
  2906.         cmp edi, p1
  2907.         jne short beg1v
  2908. endv: pop edi
  2909.         pop esi
  2910.         pop ebx
  2911.     }
  2912. }
  2913.  
  2914. void vrendzfogsse (long sx, long sy, long p1, long iplc, long iinc)
  2915. {
  2916.     _asm
  2917.     {
  2918.         push ebx
  2919.         push esi
  2920.         push edi
  2921. begvasm_p3:
  2922.         mov esi, sx
  2923.         mov eax, sy
  2924.         mov edx, p1
  2925.         mov ecx, ylookup[eax*4]
  2926.         add ecx, frameplace
  2927.         lea edx, [ecx+edx*4]
  2928.         lea edi, [ecx+esi*4]
  2929.  
  2930.         mov ecx, esi
  2931.         and ecx, 0xfffffffc
  2932.         cvtsi2ss xmm0, ecx
  2933.         cvtsi2ss xmm4, eax
  2934.         movss xmm1, xmm0
  2935.         movss xmm5, xmm4
  2936.         mulss xmm0, optistrx
  2937.         mulss xmm1, optistry
  2938.         mulss xmm4, optiheix
  2939.         mulss xmm5, optiheiy
  2940.         addss xmm0, optiaddx
  2941.         addss xmm1, optiaddy
  2942.         addss xmm0, xmm4
  2943.         addss xmm1, xmm5
  2944.  
  2945.         shufps xmm0, xmm0, 0
  2946.         shufps xmm1, xmm1, 0
  2947.         movaps xmm2, opti4asm[2*16]
  2948.         movaps xmm3, opti4asm[3*16]
  2949.         addps xmm0, opti4asm[0*16]
  2950.         addps xmm1, opti4asm[1*16]
  2951.             ;xmm0 =  xmm0      ^2 +  xmm1      ^2        (p)
  2952.             ;xmm2 = (xmm0+xmm2)^2 + (xmm1+xmm3)^2 - xmm0 (v)
  2953.             ;xmm1 = ...                                  (a)
  2954.         addps xmm2, xmm0  ;This block converts inner loop...
  2955.         addps xmm3, xmm1  ;from: 1 / sqrt(x*x + y*y), x += xi, y += yi;
  2956.         mulps xmm0, xmm0  ;  to: 1 / sqrt(p), p += v, v += a;
  2957.         mulps xmm1, xmm1
  2958.         mulps xmm2, xmm2
  2959.         mulps xmm3, xmm3
  2960.         addps xmm0, xmm1
  2961.         movaps xmm1, opti4asm[4*16]
  2962.         addps xmm2, xmm3
  2963.         subps xmm2, xmm0
  2964.  
  2965.         mov p1, edx
  2966.         mov ecx, zbufoff
  2967.         shl esi, 2
  2968.         add esi, uurend
  2969.         mov ebx, iplc
  2970.  
  2971.         cmp edi, edx
  2972.         jae short endv
  2973.  
  2974.             ;Do first 0-3 pixels to align unrolled loop of 4
  2975.         test edi, 15
  2976.         jz short skip1va
  2977.  
  2978.         test edi, 8
  2979.         jz short skipshufc
  2980.         shufps xmm0, xmm0, 0x4e ;rotate right by 2
  2981. skipshufc:
  2982.         test edi, 4
  2983.         jz short skipshufd
  2984.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  2985. skipshufd:
  2986.  
  2987. beg1va:
  2988.         mov edx, [esi]
  2989.         mov eax, [esi+MAXXDIM*4]
  2990.         add eax, edx
  2991.         sar edx, 16
  2992.         mov edx, angstart[edx*4]
  2993.         mov [esi], eax
  2994.  
  2995.             ;Z
  2996.         cvtsi2ss xmm7, [edx+ebx*8+4]
  2997.         rsqrtss xmm3, xmm0
  2998.         mulss xmm7, xmm3
  2999.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  3000.         movss [edi+ecx], xmm7
  3001.  
  3002.             ;Col
  3003.         punpcklbw mm0, [edx+ebx*8]
  3004.         psrlw mm0, 8
  3005.         movq mm1, fogcol
  3006.         psubw mm1, mm0
  3007.         paddw mm1, mm1
  3008.         mov eax, [edx+ebx*8+4]
  3009.         shr eax, 16+4
  3010.         pmulhw mm1, foglut[eax*8]
  3011.         paddw mm0, mm1
  3012.         packuswb mm0, mm1
  3013.         movd [edi], mm0
  3014.  
  3015.         add ebx, iinc
  3016.         add esi, 4
  3017.         add edi, 4
  3018.         cmp edi, p1
  3019.         jz short endv
  3020.         test edi, 15
  3021.         jnz short beg1va
  3022.  
  3023.         addps xmm0, xmm2
  3024.         addps xmm2, xmm1
  3025. skip1va:
  3026.         lea edx, [edi+16]
  3027.         cmp edx, p1
  3028.         ja short prebeg1v
  3029.  
  3030.         cmp iinc, 0
  3031.         jl short beg4vn
  3032.  
  3033. beg4vp:
  3034.         movq mm6, [esi]
  3035.         movq mm7, [esi+8]
  3036.         pextrw eax, mm6, 1
  3037.         pextrw edx, mm6, 3
  3038.         paddd mm6, [esi+MAXXDIM*4]
  3039.         mov eax, angstart[eax*4]
  3040.         mov edx, angstart[edx*4]
  3041.         movq mm4, [eax+ebx*8]
  3042.         movq mm1, [edx+ebx*8+8]
  3043.         pextrw eax, mm7, 1
  3044.         pextrw edx, mm7, 3
  3045.         paddd mm7, [esi+8+MAXXDIM*4]
  3046.         mov eax, angstart[eax*4]
  3047.         mov edx, angstart[edx*4]
  3048.         movq mm5, [eax+ebx*8+16]
  3049.         movq mm3, [edx+ebx*8+24]
  3050.         add ebx, 4
  3051.  
  3052.             ;Do Z
  3053.         movq mm0, mm4
  3054.         movq mm2, mm5
  3055.         punpckhdq mm4, mm1
  3056.         punpckhdq mm5, mm3
  3057.         cvtpi2ps xmm7, mm4
  3058.         cvtpi2ps xmm4, mm5
  3059.         rsqrtps xmm3, xmm0
  3060.         movlhps xmm7, xmm4
  3061.         mulps xmm7, xmm3
  3062.         movntps [edi+ecx], xmm7
  3063.         addps xmm0, xmm2
  3064.         addps xmm2, xmm1
  3065.  
  3066.         movq [esi], mm6
  3067.         movq [esi+8], mm7
  3068.  
  3069.             ;Do color
  3070.         pxor mm7, mm7
  3071.         punpcklbw mm0, mm7
  3072.         punpcklbw mm1, mm7
  3073.         punpcklbw mm2, mm7
  3074.         punpcklbw mm3, mm7
  3075.  
  3076.         movq mm7, fogcol
  3077.         psubw mm7, mm0
  3078.         paddw mm7, mm7
  3079.         pextrw eax, mm4, 1
  3080.         shr eax, 4
  3081.         pmulhw mm7, foglut[eax*8]
  3082.         paddw mm0, mm7
  3083.  
  3084.         movq mm7, fogcol
  3085.         psubw mm7, mm1
  3086.         paddw mm7, mm7
  3087.         pextrw eax, mm4, 3
  3088.         shr eax, 4
  3089.         pmulhw mm7, foglut[eax*8]
  3090.         paddw mm1, mm7
  3091.  
  3092.         movq mm7, fogcol
  3093.         psubw mm7, mm2
  3094.         paddw mm7, mm7
  3095.         pextrw eax, mm5, 1
  3096.         shr eax, 4
  3097.         pmulhw mm7, foglut[eax*8]
  3098.         paddw mm2, mm7
  3099.  
  3100.         movq mm7, fogcol
  3101.         psubw mm7, mm3
  3102.         paddw mm7, mm7
  3103.         pextrw eax, mm5, 3
  3104.         shr eax, 4
  3105.         pmulhw mm7, foglut[eax*8]
  3106.         paddw mm3, mm7
  3107.  
  3108.         packuswb mm0, mm1
  3109.         packuswb mm2, mm3
  3110.         movntq [edi], mm0
  3111.         movntq [edi+8], mm2
  3112.  
  3113.         add esi, 16
  3114.         add edi, 16
  3115.         lea edx, [edi+16]
  3116.         cmp edx, p1
  3117.         jbe short beg4vp
  3118.         cmp edi, p1
  3119.         jae short endv
  3120.         jmp short prebeg1v
  3121.  
  3122. beg4vn:
  3123.         movq mm6, [esi]
  3124.         movq mm7, [esi+8]
  3125.         pextrw eax, mm6, 1
  3126.         pextrw edx, mm6, 3
  3127.         paddd mm6, [esi+MAXXDIM*4]
  3128.         mov eax, angstart[eax*4]
  3129.         mov edx, angstart[edx*4]
  3130.         movq mm4, [eax+ebx*8]
  3131.         movq mm1, [edx+ebx*8-8]
  3132.         pextrw eax, mm7, 1
  3133.         pextrw edx, mm7, 3
  3134.         paddd mm7, [esi+8+MAXXDIM*4]
  3135.         mov eax, angstart[eax*4]
  3136.         mov edx, angstart[edx*4]
  3137.         movq mm5, [eax+ebx*8-16]
  3138.         movq mm3, [edx+ebx*8-24]
  3139.         sub ebx, 4
  3140.  
  3141.             ;Do Z
  3142.         movq mm0, mm4
  3143.         movq mm2, mm5
  3144.         punpckhdq mm4, mm1
  3145.         punpckhdq mm5, mm3
  3146.         cvtpi2ps xmm7, mm4
  3147.         cvtpi2ps xmm4, mm5
  3148.         rsqrtps xmm3, xmm0
  3149.         movlhps xmm7, xmm4
  3150.         mulps xmm7, xmm3
  3151.         movntps [edi+ecx], xmm7
  3152.         addps xmm0, xmm2
  3153.         addps xmm2, xmm1
  3154.  
  3155.         movq [esi], mm6
  3156.         movq [esi+8], mm7
  3157.  
  3158.             ;Do color
  3159.         pxor mm7, mm7
  3160.         punpcklbw mm0, mm7
  3161.         punpcklbw mm1, mm7
  3162.         punpcklbw mm2, mm7
  3163.         punpcklbw mm3, mm7
  3164.  
  3165.         movq mm7, fogcol
  3166.         psubw mm7, mm0
  3167.         paddw mm7, mm7
  3168.         pextrw eax, mm4, 1
  3169.         shr eax, 4
  3170.         pmulhw mm7, foglut[eax*8]
  3171.         paddw mm0, mm7
  3172.  
  3173.         movq mm7, fogcol
  3174.         psubw mm7, mm1
  3175.         paddw mm7, mm7
  3176.         pextrw eax, mm4, 3
  3177.         shr eax, 4
  3178.         pmulhw mm7, foglut[eax*8]
  3179.         paddw mm1, mm7
  3180.  
  3181.         movq mm7, fogcol
  3182.         psubw mm7, mm2
  3183.         paddw mm7, mm7
  3184.         pextrw eax, mm5, 1
  3185.         shr eax, 4
  3186.         pmulhw mm7, foglut[eax*8]
  3187.         paddw mm2, mm7
  3188.  
  3189.         movq mm7, fogcol
  3190.         psubw mm7, mm3
  3191.         paddw mm7, mm7
  3192.         pextrw eax, mm5, 3
  3193.         shr eax, 4
  3194.         pmulhw mm7, foglut[eax*8]
  3195.         paddw mm3, mm7
  3196.  
  3197.         packuswb mm0, mm1
  3198.         packuswb mm2, mm3
  3199.         movntq [edi], mm0
  3200.         movntq [edi+8], mm2
  3201.  
  3202.         add esi, 16
  3203.         add edi, 16
  3204.         lea edx, [edi+16]
  3205.         cmp edx, p1
  3206.         jbe short beg4vn
  3207.         cmp edi, p1
  3208.         jae short endv
  3209.  
  3210. prebeg1v:
  3211. beg1v:
  3212.         mov edx, [esi]
  3213.         mov eax, [esi+MAXXDIM*4]
  3214.         add eax, edx
  3215.         sar edx, 16
  3216.         mov edx, angstart[edx*4]
  3217.         mov [esi], eax
  3218.  
  3219.             ;Z
  3220.         cvtsi2ss xmm7, [edx+ebx*8+4]
  3221.         rsqrtss xmm3, xmm0
  3222.         mulss xmm7, xmm3
  3223.         shufps xmm0, xmm0, 0x39 ;rotate right by 1
  3224.         movss [edi+ecx], xmm7
  3225.  
  3226.             ;Col
  3227.         punpcklbw mm0, [edx+ebx*8]
  3228.         psrlw mm0, 8
  3229.         movq mm1, fogcol
  3230.         psubw mm1, mm0
  3231.         paddw mm1, mm1
  3232.         mov eax, [edx+ebx*8+4]
  3233.         shr eax, 16+4
  3234.         pmulhw mm1, foglut[eax*8]
  3235.         paddw mm0, mm1
  3236.         packuswb mm0, mm1
  3237.         movd [edi], mm0
  3238.  
  3239.         add ebx, iinc
  3240.         add esi, 4
  3241.         add edi, 4
  3242.         cmp edi, p1
  3243.         jne short beg1v
  3244. endv: pop edi
  3245.         pop esi
  3246.         pop ebx
  3247.     }
  3248. }
  3249.  
  3250. void vrendz3dn (long sx, long sy, long p1, long iplc, long iinc)
  3251. {
  3252.     _asm
  3253.     {
  3254.         push ebx
  3255.         push esi
  3256.         push edi
  3257.         mov esi, p1
  3258.         mov edi, sx
  3259.         cmp edi, esi
  3260.         jae short endv
  3261.         mov eax, sy
  3262.         mov eax, ylookup[eax*4]
  3263.         add eax, frameplace
  3264.         lea esi, [eax+esi*4]    ;esi = p1
  3265.         lea edi, [eax+edi*4]    ;edi = p0
  3266.  
  3267.         movd mm0, sx
  3268.         punpckldq mm0, sy
  3269.         pi2fd mm0, mm0          ;mm0: (float)sy (float)sx
  3270.         pshufw mm2, mm0, 0xee   ;mm2: (float)sy (float)sy
  3271.         punpckldq mm0, mm0      ;mm0: (float)sx (float)sx
  3272.         movd mm1, optistrx
  3273.         punpckldq mm1, optistry
  3274.         pfmul mm0, mm1          ;mm0: (float)sx*optistry (float)sx*optistrx
  3275.         movd mm3, optiheix
  3276.         punpckldq mm3, optiheiy
  3277.         pfmul mm2, mm3          ;mm2: (float)sy*optiheiy (float)sy*optiheix
  3278.         pfadd mm0, mm2
  3279.         movd mm3, optiaddx
  3280.         punpckldq mm3, optiaddy ;mm3: optiaddy optiaddx
  3281.         pfadd mm0, mm3          ;mm0: diry diry
  3282.  
  3283.         mov ecx, zbufoff
  3284.         mov edx, iplc
  3285.         mov ebx, sx
  3286.         mov eax, uurend
  3287.         lea ebx, [eax+ebx*4]
  3288.  
  3289. begv_3dn:
  3290.         movd mm5, [ebx]
  3291.         pextrw eax, mm5, 1
  3292.         paddd mm5, [ebx+MAXXDIM*4]
  3293.         movd [ebx], mm5
  3294.         mov eax, angstart[eax*4]
  3295.         movq mm2, [eax+edx*8]   ;mm2:      dist       col
  3296.         pshufw mm3, mm2, 0xee   ;mm3:         ?      dist
  3297.         pi2fd mm3, mm3          ;mm3:         ?   (f)dist
  3298.         movq mm4, mm0           ;mm4:      diry      dirx
  3299.         pfmul mm4, mm4          ;mm4:    diry^2    dirx^2
  3300.         pfadd mm0, mm1          ;mm0: dirx+optx diry+opty (unrelated)
  3301.         pfacc mm4, mm4          ;mm4: (x^2+y^2)   x^2+y^2
  3302.         pfrsqrt mm4, mm4        ;mm4: 1/sqrt(*) 1/sqrt(*)
  3303.         pfmul mm3, mm4          ;mm3:         0    zvalue
  3304.         movd [edi], mm2
  3305.         movd [edi+ecx], mm3
  3306.         add edx, iinc
  3307.         add ebx, 4
  3308.         add edi, 4
  3309.         cmp edi, esi
  3310.         jb short begv_3dn
  3311. endv: pop edi
  3312.         pop esi
  3313.         pop ebx
  3314.     }
  3315. }
  3316.  
  3317. void vrendzfog3dn (long sx, long sy, long p1, long iplc, long iinc)
  3318. {
  3319.     _asm
  3320.     {
  3321.         push ebx
  3322.         push esi
  3323.         push edi
  3324.         mov esi, p1
  3325.         mov edi, sx
  3326.         cmp edi, esi
  3327.         jae short endv
  3328.         mov eax, sy
  3329.         mov eax, ylookup[eax*4]
  3330.         add eax, frameplace
  3331.         lea esi, [eax+esi*4]    ;esi = p1
  3332.         lea edi, [eax+edi*4]    ;edi = p0
  3333.  
  3334.         movd mm0, sx
  3335.         punpckldq mm0, sy
  3336.         pi2fd mm0, mm0          ;mm0: (float)sy (float)sx
  3337.         pshufw mm2, mm0, 0xee   ;mm2: (float)sy (float)sy
  3338.         punpckldq mm0, mm0      ;mm0: (float)sx (float)sx
  3339.         movd mm1, optistrx
  3340.         punpckldq mm1, optistry
  3341.         pfmul mm0, mm1          ;mm0: (float)sx*optistry (float)sx*optistrx
  3342.         movd mm3, optiheix
  3343.         punpckldq mm3, optiheiy
  3344.         pfmul mm2, mm3          ;mm2: (float)sy*optiheiy (float)sy*optiheix
  3345.         pfadd mm0, mm2
  3346.         movd mm3, optiaddx
  3347.         punpckldq mm3, optiaddy ;mm3: optiaddy optiaddx
  3348.         pfadd mm0, mm3          ;mm0: diry diry
  3349.  
  3350.         pxor mm6, mm6
  3351.  
  3352.         mov ecx, zbufoff
  3353.         mov edx, iplc
  3354.         mov ebx, sx
  3355.         mov eax, uurend
  3356.         lea ebx, [eax+ebx*4]
  3357.  
  3358. begv_3dn:
  3359.         movd mm5, [ebx]
  3360.         pextrw eax, mm5, 1
  3361.         paddd mm5, [ebx+MAXXDIM*4]
  3362.         movd [ebx], mm5
  3363.         mov eax, angstart[eax*4]
  3364.         movq mm2, [eax+edx*8]   ;mm2:      dist       col
  3365.         pshufw mm3, mm2, 0xee   ;mm3:         ?      dist
  3366.         pi2fd mm3, mm3          ;mm3:         ?   (f)dist
  3367.         movq mm4, mm0           ;mm4:      diry      dirx
  3368.         pfmul mm4, mm4          ;mm4:    diry^2    dirx^2
  3369.         pfadd mm0, mm1          ;mm0: dirx+optx diry+opty (unrelated)
  3370.         pfacc mm4, mm4          ;mm4: (x^2+y^2)   x^2+y^2
  3371.         pfrsqrt mm4, mm4        ;mm4: 1/sqrt(*) 1/sqrt(*)
  3372.         pfmul mm3, mm4          ;mm3:         0    zvalue
  3373.  
  3374.             ;Extra calculations for fog
  3375.         pextrw eax, mm2, 3
  3376.         punpcklbw mm2, mm6
  3377.         movq mm4, fogcol
  3378.         psubw mm4, mm2
  3379.         paddw mm4, mm4
  3380.         shr eax, 4
  3381.         pmulhw mm4, foglut[eax*8]
  3382.         paddw mm2, mm4
  3383.         packuswb mm2, mm4
  3384.  
  3385.         movd [edi], mm2
  3386.         movd [edi+ecx], mm3
  3387.         add edx, iinc
  3388.         add ebx, 4
  3389.         add edi, 4
  3390.         cmp edi, esi
  3391.         jb short begv_3dn
  3392. endv: pop edi
  3393.         pop esi
  3394.         pop ebx
  3395.     }
  3396. }
  3397.  
  3398. #endif
  3399.  
  3400. void setcamera (dpoint3d *ipo, dpoint3d *ist, dpoint3d *ihe, dpoint3d *ifo,
  3401.                      float dahx, float dahy, float dahz)
  3402. {
  3403.     long i, j;
  3404.  
  3405.     gipos.x = ipo->x; gipos.y = ipo->y; gipos.z = ipo->z;
  3406.     gistr.x = ist->x; gistr.y = ist->y; gistr.z = ist->z;
  3407.     gihei.x = ihe->x; gihei.y = ihe->y; gihei.z = ihe->z;
  3408.     gifor.x = ifo->x; gifor.y = ifo->y; gifor.z = ifo->z;
  3409.     gihx = dahx; gihy = dahy; gihz = dahz;
  3410.  
  3411.     gixs.x = gistr.x; gixs.y = gihei.x; gixs.z = gifor.x;
  3412.     giys.x = gistr.y; giys.y = gihei.y; giys.z = gifor.y;
  3413.     gizs.x = gistr.z; gizs.y = gihei.z; gizs.z = gifor.z;
  3414.     giadd.x = -(gipos.x*gistr.x + gipos.y*gistr.y + gipos.z*gistr.z);
  3415.     giadd.y = -(gipos.x*gihei.x + gipos.y*gihei.y + gipos.z*gihei.z);
  3416.     giadd.z = -(gipos.x*gifor.x + gipos.y*gifor.y + gipos.z*gifor.z);
  3417.  
  3418.     gcorn[0].x = -gihx*gistr.x - gihy*gihei.x + gihz*gifor.x;
  3419.     gcorn[0].y = -gihx*gistr.y - gihy*gihei.y + gihz*gifor.y;
  3420.     gcorn[0].z = -gihx*gistr.z - gihy*gihei.z + gihz*gifor.z;
  3421.     gcorn[1].x = xres*gistr.x+gcorn[0].x;
  3422.     gcorn[1].y = xres*gistr.y+gcorn[0].y;
  3423.     gcorn[1].z = xres*gistr.z+gcorn[0].z;
  3424.     gcorn[2].x = yres*gihei.x+gcorn[1].x;
  3425.     gcorn[2].y = yres*gihei.y+gcorn[1].y;
  3426.     gcorn[2].z = yres*gihei.z+gcorn[1].z;
  3427.     gcorn[3].x = yres*gihei.x+gcorn[0].x;
  3428.     gcorn[3].y = yres*gihei.y+gcorn[0].y;
  3429.     gcorn[3].z = yres*gihei.z+gcorn[0].z;
  3430.     for(j=0,i=3;j<4;i=j++)
  3431.     {
  3432.         ginor[i].x = gcorn[i].y*gcorn[j].z - gcorn[i].z*gcorn[j].y;
  3433.         ginor[i].y = gcorn[i].z*gcorn[j].x - gcorn[i].x*gcorn[j].z;
  3434.         ginor[i].z = gcorn[i].x*gcorn[j].y - gcorn[i].y*gcorn[j].x;
  3435.     }
  3436. }
  3437.  
  3438. void opticast ()
  3439. {
  3440.     float f, ff, cx, cy, fx, fy, gx, gy, x0, y0, x1, y1, x2, y2, x3, y3;
  3441.     long i, j, sx, sy, p0, p1, cx16, cy16, kadd, kmul, u, u1, ui;
  3442.  
  3443.     if (gifor.z < 0) giforzsgn = -1; else giforzsgn = 1; //giforzsgn = (gifor.z < 0);
  3444.  
  3445.     gixyi[0] = (VSID<<2); gixyi[1] = -gixyi[0];
  3446.     glipos.x = ((long)gipos.x);
  3447.     glipos.y = ((long)gipos.y);
  3448.     glipos.z = ((long)gipos.z);
  3449.     gpixy = (long)&sptr[glipos.y*VSID + glipos.x];
  3450.     ftol(gipos.z*PREC-.5f,&gposz);
  3451.     gposxfrac[1] = gipos.x - (float)glipos.x; gposxfrac[0] = 1-gposxfrac[1];
  3452.     gposyfrac[1] = gipos.y - (float)glipos.y; gposyfrac[0] = 1-gposyfrac[1];
  3453. #if USEV5ASM
  3454.     for(j=u=0;j<gmipnum;j++,u+=i)
  3455.         for(i=0;i<(256>>j)+4;i++)
  3456.             gylookup[i+u] = ((((gposz>>j)-i*PREC)>>(16-j))&0x0000ffff);
  3457.     gxmip = max(vx5.mipscandist,4)*PREC;
  3458. #else
  3459.     for(i=0;i<256+4;i++) gylookup[i] = (i*PREC-gposz);
  3460. #endif
  3461.     gmaxscandist = min(max(vx5.maxscandist,1),2047)*PREC;
  3462.  
  3463. #if (USEZBUFFER != 1)
  3464.     hrend = hrendnoz; vrend = vrendnoz;
  3465. #else
  3466.     if (ofogdist < 0)
  3467.     {
  3468.         if (cputype&(1<<25)) { hrend = hrendzsse; vrend = vrendzsse; }
  3469.                              else { hrend = hrendz3dn; vrend = vrendz3dn; }
  3470.     }
  3471.     else
  3472.     {
  3473.         if (cputype&(1<<25)) { hrend = hrendzfogsse; vrend = vrendzfogsse; }
  3474.                              else { hrend = hrendzfog3dn; vrend = vrendzfog3dn; }
  3475.  
  3476.     }
  3477. #endif
  3478.     if (ofogdist < 0) nskypic = skypic;
  3479.                   else { nskypic = skyoff = 0; } //Optimization hack: draw sky as pure black when using fog
  3480.  
  3481.     gstartv = (char *)*(long *)gpixy;
  3482.     if (glipos.z >= gstartv[1])
  3483.     {
  3484.         do
  3485.         {
  3486.             if (!gstartv[0]) return;
  3487.             gstartv += gstartv[0]*4;
  3488.         } while (glipos.z >= gstartv[1]);
  3489.         if (glipos.z < gstartv[3]) return;
  3490.         gstartz0 = gstartv[3];
  3491.     } else gstartz0 = 0;
  3492.     gstartz1 = gstartv[1];
  3493.  
  3494.     if (gifor.z == 0) f = 32000; else f = gihz/gifor.z;
  3495.     f = min(max(f,-32000),32000);
  3496.     cx = gistr.z*f + gihx;
  3497.     cy = gihei.z*f + gihy;
  3498.  
  3499.     wx0 = (float)(-(vx5.anginc)); wx1 = (float)(xres-1+(vx5.anginc));
  3500.     wy0 = (float)(-(vx5.anginc)); wy1 = (float)(yres-1+(vx5.anginc));
  3501.     ftol(wx0,&iwx0); ftol(wx1,&iwx1);
  3502.     ftol(wy0,&iwy0); ftol(wy1,&iwy1);
  3503.  
  3504.     fx = wx0-cx; fy = wy0-cy; gx = wx1-cx; gy = wy1-cy;
  3505.     x0 = x3 = wx0; y0 = y1 = wy0; x1 = x2 = wx1; y2 = y3 = wy1;
  3506.     if (fy < 0)
  3507.     {
  3508.         if (fx < 0) { f = sqrt(fx*fy); x0 = cx-f; y0 = cy-f; }
  3509.         if (gx > 0) { f = sqrt(-gx*fy); x1 = cx+f; y1 = cy-f; }
  3510.     }
  3511.     if (gy > 0)
  3512.     {
  3513.         if (gx > 0) { f = sqrt(gx*gy); x2 = cx+f; y2 = cy+f; }
  3514.         if (fx < 0) { f = sqrt(-fx*gy); x3 = cx-f; y3 = cy+f; }
  3515.     }
  3516.     if (x0 > x1) { if (fx < 0) y0 = fx/gx*fy + cy; else y1 = gx/fx*fy + cy; }
  3517.     if (y1 > y2) { if (fy < 0) x1 = fy/gy*gx + cx; else x2 = gy/fy*gx + cx; }
  3518.     if (x2 < x3) { if (fx < 0) y3 = fx/gx*gy + cy; else y2 = gx/fx*gy + cy; }
  3519.     if (y3 < y0) { if (fy < 0) x0 = fy/gy*fx + cx; else x3 = gy/fy*fx + cx; }
  3520.         //This makes precision errors cause pixels to overwrite rather than omit
  3521.     x0 -= .01; x1 += .01;
  3522.     y1 -= .01; y2 += .01;
  3523.     x3 -= .01; x2 += .01;
  3524.     y0 -= .01; y3 += .01;
  3525.  
  3526.     f = 1048576.0 / gihz;
  3527.     optistrx = gistr.x*f; optiheix = gihei.x*f; optiaddx = gcorn[0].x*f;
  3528.     optistry = gistr.y*f; optiheiy = gihei.y*f; optiaddy = gcorn[0].y*f;
  3529. #ifdef _MSC_VER
  3530.     opti4[0].y = optistrx; opti4[0].z = optistrx*2; opti4[0].z2 = optistrx*3;
  3531.     opti4[1].y = optistry; opti4[1].z = optistry*2; opti4[1].z2 = optistry*3;
  3532.     opti4[2].x = opti4[2].y = opti4[2].z = opti4[2].z2 = optistrx*4.0f;
  3533.     opti4[3].x = opti4[3].y = opti4[3].z = opti4[3].z2 = optistry*4.0f;
  3534.     opti4[4].x = opti4[4].y = opti4[4].z = opti4[4].z2 = (optistrx*optistrx + optistry*optistry)*32.0f; //NEW ALGO!
  3535. #endif
  3536.  
  3537.     ftol(cx*65536,&cx16);
  3538.     ftol(cy*65536,&cy16);
  3539.  
  3540.     ftol((x1-x0)/vx5.anginc,&j);
  3541.     if ((fy < 0) && (j > 0)) //(cx,cy),(x0,wy0),(x1,wy0)
  3542.     {
  3543.         ff = (x1-x0) / (float)j; grd = 1.0f / (wy0-cy);
  3544.         gscanptr = (castdat *)radar; skycurlng = -1; skycurdir = -giforzsgn;
  3545.         for(i=0,f=x0+ff*.5f;i<j;f+=ff,i++)
  3546.         {
  3547.             vline(cx,cy,f,wy0,&p0,&p1);
  3548.             if (giforzsgn < 0) angstart[i] = gscanptr+p0; else angstart[i] = gscanptr-p1;
  3549.             gscanptr += labs(p1-p0)+1;
  3550.         }
  3551.  
  3552.         j <<= 16; f = (float)j / ((x1-x0)*grd); ftol((cx-x0)*grd*f,&kadd);
  3553.         ftol(cx-.5f,&p1); p0 = lbound0(p1+1,xres); p1 = lbound0(p1,xres);
  3554.         ftol(cy-0.50005f,&sy); if (sy >= yres) sy = yres-1;
  3555.         ff = (fabs((float)p1-cx)+1)*f/2147483647.0 + cy; //Anti-crash hack
  3556.         while ((ff < sy) && (sy >= 0)) sy--;
  3557.         if (sy >= 0)
  3558.         {
  3559.             ftol(f,&kmul);
  3560.             for(;sy>=0;sy--) if (isshldiv16safe(kmul,(sy<<16)-cy16)) break; //Anti-crash hack
  3561.             if (giforzsgn < 0) i = -sy; else i = sy;
  3562.             for(;sy>=0;sy--,i-=giforzsgn)
  3563.             {
  3564.                 ui = shldiv16(kmul,(sy<<16)-cy16);
  3565.                 u = mulshr16((p0<<16)-cx16,ui)+kadd;
  3566.                 while ((p0 > 0) && (u >= ui)) { u -= ui; p0--; }
  3567.                 u1 = (p1-p0)*ui + u;
  3568.                 while ((p1 < xres) && (u1 < j)) { u1 += ui; p1++; }
  3569.                 if (p0 < p1) hrend(p0,sy,p1,u,ui,i);
  3570.             }
  3571.             _asm emms
  3572.         }
  3573.     }
  3574.  
  3575.     ftol((y2-y1)/vx5.anginc,&j);
  3576.     if ((gx > 0) && (j > 0)) //(cx,cy),(wx1,y1),(wx1,y2)
  3577.     {
  3578.         ff = (y2-y1) / (float)j; grd = 1.0f / (wx1-cx);
  3579.         gscanptr = (castdat *)radar; skycurlng = -1; skycurdir = -giforzsgn;
  3580.         for(i=0,f=y1+ff*.5f;i<j;f+=ff,i++)
  3581.         {
  3582.             hline(cx,cy,wx1,f,&p0,&p1);
  3583.             if (giforzsgn < 0) angstart[i] = gscanptr-p0; else angstart[i] = gscanptr+p1;
  3584.             gscanptr += labs(p1-p0)+1;
  3585.         }
  3586.  
  3587.         j <<= 16; f = (float)j / ((y2-y1)*grd); ftol((cy-y1)*grd*f,&kadd);
  3588.         ftol(cy-.5f,&p1); p0 = lbound0(p1+1,yres); p1 = lbound0(p1,yres);
  3589.         ftol(cx+0.50005f,&sx); if (sx < 0) sx = 0;
  3590.         ff = (fabs((float)p1-cy)+1)*f/2147483647.0 + cx; //Anti-crash hack
  3591.         while ((ff > sx) && (sx < xres)) sx++;
  3592.         if (sx < xres)
  3593.         {
  3594.             ftol(f,&kmul);
  3595.             for(;sx<xres;sx++) if (isshldiv16safe(kmul,(sx<<16)-cx16)) break; //Anti-crash hack
  3596.             for(;sx<xres;sx++)
  3597.             {
  3598.                 ui = shldiv16(kmul,(sx<<16)-cx16);
  3599.                 u = mulshr16((p0<<16)-cy16,ui)+kadd;
  3600.                 while ((p0 > 0) && (u >= ui)) { u -= ui; lastx[--p0] = sx; }
  3601.                 uurend[sx] = u; uurend[sx+MAXXDIM] = ui; u += (p1-p0)*ui;
  3602.                 while ((p1 < yres) && (u < j)) { u += ui; lastx[p1++] = sx; }
  3603.             }
  3604.             if (giforzsgn < 0)
  3605.                   { for(sy=p0;sy<p1;sy++) vrend(lastx[sy],sy,xres,lastx[sy],1); }
  3606.             else { for(sy=p0;sy<p1;sy++) vrend(lastx[sy],sy,xres,-lastx[sy],-1); }
  3607.             _asm emms
  3608.         }
  3609.     }
  3610.  
  3611.     ftol((x2-x3)/vx5.anginc,&j);
  3612.     if ((gy > 0) && (j > 0)) //(cx,cy),(x2,wy1),(x3,wy1)
  3613.     {
  3614.         ff = (x2-x3) / (float)j; grd = 1.0f / (wy1-cy);
  3615.         gscanptr = (castdat *)radar; skycurlng = -1; skycurdir = giforzsgn;
  3616.         for(i=0,f=x3+ff*.5f;i<j;f+=ff,i++)
  3617.         {
  3618.             vline(cx,cy,f,wy1,&p0,&p1);
  3619.             if (giforzsgn < 0) angstart[i] = gscanptr-p0; else angstart[i] = gscanptr+p1;
  3620.             gscanptr += labs(p1-p0)+1;
  3621.         }
  3622.  
  3623.         j <<= 16; f = (float)j / ((x2-x3)*grd); ftol((cx-x3)*grd*f,&kadd);
  3624.         ftol(cx-.5f,&p1); p0 = lbound0(p1+1,xres); p1 = lbound0(p1,xres);
  3625.         ftol(cy+0.50005f,&sy); if (sy < 0) sy = 0;
  3626.         ff = (fabs((float)p1-cx)+1)*f/2147483647.0 + cy; //Anti-crash hack
  3627.         while ((ff > sy) && (sy < yres)) sy++;
  3628.         if (sy < yres)
  3629.         {
  3630.             ftol(f,&kmul);
  3631.             for(;sy<yres;sy++) if (isshldiv16safe(kmul,(sy<<16)-cy16)) break; //Anti-crash hack
  3632.             if (giforzsgn < 0) i = sy; else i = -sy;
  3633.             for(;sy<yres;sy++,i-=giforzsgn)
  3634.             {
  3635.                 ui = shldiv16(kmul,(sy<<16)-cy16);
  3636.                 u = mulshr16((p0<<16)-cx16,ui)+kadd;
  3637.                 while ((p0 > 0) && (u >= ui)) { u -= ui; p0--; }
  3638.                 u1 = (p1-p0)*ui + u;
  3639.                 while ((p1 < xres) && (u1 < j)) { u1 += ui; p1++; }
  3640.                 if (p0 < p1) hrend(p0,sy,p1,u,ui,i);
  3641.             }
  3642.             _asm emms
  3643.         }
  3644.     }
  3645.  
  3646.     ftol((y3-y0)/vx5.anginc,&j);
  3647.     if ((fx < 0) && (j > 0)) //(cx,cy),(wx0,y3),(wx0,y0)
  3648.     {
  3649.         ff = (y3-y0) / (float)j; grd = 1.0f / (wx0-cx);
  3650.         gscanptr = (castdat *)radar; skycurlng = -1; skycurdir = giforzsgn;
  3651.         for(i=0,f=y0+ff*.5f;i<j;f+=ff,i++)
  3652.         {
  3653.             hline(cx,cy,wx0,f,&p0,&p1);
  3654.             if (giforzsgn < 0) angstart[i] = gscanptr+p0; else angstart[i] = gscanptr-p1;
  3655.             gscanptr += labs(p1-p0)+1;
  3656.         }
  3657.  
  3658.         j <<= 16; f = (float)j / ((y3-y0)*grd); ftol((cy-y0)*grd*f,&kadd);
  3659.         ftol(cy-.5f,&p1); p0 = lbound0(p1+1,yres); p1 = lbound0(p1,yres);
  3660.         ftol(cx-0.50005f,&sx); if (sx >= xres) sx = xres-1;
  3661.         ff = (fabs((float)p1-cy)+1)*f/2147483647.0 + cx; //Anti-crash hack
  3662.         while ((ff < sx) && (sx >= 0)) sx--;
  3663.         if (sx >= 0)
  3664.         {
  3665.             ftol(f,&kmul);
  3666.             for(;sx>=0;sx--) if (isshldiv16safe(kmul,(sx<<16)-cx16)) break; //Anti-crash hack
  3667.             for(;sx>=0;sx--)
  3668.             {
  3669.                 ui = shldiv16(kmul,(sx<<16)-cx16);
  3670.                 u = mulshr16((p0<<16)-cy16,ui)+kadd;
  3671.                 while ((p0 > 0) && (u >= ui)) { u -= ui; lastx[--p0] = sx; }
  3672.                 uurend[sx] = u; uurend[sx+MAXXDIM] = ui; u += (p1-p0)*ui;
  3673.                 while ((p1 < yres) && (u < j)) { u += ui; lastx[p1++] = sx; }
  3674.             }
  3675.             for(sy=p0;sy<p1;sy++) vrend(0,sy,lastx[sy]+1,0,giforzsgn);
  3676.             _asm emms
  3677.         }
  3678.     }
  3679. }
  3680.  
  3681.     //0: asm temp for current x
  3682.     //1: asm temp for current y
  3683.     //2: bottom (28)
  3684.     //3: top    ( 0)
  3685.     //4: left   ( 8)
  3686.     //5: right  (24)
  3687.     //6: up     (12)
  3688.     //7: down   (12)
  3689.     //setsideshades(0,0,0,0,0,0);
  3690.     //setsideshades(0,28,8,24,12,12);
  3691. void setsideshades (char sto, char sbo, char sle, char sri, char sup, char sdo)
  3692. {
  3693.     ((char *)&gcsub[2])[7] = sbo; ((char *)&gcsub[3])[7] = sto;
  3694.     ((char *)&gcsub[4])[7] = sle; ((char *)&gcsub[5])[7] = sri;
  3695.     ((char *)&gcsub[6])[7] = sup; ((char *)&gcsub[7])[7] = sdo;
  3696.     if (!(sto|sbo|sle|sri|sup|sdo))
  3697.     {
  3698.         vx5.sideshademode = 0;
  3699.         ((char *)&gcsub[0])[7] = ((char *)&gcsub[1])[7] = 0x00;
  3700.     }
  3701.     else vx5.sideshademode = 1;
  3702. }
  3703.  
  3704.     //MUST have more than: CEILING(max possible CLIPRADIUS) * 4 entries!
  3705. #define MAXCLIPIT (VSID*4) //VSID*2+4 is not a power of 2!
  3706. static lpoint2d clipit[MAXCLIPIT];
  3707.  
  3708. double findmaxcr (double px, double py, double pz, double cr)
  3709. {
  3710.     double f, g, maxcr, thresh2;
  3711.     long x, y, z, i0, i1, ix, y0, y1, z0, z1;
  3712.     char *v;
  3713.  
  3714.     thresh2 = cr+1.7321+1; thresh2 *= thresh2;
  3715.     maxcr = cr*cr;
  3716.  
  3717.         //Find closest point of all nearby cubes to (px,py,pz)
  3718.     x = (long)px; y = (long)py; z = (long)pz; i0 = i1 = 0; ix = x; y0 = y1 = y;
  3719.     while (1)
  3720.     {
  3721.         f = max(fabs((double)x+.5-px)-.5,0);
  3722.         g = max(fabs((double)y+.5-py)-.5,0);
  3723.         f = f*f + g*g;
  3724.         if (f < maxcr)
  3725.         {
  3726.             if (((unsigned long)x >= VSID) || ((unsigned long)y >= VSID))
  3727.                 { z0 = z1 = 0; }
  3728.             else
  3729.             {
  3730.                 v = sptr[y*VSID+x];
  3731.                 if (z >= v[1])
  3732.                 {
  3733.                     while (1)
  3734.                     {
  3735.                         if (!v[0]) { z0 = z1 = 0; break; }
  3736.                         v += v[0]*4;
  3737.                         if (z < v[1]) { z0 = v[3]; z1 = v[1]; break; }
  3738.                     }
  3739.                 }
  3740.                 else { z0 = MAXZDIM-2048; z1 = v[1]; }
  3741.             }
  3742.  
  3743.             if ((pz <= z0) || (pz >= z1))
  3744.                 maxcr = f;
  3745.             else
  3746.             {
  3747.                 g = min(pz-(double)z0,(double)z1-pz);
  3748.                 f += g*g; if (f < maxcr) maxcr = f;
  3749.             }
  3750.         }
  3751.  
  3752.         if ((x-px)*(x-px)+(y-py)*(y-py) < thresh2)
  3753.         {
  3754.             if ((x <= ix) && (x > 0))
  3755.                 { clipit[i1].x = x-1; clipit[i1].y = y; i1 = ((i1+1)&(MAXCLIPIT-1)); }
  3756.             if ((x >= ix) && (x < VSID-1))
  3757.                 { clipit[i1].x = x+1; clipit[i1].y = y; i1 = ((i1+1)&(MAXCLIPIT-1)); }
  3758.             if ((y <= y0) && (y > 0))
  3759.                 { clipit[i1].x = x; clipit[i1].y = y-1; i1 = ((i1+1)&(MAXCLIPIT-1)); y0--; }
  3760.             if ((y >= y1) && (y < VSID-1))
  3761.                 { clipit[i1].x = x; clipit[i1].y = y+1; i1 = ((i1+1)&(MAXCLIPIT-1)); y1++; }
  3762.         }
  3763.         if (i0 == i1) break;
  3764.         x = clipit[i0].x; y = clipit[i0].y; i0 = ((i0+1)&(MAXCLIPIT-1));
  3765.     }
  3766.     return(sqrt(maxcr));
  3767. }
  3768.  
  3769. #if 0
  3770.  
  3771.     //Point: (x,y), line segment: (px,py)-(px+vx,py+vy)
  3772.     //Returns 1 if point is closer than sqrt(cr2) to line
  3773. long dist2linept2d (double x, double y, double px, double py, double vx, double vy, double cr2)
  3774. {
  3775.     double f, g;
  3776.     x -= px; y -= py; f = x*vx + y*vy; if (f <= 0) return(x*x + y*y <= cr2);
  3777.     g = vx*vx + vy*vy; if (f >= g) { x -= vx; y -= vy; return(x*x + y*y <= cr2); }
  3778.     x = x*g-vx*f; y = y*g-vy*f; return(x*x + y*y <= cr2*g*g);
  3779. }
  3780.  
  3781. static char clipbuf[MAXZDIM+16]; //(8 extra on each side)
  3782. long sphtraceo (double px, double py, double pz,    //start pt
  3783.                     double vx, double vy, double vz,    //move vector
  3784.                     double *nx, double *ny, double *nz, //new pt after collision
  3785.                     double *fx, double *fy, double *fz, //pt that caused collision
  3786.                     double cr, double acr)
  3787. {
  3788.     double t, u, ex, ey, ez, Za, Zb, Zc, thresh2;
  3789.     double vxyz, vyz, vxz, vxy, rvxyz, rvyz, rvxz, rvxy, rvx, rvy, rvz, cr2;
  3790.     long i, i0, i1, x, y, z, xx, yy, zz, v, vv, ix, y0, y1, z0, z1;
  3791.     char *vp;
  3792.  
  3793.     t = 1;
  3794.     (*nx) = px + vx;
  3795.     (*ny) = py + vy;
  3796.     (*nz) = pz + vz;
  3797.  
  3798.     z0 = max((long)(min(pz,*nz)-cr)-2,-1);
  3799.     z1 = min((long)(max(pz,*nz)+cr)+2,MAXZDIM);
  3800.  
  3801.     thresh2 = cr+1.7321+1; thresh2 *= thresh2;
  3802.  
  3803.     vyz = vz*vz; vxz = vx*vx; vxy = vy*vy; cr2 = cr*cr;
  3804.     vyz += vxy; vxy += vxz; vxyz = vyz + vxz; vxz += vz*vz;
  3805.     rvx = 1.0 / vx; rvy = 1.0 / vy; rvz = 1.0 / vz;
  3806.     rvyz = 1.0 / vyz; rvxz = 1.0 / vxz; rvxy = 1.0 / vxy;
  3807.     rvxyz = 1.0 / vxyz;
  3808.  
  3809.         //Algorithm fails (stops short) if cr < 2 :(
  3810.     i0 = i1 = 0; ix = x = (long)px; y = y0 = y1 = (long)py;
  3811.     while (1)
  3812.     {
  3813.         for(z=z0;z<=z1;z++) clipbuf[z+8] = 0;
  3814.         i = 16;
  3815.         for(yy=y;yy<y+2;yy++)
  3816.             for(xx=x;xx<x+2;xx++,i<<=1)
  3817.             {
  3818.                 z = z0;
  3819.                 if ((unsigned long)(xx|yy) < VSID)
  3820.                 {
  3821.                     vp = sptr[yy*VSID+xx];
  3822.                     while (1)
  3823.                     {
  3824.                         if (vp[1] > z) z = vp[1];
  3825.                         if (!vp[0]) break;
  3826.                         vp += vp[0]*4;
  3827.                         zz = vp[3]; if (zz > z1) zz = z1;
  3828.                         while (z < zz) clipbuf[(z++)+8] |= i;
  3829.                     }
  3830.                 }
  3831.                 while (z <= z1) clipbuf[(z++)+8] |= i;
  3832.             }
  3833.  
  3834.         xx = x+1; yy = y+1; v = clipbuf[z0+8];
  3835.         for(z=z0;z<z1;z++)
  3836.         {
  3837.             zz = z+1; v = (v>>4)|clipbuf[zz+8];
  3838.             if ((!v) || (v == 255)) continue;
  3839.  
  3840. //---------------Check 1(8) corners of cube (sphere intersection)-------------
  3841.  
  3842.             //if (((v-1)^v) >= v)  //True if v is: {1,2,4,8,16,32,64,128}
  3843.             if (!(v&(v-1)))      //Same as above, but {0,1,2,4,...} (v's never 0)
  3844.             {
  3845.                 ex = xx-px; ey = yy-py; ez = zz-pz;
  3846.                 Zb = ex*vx + ey*vy + ez*vz;
  3847.                 Zc = ex*ex + ey*ey + ez*ez - cr2;
  3848.                 u = Zb*Zb - vxyz*Zc;
  3849.                 if ((((long *)&u)[1] | ((long *)&Zb)[1]) >= 0)
  3850.                 //if ((u >= 0) && (Zb >= 0))
  3851.                 {
  3852.                         //   //Proposed compare optimization:
  3853.                         //f = Zb*Zb-u; g = vxyz*t; h = (Zb*2-g)*g;
  3854.                         //if ((unsigned __int64 *)&f < (unsigned __int64 *)&h)
  3855.                     u = (Zb - sqrt(u)) * rvxyz;
  3856.                     if ((u >= 0) && (u < t))
  3857.                     {
  3858.                         *fx = xx; *fy = yy; *fz = zz; t = u;
  3859.                         *nx = vx*u + px; *ny = vy*u + py; *nz = vz*u + pz;
  3860.                     }
  3861.                 }
  3862.             }
  3863.  
  3864. //---------------Check 3(12) edges of cube (cylinder intersection)-----------
  3865.  
  3866.             vv = v&0x55; if (((vv-1)^vv) >= vv)  //True if (v&0x55)={1,4,16,64}
  3867.             {
  3868.                 ey = yy-py; ez = zz-pz;
  3869.                 Zb = ey*vy + ez*vz;
  3870.                 Zc = ey*ey + ez*ez - cr2;
  3871.                 u = Zb*Zb - vyz*Zc;
  3872.                 if ((((long *)&u)[1] | ((long *)&Zb)[1]) >= 0)
  3873.                 //if ((u >= 0) && (Zb >= 0))
  3874.                 {
  3875.                     u = (Zb - sqrt(u)) * rvyz;
  3876.                     if ((u >= 0) && (u < t))
  3877.                     {
  3878.                         ex = vx*u + px;
  3879.                         if ((ex >= x) && (ex <= xx))
  3880.                         {
  3881.                             *fx = ex; *fy = yy; *fz = zz; t = u;
  3882.                             *nx = ex; *ny = vy*u + py; *nz = vz*u + pz;
  3883.                         }
  3884.                     }
  3885.                 }
  3886.             }
  3887.             vv = v&0x33; if (((vv-1)^vv) >= vv) //True if (v&0x33)={1,2,16,32}
  3888.             {
  3889.                 ex = xx-px; ez = zz-pz;
  3890.                 Zb = ex*vx + ez*vz;
  3891.                 Zc = ex*ex + ez*ez - cr2;
  3892.                 u = Zb*Zb - vxz*Zc;
  3893.                 if ((((long *)&u)[1] | ((long *)&Zb)[1]) >= 0)
  3894.                 //if ((u >= 0) && (Zb >= 0))
  3895.                 {
  3896.                     u = (Zb - sqrt(u)) * rvxz;
  3897.                     if ((u >= 0) && (u < t))
  3898.                     {
  3899.                         ey = vy*u + py;
  3900.                         if ((ey >= y) && (ey <= yy))
  3901.                         {
  3902.                             *fx = xx; *fy = ey; *fz = zz; t = u;
  3903.                             *nx = vx*u + px; *ny = ey; *nz = vz*u + pz;
  3904.                         }
  3905.                     }
  3906.                 }
  3907.             }
  3908.             vv = v&0x0f; if (((vv-1)^vv) >= vv) //True if (v&0x0f)={1,2,4,8}
  3909.             {
  3910.                 ex = xx-px; ey = yy-py;
  3911.                 Zb = ex*vx + ey*vy;
  3912.                 Zc = ex*ex + ey*ey - cr2;
  3913.                 u = Zb*Zb - vxy*Zc;
  3914.                 if ((((long *)&u)[1] | ((long *)&Zb)[1]) >= 0)
  3915.                 //if ((u >= 0) && (Zb >= 0))
  3916.                 {
  3917.                     u = (Zb - sqrt(u)) * rvxy;
  3918.                     if ((u >= 0) && (u < t))
  3919.                     {
  3920.                         ez = vz*u + pz;
  3921.                         if ((ez >= z) && (ez <= zz))
  3922.                         {
  3923.                             *fx = xx; *fy = yy; *fz = ez; t = u;
  3924.                             *nx = vx*u + px; *ny = vy*u + py; *nz = ez;
  3925.                         }
  3926.                     }
  3927.                 }
  3928.             }
  3929.  
  3930. //---------------Check 3(6) faces of cube (plane intersection)---------------
  3931.  
  3932.             if (vx)
  3933.             {
  3934.                 switch(v&0x03)
  3935.                 {
  3936.                     case 0x01: ex = xx+cr; if ((vx > 0) || (px < ex)) goto skipfacex; break;
  3937.                     case 0x02: ex = xx-cr; if ((vx < 0) || (px > ex)) goto skipfacex; break;
  3938.                     default: goto skipfacex;
  3939.                 }
  3940.                 u = (ex - px) * rvx;
  3941.                 if ((u >= 0) && (u < t))
  3942.                 {
  3943.                     ey = vy*u + py;
  3944.                     ez = vz*u + pz;
  3945.                     if ((ey >= y) && (ey <= yy) && (ez >= z) && (ez <= zz))
  3946.                     {
  3947.                         *fx = xx; *fy = ey; *fz = ez; t = u;
  3948.                         *nx = ex; *ny = ey; *nz = ez;
  3949.                     }
  3950.                 }
  3951.             }
  3952. skipfacex:;
  3953.             if (vy)
  3954.             {
  3955.                 switch(v&0x05)
  3956.                 {
  3957.                     case 0x01: ey = yy+cr; if ((vy > 0) || (py < ey)) goto skipfacey; break;
  3958.                     case 0x04: ey = yy-cr; if ((vy < 0) || (py > ey)) goto skipfacey; break;
  3959.                     default: goto skipfacey;
  3960.                 }
  3961.                 u = (ey - py) * rvy;
  3962.                 if ((u >= 0) && (u < t))
  3963.                 {
  3964.                     ex = vx*u + px;
  3965.                     ez = vz*u + pz;
  3966.                     if ((ex >= x) && (ex <= xx) && (ez >= z) && (ez <= zz))
  3967.                     {
  3968.                         *fx = ex; *fy = yy; *fz = ez; t = u;
  3969.                         *nx = ex; *ny = ey; *nz = ez;
  3970.                     }
  3971.                 }
  3972.             }
  3973. skipfacey:;
  3974.             if (vz)
  3975.             {
  3976.                 switch(v&0x11)
  3977.                 {
  3978.                     case 0x01: ez = zz+cr; if ((vz > 0) || (pz < ez)) goto skipfacez; break;
  3979.                     case 0x10: ez = zz-cr; if ((vz < 0) || (pz > ez)) goto skipfacez; break;
  3980.                     default: goto skipfacez;
  3981.                 }
  3982.                 u = (ez - pz) * rvz;
  3983.                 if ((u >= 0) && (u < t))
  3984.                 {
  3985.                     ex = vx*u + px;
  3986.                     ey = vy*u + py;
  3987.                     if ((ex >= x) && (ex <= xx) && (ey >= y) && (ey <= yy))
  3988.                     {
  3989.                         *fx = ex; *fy = ey; *fz = zz; t = u;
  3990.                         *nx = ex; *ny = ey; *nz = ez;
  3991.                     }
  3992.                 }
  3993.             }
  3994. skipfacez:;
  3995.         }
  3996.  
  3997.         if ((x <= ix) && (x > 0) && (dist2linept2d(x-1,y,px,py,vx,vy,thresh2)))
  3998.             { clipit[i1].x = x-1; clipit[i1].y = y; i1 = ((i1+1)&(MAXCLIPIT-1)); }
  3999.         if ((x >= ix) && (x < VSID-1) && (dist2linept2d(x+1,y,px,py,vx,vy,thresh2)))
  4000.             { clipit[i1].x = x+1; clipit[i1].y = y; i1 = ((i1+1)&(MAXCLIPIT-1)); }
  4001.         if ((y <= y0) && (y > 0) && (dist2linept2d(x,y-1,px,py,vx,vy,thresh2)))
  4002.             { clipit[i1].x = x; clipit[i1].y = y-1; i1 = ((i1+1)&(MAXCLIPIT-1)); y0--; }
  4003.         if ((y >= y1) && (y < VSID-1) && (dist2linept2d(x,y+1,px,py,vx,vy,thresh2)))
  4004.             { clipit[i1].x = x; clipit[i1].y = y+1; i1 = ((i1+1)&(MAXCLIPIT-1)); y1++; }
  4005.         if (i0 == i1) break;
  4006.         x = clipit[i0].x; y = clipit[i0].y; i0 = ((i0+1)&(MAXCLIPIT-1));
  4007.     }
  4008.  
  4009.     if ((*nx) < acr) (*nx) = acr;
  4010.     if ((*ny) < acr) (*ny) = acr;
  4011.     if ((*nx) > VSID-acr) (*nx) = VSID-acr;
  4012.     if ((*ny) > VSID-acr) (*ny) = VSID-acr;
  4013.     if ((*nz) > MAXZDIM-1-acr) (*nz) = MAXZDIM-1-acr;
  4014.     if ((*nz) < MAXZDIM-2048) (*nz) = MAXZDIM-2048;
  4015.  
  4016.     return (t == 1);
  4017. }
  4018.  
  4019. #endif
  4020.  
  4021. static double gx0, gy0, gcrf2, grdst, gendt, gux, guy;
  4022. static long gdist2square (double x, double y)
  4023. {
  4024.     double t;
  4025.     x -= gx0; y -= gy0; t = x*gux + y*guy; if (t <= 0) t = gcrf2;
  4026.     else if (t*grdst >= gendt) { x -= gux*gendt; y -= guy*gendt; t = gcrf2; }
  4027.     else t = t*t*grdst + gcrf2;
  4028.     return(x*x + y*y <= t);
  4029. }
  4030.  
  4031. long sphtrace (double x0, double y0, double z0,          //start pt
  4032.                     double vx, double vy, double vz,          //move vector
  4033.                     double *hitx, double *hity, double *hitz, //new pt after collision
  4034.                     double *clpx, double *clpy, double *clpz, //pt causing collision
  4035.                     double cr, double acr)
  4036. {
  4037.     double f, t, dax, day, daz, vyx, vxy, vxz, vyz, rvz, cr2, fz, fc;
  4038.     double dx, dy, dx1, dy1;
  4039.     double nx, ny, intx, inty, intz, dxy, dxz, dyz, dxyz, rxy, rxz, ryz, rxyz;
  4040.     long i, j, x, y, ix, iy0, iy1, i0, i1, iz[2], cz0, cz1;
  4041.     char *v;
  4042.  
  4043.          //Precalculate global constants for ins & getval functions
  4044.     if ((vx == 0) && (vy == 0) && (vz == 0))
  4045.         { (*hitx) = x0; (*hity) = y0; (*hitz) = z0; return(1); }
  4046.     gux = vx; guy = vy; gx0 = x0; gy0 = y0; dxy = vx*vx + vy*vy;
  4047.     if (dxy != 0) rxy = 1.0 / dxy; else rxy = 0;
  4048.     grdst = rxy; gendt = 1; cr2 = cr*cr; t = cr + 0.7072; gcrf2 = t*t;
  4049.  
  4050.     if (((long *)&vz)[1] >= 0) { dtol(   z0-cr-.5,&cz0); dtol(vz+z0+cr-.5,&cz1); }
  4051.                                  else { dtol(vz+z0-cr-.5,&cz0); dtol(   z0+cr-.5,&cz1); }
  4052.  
  4053.         //Precalculate stuff for closest point on cube finder
  4054.     dax = 0; day = 0; vyx = 0; vxy = 0; rvz = 0; vxz = 0; vyz = 0;
  4055.     if (vx != 0) { vyx = vy/vx; if (((long *)&vx)[1] >= 0) dax = x0+cr; else dax = x0-cr-1; }
  4056.     if (vy != 0) { vxy = vx/vy; if (((long *)&vy)[1] >= 0) day = y0+cr; else day = y0-cr-1; }
  4057.     if (vz != 0)
  4058.     {
  4059.         rvz = 1.0/vz; vxz = vx*rvz; vyz = vy*rvz;
  4060.         if (((long *)&vz)[1] >= 0) daz = z0+cr; else daz = z0-cr;
  4061.     }
  4062.  
  4063.     dxyz = vz*vz;
  4064.     dxz = vx*vx+dxyz; if (dxz != 0) rxz = 1.0 / dxz;
  4065.     dyz = vy*vy+dxyz; if (dyz != 0) ryz = 1.0 / dyz;
  4066.     dxyz += dxy; rxyz = 1.0 / dxyz;
  4067.  
  4068.     dtol(x0-.5,&x); dtol(y0-.5,&y);
  4069.     ix = x; iy0 = iy1 = y;
  4070.     i0 = 0; clipit[0].x = x; clipit[0].y = y; i1 = 1;
  4071.     do
  4072.     {
  4073.         x = clipit[i0].x; y = clipit[i0].y; i0 = ((i0+1)&(MAXCLIPIT-1));
  4074.  
  4075.         dx = (double)x; dx1 = (double)(x+1);
  4076.         dy = (double)y; dy1 = (double)(y+1);
  4077.  
  4078.             //closest point on cube finder
  4079.             //Plane intersection (both vertical planes)
  4080. #if 0
  4081.         intx = dbound((dy-day)*vxy + x0,dx,dx1);
  4082.         inty = dbound((dx-dax)*vyx + y0,dy,dy1);
  4083. #else
  4084.         intx = (dy-day)*vxy + x0;
  4085.         inty = (dx-dax)*vyx + y0;
  4086.         if (((long *)&intx)[1] < ((long *)&dx)[1]) intx = dx;
  4087.         if (((long *)&inty)[1] < ((long *)&dy)[1]) inty = dy;
  4088.         if (((long *)&intx)[1] >= ((long *)&dx1)[1]) intx = dx1;
  4089.         if (((long *)&inty)[1] >= ((long *)&dy1)[1]) inty = dy1;
  4090.         //if (intx < (double)x) intx = (double)x;
  4091.         //if (inty < (double)y) inty = (double)y;
  4092.         //if (intx > (double)(x+1)) intx = (double)(x+1);
  4093.         //if (inty > (double)(y+1)) inty = (double)(y+1);
  4094. #endif
  4095.  
  4096.         do
  4097.         {
  4098.             if (((long *)&dxy)[1] == 0) { t = -1.0; continue; }
  4099.             nx = intx-x0; ny = inty-y0; t = vx*nx + vy*ny; if (((long *)&t)[1] < 0) continue;
  4100.             f = cr2 - nx*nx - ny*ny; if (((long *)&f)[1] >= 0) { t = -1.0; continue; }
  4101.             f = f*dxy + t*t; if (((long *)&f)[1] < 0) { t = -1.0; continue; }
  4102.             t = (t-sqrt(f))*rxy;
  4103.         } while (0);
  4104.         if (t >= gendt) goto sphtracecont;
  4105.         if (((long *)&t)[1] < 0) intz = z0; else intz = vz*t + z0;
  4106.  
  4107.             //Find closest ceil(iz[0]) & flor(iz[1]) in (x,y) column
  4108.         dtol(intz-.5,&i);
  4109.         if ((unsigned long)(x|y) < VSID)
  4110.         {
  4111.             v = sptr[y*VSID+x]; iz[0] = MAXZDIM-2048; iz[1] = v[1];
  4112.             while (i >= iz[1])
  4113.             {
  4114.                 if (!v[0]) { iz[1] = -1; break; }
  4115.                 v += v[0]*4;
  4116.                 iz[0] = v[3]; if (i < iz[0]) { iz[1] = -1; break; }
  4117.                 iz[1] = v[1];
  4118.             }
  4119.         }
  4120.         else iz[1] = -1;
  4121.  
  4122.             //hit xz plane, yz plane or z-axis edge?
  4123.         if (iz[1] < 0) //Treat whole column as solid
  4124.         {
  4125.             if (((long *)&t)[1] >= 0) { gendt = t; (*clpx) = intx; (*clpy) = inty; (*clpz) = intz; goto sphtracecont; }
  4126.         }
  4127.  
  4128.             //Must check tops & bottoms of slab
  4129.         for(i=1;i>=0;i--)
  4130.         {
  4131.                 //Ceil/flor outside of quick&dirty bounding box
  4132.             if ((iz[i] < cz0) || (iz[i] > cz1)) continue;
  4133.  
  4134.                 //Plane intersection (parallel to ground)
  4135.             intz = (double)iz[i]; t = intz-daz;
  4136.             intx = t*vxz + x0;
  4137.             inty = t*vyz + y0;
  4138.  
  4139.             j = 0;                         // A ³ 8 ³ 9
  4140.             //     if (intx < dx)  j |= 2; //ΔΔΔΕΔΔΔΕΔΔΔ
  4141.             //else if (intx > dx1) j |= 1; // 2 ³ 0 ³ 1
  4142.             //     if (inty < dy)  j |= 8; //ΔΔΔΕΔΔΔΕΔΔΔ
  4143.             //else if (inty > dy1) j |= 4; // 6 ³ 4 ³ 5
  4144.                   if (((long *)&intx)[1] <  ((long *)&dx)[1])  j |= 2;
  4145.             else if (((long *)&intx)[1] >= ((long *)&dx1)[1]) j |= 1;
  4146.                   if (((long *)&inty)[1] <  ((long *)&dy)[1])  j |= 8;
  4147.             else if (((long *)&inty)[1] >= ((long *)&dy1)[1]) j |= 4;
  4148.  
  4149.                 //NOTE: only need to check once per "for"!
  4150.             if ((!j) && (vz != 0)) //hit xy plane?
  4151.             {
  4152.                 t *= rvz;
  4153.                 if ((((long *)&t)[1] >= 0) && (t < gendt)) { gendt = t; (*clpx) = intx; (*clpy) = inty; (*clpz) = intz; }
  4154.                 continue;
  4155.             }
  4156.  
  4157.                 //common calculations used for rest of checks...
  4158.             fz = intz-z0; fc = cr2-fz*fz; fz *= vz;
  4159.  
  4160.             if (j&3)
  4161.             {
  4162.                 nx = (double)((j&1)+x);
  4163.                 if (((long *)&dxz)[1] != 0) //hit y-axis edge?
  4164.                 {
  4165.                     f = nx-x0; t = vx*f + fz; f = (fc - f*f)*dxz + t*t;
  4166.                     if (((long *)&f)[1] >= 0) t = (t-sqrt(f))*rxz; else t = -1.0;
  4167.                 } else t = -1.0;
  4168.                 ny = vy*t + y0;
  4169.                       if (((long *)&ny)[1] > ((long *)&dy1)[1]) j |= 0x10;
  4170.                 else if (((long *)&ny)[1] >= ((long *)&dy)[1])
  4171.                 {
  4172.                     if ((((long *)&t)[1] >= 0) && (t < gendt)) { gendt = t; (*clpx) = nx; (*clpy) = ny; (*clpz) = intz; }
  4173.                     continue;
  4174.                 }
  4175.                 inty = (double)(((j>>4)&1)+y);
  4176.             }
  4177.             else inty = (double)(((j>>2)&1)+y);
  4178.  
  4179.             if (j&12)
  4180.             {
  4181.                 ny = (double)(((j>>2)&1)+y);
  4182.                 if (((long *)&dyz)[1] != 0) //hit x-axis edge?
  4183.                 {
  4184.                     f = ny-y0; t = vy*f + fz; f = (fc - f*f)*dyz + t*t;
  4185.                     if (((long *)&f)[1] >= 0) t = (t-sqrt(f))*ryz; else t = -1.0;
  4186.                 } else t = -1.0;
  4187.                 nx = vx*t + x0;
  4188.                       if (((long *)&nx)[1] > ((long *)&dx1)[1]) j |= 0x20;
  4189.                 else if (((long *)&nx)[1] >= ((long *)&dx)[1])
  4190.                 {
  4191.                     if ((((long *)&t)[1] >= 0) && (t < gendt)) { gendt = t; (*clpx) = nx; (*clpy) = ny; (*clpz) = intz; }
  4192.                     continue;
  4193.                 }
  4194.                 intx = (double)(((j>>5)&1)+x);
  4195.             }
  4196.             else intx = (double)((j&1)+x);
  4197.  
  4198.                 //hit corner?
  4199.             nx = intx-x0; ny = inty-y0;
  4200.             t = vx*nx + vy*ny + fz; if (((long *)&t)[1] < 0) continue;
  4201.             f = fc - nx*nx - ny*ny; if (((long *)&f)[1] >= 0) continue;
  4202.             f = f*dxyz + t*t; if (((long *)&f)[1] < 0) continue;
  4203.             t = (t-sqrt(f))*rxyz;
  4204.             if (t < gendt) { gendt = t; (*clpx) = intx; (*clpy) = inty; (*clpz) = intz; }
  4205.         }
  4206. sphtracecont:;
  4207.         if ((x <= ix)  && (x >      0) && (gdist2square(dx- .5,dy+ .5))) { clipit[i1].x = x-1; clipit[i1].y = y; i1 = ((i1+1)&(MAXCLIPIT-1)); }
  4208.         if ((x >= ix)  && (x < VSID-1) && (gdist2square(dx+1.5,dy+ .5))) { clipit[i1].x = x+1; clipit[i1].y = y; i1 = ((i1+1)&(MAXCLIPIT-1)); }
  4209.         if ((y <= iy0) && (y >      0) && (gdist2square(dx+ .5,dy- .5))) { clipit[i1].x = x; clipit[i1].y = y-1; i1 = ((i1+1)&(MAXCLIPIT-1)); iy0 = y-1; }
  4210.         if ((y >= iy1) && (y < VSID-1) && (gdist2square(dx+ .5,dy+1.5))) { clipit[i1].x = x; clipit[i1].y = y+1; i1 = ((i1+1)&(MAXCLIPIT-1)); iy1 = y+1; }
  4211.     } while (i0 != i1);
  4212. #if 1
  4213.     (*hitx) = dbound(vx*gendt + x0,acr,VSID-acr);
  4214.     (*hity) = dbound(vy*gendt + y0,acr,VSID-acr);
  4215.     (*hitz) = dbound(vz*gendt + z0,MAXZDIM-2048+acr,MAXZDIM-1-acr);
  4216. #else
  4217.     (*hitx) = min(max(vx*gendt + x0,acr),VSID-acr);
  4218.     (*hity) = min(max(vy*gendt + y0,acr),VSID-acr);
  4219.     (*hitz) = min(max(vz*gendt + z0,MAXZDIM-2048+acr),MAXZDIM-1-acr);
  4220. #endif
  4221.     return(gendt == 1);
  4222. }
  4223.  
  4224. void clipmove (dpoint3d *p, dpoint3d *v, double acr)
  4225. {
  4226.     double f, gx, gy, gz, nx, ny, nz, ex, ey, ez, hitx, hity, hitz, cr;
  4227.     //double nx2, ny2, nz2, ex2, ey2, ez2; //double ox, oy, oz;
  4228.     long i, j, k;
  4229.  
  4230.     //ox = p->x; oy = p->y; oz = p->z;
  4231.     gx = p->x+v->x; gy = p->y+v->y; gz = p->z+v->z;
  4232.  
  4233.     cr = findmaxcr(p->x,p->y,p->z,acr);
  4234.     vx5.clipmaxcr = cr;
  4235.  
  4236.     vx5.cliphitnum = 0;
  4237.     for(i=0;i<3;i++)
  4238.     {
  4239.         if ((v->x == 0) && (v->y == 0) && (v->z == 0)) break;
  4240.  
  4241.         cr -= 1e-7;  //Shrinking radius error control hack
  4242.  
  4243.         //j = sphtraceo(p->x,p->y,p->z,v->x,v->y,v->z,&nx,&ny,&nz,&ex,&ey,&ez,cr,acr);
  4244.         //k = sphtraceo(p->x,p->y,p->z,v->x,v->y,v->z,&nx2,&ny2,&nz2,&ex2,&ey2,&ez2,cr,acr);
  4245.  
  4246.         j = sphtrace(p->x,p->y,p->z,v->x,v->y,v->z,&nx,&ny,&nz,&ex,&ey,&ez,cr,acr);
  4247.  
  4248.         //if ((j != k) || (fabs(nx-nx2) > .000001) || (fabs(ny-ny2) > .000001) || (fabs(nz-nz2) > .000001) ||
  4249.         //   ((j == 0) && ((fabs(ex-ex2) > .000001) || (fabs(ey-ey2) > .000001) || (fabs(ez-ez2) > .000001))))
  4250.         //{
  4251.         //   printf("%d %f %f %f %f %f %f\n",i,p->x,p->y,p->z,v->x,v->y,v->z);
  4252.         //   printf("%f %f %f ",nx,ny,nz); if (!j) printf("%f %f %f\n",ex,ey,ez); else printf("\n");
  4253.         //   printf("%f %f %f ",nx2,ny2,nz2); if (!k) printf("%f %f %f\n",ex2,ey2,ez2); else printf("\n");
  4254.         //   printf("\n");
  4255.         //}
  4256.         if (j) { p->x = nx; p->y = ny; p->z = nz; break; }
  4257.  
  4258.         vx5.cliphit[i].x = ex; vx5.cliphit[i].y = ey; vx5.cliphit[i].z = ez;
  4259.         vx5.cliphitnum = i+1;
  4260.         p->x = nx; p->y = ny; p->z = nz;
  4261.  
  4262.             //Calculate slide vector
  4263.         v->x = gx-nx; v->y = gy-ny; v->z = gz-nz;
  4264.         switch(i)
  4265.         {
  4266.             case 0:
  4267.                 hitx = ex-nx; hity = ey-ny; hitz = ez-nz;
  4268.                 f = (v->x*hitx + v->y*hity + v->z*hitz) / (cr * cr);
  4269.                 v->x -= hitx*f; v->y -= hity*f; v->z -= hitz*f;
  4270.                 break;
  4271.             case 1:
  4272.                 nx -= ex; ny -= ey; nz -= ez;
  4273.                 ex = hitz*ny - hity*nz;
  4274.                 ey = hitx*nz - hitz*nx;
  4275.                 ez = hity*nx - hitx*ny;
  4276.                 f = ex*ex + ey*ey + ez*ez; if (f <= 0) break;
  4277.                 f = (v->x*ex + v->y*ey + v->z*ez) / f;
  4278.                 v->x = ex*f; v->y = ey*f; v->z = ez*f;
  4279.                 break;
  4280.             default: break;
  4281.         }
  4282.     }
  4283.  
  4284.         //If you didn't move much, then don't move at all. This helps prevents
  4285.         //cliprad from shrinking, but you get stuck too much :(
  4286.     //if ((p->x-ox)*(p->x-ox) + (p->y-oy)*(p->y-oy) + (p->z-oz)*(p->z-oz) < 1e-12)
  4287.     //   { p->x = ox; p->y = oy; p->z = oz; }
  4288. }
  4289.  
  4290. long cansee (point3d *p0, point3d *p1, lpoint3d *hit)
  4291. {
  4292.     lpoint3d a, c, d, p, i;
  4293.     point3d f, g;
  4294.     long cnt;
  4295.  
  4296.     ftol(p0->x-.5,&a.x); ftol(p0->y-.5,&a.y); ftol(p0->z-.5,&a.z);
  4297.     if (isvoxelsolid(a.x,a.y,a.z)) { hit->x = a.x; hit->y = a.y; hit->z = a.z; return(0); }
  4298.     ftol(p1->x-.5,&c.x); ftol(p1->y-.5,&c.y); ftol(p1->z-.5,&c.z);
  4299.     cnt = 0;
  4300.  
  4301.           if (c.x <  a.x) { d.x = -1; f.x = p0->x-a.x;   g.x = (p0->x-p1->x)*1024; cnt += a.x-c.x; }
  4302.     else if (c.x != a.x) { d.x =  1; f.x = a.x+1-p0->x; g.x = (p1->x-p0->x)*1024; cnt += c.x-a.x; }
  4303.     else f.x = g.x = 0;
  4304.           if (c.y <  a.y) { d.y = -1; f.y = p0->y-a.y;   g.y = (p0->y-p1->y)*1024; cnt += a.y-c.y; }
  4305.     else if (c.y != a.y) { d.y =  1; f.y = a.y+1-p0->y; g.y = (p1->y-p0->y)*1024; cnt += c.y-a.y; }
  4306.     else f.y = g.y = 0;
  4307.           if (c.z <  a.z) { d.z = -1; f.z = p0->z-a.z;   g.z = (p0->z-p1->z)*1024; cnt += a.z-c.z; }
  4308.     else if (c.z != a.z) { d.z =  1; f.z = a.z+1-p0->z; g.z = (p1->z-p0->z)*1024; cnt += c.z-a.z; }
  4309.     else f.z = g.z = 0;
  4310.  
  4311.     ftol(f.x*g.z - f.z*g.x,&p.x); ftol(g.x,&i.x);
  4312.     ftol(f.y*g.z - f.z*g.y,&p.y); ftol(g.y,&i.y);
  4313.     ftol(f.y*g.x - f.x*g.y,&p.z); ftol(g.z,&i.z);
  4314.  
  4315.         //NOTE: GIGO! This can happen if p0,p1 (cansee input) is NaN, Inf, etc...
  4316.     if ((unsigned long)cnt > (VSID+VSID+2048)*2) cnt = (VSID+VSID+2048)*2;
  4317.     while (cnt > 0)
  4318.     {
  4319.         if (((p.x|p.y) >= 0) && (a.z != c.z)) { a.z += d.z; p.x -= i.x; p.y -= i.y; }
  4320.         else if ((p.z >= 0) && (a.x != c.x))  { a.x += d.x; p.x += i.z; p.z -= i.y; }
  4321.         else                                  { a.y += d.y; p.y += i.z; p.z += i.x; }
  4322.         if (isvoxelsolid(a.x,a.y,a.z)) break;
  4323.         cnt--;
  4324.     }
  4325.     hit->x = a.x; hit->y = a.y; hit->z = a.z; return(!cnt);
  4326. }
  4327.  
  4328.     //  p: start position
  4329.     //  d: direction
  4330.     //  h: coordinate of voxel hit (if any)
  4331.     //ind: pointer to surface voxel's 32-bit color (0 if none hit)
  4332.     //dir: 0-5: last direction moved upon hit (-1 if inside solid)
  4333. void hitscan (dpoint3d *p, dpoint3d *d, lpoint3d *h, long **ind, long *dir)
  4334. {
  4335.     long ixi, iyi, izi, dx, dy, dz, dxi, dyi, dzi, z0, z1, minz;
  4336.     float f, kx, ky, kz;
  4337.     char *v;
  4338.  
  4339.         //Note: (h->x,h->y,h->z) MUST be rounded towards -inf
  4340.     (h->x) = (long)p->x;
  4341.     (h->y) = (long)p->y;
  4342.     (h->z) = (long)p->z;
  4343.     if ((unsigned long)(h->x|h->y) >= VSID) { (*ind) = 0; (*dir) = -1; return; }
  4344.     ixi = (((((signed long *)&d->x)[1])>>31)|1);
  4345.     iyi = (((((signed long *)&d->y)[1])>>31)|1);
  4346.     izi = (((((signed long *)&d->z)[1])>>31)|1);
  4347.  
  4348.     minz = min(h->z,0);
  4349.  
  4350.     f = 0x3fffffff/VSID; //Maximum delta value
  4351.     if ((fabs(d->x) >= fabs(d->y)) && (fabs(d->x) >= fabs(d->z)))
  4352.     {
  4353.         kx = 1024.0;
  4354.         if (d->y == 0) ky = f; else ky = min(fabs(d->x/d->y)*1024.0,f);
  4355.         if (d->z == 0) kz = f; else kz = min(fabs(d->x/d->z)*1024.0,f);
  4356.     }
  4357.     else if (fabs(d->y) >= fabs(d->z))
  4358.     {
  4359.         ky = 1024.0;
  4360.         if (d->x == 0) kx = f; else kx = min(fabs(d->y/d->x)*1024.0,f);
  4361.         if (d->z == 0) kz = f; else kz = min(fabs(d->y/d->z)*1024.0,f);
  4362.     }
  4363.     else
  4364.     {
  4365.         kz = 1024.0;
  4366.         if (d->x == 0) kx = f; else kx = min(fabs(d->z/d->x)*1024.0,f);
  4367.         if (d->y == 0) ky = f; else ky = min(fabs(d->z/d->y)*1024.0,f);
  4368.     }
  4369.     ftol(kx,&dxi); ftol((p->x-(float)h->x)*kx,&dx); if (ixi >= 0) dx = dxi-dx;
  4370.     ftol(ky,&dyi); ftol((p->y-(float)h->y)*ky,&dy); if (iyi >= 0) dy = dyi-dy;
  4371.     ftol(kz,&dzi); ftol((p->z-(float)h->z)*kz,&dz); if (izi >= 0) dz = dzi-dz;
  4372.  
  4373.     v = sptr[h->y*VSID+h->x];
  4374.     if (h->z >= v[1])
  4375.     {
  4376.         do
  4377.         {
  4378.             if (!v[0]) { (*ind) = 0; (*dir) = -1; return; }
  4379.             v += v[0]*4;
  4380.         } while (h->z >= v[1]);
  4381.         z0 = v[3];
  4382.     } else z0 = minz;
  4383.     z1 = v[1];
  4384.  
  4385.     while (1)
  4386.     {
  4387.         //Check cube at: h->x,h->y,h->z
  4388.  
  4389.         if ((dz <= dx) && (dz <= dy))
  4390.         {
  4391.             h->z += izi; dz += dzi; (*dir) = 5-(izi>0);
  4392.  
  4393.                 //Check if h->z ran into anything solid
  4394.             if (h->z < z0)
  4395.             {
  4396.                 if (h->z < minz) (*ind) = 0; else (*ind) = (long *)&v[-4];
  4397.                 return;
  4398.             }
  4399.             if (h->z >= z1) { (*ind) = (long *)&v[4]; return; }
  4400.         }
  4401.         else
  4402.         {
  4403.             if (dx < dy)
  4404.             {
  4405.                 h->x += ixi; dx += dxi; (*dir) = 1-(ixi>0);
  4406.                 if ((unsigned long)h->x >= VSID) { (*ind) = 0; return; }
  4407.             }
  4408.             else
  4409.             {
  4410.                 h->y += iyi; dy += dyi; (*dir) = 3-(iyi>0);
  4411.                 if ((unsigned long)h->y >= VSID) { (*ind) = 0; return; }
  4412.             }
  4413.  
  4414.                 //Check if (h->x, h->y) ran into anything solid
  4415.             v = sptr[h->y*VSID+h->x];
  4416.             while (1)
  4417.             {
  4418.                 if (h->z < v[1])
  4419.                 {
  4420.                     if (v == sptr[h->y*VSID+h->x]) { z0 = minz; z1 = v[1]; break; }
  4421.                     if (h->z < v[3]) { (*ind) = (long *)&v[(h->z-v[3])*4]; return; }
  4422.                     z0 = v[3]; z1 = v[1]; break;
  4423.                 }
  4424.                 else if ((h->z <= v[2]) || (!v[0]))
  4425.                     { (*ind) = (long *)&v[(h->z-v[1])*4+4]; return; }
  4426.  
  4427.                 v += v[0]*4;
  4428.             }
  4429.         }
  4430.     }
  4431. }
  4432.  
  4433.     // p0: start position
  4434.     // v0: direction
  4435.     //spr: pointer of sprite to test collision with
  4436.     //  h: coordinate of voxel hit in sprite coordinates (if any)
  4437.     //ind: pointer to voxel hit (kv6voxtype) (0 if none hit)
  4438.     //vsc:  input: max multiple/fraction of v0's length to scan (1.0 for |v0|)
  4439.     //     output: multiple/fraction of v0's length of hit point
  4440. void sprhitscan (dpoint3d *p0, dpoint3d *v0, vx5sprite *spr, lpoint3d *h, kv6voxtype **ind, float *vsc)
  4441. {
  4442.     kv6voxtype *vx[4];
  4443.     kv6data *kv;
  4444.     point3d t, u, v;
  4445.     lpoint3d a, d, p, q;
  4446.     float f, g;
  4447.     long i, x, y, xup, ix0, ix1;
  4448.  
  4449.     (*ind) = 0;
  4450.     if (spr->flags&2)
  4451.     {
  4452.         kfatype *kf = spr->kfaptr;
  4453.             //This sets the sprite pointer to be the parent sprite (voxnum
  4454.             //   of the main sprite is invalid for KFA sprites!)
  4455.         spr = &kf->spr[kf->hingesort[(kf->numhin)-1]];
  4456.     }
  4457.     kv = spr->voxnum; if (!kv) return;
  4458.  
  4459.         //d transformed to spr space (0,0,0,kv->xsiz,kv->ysiz,kv->zsiz)
  4460.     v.x = v0->x*spr->s.x + v0->y*spr->s.y + v0->z*spr->s.z;
  4461.     v.y = v0->x*spr->h.x + v0->y*spr->h.y + v0->z*spr->h.z;
  4462.     v.z = v0->x*spr->f.x + v0->y*spr->f.y + v0->z*spr->f.z;
  4463.  
  4464.         //p transformed to spr space (0,0,0,kv->xsiz,kv->ysiz,kv->zsiz)
  4465.     t.x = p0->x-spr->p.x;
  4466.     t.y = p0->y-spr->p.y;
  4467.     t.z = p0->z-spr->p.z;
  4468.     u.x = t.x*spr->s.x + t.y*spr->s.y + t.z*spr->s.z;
  4469.     u.y = t.x*spr->h.x + t.y*spr->h.y + t.z*spr->h.z;
  4470.     u.z = t.x*spr->f.x + t.y*spr->f.y + t.z*spr->f.z;
  4471.     u.x /= (spr->s.x*spr->s.x + spr->s.y*spr->s.y + spr->s.z*spr->s.z);
  4472.     u.y /= (spr->h.x*spr->h.x + spr->h.y*spr->h.y + spr->h.z*spr->h.z);
  4473.     u.z /= (spr->f.x*spr->f.x + spr->f.y*spr->f.y + spr->f.z*spr->f.z);
  4474.     u.x += kv->xpiv; u.y += kv->ypiv; u.z += kv->zpiv;
  4475.  
  4476.     ix0 = max(vx5.xplanemin,0);
  4477.     ix1 = min(vx5.xplanemax,kv->xsiz);
  4478.  
  4479.         //Increment ray until it hits bounding box
  4480.         // (ix0,0,0,ix1-1ulp,kv->ysiz-1ulp,kv->zsiz-1ulp)
  4481.     g = (float)ix0;
  4482.     t.x = (float)ix1;      (*(long *)&t.x)--;
  4483.     t.y = (float)kv->ysiz; (*(long *)&t.y)--;
  4484.     t.z = (float)kv->zsiz; (*(long *)&t.z)--;
  4485.           if (u.x <   g) { if (v.x <= 0) return; f = (  g-u.x)/v.x; u.x =   g; u.y += v.y*f; u.z += v.z*f; }
  4486.     else if (u.x > t.x) { if (v.x >= 0) return; f = (t.x-u.x)/v.x; u.x = t.x; u.y += v.y*f; u.z += v.z*f; }
  4487.           if (u.y <   0) { if (v.y <= 0) return; f = (  0-u.y)/v.y; u.y =   0; u.x += v.x*f; u.z += v.z*f; }
  4488.     else if (u.y > t.y) { if (v.y >= 0) return; f = (t.y-u.y)/v.y; u.y = t.y; u.x += v.x*f; u.z += v.z*f; }
  4489.           if (u.z <   0) { if (v.z <= 0) return; f = (  0-u.z)/v.z; u.z =   0; u.x += v.x*f; u.y += v.y*f; }
  4490.     else if (u.z > t.z) { if (v.z >= 0) return; f = (t.z-u.z)/v.z; u.z = t.z; u.x += v.x*f; u.y += v.y*f; }
  4491.  
  4492.     ix1 -= ix0;
  4493.  
  4494.     g = 262144.0 / sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
  4495.  
  4496.         //Note: (a.x,a.y,a.z) MUST be rounded towards -inf
  4497.     ftol(u.x-.5,&a.x); if ((unsigned long)(a.x-ix0) >= ix1) return;
  4498.     ftol(u.y-.5,&a.y); if ((unsigned long)a.y >= kv->ysiz) return;
  4499.     ftol(u.z-.5,&a.z); if ((unsigned long)a.z >= kv->zsiz) return;
  4500.     if (*(long *)&v.x < 0) { d.x = -1; u.x -= a.x;      v.x *= -g; }
  4501.                             else { d.x =  1; u.x = a.x+1-u.x; v.x *=  g; }
  4502.     if (*(long *)&v.y < 0) { d.y = -1; u.y -= a.y;      v.y *= -g; }
  4503.                             else { d.y =  1; u.y = a.y+1-u.y; v.y *=  g; }
  4504.     if (*(long *)&v.z < 0) { d.z = -1; u.z -= a.z;      v.z *= -g; }
  4505.                             else { d.z =  1; u.z = a.z+1-u.z; v.z *=  g; }
  4506.     ftol(u.x*v.z - u.z*v.x,&p.x); ftol(v.x,&q.x);
  4507.     ftol(u.y*v.z - u.z*v.y,&p.y); ftol(v.y,&q.y);
  4508.     ftol(u.y*v.x - u.x*v.y,&p.z); ftol(v.z,&q.z);
  4509.  
  4510.         //Check if voxel at: (a.x,a.y,a.z) is solid
  4511.     vx[0] = kv->vox;
  4512.     for(x=0;x<a.x;x++) vx[0] += kv->xlen[x];
  4513.     vx[1] = vx[0]; xup = x*kv->ysiz;
  4514.     for(y=0;y<a.y;y++) vx[1] += kv->ylen[xup+y];
  4515.     vx[2] = vx[1]; vx[3] = &vx[1][kv->ylen[xup+y]];
  4516.  
  4517.     while (1)
  4518.     {
  4519.         //vs = kv->vox; //Brute force: remove all vx[?] code to enable this
  4520.         //for(x=0;x<a.x;x++) vs += kv->xlen[x];
  4521.         //for(y=0;y<a.y;y++) vs += kv->ylen[x*kv->ysiz+y];
  4522.         //for(ve=&vs[kv->ylen[x+y]];vs<ve;vs++) if (vs->z == a.z) break;
  4523.  
  4524.             //Check if voxel at: (a.x,a.y,a.z) is solid
  4525.         if (vx[1] < vx[3])
  4526.         {
  4527.             while ((a.z < vx[2]->z) && (vx[2] > vx[1]  )) vx[2]--;
  4528.             while ((a.z > vx[2]->z) && (vx[2] < vx[3]-1)) vx[2]++;
  4529.             if (a.z == vx[2]->z) break;
  4530.         }
  4531.  
  4532.         if ((p.x|p.y) >= 0)
  4533.         {
  4534.             a.z += d.z; if ((unsigned long)a.z >= kv->zsiz) return;
  4535.             p.x -= q.x; p.y -= q.y;
  4536.         }
  4537.         else if (p.z < 0)
  4538.         {
  4539.             a.y += d.y; if ((unsigned long)a.y >= kv->ysiz) return;
  4540.             p.y += q.z; p.z += q.x;
  4541.  
  4542.             if (a.y < y) { y--; vx[1] -= kv->ylen[xup+y];      }
  4543.             if (a.y > y) {      vx[1] += kv->ylen[xup+y]; y++; }
  4544.             vx[2] = vx[1]; vx[3] = &vx[1][kv->ylen[xup+y]];
  4545.         }
  4546.         else
  4547.         {
  4548.             a.x += d.x; if ((unsigned long)(a.x-ix0) >= ix1) return;
  4549.             p.x += q.z; p.z -= q.y;
  4550.  
  4551.             if (a.x < x) { x--; vx[0] -= kv->xlen[x];      xup -= kv->ysiz; }
  4552.             if (a.x > x) {      vx[0] += kv->xlen[x]; x++; xup += kv->ysiz; }
  4553.             if ((a.y<<1) < kv->ysiz) //Start y-slice search from closer side
  4554.             {
  4555.                 vx[1] = vx[0];
  4556.                 for(y=0;y<a.y;y++) vx[1] += kv->ylen[xup+y];
  4557.             }
  4558.             else
  4559.             {
  4560.                 vx[1] = &vx[0][kv->xlen[x]];
  4561.                 for(y=kv->ysiz;y>a.y;y--) vx[1] -= kv->ylen[xup+y-1];
  4562.             }
  4563.             vx[2] = vx[1]; vx[3] = &vx[1][kv->ylen[xup+y]];
  4564.         }
  4565.     }
  4566.  
  4567.         //given: a = kv6 coordinate, find: v = vxl coordinate
  4568.     u.x = (float)a.x-kv->xpiv;
  4569.     u.y = (float)a.y-kv->ypiv;
  4570.     u.z = (float)a.z-kv->zpiv;
  4571.     v.x = u.x*spr->s.x + u.y*spr->h.x + u.z*spr->f.x + spr->p.x;
  4572.     v.y = u.x*spr->s.y + u.y*spr->h.y + u.z*spr->f.y + spr->p.y;
  4573.     v.z = u.x*spr->s.z + u.y*spr->h.z + u.z*spr->f.z + spr->p.z;
  4574.  
  4575.         //Stupid dot product stuff...
  4576.     f = ((v.x-p0->x)*v0->x + (v.y-p0->y)*v0->y + (v.z-p0->z)*v0->z) /
  4577.           (v0->x*v0->x + v0->y*v0->y + v0->z*v0->z);
  4578.     if (f >= (*vsc)) return;
  4579.     { (*vsc) = f; (*h) = a; (*ind) = vx[2]; (*vsc) = f; }
  4580. }
  4581.  
  4582. unsigned long calcglobalmass ()
  4583. {
  4584.     unsigned long i, j;
  4585.     char *v;
  4586.  
  4587.     j = VSID*VSID*256;
  4588.     for(i=0;i<VSID*VSID;i++)
  4589.     {
  4590.         v = sptr[i]; j -= v[1];
  4591.         while (v[0]) { v += v[0]*4; j += v[3]-v[1]; }
  4592.     }
  4593.     return(j);
  4594. }
  4595.  
  4596. void loadnul (dpoint3d *ipo, dpoint3d *ist, dpoint3d *ihe, dpoint3d *ifo)
  4597. {
  4598.     lpoint3d lp0, lp1;
  4599.     long i, x, y;
  4600.     char *v;
  4601.     float f;
  4602.  
  4603.     if (!vbuf) { vbuf = (long *)malloc((VOXSIZ>>2)<<2); if (!vbuf) evilquit("vbuf malloc failed"); }
  4604.     if (!vbit) { vbit = (long *)malloc((VOXSIZ>>7)<<2); if (!vbit) evilquit("vbuf malloc failed"); }
  4605.  
  4606.     v = (char *)(&vbuf[1]); //1st dword for voxalloc compare logic optimization
  4607.  
  4608.         //Completely re-compile vbuf
  4609.     for(x=0;x<VSID;x++)
  4610.         for(y=0;y<VSID;y++)
  4611.         {
  4612.             sptr[y*VSID+x] = v;
  4613.             i = 0; // + (rand()&1);  //i = default height of plain
  4614.             v[0] = 0;
  4615.             v[1] = i;
  4616.             v[2] = i;
  4617.             v[3] = 0;  //z0 (Dummy filler)
  4618.             //i = ((((x+y)>>3) + ((x^y)>>4)) % 231) + 16;
  4619.             //i = (i<<16)+(i<<8)+i;
  4620.             v += 4;
  4621.             (*(long *)v) = ((x^y)&15)*0x10101+0x807c7c7c; //colorjit(i,0x70707)|0x80000000;
  4622.             v += 4;
  4623.         }
  4624.  
  4625.     memset(&sptr[VSID*VSID],0,sizeof(sptr)-VSID*VSID*4);
  4626.     vbiti = (((long)v-(long)vbuf)>>2); //# vbuf longs/vbit bits allocated
  4627.     clearbuf((void *)vbit,vbiti>>5,-1);
  4628.     clearbuf((void *)&vbit[vbiti>>5],(VOXSIZ>>7)-(vbiti>>5),0);
  4629.     vbit[vbiti>>5] = (1<<vbiti)-1;
  4630.  
  4631.         //Blow out sphere and stick you inside map
  4632.     vx5.colfunc = jitcolfunc; vx5.curcol = 0x80704030;
  4633.  
  4634.     lp0.x = VSID*.5-90; lp0.y = VSID*.5-90; lp0.z = MAXZDIM*.5-45;
  4635.     lp1.x = VSID*.5+90; lp1.y = VSID*.5+90; lp1.z = MAXZDIM*.5+45;
  4636.     setrect(&lp0,&lp1,-1);
  4637.     //lp.x = VSID*.5; lp.y = VSID*.5; lp.z = MAXZDIM*.5; setsphere(&lp,64,-1);
  4638.  
  4639.     vx5.globalmass = calcglobalmass();
  4640.  
  4641.     ipo->x = VSID*.5; ipo->y = VSID*.5; ipo->z = MAXZDIM*.5; //ipo->z = -16;
  4642.     f = 0.0*PI/180.0;
  4643.     ist->x = cos(f); ist->y = sin(f); ist->z = 0;
  4644.     ihe->x = 0; ihe->y = 0; ihe->z = 1;
  4645.     ifo->x = sin(f); ifo->y = -cos(f); ifo->z = 0;
  4646.  
  4647.     gmipnum = 1; vx5.flstnum = 0;
  4648.     updatebbox(0,0,0,VSID,VSID,MAXZDIM,0);
  4649. }
  4650.  
  4651. long loaddta (const char *filename, dpoint3d *ipo, dpoint3d *ist, dpoint3d *ihe, dpoint3d *ifo)
  4652. {
  4653.     long i, j, p, leng, minz = 255, maxz = 0, h[5], longpal[256];
  4654.     char dat, *dtahei, *dtacol, *v, dafilename[MAX_PATH];
  4655.     float f;
  4656.     FILE *fp;
  4657.  
  4658.     if (!vbuf) { vbuf = (long *)malloc((VOXSIZ>>2)<<2); if (!vbuf) evilquit("vbuf malloc failed"); }
  4659.     if (!vbit) { vbit = (long *)malloc((VOXSIZ>>7)<<2); if (!vbit) evilquit("vbuf malloc failed"); }
  4660.  
  4661.     if (VSID != 1024) return(0);
  4662.     v = (char *)(&vbuf[1]); //1st dword for voxalloc compare logic optimization
  4663.  
  4664.     strcpy(dafilename,filename);
  4665.  
  4666.     dtahei = (char *)(&vbuf[(VOXSIZ-2097152)>>2]);
  4667.     dtacol = (char *)(&vbuf[(VOXSIZ-1048576)>>2]);
  4668.  
  4669.     dafilename[0] = 'd';
  4670.     if (!kzopen(dafilename)) return(0);
  4671.     kzseek(128,SEEK_SET); p = 0;
  4672.     while (p < 1024*1024)
  4673.     {
  4674.         dat = kzgetc();
  4675.         if (dat >= 192) { leng = dat-192; dat = kzgetc(); }
  4676.                       else { leng = 1; }
  4677.         dat = 255-dat;
  4678.         if (dat < minz) minz = dat;
  4679.         if (dat > maxz) maxz = dat;
  4680.         while (leng-- > 0) dtahei[p++] = dat;
  4681.     }
  4682.     kzclose();
  4683.  
  4684.     dafilename[0] = 'c';
  4685.     if (!kzopen(dafilename)) return(0);
  4686.     kzseek(128,SEEK_SET);
  4687.     p = 0;
  4688.     while (p < 1024*1024)
  4689.     {
  4690.         dat = kzgetc();
  4691.         if (dat >= 192) { leng = dat-192; dat = kzgetc(); }
  4692.                       else { leng = 1; }
  4693.         while (leng-- > 0) dtacol[p++] = dat;
  4694.     }
  4695.  
  4696.     dat = kzgetc();
  4697.     if (dat == 0xc)
  4698.         for(i=0;i<256;i++)
  4699.         {
  4700.             longpal[i] = kzgetc();
  4701.             longpal[i] = (longpal[i]<<8)+kzgetc();
  4702.             longpal[i] = (longpal[i]<<8)+kzgetc() + 0x80000000;
  4703.         }
  4704.  
  4705.     kzclose();
  4706.  
  4707.         //Fill board data
  4708.     minz = lbound(128-((minz+maxz)>>1),-minz,255-maxz);
  4709.     for(p=0;p<1024*1024;p++)
  4710.     {
  4711.         h[0] = (long)dtahei[p];
  4712.         h[1] = (long)dtahei[((p-1)&0x3ff)+((p     )&0xffc00)];
  4713.         h[2] = (long)dtahei[((p+1)&0x3ff)+((p     )&0xffc00)];
  4714.         h[3] = (long)dtahei[((p  )&0x3ff)+((p-1024)&0xffc00)];
  4715.         h[4] = (long)dtahei[((p  )&0x3ff)+((p+1024)&0xffc00)];
  4716.  
  4717.         j = 1;
  4718.         for(i=4;i>0;i--) if (h[i]-h[0] > j) j = h[i]-h[0];
  4719.  
  4720.         sptr[p] = v;
  4721.         v[0] = 0;
  4722.         v[1] = dtahei[p]+minz;
  4723.         v[2] = dtahei[p]+minz+j-1;
  4724.         v[3] = 0; //dummy (z top)
  4725.         v += 4;
  4726.         for(;j;j--) { *(long *)v = colorjit(longpal[dtacol[p]],0x70707); v += 4; }
  4727.     }
  4728.  
  4729.     memset(&sptr[VSID*VSID],0,sizeof(sptr)-VSID*VSID*4);
  4730.     vbiti = (((long)v-(long)vbuf)>>2); //# vbuf longs/vbit bits allocated
  4731.     clearbuf((void *)vbit,vbiti>>5,-1);
  4732.     clearbuf((void *)&vbit[vbiti>>5],(VOXSIZ>>7)-(vbiti>>5),0);
  4733.     vbit[vbiti>>5] = (1<<vbiti)-1;
  4734.  
  4735.     vx5.globalmass = calcglobalmass();
  4736.  
  4737.     ipo->x = VSID*.5; ipo->y = VSID*.5; ipo->z = 128;
  4738.     f = 0.0*PI/180.0;
  4739.     ist->x = cos(f); ist->y = sin(f); ist->z = 0;
  4740.     ihe->x = 0; ihe->y = 0; ihe->z = 1;
  4741.     ifo->x = sin(f); ifo->y = -cos(f); ifo->z = 0;
  4742.  
  4743.     gmipnum = 1; vx5.flstnum = 0;
  4744.     updatebbox(0,0,0,VSID,VSID,MAXZDIM,0);
  4745.     return(1);
  4746. }
  4747.  
  4748. long loadpng (const char *filename, dpoint3d *ipo, dpoint3d *ist, dpoint3d *ihe, dpoint3d *ifo)
  4749. {
  4750.     unsigned long *pngdat, dat[5];
  4751.     long i, j, k, l, p, leng, minz = 255, maxz = 0;
  4752.     char *v, *buf;
  4753.     float f;
  4754.     FILE *fp;
  4755.  
  4756.     if (!vbuf) { vbuf = (long *)malloc((VOXSIZ>>2)<<2); if (!vbuf) evilquit("vbuf malloc failed"); }
  4757.     if (!vbit) { vbit = (long *)malloc((VOXSIZ>>7)<<2); if (!vbit) evilquit("vbuf malloc failed"); }
  4758.  
  4759.     if (VSID != 1024) return(0);
  4760.     v = (char *)(&vbuf[1]); //1st dword for voxalloc compare logic optimization
  4761.  
  4762.     if (!kzopen(filename)) return(0);
  4763.     leng = kzfilelength();
  4764.     buf = (char *)malloc(leng); if (!buf) { kzclose(); return(0); }
  4765.     kzread(buf,leng);
  4766.     kzclose();
  4767.  
  4768.     kpgetdim(buf,leng,&i,&j); if ((i != VSID) && (j != VSID)) { free(buf); return(0); }
  4769.     pngdat = (unsigned long *)(&vbuf[(VOXSIZ-VSID*VSID*4)>>2]);
  4770.     if (kprender(buf,leng,(long)pngdat,VSID<<2,VSID,VSID,0,0) < 0) return(0);
  4771.     free(buf);
  4772.  
  4773.     for(i=0;i<VSID*VSID;i++)
  4774.     {
  4775.         if ((pngdat[i]>>24) < minz) minz = (pngdat[i]>>24);
  4776.         if ((pngdat[i]>>24) > maxz) maxz = (pngdat[i]>>24);
  4777.     }
  4778.  
  4779.         //Fill board data
  4780.     minz = lbound(128-((minz+maxz)>>1),-minz,255-maxz);
  4781.     for(p=0;p<VSID*VSID;p++)
  4782.     {
  4783.         dat[0] = pngdat[p];
  4784.         dat[1] = pngdat[((p-1)&(VSID-1))+((p     )&((VSID-1)*VSID))];
  4785.         dat[2] = pngdat[((p+1)&(VSID-1))+((p     )&((VSID-1)*VSID))];
  4786.         dat[3] = pngdat[((p  )&(VSID-1))+((p-VSID)&((VSID-1)*VSID))];
  4787.         dat[4] = pngdat[((p  )&(VSID-1))+((p+VSID)&((VSID-1)*VSID))];
  4788.  
  4789.         j = 1; l = dat[0];
  4790.         for(i=4;i>0;i--)
  4791.             if (((signed long)((dat[i]>>24)-(dat[0]>>24))) > j)
  4792.                 { j = (dat[i]>>24)-(dat[0]>>24); l = dat[i]; }
  4793.  
  4794.         sptr[p] = v;
  4795.         v[0] = 0;
  4796.         v[1] = (pngdat[p]>>24)+minz;
  4797.         v[2] = (pngdat[p]>>24)+minz+j-1;
  4798.         v[3] = 0; //dummy (z top)
  4799.         v += 4;
  4800.         k = (pngdat[p]&0xffffff)|0x80000000;
  4801.         if (j == 2)
  4802.         {
  4803.             l = (((  l     &255)-( k     &255))>>1)      +
  4804.                  (((((l>> 8)&255)-((k>> 8)&255))>>1)<< 8) +
  4805.                  (((((l>>16)&255)-((k>>16)&255))>>1)<<16);
  4806.         }
  4807.         else if (j > 2)
  4808.         {
  4809.             l = (((  l     &255)-( k     &255))/j)      +
  4810.                  (((((l>> 8)&255)-((k>> 8)&255))/j)<< 8) +
  4811.                  (((((l>>16)&255)-((k>>16)&255))/j)<<16);
  4812.         }
  4813.         *(long *)v = k; v += 4; j--;
  4814.         while (j) { k += l; *(long *)v = colorjit(k,0x30303); v += 4; j--; }
  4815.     }
  4816.  
  4817.     memset(&sptr[VSID*VSID],0,sizeof(sptr)-VSID*VSID*4);
  4818.     vbiti = (((long)v-(long)vbuf)>>2); //# vbuf longs/vbit bits allocated
  4819.     clearbuf((void *)vbit,vbiti>>5,-1);
  4820.     clearbuf((void *)&vbit[vbiti>>5],(VOXSIZ>>7)-(vbiti>>5),0);
  4821.     vbit[vbiti>>5] = (1<<vbiti)-1;
  4822.  
  4823.     vx5.globalmass = calcglobalmass();
  4824.  
  4825.     ipo->x = VSID*.5; ipo->y = VSID*.5; ipo->z = 128;
  4826.     f = 0.0*PI/180.0;
  4827.     ist->x = cos(f); ist->y = sin(f); ist->z = 0;
  4828.     ihe->x = 0; ihe->y = 0; ihe->z = 1;
  4829.     ifo->x = sin(f); ifo->y = -cos(f); ifo->z = 0;
  4830.  
  4831.     gmipnum = 1; vx5.flstnum = 0;
  4832.     updatebbox(0,0,0,VSID,VSID,MAXZDIM,0);
  4833.     return(1);
  4834. }
  4835.  
  4836.  
  4837. //Quake3 .BSP loading code begins --------------------------------------------
  4838. typedef struct { long c, i; float z, z1; } vlinerectyp;
  4839. static point3d q3pln[5250];
  4840. static float q3pld[5250], q3vz[256];
  4841. static long q3nod[4850][3], q3lf[4850];
  4842. long vlinebsp (float x, float y, float z0, float z1, float *dvz)
  4843. {
  4844.     vlinerectyp vlrec[64];
  4845.     float z, t;
  4846.     long i, j, vcnt, vlcnt;
  4847.     char vt[256];
  4848.  
  4849.     vcnt = 1; i = 0; vlcnt = 0; vt[0] = 17;
  4850.     while (1)
  4851.     {
  4852.         if (i < 0)
  4853.         {
  4854.             if (vt[vcnt-1] != (q3lf[~i]&255))
  4855.                 { dvz[vcnt] = z0; vt[vcnt] = (q3lf[~i]&255); vcnt++; }
  4856.         }
  4857.         else
  4858.         {
  4859.             j = q3nod[i][0]; z = q3pld[j] - q3pln[j].x*x - q3pln[j].y*y;
  4860.             t = q3pln[j].z*z0-z;
  4861.             if ((t < 0) == (q3pln[j].z*z1 < z))
  4862.                 { vlrec[vlcnt].c = 0; i = q3nod[i][(t<0)+1]; }
  4863.             else
  4864.             {
  4865.                 z /= q3pln[j].z; j = (q3pln[j].z<0)+1;
  4866.                 vlrec[vlcnt].c = 1; vlrec[vlcnt].i = q3nod[i][j];
  4867.                 vlrec[vlcnt].z = z; vlrec[vlcnt].z1 = z1;
  4868.                 i = q3nod[i][3-j]; z1 = z;
  4869.             }
  4870.             vlcnt++; continue;
  4871.         }
  4872.         do { vlcnt--; if (vlcnt < 0) return(vcnt); } while (!vlrec[vlcnt].c);
  4873.         vlrec[vlcnt].c = 0; i = vlrec[vlcnt].i;
  4874.         z0 = vlrec[vlcnt].z; z1 = vlrec[vlcnt].z1;
  4875.         vlcnt++;
  4876.     }
  4877.     return(0);
  4878. }
  4879.  
  4880.     //Stupidly useless declarations:
  4881. void delslab(long *b2, long y0, long y1);
  4882. long *scum2(long x, long y);
  4883. void scum2finish();
  4884.  
  4885. void loadbsp (const char *filnam, dpoint3d *ipo, dpoint3d *ist, dpoint3d *ihe, dpoint3d *ifo)
  4886. {
  4887.     FILE *fp;
  4888.     dpoint3d dp;
  4889.     float f, xof, yof, zof, sc, rsc;
  4890.     long numplanes, numnodes, numleafs, fpos[17], flng[17];
  4891.     long i, x, y, z, z0, z1, vcnt, *lptr, minx, miny, minz, maxx, maxy, maxz;
  4892.     char *v;
  4893.  
  4894.     if (!vbuf) { vbuf = (long *)malloc((VOXSIZ>>2)<<2); if (!vbuf) evilquit("vbuf malloc failed"); }
  4895.     if (!vbit) { vbit = (long *)malloc((VOXSIZ>>7)<<2); if (!vbit) evilquit("vbuf malloc failed"); }
  4896.  
  4897.         //Completely re-compile vbuf
  4898.     v = (char *)(&vbuf[1]); //1st dword for voxalloc compare logic optimization
  4899.     for(x=0;x<VSID;x++)
  4900.         for(y=0;y<VSID;y++)
  4901.         {
  4902.             sptr[y*VSID+x] = v; v[0] = 0; v[1] = 0; v[2] = 0; v[3] = 0; v += 4;
  4903.             (*(long *)v) = ((x^y)&15)*0x10101+0x807c7c7c; v += 4;
  4904.         }
  4905.  
  4906.     memset(&sptr[VSID*VSID],0,sizeof(sptr)-VSID*VSID*4);
  4907.     vbiti = (((long)v-(long)vbuf)>>2); //# vbuf longs/vbit bits allocated
  4908.     clearbuf((void *)vbit,vbiti>>5,-1);
  4909.     clearbuf((void *)&vbit[vbiti>>5],(VOXSIZ>>7)-(vbiti>>5),0);
  4910.     vbit[vbiti>>5] = (1<<vbiti)-1;
  4911.  
  4912.     if (!kzopen(filnam)) return;
  4913.     kzread(&i,4); if (i != 0x50534249) { kzclose(); return; }
  4914.     kzread(&i,4); if (i != 0x2e) { kzclose(); return; }
  4915.     for(i=0;i<17;i++) { kzread(&fpos[i],4); kzread(&flng[i],4); }
  4916.     kzseek(fpos[2],SEEK_SET); numplanes = flng[2]/16;
  4917.     for(i=0;i<numplanes;i++) { kzread(&q3pln[i].x,12); kzread(&q3pld[i],4); }
  4918.     kzseek(fpos[3],SEEK_SET); numnodes = flng[3]/36;
  4919.     minx = 0x7fffffff; miny = 0x7fffffff; minz = 0x7fffffff;
  4920.     maxx = 0x80000000; maxy = 0x80000000; maxz = 0x80000000;
  4921.     for(i=0;i<numnodes;i++)
  4922.     {
  4923.         kzread(&q3nod[i][0],12);
  4924.         kzread(&x,4); if (x < minx) minx = x;
  4925.         kzread(&x,4); if (x < miny) miny = x;
  4926.         kzread(&x,4); if (x < minz) minz = x;
  4927.         kzread(&x,4); if (x > maxx) maxx = x;
  4928.         kzread(&x,4); if (x > maxy) maxy = x;
  4929.         kzread(&x,4); if (x > maxz) maxz = x;
  4930.     }
  4931.     kzseek(fpos[4]+4,SEEK_SET); numleafs = flng[4]/48;
  4932.     for(i=0;i<numleafs;i++) { kzread(&q3lf[i],4); kzseek(44,SEEK_CUR); }
  4933.     kzclose();
  4934.  
  4935.     sc = (float)(VSID-2)/(float)(maxx-minx);
  4936.     rsc = (float)(VSID-2)/(float)(maxy-miny); if (rsc < sc) sc = rsc;
  4937.     rsc = (float)(MAXZDIM-2)/(float)(maxz-minz); if (rsc < sc) sc = rsc;
  4938.     //i = *(long *)sc; i &= 0xff800000; sc = *(float *)i;
  4939.     xof = (-(float)(minx+maxx)*sc + VSID   )*.5;
  4940.     yof = (+(float)(miny+maxy)*sc + VSID   )*.5;
  4941.     zof = (+(float)(minz+maxz)*sc + MAXZDIM)*.5;
  4942.  
  4943.     rsc = 1.0 / sc;
  4944.     vx5.colfunc = curcolfunc; //0<x0<x1<VSID, 0<y0<y1<VSID, 0<z0<z1<256,
  4945.     for(y=0;y<VSID;y++)
  4946.         for(x=0;x<VSID;x++)
  4947.         {
  4948.             lptr = scum2(x,y);
  4949.  
  4950.                 //voxx = q3x*+sc + xof;
  4951.                 //voxy = q3y*-sc + yof;
  4952.                 //voxz = q3z*-sc + zof;
  4953.             vcnt = vlinebsp(((float)x-xof)*rsc,((float)y-yof)*-rsc,-65536.0,65536.0,q3vz);
  4954.             for(i=vcnt-2;i>0;i-=2)
  4955.             {
  4956.                 ftol(-q3vz[i+1]*sc+zof,&z0); if (z0 < 0) z0 = 0;
  4957.                 ftol(-q3vz[i  ]*sc+zof,&z1); if (z1 > MAXZDIM) z1 = MAXZDIM;
  4958.                 delslab(lptr,z0,z1);
  4959.             }
  4960.         }
  4961.     scum2finish();
  4962.  
  4963.     vx5.globalmass = calcglobalmass();
  4964.  
  4965.         //Find a spot that isn't too close to a wall
  4966.     sc = -1; ipo->x = VSID*.5; ipo->y = VSID*.5; ipo->z = -16;
  4967.     for(i=4096;i>=0;i--)
  4968.     {
  4969.         x = (rand()%VSID); y = (rand()%VSID); z = (rand()%MAXZDIM);
  4970.         if (!isvoxelsolid(x,y,z))
  4971.         {
  4972.             rsc = findmaxcr((double)x+.5,(double)y+.5,(double)z+.5,5.0);
  4973.             if (rsc <= sc) continue;
  4974.             ipo->x = (double)x+.5; ipo->y = (double)x+.5; ipo->z = (double)x+.5;
  4975.             sc = rsc; if (sc >= 5.0) break;
  4976.         }
  4977.     }
  4978.     f = 0.0*PI/180.0;
  4979.     ist->x = cos(f); ist->y = sin(f); ist->z = 0;
  4980.     ihe->x = 0; ihe->y = 0; ihe->z = 1;
  4981.     ifo->x = sin(f); ifo->y = -cos(f); ifo->z = 0;
  4982.  
  4983.     gmipnum = 1; vx5.flstnum = 0;
  4984.     updatebbox(0,0,0,VSID,VSID,MAXZDIM,0);
  4985. }
  4986.  
  4987. //Quake3 .BSP loading code ends ----------------------------------------------
  4988.  
  4989. long loadvxl (const char *lodfilnam, dpoint3d *ipo, dpoint3d *ist, dpoint3d *ihe, dpoint3d *ifo)
  4990. {
  4991.     FILE *fil;
  4992.     long i, j, fsiz;
  4993.     char *v, *v2;
  4994.  
  4995.     if (!vbuf) { vbuf = (long *)malloc((VOXSIZ>>2)<<2); if (!vbuf) evilquit("vbuf malloc failed"); }
  4996.     if (!vbit) { vbit = (long *)malloc((VOXSIZ>>7)<<2); if (!vbit) evilquit("vbuf malloc failed"); }
  4997.  
  4998.     if (!kzopen(lodfilnam)) return(0);
  4999.     fsiz = kzfilelength();
  5000.  
  5001.     kzread(&i,4); if (i != 0x09072000) return(0);
  5002.     kzread(&i,4); if (i != VSID) return(0);
  5003.     kzread(&i,4); if (i != VSID) return(0);
  5004.     kzread(ipo,24);
  5005.     kzread(ist,24);
  5006.     kzread(ihe,24);
  5007.     kzread(ifo,24);
  5008.  
  5009.     v = (char *)(&vbuf[1]); //1st dword for voxalloc compare logic optimization
  5010.     kzread((void *)v,fsiz-kztell());
  5011.  
  5012.     for(i=0;i<VSID*VSID;i++)
  5013.     {
  5014.         sptr[i] = v;
  5015.         while (v[0]) v += (((long)v[0])<<2);
  5016.         v += ((((long)v[2])-((long)v[1])+2)<<2);
  5017.     }
  5018.     kzclose();
  5019.  
  5020.     memset(&sptr[VSID*VSID],0,sizeof(sptr)-VSID*VSID*4);
  5021.     vbiti = (((long)v-(long)vbuf)>>2); //# vbuf longs/vbit bits allocated
  5022.     clearbuf((void *)vbit,vbiti>>5,-1);
  5023.     clearbuf((void *)&vbit[vbiti>>5],(VOXSIZ>>7)-(vbiti>>5),0);
  5024.     vbit[vbiti>>5] = (1<<vbiti)-1;
  5025.  
  5026.     vx5.globalmass = calcglobalmass();
  5027.     backedup = -1;
  5028.  
  5029.     gmipnum = 1; vx5.flstnum = 0;
  5030.     updatebbox(0,0,0,VSID,VSID,MAXZDIM,0);
  5031.     return(1);
  5032. }
  5033.  
  5034. long savevxl (const char *savfilnam, dpoint3d *ipo, dpoint3d *ist, dpoint3d *ihe, dpoint3d *ifo)
  5035. {
  5036.     FILE *fil;
  5037.     long i;
  5038.  
  5039.     if (!(fil = fopen(savfilnam,"wb"))) return(0);
  5040.     i = 0x09072000; fwrite(&i,4,1,fil);  //Version
  5041.     i = VSID; fwrite(&i,4,1,fil);
  5042.     i = VSID; fwrite(&i,4,1,fil);
  5043.     fwrite(ipo,24,1,fil);
  5044.     fwrite(ist,24,1,fil);
  5045.     fwrite(ihe,24,1,fil);
  5046.     fwrite(ifo,24,1,fil);
  5047.     for(i=0;i<VSID*VSID;i++) fwrite((void *)sptr[i],slng(sptr[i]),1,fil);
  5048.     fclose(fil);
  5049.     return(1);
  5050. }
  5051.  
  5052. long loadsky (const char *skyfilnam)
  5053. {
  5054.     long x, y, xoff, yoff;
  5055.     float ang, f;
  5056.  
  5057.     if (skypic) { free((void *)skypic); skypic = skyoff = 0; }
  5058.     xoff = yoff = 0;
  5059.  
  5060.     if (!stricmp(skyfilnam,"BLACK")) return(0);
  5061.     if (!stricmp(skyfilnam,"BLUE")) goto loadbluesky;
  5062.  
  5063.     kpzload(skyfilnam,&skypic,&skybpl,&skyxsiz,&skyysiz);
  5064.     if (!skypic)
  5065.     {
  5066.         long r, g, b, *p;
  5067. loadbluesky:;
  5068.             //Load default sky
  5069.         skyxsiz = 512; skyysiz = 1; skybpl = skyxsiz*4;
  5070.         if (!(skypic = (long)malloc(skyysiz*skybpl))) return(-1);
  5071.  
  5072.         p = (long *)skypic; y = skyxsiz*skyxsiz;
  5073.         for(x=0;x<=(skyxsiz>>1);x++)
  5074.         {
  5075.             p[x] = ((((x*1081 - skyxsiz*252)*x)/y + 35)<<16)+
  5076.                      ((((x* 950 - skyxsiz*198)*x)/y + 53)<<8)+
  5077.                       (((x* 439 - skyxsiz* 21)*x)/y + 98);
  5078.         }
  5079.         p[skyxsiz-1] = 0x50903c;
  5080.         r = ((p[skyxsiz>>1]>>16)&255);
  5081.         g = ((p[skyxsiz>>1]>>8)&255);
  5082.         b = ((p[skyxsiz>>1])&255);
  5083.         for(x=(skyxsiz>>1)+1;x<skyxsiz;x++)
  5084.         {
  5085.             p[x] = ((((0x50-r)*(x-(skyxsiz>>1)))/(skyxsiz-1-(skyxsiz>>1))+r)<<16)+
  5086.                      ((((0x90-g)*(x-(skyxsiz>>1)))/(skyxsiz-1-(skyxsiz>>1))+g)<<8)+
  5087.                      ((((0x3c-b)*(x-(skyxsiz>>1)))/(skyxsiz-1-(skyxsiz>>1))+b));
  5088.         }
  5089.         y = skyxsiz*skyysiz;
  5090.         for(x=skyxsiz;x<y;x++) p[x] = p[x-skyxsiz];
  5091.     }
  5092.  
  5093.         //Initialize look-up table for longitudes
  5094.     if (skylng) free((void *)skylng);
  5095.     if (!(skylng = (point2d *)malloc(skyysiz*8))) return(-1);
  5096.     f = PI*2.0 / ((float)skyysiz);
  5097.     for(y=skyysiz-1;y>=0;y--)
  5098.         fcossin((float)y*f+PI,&skylng[y].x,&skylng[y].y);
  5099.     skylngmul = (float)skyysiz/(PI*2);
  5100.         //This makes those while loops in gline() not lockup when skyysiz==1
  5101.     if (skyysiz == 1) { skylng[0].x = 0; skylng[0].y = 0; }
  5102.  
  5103.         //Initialize look-up table for latitudes
  5104.     if (skylat) free((void *)skylat);
  5105.     if (!(skylat = (long *)malloc(skyxsiz*4))) return(-1);
  5106.     f = PI*.5 / ((float)skyxsiz);
  5107.     for(x=skyxsiz-1;x;x--)
  5108.     {
  5109.         ang = (float)((x<<1)-skyxsiz)*f;
  5110.         ftol(cos(ang)*32767.0,&xoff);
  5111.         ftol(sin(ang)*32767.0,&yoff);
  5112.         skylat[x] = (xoff<<16)+((-yoff)&65535);
  5113.     }
  5114.     skylat[0] = 0; //Hack to make sure assembly index never goes < 0
  5115.     skyxsiz--; //Hack for assembly code
  5116.  
  5117.     return(0);
  5118. }
  5119.  
  5120. void orthonormalize (point3d *v0, point3d *v1, point3d *v2)
  5121. {
  5122.     float t;
  5123.  
  5124.     t = 1.0 / sqrt((v0->x)*(v0->x) + (v0->y)*(v0->y) + (v0->z)*(v0->z));
  5125.     (v0->x) *= t; (v0->y) *= t; (v0->z) *= t;
  5126.     t = (v1->x)*(v0->x) + (v1->y)*(v0->y) + (v1->z)*(v0->z);
  5127.     (v1->x) -= t*(v0->x); (v1->y) -= t*(v0->y); (v1->z) -= t*(v0->z);
  5128.     t = 1.0 / sqrt((v1->x)*(v1->x) + (v1->y)*(v1->y) + (v1->z)*(v1->z));
  5129.     (v1->x) *= t; (v1->y) *= t; (v1->z) *= t;
  5130.     (v2->x) = (v0->y)*(v1->z) - (v0->z)*(v1->y);
  5131.     (v2->y) = (v0->z)*(v1->x) - (v0->x)*(v1->z);
  5132.     (v2->z) = (v0->x)*(v1->y) - (v0->y)*(v1->x);
  5133. }
  5134.  
  5135. void dorthonormalize (dpoint3d *v0, dpoint3d *v1, dpoint3d *v2)
  5136. {
  5137.     double t;
  5138.  
  5139.     t = 1.0 / sqrt((v0->x)*(v0->x) + (v0->y)*(v0->y) + (v0->z)*(v0->z));
  5140.     (v0->x) *= t; (v0->y) *= t; (v0->z) *= t;
  5141.     t = (v1->x)*(v0->x) + (v1->y)*(v0->y) + (v1->z)*(v0->z);
  5142.     (v1->x) -= t*(v0->x); (v1->y) -= t*(v0->y); (v1->z) -= t*(v0->z);
  5143.     t = 1.0 / sqrt((v1->x)*(v1->x) + (v1->y)*(v1->y) + (v1->z)*(v1->z));
  5144.     (v1->x) *= t; (v1->y) *= t; (v1->z) *= t;
  5145.     (v2->x) = (v0->y)*(v1->z) - (v0->z)*(v1->y);
  5146.     (v2->y) = (v0->z)*(v1->x) - (v0->x)*(v1->z);
  5147.     (v2->z) = (v0->x)*(v1->y) - (v0->y)*(v1->x);
  5148. }
  5149.  
  5150. void orthorotate (float ox, float oy, float oz, point3d *ist, point3d *ihe, point3d *ifo)
  5151. {
  5152.     float f, t, dx, dy, dz, rr[9];
  5153.  
  5154.     fcossin(ox,&ox,&dx);
  5155.     fcossin(oy,&oy,&dy);
  5156.     fcossin(oz,&oz,&dz);
  5157.     f = ox*oz; t = dx*dz; rr[0] =  t*dy + f; rr[7] = -f*dy - t;
  5158.     f = ox*dz; t = dx*oz; rr[1] = -f*dy + t; rr[6] =  t*dy - f;
  5159.     rr[2] = dz*oy; rr[3] = -dx*oy; rr[4] = ox*oy; rr[8] = oz*oy; rr[5] = dy;
  5160.     ox = ist->x; oy = ihe->x; oz = ifo->x;
  5161.     ist->x = ox*rr[0] + oy*rr[3] + oz*rr[6];
  5162.     ihe->x = ox*rr[1] + oy*rr[4] + oz*rr[7];
  5163.     ifo->x = ox*rr[2] + oy*rr[5] + oz*rr[8];
  5164.     ox = ist->y; oy = ihe->y; oz = ifo->y;
  5165.     ist->y = ox*rr[0] + oy*rr[3] + oz*rr[6];
  5166.     ihe->y = ox*rr[1] + oy*rr[4] + oz*rr[7];
  5167.     ifo->y = ox*rr[2] + oy*rr[5] + oz*rr[8];
  5168.     ox = ist->z; oy = ihe->z; oz = ifo->z;
  5169.     ist->z = ox*rr[0] + oy*rr[3] + oz*rr[6];
  5170.     ihe->z = ox*rr[1] + oy*rr[4] + oz*rr[7];
  5171.     ifo->z = ox*rr[2] + oy*rr[5] + oz*rr[8];
  5172.     //orthonormalize(ist,ihe,ifo);
  5173. }
  5174.  
  5175. void dorthorotate (double ox, double oy, double oz, dpoint3d *ist, dpoint3d *ihe, dpoint3d *ifo)
  5176. {
  5177.     double f, t, dx, dy, dz, rr[9];
  5178.  
  5179.     dcossin(ox,&ox,&dx);
  5180.     dcossin(oy,&oy,&dy);
  5181.     dcossin(oz,&oz,&dz);
  5182.     f = ox*oz; t = dx*dz; rr[0] =  t*dy + f; rr[7] = -f*dy - t;
  5183.     f = ox*dz; t = dx*oz; rr[1] = -f*dy + t; rr[6] =  t*dy - f;
  5184.     rr[2] = dz*oy; rr[3] = -dx*oy; rr[4] = ox*oy; rr[8] = oz*oy; rr[5] = dy;
  5185.     ox = ist->x; oy = ihe->x; oz = ifo->x;
  5186.     ist->x = ox*rr[0] + oy*rr[3] + oz*rr[6];
  5187.     ihe->x = ox*rr[1] + oy*rr[4] + oz*rr[7];
  5188.     ifo->x = ox*rr[2] + oy*rr[5] + oz*rr[8];
  5189.     ox = ist->y; oy = ihe->y; oz = ifo->y;
  5190.     ist->y = ox*rr[0] + oy*rr[3] + oz*rr[6];
  5191.     ihe->y = ox*rr[1] + oy*rr[4] + oz*rr[7];
  5192.     ifo->y = ox*rr[2] + oy*rr[5] + oz*rr[8];
  5193.     ox = ist->z; oy = ihe->z; oz = ifo->z;
  5194.     ist->z = ox*rr[0] + oy*rr[3] + oz*rr[6];
  5195.     ihe->z = ox*rr[1] + oy*rr[4] + oz*rr[7];
  5196.     ifo->z = ox*rr[2] + oy*rr[5] + oz*rr[8];
  5197.     //dorthonormalize(ist,ihe,ifo);
  5198. }
  5199.  
  5200. void axisrotate (point3d *p, point3d *axis, float w)
  5201. {
  5202.     point3d ax;
  5203.     float t, c, s, ox, oy, oz, k[9];
  5204.  
  5205.     fcossin(w,&c,&s);
  5206.     t = axis->x*axis->x + axis->y*axis->y + axis->z*axis->z; if (t == 0) return;
  5207.     t = 1.0 / sqrt(t); ax.x = axis->x*t; ax.y = axis->y*t; ax.z = axis->z*t;
  5208.  
  5209.     t = 1.0-c;
  5210.     k[0] = ax.x*t; k[7] = ax.x*s; oz = ax.y*k[0];
  5211.     k[4] = ax.y*t; k[2] = ax.y*s; oy = ax.z*k[0];
  5212.     k[8] = ax.z*t; k[3] = ax.z*s; ox = ax.z*k[4];
  5213.     k[0] = ax.x*k[0] + c; k[5] = ox - k[7]; k[7] += ox;
  5214.     k[4] = ax.y*k[4] + c; k[6] = oy - k[2]; k[2] += oy;
  5215.     k[8] = ax.z*k[8] + c; k[1] = oz - k[3]; k[3] += oz;
  5216.  
  5217.     ox = p->x; oy = p->y; oz = p->z;
  5218.     p->x = ox*k[0] + oy*k[1] + oz*k[2];
  5219.     p->y = ox*k[3] + oy*k[4] + oz*k[5];
  5220.     p->z = ox*k[6] + oy*k[7] + oz*k[8];
  5221. }
  5222.  
  5223. void slerp (point3d *istr, point3d *ihei, point3d *ifor,
  5224.                 point3d *istr2, point3d *ihei2, point3d *ifor2,
  5225.                 point3d *ist, point3d *ihe, point3d *ifo, float rat)
  5226. {
  5227.     point3d ax;
  5228.     float c, s, t, ox, oy, oz, k[9];
  5229.  
  5230.     ist->x = istr->x; ist->y = istr->y; ist->z = istr->z;
  5231.     ihe->x = ihei->x; ihe->y = ihei->y; ihe->z = ihei->z;
  5232.     ifo->x = ifor->x; ifo->y = ifor->y; ifo->z = ifor->z;
  5233.  
  5234.     ax.x = istr->y*istr2->z - istr->z*istr2->y + ihei->y*ihei2->z - ihei->z*ihei2->y + ifor->y*ifor2->z - ifor->z*ifor2->y;
  5235.     ax.y = istr->z*istr2->x - istr->x*istr2->z + ihei->z*ihei2->x - ihei->x*ihei2->z + ifor->z*ifor2->x - ifor->x*ifor2->z;
  5236.     ax.z = istr->x*istr2->y - istr->y*istr2->x + ihei->x*ihei2->y - ihei->y*ihei2->x + ifor->x*ifor2->y - ifor->y*ifor2->x;
  5237.     t = ax.x*ax.x + ax.y*ax.y + ax.z*ax.z; if (t == 0) return;
  5238.  
  5239.         //Based on the vector suck-out method (see ROTATE2.BAS)
  5240.     ox = istr->x*ax.x + istr->y*ax.y + istr->z*ax.z;
  5241.     oy = ihei->x*ax.x + ihei->y*ax.y + ihei->z*ax.z;
  5242.     if (fabs(ox) < fabs(oy))
  5243.         { c = istr->x*istr2->x + istr->y*istr2->y + istr->z*istr2->z; s = ox*ox; }
  5244.     else
  5245.         { c = ihei->x*ihei2->x + ihei->y*ihei2->y + ihei->z*ihei2->z; s = oy*oy; }
  5246.     if (t == s) return;
  5247.     c = (c*t - s) / (t-s);
  5248.     if (c < -1) c = -1;
  5249.     if (c > 1) c = 1;
  5250.     fcossin(acos(c)*rat,&c,&s);
  5251.  
  5252.     t = 1.0 / sqrt(t); ax.x *= t; ax.y *= t; ax.z *= t;
  5253.  
  5254.     t = 1.0f-c;
  5255.     k[0] = ax.x*t; k[7] = ax.x*s; oz = ax.y*k[0];
  5256.     k[4] = ax.y*t; k[2] = ax.y*s; oy = ax.z*k[0];
  5257.     k[8] = ax.z*t; k[3] = ax.z*s; ox = ax.z*k[4];
  5258.     k[0] = ax.x*k[0] + c; k[5] = ox - k[7]; k[7] += ox;
  5259.     k[4] = ax.y*k[4] + c; k[6] = oy - k[2]; k[2] += oy;
  5260.     k[8] = ax.z*k[8] + c; k[1] = oz - k[3]; k[3] += oz;
  5261.  
  5262.     ox = ist->x; oy = ist->y; oz = ist->z;
  5263.     ist->x = ox*k[0] + oy*k[1] + oz*k[2];
  5264.     ist->y = ox*k[3] + oy*k[4] + oz*k[5];
  5265.     ist->z = ox*k[6] + oy*k[7] + oz*k[8];
  5266.  
  5267.     ox = ihe->x; oy = ihe->y; oz = ihe->z;
  5268.     ihe->x = ox*k[0] + oy*k[1] + oz*k[2];
  5269.     ihe->y = ox*k[3] + oy*k[4] + oz*k[5];
  5270.     ihe->z = ox*k[6] + oy*k[7] + oz*k[8];
  5271.  
  5272.     ox = ifo->x; oy = ifo->y; oz = ifo->z;
  5273.     ifo->x = ox*k[0] + oy*k[1] + oz*k[2];
  5274.     ifo->y = ox*k[3] + oy*k[4] + oz*k[5];
  5275.     ifo->z = ox*k[6] + oy*k[7] + oz*k[8];
  5276. }
  5277.  
  5278. void expandrle (long x, long y, long *uind)
  5279. {
  5280.     long i;
  5281.     char *v;
  5282.  
  5283.     if ((x|y)&(~(VSID-1))) { uind[0] = 0; uind[1] = MAXZDIM; return; }
  5284.  
  5285.     v = sptr[y*VSID+x]; uind[0] = v[1]; i = 2;
  5286.     while (v[0])
  5287.     {
  5288.         v += v[0]*4; if (v[3] >= v[1]) continue;
  5289.         uind[i-1] = v[3]; uind[i] = v[1]; i += 2;
  5290.     }
  5291.     uind[i-1] = MAXZDIM;
  5292. }
  5293.  
  5294.     //Inputs:  n0[<=MAXZDIM]: rle buffer of column to compress
  5295.     //         n1-4[<=MAXZDIM]: neighboring rle buffers
  5296.     //         top,bot,top,bot,... (ends when bot == MAXZDIM)
  5297.     //         px,py: takes color from original column (before modification)
  5298.     //            If originally unexposed, calls vx5.colfunc(.)
  5299.     //Outputs: cbuf[MAXCSIZ]: compressed output buffer
  5300.     //Returns: n: length of compressed buffer (in bytes)
  5301. long compilerle (long *n0, long *n1, long *n2, long *n3, long *n4, char *cbuf, long px, long py)
  5302. {
  5303.     long i, ia, ze, zend, onext, dacnt, n, *ic;
  5304.     lpoint3d p;
  5305.     char *v;
  5306.  
  5307.     p.x = px; p.y = py;
  5308.  
  5309.         //Generate pointers to color slabs in this format:
  5310.         //   0:z0,  1:z1,  2:(pointer to z0's color)-z0
  5311.     v = sptr[py*VSID+px]; ic = tbuf2;
  5312.     while (1)
  5313.     {
  5314.         ia = v[1]; p.z = v[2];
  5315.         ic[0] = ia; ic[1] = p.z+1; ic[2] = ((long)v)-(ia<<2)+4; ic += 3;
  5316.         i = v[0]; if (!i) break;
  5317.         v += i*4; ze = v[3];
  5318.         ic[0] = ze+p.z-ia-i+2; ic[1] = ze; ic[2] = ((long)v)-(ze<<2); ic += 3;
  5319.     }
  5320.     ic[0] = MAXZDIM; ic[1] = MAXZDIM;
  5321.  
  5322.     p.z = n0[0]; cbuf[1] = n0[0];
  5323.     ze = n0[1]; cbuf[2] = ze-1;
  5324.     cbuf[3] = 0;
  5325.     i = onext = 0; ic = tbuf2; ia = 15; n = 4;
  5326.     if (ze != MAXZDIM) zend = ze-1; else zend = -1;
  5327.     while (1)
  5328.     {
  5329.         dacnt = 0;
  5330.         while (1)
  5331.         {
  5332.             do
  5333.             {
  5334.                 while (p.z >= ic[1]) ic += 3;
  5335.                 if (p.z >= ic[0]) *(long *)&cbuf[n] = *(long *)(ic[2]+(p.z<<2));
  5336.                                  else *(long *)&cbuf[n] = vx5.colfunc(&p);
  5337.                 n += 4; p.z++; if (p.z >= ze) goto rlendit2;
  5338.                 while (p.z >= n1[0]) { n1++; ia ^= 1; }
  5339.                 while (p.z >= n2[0]) { n2++; ia ^= 2; }
  5340.                 while (p.z >= n3[0]) { n3++; ia ^= 4; }
  5341.                 while (p.z >= n4[0]) { n4++; ia ^= 8; }
  5342.             } while ((ia) || (p.z == zend));
  5343.  
  5344.             if (!dacnt) { cbuf[onext+2] = p.z-1; dacnt = 1; }
  5345.             else
  5346.             {
  5347.                 cbuf[onext] = ((n-onext)>>2); onext = n;
  5348.                 cbuf[n+1] = p.z; cbuf[n+2] = p.z-1; cbuf[n+3] = p.z; n += 4;
  5349.             }
  5350.  
  5351.             if ((n1[0] < n2[0]) && (n1[0] < n3[0]) && (n1[0] < n4[0]))
  5352.                 { if (n1[0] >= ze) { p.z = ze-1; } else { p.z = *n1++; ia ^= 1; } }
  5353.             else if ((n2[0] < n3[0]) && (n2[0] < n4[0]))
  5354.                 { if (n2[0] >= ze) { p.z = ze-1; } else { p.z = *n2++; ia ^= 2; } }
  5355.             else if (n3[0] < n4[0])
  5356.                 { if (n3[0] >= ze) { p.z = ze-1; } else { p.z = *n3++; ia ^= 4; } }
  5357.             else
  5358.                 { if (n4[0] >= ze) { p.z = ze-1; } else { p.z = *n4++; ia ^= 8; } }
  5359.  
  5360.             if (p.z == MAXZDIM-1) goto rlenditall;
  5361.         }
  5362. rlendit2:;
  5363.         if (ze >= MAXZDIM) break;
  5364.  
  5365.         i += 2;
  5366.         cbuf[onext] = ((n-onext)>>2); onext = n;
  5367.         p.z = n0[i]; cbuf[n+1] = n0[i]; cbuf[n+3] = ze;
  5368.         ze = n0[i+1]; cbuf[n+2] = ze-1;
  5369.         n += 4;
  5370.     }
  5371. rlenditall:;
  5372.     cbuf[onext] = 0;
  5373.     return(n);
  5374. }
  5375.  
  5376.     //Delete everything on b2() in y0<=y<y1
  5377. void delslab (long *b2, long y0, long y1)
  5378. {
  5379.     long i, j, z;
  5380.  
  5381.     if (y1 >= MAXZDIM) y1 = MAXZDIM-1;
  5382.     if ((y0 >= y1) || (!b2)) return;
  5383.     for(z=0;y0>=b2[z+1];z+=2);
  5384.     if (y0 > b2[z])
  5385.     {
  5386.         if (y1 < b2[z+1])
  5387.         {
  5388.             for(i=z;b2[i+1]<MAXZDIM;i+=2);
  5389.             while (i > z) { b2[i+3] = b2[i+1]; b2[i+2] = b2[i]; i -= 2; }
  5390.             b2[z+3] = b2[z+1]; b2[z+1] = y0; b2[z+2] = y1; return;
  5391.         }
  5392.         b2[z+1] = y0; z += 2;
  5393.     }
  5394.     if (y1 >= b2[z+1])
  5395.     {
  5396.         for(i=z+2;y1>=b2[i+1];i+=2);
  5397.         j = z-i; b2[z] = b2[i]; b2[z+1] = b2[i+1];
  5398.         while (b2[i+1] < MAXZDIM)
  5399.             { i += 2; b2[i+j] = b2[i]; b2[i+j+1] = b2[i+1]; }
  5400.     }
  5401.     if (y1 > b2[z]) b2[z] = y1;
  5402. }
  5403.  
  5404.     //Insert everything on b2() in y0<=y<y1
  5405. void insslab (long *b2, long y0, long y1)
  5406. {
  5407.     long i, j, z;
  5408.  
  5409.     if ((y0 >= y1) || (!b2)) return;
  5410.     for(z=0;y0>b2[z+1];z+=2);
  5411.     if (y1 < b2[z])
  5412.     {
  5413.         for(i=z;b2[i+1]<MAXZDIM;i+=2);
  5414.         do { b2[i+3] = b2[i+1]; b2[i+2] = b2[i]; i -= 2; } while (i >= z);
  5415.         b2[z+1] = y1; b2[z] = y0; return;
  5416.     }
  5417.     if (y0 < b2[z]) b2[z] = y0;
  5418.     if ((y1 >= b2[z+2]) && (b2[z+1] < MAXZDIM))
  5419.     {
  5420.         for(i=z+2;(y1 >= b2[i+2]) && (b2[i+1] < MAXZDIM);i+=2);
  5421.         j = z-i; b2[z+1] = b2[i+1];
  5422.         while (b2[i+1] < MAXZDIM)
  5423.             { i += 2; b2[i+j] = b2[i]; b2[i+j+1] = b2[i+1]; }
  5424.     }
  5425.     if (y1 > b2[z+1]) b2[z+1] = y1;
  5426. }
  5427.  
  5428. //------------------------ SETCOLUMN CODE BEGINS ----------------------------
  5429.  
  5430. static long scx0, scx1, scox0, scox1, scoox0, scoox1;
  5431. static long scex0, scex1, sceox0, sceox1, scoy = 0x80000000, *scoym3;
  5432.  
  5433. void scumline ()
  5434. {
  5435.     long i, j, k, x, y, x0, x1, *mptr, *uptr;
  5436.     char *v;
  5437.  
  5438.     x0 = min(scox0-1,min(scx0,scoox0)); scoox0 = scox0; scox0 = scx0;
  5439.     x1 = max(scox1+1,max(scx1,scoox1)); scoox1 = scox1; scox1 = scx1;
  5440.  
  5441.     uptr = &scoym3[SCPITCH]; if (uptr == &radar[SCPITCH*9]) uptr = &radar[SCPITCH*6];
  5442.     mptr = &uptr[SCPITCH];   if (mptr == &radar[SCPITCH*9]) mptr = &radar[SCPITCH*6];
  5443.  
  5444.     if ((x1 < sceox0) || (x0 > sceox1))
  5445.     {
  5446.         for(x=x0;x<=x1;x++) expandstack(x,scoy-2,&uptr[x*SCPITCH*3]);
  5447.     }
  5448.     else
  5449.     {
  5450.         for(x=x0;x<sceox0;x++) expandstack(x,scoy-2,&uptr[x*SCPITCH*3]);
  5451.         for(x=x1;x>sceox1;x--) expandstack(x,scoy-2,&uptr[x*SCPITCH*3]);
  5452.     }
  5453.  
  5454.     if ((scex1|x1) >= 0)
  5455.     {
  5456.         for(x=x1+2;x<scex0;x++) expandstack(x,scoy-1,&mptr[x*SCPITCH*3]);
  5457.         for(x=x0-2;x>scex1;x--) expandstack(x,scoy-1,&mptr[x*SCPITCH*3]);
  5458.     }
  5459.     if ((x1+1 < scex0) || (x0-1 > scex1))
  5460.     {
  5461.         for(x=x0-1;x<=x1+1;x++) expandstack(x,scoy-1,&mptr[x*SCPITCH*3]);
  5462.     }
  5463.     else
  5464.     {
  5465.         for(x=x0-1;x<scex0;x++) expandstack(x,scoy-1,&mptr[x*SCPITCH*3]);
  5466.         for(x=x1+1;x>scex1;x--) expandstack(x,scoy-1,&mptr[x*SCPITCH*3]);
  5467.     }
  5468.     sceox0 = min(x0-1,scex0);
  5469.     sceox1 = max(x1+1,scex1);
  5470.  
  5471.     if ((x1 < scx0) || (x0 > scx1))
  5472.     {
  5473.         for(x=x0;x<=x1;x++) expandstack(x,scoy,&scoym3[x*SCPITCH*3]);
  5474.     }
  5475.     else
  5476.     {
  5477.         for(x=x0;x<scx0;x++) expandstack(x,scoy,&scoym3[x*SCPITCH*3]);
  5478.         for(x=x1;x>scx1;x--) expandstack(x,scoy,&scoym3[x*SCPITCH*3]);
  5479.     }
  5480.     scex0 = x0;
  5481.     scex1 = x1;
  5482.  
  5483.     y = scoy-1; if (y&(~(VSID-1))) return;
  5484.     if (x0 < 0) x0 = 0;
  5485.     if (x1 >= VSID) x1 = VSID-1;
  5486.     i = y*VSID+x0; k = x0*SCPITCH*3;
  5487.     for(x=x0;x<=x1;x++,i++,k+=SCPITCH*3)
  5488.     {
  5489.         v = sptr[i]; vx5.globalmass += v[1];
  5490.         while (v[0]) { v += v[0]*4; vx5.globalmass += v[1]-v[3]; }
  5491.  
  5492.             //De-allocate column (x,y)
  5493.         voxdealloc(sptr[i]);
  5494.  
  5495.         j = compilestack(&mptr[k],&mptr[k-SCPITCH*3],&mptr[k+SCPITCH*3],&uptr[k],&scoym3[k],
  5496.                               tbuf,x,y);
  5497.  
  5498.             //Allocate & copy to new column (x,y)
  5499.         sptr[i] = v = voxalloc(j); copybuf((void *)tbuf,(void *)v,j>>2);
  5500.  
  5501.         vx5.globalmass -= v[1];
  5502.         while (v[0]) { v += v[0]*4; vx5.globalmass += v[3]-v[1]; }
  5503.     }
  5504. }
  5505.  
  5506.     //x: x on voxel map
  5507.     //y: y on voxel map
  5508.     //z0: highest z on column
  5509.     //z1: lowest z(+1) on column
  5510.     //nbuf: buffer of color data from nbuf[z0] to nbuf[z1-1];
  5511.     //           -3: don't modify voxel
  5512.     //           -2: solid voxel (unexposed): to be calculated in compilestack
  5513.     //           -1: write air voxel
  5514.     //   0-16777215: write solid voxel (exposed)
  5515. void scum (long x, long y, long z0, long z1, long *nbuf)
  5516. {
  5517.     long z, *mptr;
  5518.  
  5519.     if ((x|y)&(~(VSID-1))) return;
  5520.  
  5521.     if (y != scoy)
  5522.     {
  5523.         if (scoy >= 0)
  5524.         {
  5525.             scumline();
  5526.             while (scoy < y-1)
  5527.             {
  5528.                 scx0 = 0x7fffffff; scx1 = 0x80000000;
  5529.                 scoy++; scoym3 += SCPITCH; if (scoym3 == &radar[SCPITCH*9]) scoym3 = &radar[SCPITCH*6];
  5530.                 scumline();
  5531.             }
  5532.             scoy++; scoym3 += SCPITCH; if (scoym3 == &radar[SCPITCH*9]) scoym3 = &radar[SCPITCH*6];
  5533.         }
  5534.         else
  5535.         {
  5536.             scoox0 = scox0 = 0x7fffffff;
  5537.             sceox0 = scex0 = x+1;
  5538.             sceox1 = scex1 = x;
  5539.             scoy = y; scoym3 = &radar[SCPITCH*6];
  5540.         }
  5541.         scx0 = x;
  5542.     }
  5543.     else
  5544.     {
  5545.         while (scx1 < x-1) { scx1++; expandstack(scx1,y,&scoym3[scx1*SCPITCH*3]); }
  5546.     }
  5547.  
  5548.     mptr = &scoym3[x*SCPITCH*3]; scx1 = x; expandstack(x,y,mptr);
  5549.  
  5550.         //Modify column (x,y):
  5551.     if (nbuf[MAXZDIM-1] == -1) nbuf[MAXZDIM-1] = -2; //Bottom voxel must be solid
  5552.     for(z=z0;z<z1;z++)
  5553.         if (nbuf[z] != -3) mptr[z] = nbuf[z];
  5554. }
  5555.  
  5556. void scumfinish ()
  5557. {
  5558.     long i;
  5559.  
  5560.     if (scoy == 0x80000000) return;
  5561.     for(i=2;i;i--)
  5562.     {
  5563.         scumline(); scx0 = 0x7fffffff; scx1 = 0x80000000;
  5564.         scoy++; scoym3 += SCPITCH; if (scoym3 == &radar[SCPITCH*9]) scoym3 = &radar[SCPITCH*6];
  5565.     }
  5566.     scumline(); scoy = 0x80000000;
  5567. }
  5568.  
  5569.     //Example of how to use this code:
  5570.     //vx5.colfunc = curcolfunc; //0<x0<x1<VSID, 0<y0<y1<VSID, 0<z0<z1<256,
  5571.     //clearbuf((void *)&templongbuf[z0],z1-z0,-1); //Ex: set all voxels to air
  5572.     //for(y=y0;y<y1;y++) //MUST iterate x&y in this order, but can skip around
  5573.     //   for(x=x0;x<x1;x++)
  5574.     //      if (rand()&8) scum(x,y,z0,z1,templongbuf));
  5575.     //scumfinish(); //MUST call this when done!
  5576.  
  5577. void scum2line ()
  5578. {
  5579.     long i, j, k, x, y, x0, x1, *mptr, *uptr;
  5580.     char *v;
  5581.  
  5582.     x0 = min(scox0-1,min(scx0,scoox0)); scoox0 = scox0; scox0 = scx0;
  5583.     x1 = max(scox1+1,max(scx1,scoox1)); scoox1 = scox1; scox1 = scx1;
  5584.  
  5585.     uptr = &scoym3[SCPITCH]; if (uptr == &radar[SCPITCH*9]) uptr = &radar[SCPITCH*6];
  5586.     mptr = &uptr[SCPITCH];   if (mptr == &radar[SCPITCH*9]) mptr = &radar[SCPITCH*6];
  5587.  
  5588.     if ((x1 < sceox0) || (x0 > sceox1))
  5589.     {
  5590.         for(x=x0;x<=x1;x++) expandrle(x,scoy-2,&uptr[x*SCPITCH*3]);
  5591.     }
  5592.     else
  5593.     {
  5594.         for(x=x0;x<sceox0;x++) expandrle(x,scoy-2,&uptr[x*SCPITCH*3]);
  5595.         for(x=x1;x>sceox1;x--) expandrle(x,scoy-2,&uptr[x*SCPITCH*3]);
  5596.     }
  5597.  
  5598.     if ((scex1|x1) >= 0)
  5599.     {
  5600.         for(x=x1+2;x<scex0;x++) expandrle(x,scoy-1,&mptr[x*SCPITCH*3]);
  5601.         for(x=x0-2;x>scex1;x--) expandrle(x,scoy-1,&mptr[x*SCPITCH*3]);
  5602.     }
  5603.     if ((x1+1 < scex0) || (x0-1 > scex1))
  5604.     {
  5605.         for(x=x0-1;x<=x1+1;x++) expandrle(x,scoy-1,&mptr[x*SCPITCH*3]);
  5606.     }
  5607.     else
  5608.     {
  5609.         for(x=x0-1;x<scex0;x++) expandrle(x,scoy-1,&mptr[x*SCPITCH*3]);
  5610.         for(x=x1+1;x>scex1;x--) expandrle(x,scoy-1,&mptr[x*SCPITCH*3]);
  5611.     }
  5612.     sceox0 = min(x0-1,scex0);
  5613.     sceox1 = max(x1+1,scex1);
  5614.  
  5615.     if ((x1 < scx0) || (x0 > scx1))
  5616.     {
  5617.         for(x=x0;x<=x1;x++) expandrle(x,scoy,&scoym3[x*SCPITCH*3]);
  5618.     }
  5619.     else
  5620.     {
  5621.         for(x=x0;x<scx0;x++) expandrle(x,scoy,&scoym3[x*SCPITCH*3]);
  5622.         for(x=x1;x>scx1;x--) expandrle(x,scoy,&scoym3[x*SCPITCH*3]);
  5623.     }
  5624.     scex0 = x0;
  5625.     scex1 = x1;
  5626.  
  5627.     y = scoy-1; if (y&(~(VSID-1))) return;
  5628.     if (x0 < 0) x0 = 0;
  5629.     if (x1 >= VSID) x1 = VSID-1;
  5630.     i = y*VSID+x0; k = x0*SCPITCH*3;
  5631.     for(x=x0;x<=x1;x++,i++,k+=SCPITCH*3)
  5632.     {
  5633.         j = compilerle(&mptr[k],&mptr[k-SCPITCH*3],&mptr[k+SCPITCH*3],&uptr[k],&scoym3[k],
  5634.                             tbuf,x,y);
  5635.  
  5636.         v = sptr[i]; vx5.globalmass += v[1];
  5637.         while (v[0]) { v += v[0]*4; vx5.globalmass += v[1]-v[3]; }
  5638.  
  5639.             //De-allocate column (x,y)  Note: Must be AFTER compilerle!
  5640.         voxdealloc(sptr[i]);
  5641.  
  5642.             //Allocate & copy to new column (x,y)
  5643.         sptr[i] = v = voxalloc(j); copybuf((void *)tbuf,(void *)v,j>>2);
  5644.  
  5645.         vx5.globalmass -= v[1];
  5646.         while (v[0]) { v += v[0]*4; vx5.globalmass += v[3]-v[1]; }
  5647.     }
  5648. }
  5649.  
  5650.     //x: x on voxel map
  5651.     //y: y on voxel map
  5652.     //Returns pointer to rle column (x,y)
  5653. long *scum2 (long x, long y)
  5654. {
  5655.     long *mptr;
  5656.  
  5657.     if ((x|y)&(~(VSID-1))) return(0);
  5658.  
  5659.     if (y != scoy)
  5660.     {
  5661.         if (scoy >= 0)
  5662.         {
  5663.             scum2line();
  5664.             while (scoy < y-1)
  5665.             {
  5666.                 scx0 = 0x7fffffff; scx1 = 0x80000000;
  5667.                 scoy++; scoym3 += SCPITCH; if (scoym3 == &radar[SCPITCH*9]) scoym3 = &radar[SCPITCH*6];
  5668.                 scum2line();
  5669.             }
  5670.             scoy++; scoym3 += SCPITCH; if (scoym3 == &radar[SCPITCH*9]) scoym3 = &radar[SCPITCH*6];
  5671.         }
  5672.         else
  5673.         {
  5674.             scoox0 = scox0 = 0x7fffffff;
  5675.             sceox0 = scex0 = x+1;
  5676.             sceox1 = scex1 = x;
  5677.             scoy = y; scoym3 = &radar[SCPITCH*6];
  5678.         }
  5679.         scx0 = x;
  5680.     }
  5681.     else
  5682.     {
  5683.         while (scx1 < x-1) { scx1++; expandrle(scx1,y,&scoym3[scx1*SCPITCH*3]); }
  5684.     }
  5685.  
  5686.     mptr = &scoym3[x*SCPITCH*3]; scx1 = x; expandrle(x,y,mptr);
  5687.     return(mptr);
  5688. }
  5689.  
  5690. void scum2finish ()
  5691. {
  5692.     long i;
  5693.  
  5694.     if (scoy == 0x80000000) return;
  5695.     for(i=2;i;i--)
  5696.     {
  5697.         scum2line(); scx0 = 0x7fffffff; scx1 = 0x80000000;
  5698.         scoy++; scoym3 += SCPITCH; if (scoym3 == &radar[SCPITCH*9]) scoym3 = &radar[SCPITCH*6];
  5699.     }
  5700.     scum2line(); scoy = 0x80000000;
  5701. }
  5702.  
  5703. //------------------- editing backup / restore begins ------------------------
  5704.  
  5705. void voxdontrestore ()
  5706. {
  5707.     long i;
  5708.  
  5709.     if (backedup == 1)
  5710.     {
  5711.         for(i=(bacx1-bacx0)*(bacy1-bacy0)-1;i>=0;i--) voxdealloc(bacsptr[i]);
  5712.     }
  5713.     backedup = -1;
  5714. }
  5715.  
  5716. void voxrestore ()
  5717. {
  5718.     long i, j, x, y;
  5719.     char *v, *daptr;
  5720.  
  5721.     if (backedup == 1)
  5722.     {
  5723.         i = 0;
  5724.         for(y=bacy0;y<bacy1;y++)
  5725.         {
  5726.             j = y*VSID;
  5727.             for(x=bacx0;x<bacx1;x++)
  5728.             {
  5729.                 v = sptr[j+x]; vx5.globalmass += v[1];
  5730.                 while (v[0]) { v += v[0]*4; vx5.globalmass += v[1]-v[3]; }
  5731.  
  5732.                 voxdealloc(sptr[j+x]);
  5733.                 sptr[j+x] = bacsptr[i]; i++;
  5734.  
  5735.                 v = sptr[j+x]; vx5.globalmass -= v[1];
  5736.                 while (v[0]) { v += v[0]*4; vx5.globalmass += v[3]-v[1]; }
  5737.             }
  5738.         }
  5739.         if (vx5.vxlmipuse > 1) genmipvxl(bacx0,bacy0,bacx1,bacy1);
  5740.     }
  5741.     else if (backedup == 2)
  5742.     {
  5743.         daptr = (char *)bacsptr;
  5744.         for(y=bacy0;y<bacy1;y++)
  5745.         {
  5746.             j = y*VSID;
  5747.             for(x=bacx0;x<bacx1;x++)
  5748.             {
  5749.                 for(v=sptr[j+x];v[0];v+=v[0]*4)
  5750.                     for(i=1;i<v[0];i++) v[(i<<2)+3] = *daptr++;
  5751.                 for(i=1;i<=v[2]-v[1]+1;i++) v[(i<<2)+3] = *daptr++;
  5752.             }
  5753.         }
  5754.         if (vx5.vxlmipuse > 1) genmipvxl(bacx0,bacy0,bacx1,bacy1);
  5755.     }
  5756.     backedup = -1;
  5757. }
  5758.  
  5759. void voxbackup (long x0, long y0, long x1, long y1, long tag)
  5760. {
  5761.     long i, j, n, x, y;
  5762.     char *v, *daptr;
  5763.  
  5764.     voxdontrestore();
  5765.  
  5766.     x0 = max(x0-2,0); y0 = max(y0-2,0);
  5767.     x1 = min(x1+2,VSID); y1 = min(y1+2,VSID);
  5768.     if ((x1-x0)*(y1-y0) > 262144) return;
  5769.  
  5770.     bacx0 = x0; bacy0 = y0; bacx1 = x1; bacy1 = y1; backtag = tag;
  5771.  
  5772.     if (tag&0x10000)
  5773.     {
  5774.         backedup = 1;
  5775.         i = 0;
  5776.         for(y=bacy0;y<bacy1;y++)
  5777.         {
  5778.             j = y*VSID;
  5779.             for(x=bacx0;x<bacx1;x++)
  5780.             {
  5781.                 bacsptr[i] = v = sptr[j+x]; i++;
  5782.                 n = slng(v); sptr[j+x] = voxalloc(n);
  5783.  
  5784.                 copybuf((void *)v,(void *)sptr[j+x],n>>2);
  5785.             }
  5786.         }
  5787.     }
  5788.     else if (tag&0x20000)
  5789.     {
  5790.         backedup = 2;
  5791.             //WARNING!!! Right now, function will crash if saving more than
  5792.             //   1<<20 colors :( This needs to be addressed!!!
  5793.         daptr = (char *)bacsptr;
  5794.         for(y=bacy0;y<bacy1;y++)
  5795.         {
  5796.             j = y*VSID;
  5797.             for(x=bacx0;x<bacx1;x++)
  5798.             {
  5799.                 for(v=sptr[j+x];v[0];v+=v[0]*4)
  5800.                     for(i=1;i<v[0];i++) *daptr++ = v[(i<<2)+3];
  5801.                 for(i=1;i<=v[2]-v[1]+1;i++) *daptr++ = v[(i<<2)+3];
  5802.             }
  5803.         }
  5804.     }
  5805.     else backedup = 0;
  5806. }
  5807.  
  5808. //-------------------- editing backup / restore ends -------------------------
  5809.  
  5810.     //WARNING! Make sure to set vx5.colfunc before calling this function!
  5811.     //This function is here for simplicity only - it is NOT optimal.
  5812.     //
  5813.     //   -1: set air
  5814.     //   -2: use vx5.colfunc
  5815. void setcube (long px, long py, long pz, long col)
  5816. {
  5817.     long bakcol, (*bakcolfunc)(lpoint3d *), *lptr;
  5818.  
  5819.     vx5.minx = px; vx5.maxx = px+1;
  5820.     vx5.miny = py; vx5.maxy = py+1;
  5821.     vx5.minz = pz; vx5.maxz = pz+1;
  5822.     if ((unsigned long)pz >= MAXZDIM) return;
  5823.     if ((unsigned long)col >= (unsigned long)0xfffffffe) //-1 or -2
  5824.     {
  5825.         lptr = scum2(px,py);
  5826.         if (col == -1) delslab(lptr,pz,pz+1); else insslab(lptr,pz,pz+1);
  5827.         scum2finish();
  5828.         updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,col);
  5829.         return;
  5830.     }
  5831.  
  5832.     bakcol = getcube(px,py,pz);
  5833.     if (bakcol == 1) return; //Unexposed solid
  5834.     if (bakcol != 0) //Not 0 (air)
  5835.         *(long *)bakcol = col;
  5836.     else
  5837.     {
  5838.         bakcolfunc = vx5.colfunc; bakcol = vx5.curcol;
  5839.         vx5.colfunc = curcolfunc; vx5.curcol = col;
  5840.         insslab(scum2(px,py),pz,pz+1); scum2finish();
  5841.         vx5.colfunc = bakcolfunc; vx5.curcol = bakcol;
  5842.     }
  5843.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,0);
  5844. }
  5845.  
  5846. //-------------------------- SETCOLUMN CODE ENDS ----------------------------
  5847.  
  5848. static __int64 qmulmip[8] =
  5849. {
  5850.     0x7fff7fff7fff7fff,0x4000400040004000,0x2aaa2aaa2aaa2aaa,0x2000200020002000,
  5851.     0x1999199919991999,0x1555155515551555,0x1249124912491249,0x1000100010001000
  5852. };
  5853. static long mixc[MAXZDIM>>1][8]; //4K
  5854. static long mixn[MAXZDIM>>1];    //0.5K
  5855. void genmipvxl (long x0, long y0, long x1, long y1)
  5856. {
  5857.     long i, n, oldn, x, y, z, xsiz, ysiz, zsiz, oxsiz, oysiz;
  5858.     long cz, oz, nz, zz, besti, cstat, curz[4], curzn[4][4], mipnum, mipmax;
  5859.     char *v[4], *tv, **sr, **sw, **ssr, **ssw;
  5860.  
  5861.     if ((!(x0|y0)) && (x1 == VSID) && (y1 == VSID)) mipmax = vx5.vxlmipuse;
  5862.                                                              else mipmax = gmipnum;
  5863.     if (mipmax <= 0) return;
  5864.     mipnum = 1;
  5865.  
  5866.     vx5.colfunc = curcolfunc;
  5867.     xsiz = VSID; ysiz = VSID; zsiz = MAXZDIM;
  5868.     ssr = sptr; ssw = sptr+xsiz*ysiz;
  5869.     while ((xsiz > 1) && (ysiz > 1) && (zsiz > 1) && (mipnum < mipmax))
  5870.     {
  5871.         oxsiz = xsiz; xsiz >>= 1;
  5872.         oysiz = ysiz; ysiz >>= 1;
  5873.                           zsiz >>= 1;
  5874.  
  5875.         x0--; if (x0 < 0) x0 = 0;
  5876.         y0--; if (y0 < 0) y0 = 0;
  5877.         x1++; if (x1 > VSID) x1 = VSID;
  5878.         y1++; if (y1 > VSID) y1 = VSID;
  5879.  
  5880.         x0 >>= 1; x1 = ((x1+1)>>1);
  5881.         y0 >>= 1; y1 = ((y1+1)>>1);
  5882.         for(y=y0;y<y1;y++)
  5883.         {
  5884.             sr = ssr+oxsiz*(y<<1)+(x0<<1);
  5885.             sw = ssw+xsiz*y+x0;
  5886.             for(x=x0;x<x1;x++)
  5887.             {
  5888.                     //ΪΔΔΔΒΔΔΔΒΔΔΔΒΔΔΔΏ
  5889.                     //³npt³z1 ³z1c³dum³
  5890.                     //³ b ³ g ³ r ³ i ³
  5891.                     //³ b ³ g ³ r ³ i ³
  5892.                     //³npt³z1 ³z1c³z0 ³
  5893.                     //³ b ³ g ³ r ³ i ³
  5894.                     //ΐΔΔΔΑΔΔΔΑΔΔΔΑΔΔΔΩ
  5895.                 v[0] = sr[      0];
  5896.                 v[1] = sr[      1];
  5897.                 v[2] = sr[oysiz  ];
  5898.                 v[3] = sr[oysiz+1];
  5899.                 for(i=3;i>=0;i--)
  5900.                 {
  5901.                     curz[i] = curzn[i][0] = (long)v[i][1];
  5902.                     curzn[i][1] = ((long)v[i][2])+1;
  5903.  
  5904.                     tv = v[i];
  5905.                     while (1)
  5906.                     {
  5907.                         oz = (long)tv[1];
  5908.                         for(z=oz;z<=((long)tv[2]);z++)
  5909.                         {
  5910.                             nz = (z>>1);
  5911.                             mixc[nz][mixn[nz]++] = *(long *)(&tv[((z-oz)<<2)+4]);
  5912.                         }
  5913.                         z = (z-oz) - (((long)tv[0])-1);
  5914.                         if (!tv[0]) break;
  5915.                         tv += (((long)tv[0])<<2);
  5916.                         oz = (long)tv[3];
  5917.                         for(;z<0;z++)
  5918.                         {
  5919.                             nz = ((z+oz)>>1);
  5920.                             mixc[nz][mixn[nz]++] = *(long *)(&tv[z<<2]);
  5921.                         }
  5922.                     }
  5923.                 }
  5924.                 cstat = 0; oldn = 0; n = 4; tbuf[3] = 0; z = 0x80000000;
  5925.                 while (1)
  5926.                 {
  5927.                     oz = z;
  5928.  
  5929.                         //z,besti = min,argmin(curz[0],curz[1],curz[2],curz[3])
  5930.                     besti = (((unsigned long)(curz[1]-curz[    0]))>>31);
  5931.                          i = (((unsigned long)(curz[3]-curz[    2]))>>31)+2;
  5932.                     besti +=(((( signed long)(curz[i]-curz[besti]))>>31)&(i-besti));
  5933.                     z = curz[besti]; if (z >= MAXZDIM) break;
  5934.  
  5935.                     if ((!cstat) && ((z>>1) >= ((oz+1)>>1)))
  5936.                     {
  5937.                         if (oz >= 0)
  5938.                         {
  5939.                             tbuf[oldn] = ((n-oldn)>>2);
  5940.                             tbuf[oldn+2]--;
  5941.                             tbuf[n+3] = ((oz+1)>>1);
  5942.                             oldn = n; n += 4;
  5943.                         }
  5944.                         tbuf[oldn] = 0;
  5945.                         tbuf[oldn+1] = tbuf[oldn+2] = (z>>1); cz = -1;
  5946.                     }
  5947.                     if (cstat&0x1111)
  5948.                     {
  5949.                         if (((((long)tbuf[oldn+2])<<1)+1 >= oz) && (cz < 0))
  5950.                         {
  5951.                             while ((((long)tbuf[oldn+2])<<1) < z)
  5952.                             {
  5953.                                 zz = (long)tbuf[oldn+2];
  5954.  
  5955.                                 _asm //*(long *)&tbuf[n] = mixc[zz][rand()%mixn[zz]];
  5956.                                 {    //mixn[zz] = 0;
  5957.                                     mov eax, zz
  5958.                                     mov ecx, mixn[eax*4]
  5959.                                     mov mixn[eax*4], 0
  5960.                                     shl eax, 5
  5961.                                     pxor mm0, mm0
  5962.                                     movq mm2, qmulmip[ecx*8-8]
  5963.                                     pcmpeqb mm6, mm6
  5964.                                     movq mm7, mm0
  5965.                      vxlmipbeg0:movd mm1, mixc[eax+ecx*4-4]
  5966.                                     punpcklbw mm1, mm7
  5967.                                     paddw mm0, mm1
  5968.                                     dec ecx
  5969.                                     jnz short vxlmipbeg0
  5970.                                     paddw mm0, mm0
  5971.                                     psubw mm0, mm6 ;rounding bias
  5972.                                     pmulhw mm0, mm2
  5973.                                     packuswb mm0, mm0
  5974.                                     mov eax, n
  5975.                                     movd tbuf[eax], mm0
  5976.                                 }
  5977.  
  5978.                                 tbuf[oldn+2]++; n += 4;
  5979.                             }
  5980.                         }
  5981.                         else
  5982.                         {
  5983.                             if (cz < 0) cz = (oz>>1);
  5984.                             else if ((cz<<1)+1 < oz)
  5985.                             {
  5986.                                     //Insert fake slab
  5987.                                 tbuf[oldn] = ((n-oldn)>>2);
  5988.                                 tbuf[oldn+2]--;
  5989.                                 tbuf[n] = 0;
  5990.                                 tbuf[n+1] = tbuf[n+2] = tbuf[n+3] = cz;
  5991.                                 oldn = n; n += 4;
  5992.                                 cz = (oz>>1);
  5993.                             }
  5994.                             while ((cz<<1) < z)
  5995.                             {
  5996.                                 _asm //*(long *)&tbuf[n] = mixc[cz][rand()%mixn[cz]];
  5997.                                 {    //mixn[cz] = 0;
  5998.                                     mov eax, cz
  5999.                                     mov ecx, mixn[eax*4]
  6000.                                     mov mixn[eax*4], 0
  6001.                                     shl eax, 5
  6002.                                     pxor mm0, mm0
  6003.                                     movq mm2, qmulmip[ecx*8-8]
  6004.                                     pcmpeqb mm6, mm6
  6005.                                     movq mm7, mm0
  6006.                      vxlmipbeg1:movd mm1, mixc[eax+ecx*4-4]
  6007.                                     punpcklbw mm1, mm7
  6008.                                     paddw mm0, mm1
  6009.                                     dec ecx
  6010.                                     jnz short vxlmipbeg1
  6011.                                     paddw mm0, mm0
  6012.                                     psubw mm0, mm6 ;rounding bias
  6013.                                     pmulhw mm0, mm2
  6014.                                     packuswb mm0, mm0
  6015.                                     mov eax, n
  6016.                                     movd tbuf[eax], mm0
  6017.                                 }
  6018.  
  6019.                                 cz++; n += 4;
  6020.                             }
  6021.                         }
  6022.                     }
  6023.  
  6024.                     i = (besti<<2);
  6025.                     cstat = (((1<<i)+cstat)&0x3333); //--33--22--11--00
  6026.                     switch ((cstat>>i)&3)
  6027.                     {
  6028.                         case 0: curz[besti] = curzn[besti][0]; break;
  6029.                         case 1: curz[besti] = curzn[besti][1]; break;
  6030.                         case 2:
  6031.                             if (!(v[besti][0])) { curz[besti] = MAXZDIM; }
  6032.                             else
  6033.                             {
  6034.                                 tv = v[besti]; i = (((long)tv[2])-((long)tv[1])+1)-(((long)tv[0])-1);
  6035.                                 tv += (((long)tv[0])<<2);
  6036.                                 curz[besti] = ((long)(tv[3])) + i;
  6037.                                 curzn[besti][3] = (long)(tv[3]);
  6038.                                 curzn[besti][0] = (long)(tv[1]);
  6039.                                 curzn[besti][1] = ((long)tv[2])+1;
  6040.                                 v[besti] = tv;
  6041.                             }
  6042.                             break;
  6043.                         case 3: curz[besti] = curzn[besti][3]; break;
  6044.                         //default: __assume(0); //tells MSVC default can't be reached
  6045.                     }
  6046.                 }
  6047.                 tbuf[oldn+2]--;
  6048.                 if (cz >= 0)
  6049.                 {
  6050.                     tbuf[oldn] = ((n-oldn)>>2);
  6051.                     tbuf[n] = 0;
  6052.                     tbuf[n+1] = tbuf[n+3] = cz;
  6053.                     tbuf[n+2] = cz-1;
  6054.                     n += 4;
  6055.                 }
  6056.  
  6057.                     //De-allocate column (x,y) if it exists
  6058.                 if (sw[0]) voxdealloc(sw[0]);
  6059.  
  6060.                     //Allocate & copy to new column (x,y)
  6061.                 sw[0] = voxalloc(n);
  6062.                 copybuf((void *)tbuf,(void *)sw[0],n>>2);
  6063.                 sw++; sr += 2;
  6064.             }
  6065.             sr += ysiz*2;
  6066.         }
  6067.         ssr = ssw; ssw += xsiz*ysiz;
  6068.         mipnum++; if (mipnum > gmipnum) gmipnum = mipnum;
  6069.     }
  6070.  
  6071.         //Remove extra mips (bbox must be 0,0,VSID,VSID to get inside this)
  6072.     while ((xsiz > 1) && (ysiz > 1) && (zsiz > 1) && (mipnum < gmipnum))
  6073.     {
  6074.         xsiz >>= 1; ysiz >>= 1; zsiz >>= 1;
  6075.         for(i=xsiz*ysiz;i>0;i--)
  6076.         {
  6077.             if (ssw[0]) voxdealloc(ssw[0]); //De-allocate column if it exists
  6078.             ssw++;
  6079.         }
  6080.         gmipnum--;
  6081.     }
  6082.  
  6083.     _asm emms
  6084.  
  6085. #if 0 //TEMP HACK!!!
  6086.     {
  6087.     FILE *fil;
  6088.     dpoint3d dp;
  6089.     if (!(fil = fopen("temp512.vxl","wb"))) return;
  6090.     i = 0x09072000; fwrite(&i,4,1,fil);  //Version
  6091.     i = (VSID>>1); fwrite(&i,4,1,fil);
  6092.     i = (VSID>>1); fwrite(&i,4,1,fil);
  6093.     dp.x = (double)i*.5; dp.y = (double)i*.5; dp.z = (double)i*.5;
  6094.     fwrite(&dp,24,1,fil);
  6095.     dp.x = 1.0; dp.y = 0.0; dp.z = 0.0; fwrite(&dp,24,1,fil);
  6096.     dp.x = 0.0; dp.y = 0.0; dp.z = 1.0; fwrite(&dp,24,1,fil);
  6097.     dp.x = 0.0; dp.y =-1.0; dp.z = 0.0; fwrite(&dp,24,1,fil);
  6098.     for(i=0;i<(VSID>>1)*(VSID>>1);i++)
  6099.         fwrite((void *)sptr[i+VSID*VSID],slng(sptr[i+VSID*VSID]),1,fil);
  6100.     fclose(fil);
  6101.     }
  6102.     gmipnum = 1;
  6103. #endif
  6104.  
  6105. }
  6106.  
  6107. void setsphere (lpoint3d *hit, long hitrad, long dacol)
  6108. {
  6109.     void (*modslab)(long *, long, long);
  6110.     long i, x, y, xs, ys, zs, xe, ye, ze, sq;
  6111.     float f, ff;
  6112.  
  6113.     xs = max(hit->x-hitrad,0); xe = min(hit->x+hitrad,VSID-1);
  6114.     ys = max(hit->y-hitrad,0); ye = min(hit->y+hitrad,VSID-1);
  6115.     zs = max(hit->z-hitrad,0); ze = min(hit->z+hitrad,MAXZDIM-1);
  6116.     vx5.minx = xs; vx5.maxx = xe+1;
  6117.     vx5.miny = ys; vx5.maxy = ye+1;
  6118.     vx5.minz = zs; vx5.maxz = ze+1;
  6119.     if ((xs > xe) || (ys > ye) || (zs > ze)) return;
  6120.  
  6121.     if (vx5.colfunc == sphcolfunc)
  6122.     {
  6123.         vx5.cen = hit->x+hit->y+hit->z;
  6124.         vx5.daf = 1.f/(hitrad*sqrt(3.f));
  6125.     }
  6126.  
  6127.     if (hitrad >= SETSPHMAXRAD-1) hitrad = SETSPHMAXRAD-2;
  6128.     if (dacol == -1) modslab = delslab; else modslab = insslab;
  6129.  
  6130.     tempfloatbuf[0] = 0.0f;
  6131. #if 0
  6132.         //Totally unoptimized
  6133.     for(i=1;i<=hitrad;i++) tempfloatbuf[i] = pow((float)i,vx5.curpow);
  6134. #else
  6135.     tempfloatbuf[1] = 1.0f;
  6136.     for(i=2;i<=hitrad;i++)
  6137.     {
  6138.         if (!factr[i][0]) tempfloatbuf[i] = exp(logint[i]*vx5.curpow);
  6139.         else tempfloatbuf[i] = tempfloatbuf[factr[i][0]]*tempfloatbuf[factr[i][1]];
  6140.     }
  6141. #endif
  6142.     *(long *)&tempfloatbuf[hitrad+1] = 0x7f7fffff; //3.4028235e38f; //Highest float
  6143.  
  6144.     sq = 0; //pow(fabs(x-hit->x),vx5.curpow) + "y + "z < pow(vx5.currad,vx5.curpow)
  6145.     for(y=ys;y<=ye;y++)
  6146.     {
  6147.         ff = tempfloatbuf[hitrad]-tempfloatbuf[labs(y-hit->y)];
  6148.         if (*(long *)&ff <= 0) continue;
  6149.         for(x=xs;x<=xe;x++)
  6150.         {
  6151.             f = ff-tempfloatbuf[labs(x-hit->x)]; if (*(long *)&f <= 0) continue;
  6152.             while (*(long *)&tempfloatbuf[sq] <  *(long *)&f) sq++;
  6153.             while (*(long *)&tempfloatbuf[sq] >= *(long *)&f) sq--;
  6154.             modslab(scum2(x,y),max(hit->z-sq,zs),min(hit->z+sq+1,ze));
  6155.         }
  6156.     }
  6157.     scum2finish();
  6158.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  6159. }
  6160.  
  6161. void setellipsoid (lpoint3d *hit, lpoint3d *hit2, long hitrad, long dacol, long bakit)
  6162. {
  6163.     void (*modslab)(long *, long, long);
  6164.     long x, y, xs, ys, zs, xe, ye, ze;
  6165.     float a, b, c, d, e, f, g, h, r, t, u, Za, Zb, fx0, fy0, fz0, fx1, fy1, fz1;
  6166.  
  6167.     xs = min(hit->x,hit2->x)-hitrad; xs = max(xs,0);
  6168.     ys = min(hit->y,hit2->y)-hitrad; ys = max(ys,0);
  6169.     zs = min(hit->z,hit2->z)-hitrad; zs = max(zs,0);
  6170.     xe = max(hit->x,hit2->x)+hitrad; xe = min(xe,VSID-1);
  6171.     ye = max(hit->y,hit2->y)+hitrad; ye = min(ye,VSID-1);
  6172.     ze = max(hit->z,hit2->z)+hitrad; ze = min(ze,MAXZDIM-1);
  6173.     vx5.minx = xs; vx5.maxx = xe+1;
  6174.     vx5.miny = ys; vx5.maxy = ye+1;
  6175.     vx5.minz = zs; vx5.maxz = ze+1;
  6176.     if ((xs > xe) || (ys > ye) || (zs > ze))
  6177.         { if (bakit) voxbackup(xs,ys,xs,ys,bakit); return; }
  6178.  
  6179.     fx0 = (float)hit->x; fy0 = (float)hit->y; fz0 = (float)hit->z;
  6180.     fx1 = (float)hit2->x; fy1 = (float)hit2->y; fz1 = (float)hit2->z;
  6181.  
  6182.     r = (fx1-fx0)*(fx1-fx0) + (fy1-fy0)*(fy1-fy0) + (fz1-fz0)*(fz1-fz0);
  6183.     r = sqrt((float)hitrad*(float)hitrad + r*.25);
  6184.     c = fz0*fz0 - fz1*fz1; d = r*r*-4; e = d*4;
  6185.     f = c*c + fz1*fz1 * e; g = c + c; h = (fz1-fz0)*2; c = c*h - fz1*e;
  6186.     Za = -h*h - e; if (Za <= 0) { if (bakit) voxbackup(xs,ys,xs,ys,bakit); return; }
  6187.     u = 1 / Za;
  6188.  
  6189.     if (vx5.colfunc == jitcolfunc) vx5.amount = 0x70707;
  6190.  
  6191.     if (dacol == -1) modslab = delslab; else modslab = insslab;
  6192.  
  6193.     if (bakit) voxbackup(xs,ys,xe+1,ye+1,bakit);
  6194.  
  6195.     for(y=ys;y<=ye;y++)
  6196.         for(x=xs;x<=xe;x++)
  6197.         {
  6198.             a = (x-fx0)*(x-fx0) + (y-fy0)*(y-fy0);
  6199.             b = (x-fx1)*(x-fx1) + (y-fy1)*(y-fy1);
  6200.             t = a-b+d; Zb = t*h + c;
  6201.             t = ((t+g)*t + b*e + f)*Za + Zb*Zb; if (t <= 0) continue;
  6202.             t = sqrt(t);
  6203.             ftol((Zb - t)*u,&zs); if (zs < 0) zs = 0;
  6204.             ftol((Zb + t)*u,&ze); if (ze > MAXZDIM) ze = MAXZDIM;
  6205.             modslab(scum2(x,y),zs,ze);
  6206.         }
  6207.     scum2finish();
  6208.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  6209. }
  6210.  
  6211.     //Draws a cylinder, given: 2 points, a radius, and a color
  6212.     //Code mostly optimized - original code from CYLINDER.BAS:drawcylinder
  6213. void setcylinder (lpoint3d *p0, lpoint3d *p1, long cr, long dacol, long bakit)
  6214. {
  6215.     void (*modslab)(long *, long, long);
  6216.  
  6217.     float t, ax, ay, az, bx, by, bz, cx, cy, cz, ux, uy, uz, vx, vy, vz;
  6218.     float Za, Zb, Zc, tcr, xxyy, rcz, rZa;
  6219.     float fx, fxi, xof, vx0, vy0, vz0, vz0i, vxo, vyo, vzo;
  6220.     long i, j, ix, iy, ix0, ix1, iz0, iz1, minx, maxx, miny, maxy;
  6221.     long x0, y0, z0, x1, y1, z1;
  6222.  
  6223.         //Map generic cylinder into unit space:  (0,0,0), (0,0,1), cr = 1
  6224.         //   x*x + y*y < 1, z >= 0, z < 1
  6225.     if (p0->z > p1->z)
  6226.     {
  6227.         x0 = p1->x; y0 = p1->y; z0 = p1->z;
  6228.         x1 = p0->x; y1 = p0->y; z1 = p0->z;
  6229.     }
  6230.     else
  6231.     {
  6232.         x0 = p0->x; y0 = p0->y; z0 = p0->z;
  6233.         x1 = p1->x; y1 = p1->y; z1 = p1->z;
  6234.     }
  6235.  
  6236.     xxyy = (float)((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0));
  6237.     t = xxyy + (float)(z1-z0)*(z1-z0);
  6238.     if ((t == 0) || (cr == 0))
  6239.     {
  6240.         vx5.minx = x0; vx5.maxx = x0+1;
  6241.         vx5.miny = y0; vx5.maxy = y0+1;
  6242.         vx5.minz = z0; vx5.maxz = z0+1;
  6243.         if (bakit) voxbackup(x0,y0,x0,y0,bakit);
  6244.         return;
  6245.     }
  6246.     t = 1 / t; cx = ((float)(x1-x0))*t; cy = ((float)(y1-y0))*t; cz = ((float)(z1-z0))*t;
  6247.     t = sqrt(t); ux = ((float)(x1-x0))*t; uy = ((float)(y1-y0))*t; uz = ((float)(z1-z0))*t;
  6248.  
  6249.     if (vx5.colfunc == jitcolfunc) vx5.amount = 0x70707;
  6250.  
  6251.     if (dacol == -1) modslab = delslab; else modslab = insslab;
  6252.  
  6253.     if (xxyy == 0)
  6254.     {
  6255.         iz0 = max(z0,0); iz1 = min(z1,MAXZDIM);
  6256.         minx = max(x0-cr,0); maxx = min(x0+cr,VSID-1);
  6257.         miny = max(y0-cr,0); maxy = min(y0+cr,VSID-1);
  6258.  
  6259.         vx5.minx = minx; vx5.maxx = maxx+1;
  6260.         vx5.miny = miny; vx5.maxy = maxy+1;
  6261.         vx5.minz = iz0; vx5.maxz = iz1;
  6262.         if (bakit) voxbackup(minx,miny,maxx+1,maxy+1,bakit);
  6263.  
  6264.         j = cr*cr;
  6265.         for(iy=miny;iy<=maxy;iy++)
  6266.         {
  6267.             i = j-(iy-y0)*(iy-y0);
  6268.             for(ix=minx;ix<=maxx;ix++)
  6269.                 if ((ix-x0)*(ix-x0) < i) modslab(scum2(ix,iy),iz0,iz1);
  6270.         }
  6271.         scum2finish();
  6272.         updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  6273.         return;
  6274.     }
  6275.  
  6276.     if (x0 < x1) { minx = x0; maxx = x1; } else { minx = x1; maxx = x0; }
  6277.     if (y0 < y1) { miny = y0; maxy = y1; } else { miny = y1; maxy = y0; }
  6278.     tcr = cr / sqrt(xxyy); vx = fabs((float)(x1-x0))*tcr; vy = fabs((float)(y1-y0))*tcr;
  6279.     t = vx*uz + vy;
  6280.     ftol((float)minx-t,&minx); if (minx < 0) minx = 0;
  6281.     ftol((float)maxx+t,&maxx); if (maxx >= VSID) maxx = VSID-1;
  6282.     t = vy*uz + vx;
  6283.     ftol((float)miny-t,&miny); if (miny < 0) miny = 0;
  6284.     ftol((float)maxy+t,&maxy); if (maxy >= VSID) maxy = VSID-1;
  6285.  
  6286.     vx5.minx = minx; vx5.maxx = maxx+1;
  6287.     vx5.miny = miny; vx5.maxy = maxy+1;
  6288.     vx5.minz = z0-cr; vx5.maxz = z1+cr+1;
  6289.     if (bakit) voxbackup(minx,miny,maxx+1,maxy+1,bakit);
  6290.  
  6291.     vx = (fabs(ux) < fabs(uy)); vy = 1.0f-vx; vz = 0;
  6292.     ax = uy*vz - uz*vy; ay = uz*vx - ux*vz; az = ux*vy - uy*vx;
  6293.     t = 1.0 / (sqrt(ax*ax + ay*ay + az*az)*cr);
  6294.     ax *= t; ay *= t; az *= t;
  6295.     bx = ay*uz - az*uy; by = az*ux - ax*uz; bz = ax*uy - ay*ux;
  6296.  
  6297.     Za = az*az + bz*bz; rZa = 1.0f / Za;
  6298.     if (cz != 0) { rcz = 1.0f / cz; vz0i = -rcz*cx; }
  6299.     if (y0 != y1)
  6300.     {
  6301.         t = 1.0f / ((float)(y1-y0)); fxi = ((float)(x1-x0))*t;
  6302.         fx = ((float)miny-y0)*fxi + x0; xof = fabs(tcr*xxyy*t);
  6303.     }
  6304.     else { fx = (float)minx; fxi = 0.0; xof = (float)(maxx-minx); }
  6305.  
  6306.     vy = (float)(miny-y0);
  6307.     vxo = vy*ay - z0*az;
  6308.     vyo = vy*by - z0*bz;
  6309.     vzo = vy*cy - z0*cz;
  6310.     for(iy=miny;iy<=maxy;iy++)
  6311.     {
  6312.         ftol(fx-xof,&ix0); if (ix0 < minx) ix0 = minx;
  6313.         ftol(fx+xof,&ix1); if (ix1 > maxx) ix1 = maxx;
  6314.         fx += fxi;
  6315.  
  6316.         vx = (float)(ix0-x0);
  6317.         vx0 = vx*ax + vxo; vxo += ay;
  6318.         vy0 = vx*bx + vyo; vyo += by;
  6319.         vz0 = vx*cx + vzo; vzo += cy;
  6320.  
  6321.         if (cz != 0)   //(vx0 + vx1*t)ύ + (vy0 + vy1*t)ύ = 1
  6322.         {
  6323.             vz0 *= -rcz;
  6324.             for(ix=ix0;ix<=ix1;ix++,vx0+=ax,vy0+=bx,vz0+=vz0i)
  6325.             {
  6326.                 Zb = vx0*az + vy0*bz; Zc = vx0*vx0 + vy0*vy0 - 1;
  6327.                 t = Zb*Zb - Za*Zc; if (*(long *)&t <= 0) continue; t = sqrt(t);
  6328.                 ftol(max((-Zb-t)*rZa,vz0    ),&iz0); if (iz0 < 0) iz0 = 0;
  6329.                 ftol(min((-Zb+t)*rZa,vz0+rcz),&iz1); if (iz1 > MAXZDIM) iz1 = MAXZDIM;
  6330.                 modslab(scum2(ix,iy),iz0,iz1);
  6331.             }
  6332.         }
  6333.         else
  6334.         {
  6335.             for(ix=ix0;ix<=ix1;ix++,vx0+=ax,vy0+=bx,vz0+=cx)
  6336.             {
  6337.                 if (*(unsigned long *)&vz0 >= 0x3f800000) continue; //vz0<0||vz0>=1
  6338.                 Zb = vx0*az + vy0*bz; Zc = vx0*vx0 + vy0*vy0 - 1;
  6339.                 t = Zb*Zb - Za*Zc; if (*(long *)&t <= 0) continue; t = sqrt(t);
  6340.                 ftol((-Zb-t)*rZa,&iz0); if (iz0 < 0) iz0 = 0;
  6341.                 ftol((-Zb+t)*rZa,&iz1); if (iz1 > MAXZDIM) iz1 = MAXZDIM;
  6342.                 modslab(scum2(ix,iy),iz0,iz1);
  6343.             }
  6344.         }
  6345.     }
  6346.     scum2finish();
  6347.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  6348. }
  6349.  
  6350.     //Draws a rectangle, given: 2 points as opposite corners, and a color
  6351. void setrect (lpoint3d *hit, lpoint3d *hit2, long dacol)
  6352. {
  6353.     long x, y, xs, ys, zs, xe, ye, ze;
  6354.  
  6355.         //WARNING: do NOT use lbound because 'c' not guaranteed to be >= 'b'
  6356.     xs = max(min(hit->x,hit2->x),0); xe = min(max(hit->x,hit2->x),VSID-1);
  6357.     ys = max(min(hit->y,hit2->y),0); ye = min(max(hit->y,hit2->y),VSID-1);
  6358.     zs = max(min(hit->z,hit2->z),0); ze = min(max(hit->z,hit2->z),MAXZDIM-1);
  6359.     vx5.minx = xs; vx5.maxx = xe+1;
  6360.     vx5.miny = ys; vx5.maxy = ye+1;
  6361.     vx5.minz = zs; vx5.maxz = ze+1;
  6362.     if ((xs > xe) || (ys > ye) || (zs > ze)) return;
  6363.  
  6364.     if (vx5.colfunc == jitcolfunc) vx5.amount = 0x70707;
  6365.  
  6366.     ze++;
  6367.     if (dacol == -1)
  6368.     {
  6369.         for(y=ys;y<=ye;y++)
  6370.             for(x=xs;x<=xe;x++)
  6371.                 delslab(scum2(x,y),zs,ze);
  6372.     }
  6373.     else
  6374.     {
  6375.         for(y=ys;y<=ye;y++)
  6376.             for(x=xs;x<=xe;x++)
  6377.                 insslab(scum2(x,y),zs,ze);
  6378.     }
  6379.     scum2finish();
  6380.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  6381. }
  6382.  
  6383.     //Does CSG using pre-sorted spanlist
  6384. void setspans (vspans *lst, long lstnum, lpoint3d *offs, long dacol)
  6385. {
  6386.     void (*modslab)(long *, long, long);
  6387.     long i, j, x, y, z0, z1, *lptr;
  6388.     char ox, oy;
  6389.  
  6390.     if (lstnum <= 0) return;
  6391.     if (dacol == -1) modslab = delslab; else modslab = insslab;
  6392.     vx5.minx = vx5.maxx = ((long)lst[0].x)+offs->x;
  6393.     vx5.miny = ((long)lst[       0].y)+offs->y;
  6394.     vx5.maxy = ((long)lst[lstnum-1].y)+offs->y+1;
  6395.     vx5.minz = vx5.maxz = ((long)lst[0].z0)+offs->z;
  6396.  
  6397.     i = 0; goto in2setlist;
  6398.     do
  6399.     {
  6400.         if ((ox != lst[i].x) || (oy != lst[i].y))
  6401.         {
  6402. in2setlist:;
  6403.             ox = lst[i].x; oy = lst[i].y;
  6404.             x = ((long)lst[i].x)+offs->x;
  6405.             y = ((long)lst[i].y)+offs->y;
  6406.                   if (x < vx5.minx) vx5.minx = x;
  6407.             else if (x > vx5.maxx) vx5.maxx = x;
  6408.             lptr = scum2(x,y);
  6409.         }
  6410.         if ((x|y)&(~(VSID-1))) { i++; continue; }
  6411.         z0 = ((long)lst[i].z0)+offs->z;   if (z0 < 0) z0 = 0;
  6412.         z1 = ((long)lst[i].z1)+offs->z+1; if (z1 > MAXZDIM) z1 = MAXZDIM;
  6413.         if (z0 < vx5.minz) vx5.minz = z0;
  6414.         if (z1 > vx5.maxz) vx5.maxz = z1;
  6415.         modslab(lptr,z0,z1);
  6416.         i++;
  6417.     } while (i < lstnum);
  6418.     vx5.maxx++; vx5.maxz++;
  6419.     if (vx5.minx < 0) vx5.minx = 0;
  6420.     if (vx5.miny < 0) vx5.miny = 0;
  6421.     if (vx5.maxx > VSID) vx5.maxx = VSID;
  6422.     if (vx5.maxy > VSID) vx5.maxy = VSID;
  6423.  
  6424.     scum2finish();
  6425.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  6426. }
  6427.  
  6428. void setheightmap (const unsigned char *hptr, long hpitch, long hxdim, long hydim,
  6429.                          long x0, long y0, long x1, long y1)
  6430. {
  6431.     long x, y, su, sv, u, v;
  6432.  
  6433.     if (x0 < 0) x0 = 0;
  6434.     if (y0 < 0) y0 = 0;
  6435.     if (x1 > VSID) x1 = VSID;
  6436.     if (y1 > VSID) y1 = VSID;
  6437.     vx5.minx = x0; vx5.maxx = x1;
  6438.     vx5.miny = y0; vx5.maxy = y1;
  6439.     vx5.minz = 0; vx5.maxz = MAXZDIM;
  6440.     if ((x0 >= x1) || (y0 >= y1)) return;
  6441.  
  6442.     su = x0%hxdim; sv = y0%hydim;
  6443.     for(y=y0,v=sv;y<y1;y++)
  6444.     {
  6445.         for(x=x0,u=su;x<x1;x++)
  6446.         {
  6447.             insslab(scum2(x,y),hptr[v*hpitch+u],MAXZDIM);
  6448.             u++; if (u >= hxdim) u = 0;
  6449.         }
  6450.         v++; if (v >= hydim) v = 0;
  6451.     }
  6452.     scum2finish();
  6453.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,0);
  6454. }
  6455.  
  6456. static long min0[VSID], max0[VSID]; //MAXY
  6457. static long min1[VSID], max1[VSID]; //MAXX
  6458. static long min2[VSID], max2[VSID]; //MAXY
  6459.  
  6460. static void canseerange (point3d *p0, point3d *p1)
  6461. {
  6462.     lpoint3d a, c, d, p, i;
  6463.     point3d f, g;
  6464.     long cnt, j;
  6465.  
  6466.     ftol(p0->x-.5,&a.x); ftol(p0->y-.5,&a.y); ftol(p0->z-.5,&a.z);
  6467.     ftol(p1->x-.5,&c.x); ftol(p1->y-.5,&c.y); ftol(p1->z-.5,&c.z);
  6468.     cnt = 0;
  6469.  
  6470.           if (c.x <  a.x) { d.x = -1; f.x = p0->x-a.x;   g.x = (p0->x-p1->x)*1024; cnt += a.x-c.x; }
  6471.     else if (c.x != a.x) { d.x =  1; f.x = a.x+1-p0->x; g.x = (p1->x-p0->x)*1024; cnt += c.x-a.x; }
  6472.     else f.x = g.x = 0;
  6473.           if (c.y <  a.y) { d.y = -1; f.y = p0->y-a.y;   g.y = (p0->y-p1->y)*1024; cnt += a.y-c.y; }
  6474.     else if (c.y != a.y) { d.y =  1; f.y = a.y+1-p0->y; g.y = (p1->y-p0->y)*1024; cnt += c.y-a.y; }
  6475.     else f.y = g.y = 0;
  6476.           if (c.z <  a.z) { d.z = -1; f.z = p0->z-a.z;   g.z = (p0->z-p1->z)*1024; cnt += a.z-c.z; }
  6477.     else if (c.z != a.z) { d.z =  1; f.z = a.z+1-p0->z; g.z = (p1->z-p0->z)*1024; cnt += c.z-a.z; }
  6478.     else f.z = g.z = 0;
  6479.  
  6480.     ftol(f.x*g.z - f.z*g.x,&p.x); ftol(g.x,&i.x);
  6481.     ftol(f.y*g.z - f.z*g.y,&p.y); ftol(g.y,&i.y);
  6482.     ftol(f.y*g.x - f.x*g.y,&p.z); ftol(g.z,&i.z);
  6483.     for(;cnt;cnt--)
  6484.     {
  6485.             //use a.x, a.y, a.z
  6486.         if (a.x < min0[a.y]) min0[a.y] = a.x;
  6487.         if (a.x > max0[a.y]) max0[a.y] = a.x;
  6488.         if (a.z < min1[a.x]) min1[a.x] = a.z;
  6489.         if (a.z > max1[a.x]) max1[a.x] = a.z;
  6490.         if (a.z < min2[a.y]) min2[a.y] = a.z;
  6491.         if (a.z > max2[a.y]) max2[a.y] = a.z;
  6492.  
  6493.         if (((p.x|p.y) >= 0) && (a.z != c.z)) { a.z += d.z; p.x -= i.x; p.y -= i.y; }
  6494.         else if ((p.z >= 0) && (a.x != c.x))  { a.x += d.x; p.x += i.z; p.z -= i.y; }
  6495.         else                                  { a.y += d.y; p.y += i.z; p.z += i.x; }
  6496.     }
  6497. }
  6498.  
  6499. void settri (point3d *p0, point3d *p1, point3d *p2, long bakit)
  6500. {
  6501.     point3d n;
  6502.     float f, x0, y0, z0, x1, y1, z1, rx, ry, k0, k1;
  6503.     long i, x, y, z, iz0, iz1, minx, maxx, miny, maxy;
  6504.  
  6505.     if (p0->x < p1->x) { x0 = p0->x; x1 = p1->x; } else { x0 = p1->x; x1 = p0->x; }
  6506.     if (p2->x < x0) x0 = p2->x;
  6507.     if (p2->x > x1) x1 = p2->x;
  6508.     if (p0->y < p1->y) { y0 = p0->y; y1 = p1->y; } else { y0 = p1->y; y1 = p0->y; }
  6509.     if (p2->y < y0) y0 = p2->y;
  6510.     if (p2->y > y1) y1 = p2->y;
  6511.     if (p0->z < p1->z) { z0 = p0->z; z1 = p1->z; } else { z0 = p1->z; z1 = p0->z; }
  6512.     if (p2->z < z0) z0 = p2->z;
  6513.     if (p2->z > z1) z1 = p2->z;
  6514.  
  6515.     ftol(x0-.5,&minx); ftol(y0-.5,&miny);
  6516.     ftol(x1-.5,&maxx); ftol(y1-.5,&maxy);
  6517.     vx5.minx = minx; vx5.maxx = maxx+1;
  6518.     vx5.miny = miny; vx5.maxy = maxy+1;
  6519.     ftol(z0-.5,&vx5.minz); ftol(z1+.5,&vx5.maxz);
  6520.     if (bakit) voxbackup(minx,miny,maxx+1,maxy+1,bakit);
  6521.  
  6522.     for(i=miny;i<=maxy;i++) { min0[i] = 0x7fffffff; max0[i] = 0x80000000; }
  6523.     for(i=minx;i<=maxx;i++) { min1[i] = 0x7fffffff; max1[i] = 0x80000000; }
  6524.     for(i=miny;i<=maxy;i++) { min2[i] = 0x7fffffff; max2[i] = 0x80000000; }
  6525.  
  6526.     canseerange(p0,p1);
  6527.     canseerange(p1,p2);
  6528.     canseerange(p2,p0);
  6529.  
  6530.     n.x = (p1->z-p0->z)*(p2->y-p1->y) - (p1->y-p0->y) * (p2->z-p1->z);
  6531.     n.y = (p1->x-p0->x)*(p2->z-p1->z) - (p1->z-p0->z) * (p2->x-p1->x);
  6532.     n.z = (p1->y-p0->y)*(p2->x-p1->x) - (p1->x-p0->x) * (p2->y-p1->y);
  6533.     f = 1.0 / sqrt(n.x*n.x + n.y*n.y + n.z*n.z); if (n.z < 0) f = -f;
  6534.     n.x *= f; n.y *= f; n.z *= f;
  6535.  
  6536.     if (n.z > .01)
  6537.     {
  6538.         f = -1.0 / n.z; rx = n.x*f; ry = n.y*f;
  6539.         k0 = ((n.x>=0)-p0->x)*rx + ((n.y>=0)-p0->y)*ry - ((n.z>=0)-p0->z) + .5;
  6540.         k1 = ((n.x< 0)-p0->x)*rx + ((n.y< 0)-p0->y)*ry - ((n.z< 0)-p0->z) - .5;
  6541.     }
  6542.     else { rx = 0; ry = 0; k0 = -2147000000.0; k1 = 2147000000.0; }
  6543.  
  6544.     for(y=miny;y<=maxy;y++)
  6545.         for(x=min0[y];x<=max0[y];x++)
  6546.         {
  6547.             f = (float)x*rx + (float)y*ry; ftol(f+k0,&iz0); ftol(f+k1,&iz1);
  6548.             if (iz0 < min1[x]) iz0 = min1[x];
  6549.             if (iz1 > max1[x]) iz1 = max1[x];
  6550.             if (iz0 < min2[y]) iz0 = min2[y];
  6551.             if (iz1 > max2[y]) iz1 = max2[y];
  6552.  
  6553.                 //set: (x,y,iz0) to (x,y,iz1) (inclusive)
  6554.             insslab(scum2(x,y),iz0,iz1+1);
  6555.     }
  6556.     scum2finish();
  6557.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,0);
  6558. }
  6559.  
  6560.     //Known problems:
  6561.     //1. Need to test faces for intersections on p1<->p2 line (not just edges)
  6562.     //2. Doesn't guarantee that hit point/line is purely air (but very close)
  6563.     //3. Piescan is more useful for parts of rope code :/
  6564. static long tripind[24] = {0,4,1,5,2,6,3,7,0,2,1,3,4,6,5,7,0,1,2,3,4,5,6,7};
  6565. long triscan (point3d *p0, point3d *p1, point3d *p2, point3d *hit, lpoint3d *lhit)
  6566. {
  6567.     point3d n, d[8], cp2;
  6568.     float f, g, x0, x1, y0, y1, rx, ry, k0, k1, fx, fy, fz, pval[8];
  6569.     long i, j, k, x, y, z, iz0, iz1, minx, maxx, miny, maxy, didhit;
  6570.  
  6571.     didhit = 0;
  6572.  
  6573.     if (p0->x < p1->x) { x0 = p0->x; x1 = p1->x; } else { x0 = p1->x; x1 = p0->x; }
  6574.     if (p2->x < x0) x0 = p2->x;
  6575.     if (p2->x > x1) x1 = p2->x;
  6576.     if (p0->y < p1->y) { y0 = p0->y; y1 = p1->y; } else { y0 = p1->y; y1 = p0->y; }
  6577.     if (p2->y < y0) y0 = p2->y;
  6578.     if (p2->y > y1) y1 = p2->y;
  6579.     ftol(x0-.5,&minx); ftol(y0-.5,&miny);
  6580.     ftol(x1-.5,&maxx); ftol(y1-.5,&maxy);
  6581.     for(i=miny;i<=maxy;i++) { min0[i] = 0x7fffffff; max0[i] = 0x80000000; }
  6582.     for(i=minx;i<=maxx;i++) { min1[i] = 0x7fffffff; max1[i] = 0x80000000; }
  6583.     for(i=miny;i<=maxy;i++) { min2[i] = 0x7fffffff; max2[i] = 0x80000000; }
  6584.  
  6585.     canseerange(p0,p1);
  6586.     canseerange(p1,p2);
  6587.     canseerange(p2,p0);
  6588.  
  6589.     n.x = (p1->z-p0->z)*(p2->y-p1->y) - (p1->y-p0->y) * (p2->z-p1->z);
  6590.     n.y = (p1->x-p0->x)*(p2->z-p1->z) - (p1->z-p0->z) * (p2->x-p1->x);
  6591.     n.z = (p1->y-p0->y)*(p2->x-p1->x) - (p1->x-p0->x) * (p2->y-p1->y);
  6592.     f = 1.0 / sqrt(n.x*n.x + n.y*n.y + n.z*n.z); if (n.z < 0) f = -f;
  6593.     n.x *= f; n.y *= f; n.z *= f;
  6594.  
  6595.     if (n.z > .01)
  6596.     {
  6597.         f = -1.0 / n.z; rx = n.x*f; ry = n.y*f;
  6598.         k0 = ((n.x>=0)-p0->x)*rx + ((n.y>=0)-p0->y)*ry - ((n.z>=0)-p0->z) + .5;
  6599.         k1 = ((n.x< 0)-p0->x)*rx + ((n.y< 0)-p0->y)*ry - ((n.z< 0)-p0->z) - .5;
  6600.     }
  6601.     else { rx = 0; ry = 0; k0 = -2147000000.0; k1 = 2147000000.0; }
  6602.  
  6603.     cp2.x = p2->x; cp2.y = p2->y; cp2.z = p2->z;
  6604.  
  6605.     for(y=miny;y<=maxy;y++)
  6606.         for(x=min0[y];x<=max0[y];x++)
  6607.         {
  6608.             f = (float)x*rx + (float)y*ry; ftol(f+k0,&iz0); ftol(f+k1,&iz1);
  6609.             if (iz0 < min1[x]) iz0 = min1[x];
  6610.             if (iz1 > max1[x]) iz1 = max1[x];
  6611.             if (iz0 < min2[y]) iz0 = min2[y];
  6612.             if (iz1 > max2[y]) iz1 = max2[y];
  6613.             for(z=iz0;z<=iz1;z++)
  6614.             {
  6615.                 if (!isvoxelsolid(x,y,z)) continue;
  6616.  
  6617.                 for(i=0;i<8;i++)
  6618.                 {
  6619.                     d[i].x = (float)(( i    &1)+x);
  6620.                     d[i].y = (float)(((i>>1)&1)+y);
  6621.                     d[i].z = (float)(((i>>2)&1)+z);
  6622.                     pval[i] = (d[i].x-p0->x)*n.x + (d[i].y-p0->y)*n.y + (d[i].z-p0->z)*n.z;
  6623.                 }
  6624.                 for(i=0;i<24;i+=2)
  6625.                 {
  6626.                     j = tripind[i+0];
  6627.                     k = tripind[i+1];
  6628.                     if (((*(long *)&pval[j])^(*(long *)&pval[k])) < 0)
  6629.                     {
  6630.                         f = pval[j]/(pval[j]-pval[k]);
  6631.                         fx = (d[k].x-d[j].x)*f + d[j].x;
  6632.                         fy = (d[k].y-d[j].y)*f + d[j].y;
  6633.                         fz = (d[k].z-d[j].z)*f + d[j].z;
  6634.  
  6635.                             //         (p0->x,p0->y,p0->z)
  6636.                             //             _|     |_
  6637.                             //           _|     .   |_
  6638.                             //         _|  (fx,fy,fz) |_
  6639.                             //       _|                 |_
  6640.                             //(p1->x,p1->y,p1->z)-.----(cp2.x,cp2.y,cp2.z)
  6641.    
  6642.                         if ((fabs(n.z) > fabs(n.x)) && (fabs(n.z) > fabs(n.y)))
  6643.                         { //x,y
  6644.                           // ix = p1->x + (cp2.x-p1->x)*t;
  6645.                           // iy = p1->y + (cp2.y-p1->y)*t;
  6646.                           //(iz = p1->z + (cp2.z-p1->z)*t;)
  6647.                           // ix = p0->x + (fx-p0->x)*u;
  6648.                           // iy = p0->y + (fy-p0->y)*u;
  6649.                           // (p1->x-cp2.x)*t + (fx-p0->x)*u = p1->x-p0->x;
  6650.                           // (p1->y-cp2.y)*t + (fy-p0->y)*u = p1->y-p0->y;
  6651.    
  6652.                             f = (p1->x-cp2.x)*(fy-p0->y) - (p1->y-cp2.y)*(fx-p0->x);
  6653.                             if ((*(long *)&f) == 0) continue;
  6654.                             f = 1.0 / f;
  6655.                             g = ((p1->x-cp2.x)*(p1->y-p0->y) - (p1->y-cp2.y)*(p1->x-p0->x))*f;
  6656.                             //NOTE: The following trick assumes g not * or / by f!
  6657.                             //if (((*(long *)&g)-(*(long *)&f))^(*(long *)&f)) >= 0) continue;
  6658.                             if ((*(long *)&g) < 0x3f800000) continue;
  6659.                             g = ((p1->x-p0->x)*(fy-p0->y) - (p1->y-p0->y)*(fx-p0->x))*f;
  6660.                         }
  6661.                         else if (fabs(n.y) > fabs(n.x))
  6662.                         { //x,z
  6663.                             f = (p1->x-cp2.x)*(fz-p0->z) - (p1->z-cp2.z)*(fx-p0->x);
  6664.                             if ((*(long *)&f) == 0) continue;
  6665.                             f = 1.0 / f;
  6666.                             g = ((p1->x-cp2.x)*(p1->z-p0->z) - (p1->z-cp2.z)*(p1->x-p0->x))*f;
  6667.                             if ((*(long *)&g) < 0x3f800000) continue;
  6668.                             g = ((p1->x-p0->x)*(fz-p0->z) - (p1->z-p0->z)*(fx-p0->x))*f;
  6669.                         }
  6670.                         else
  6671.                         { //y,z
  6672.                             f = (p1->y-cp2.y)*(fz-p0->z) - (p1->z-cp2.z)*(fy-p0->y);
  6673.                             if ((*(long *)&f) == 0) continue;
  6674.                             f = 1.0 / f;
  6675.                             g = ((p1->y-cp2.y)*(p1->z-p0->z) - (p1->z-cp2.z)*(p1->y-p0->y))*f;
  6676.                             if ((*(long *)&g) < 0x3f800000) continue;
  6677.                             g = ((p1->y-p0->y)*(fz-p0->z) - (p1->z-p0->z)*(fy-p0->y))*f;
  6678.                         }
  6679.                         if ((*(unsigned long *)&g) >= 0x3f800000) continue;
  6680.                         (hit->x) = fx; (hit->y) = fy; (hit->z) = fz;
  6681.                         (lhit->x) = x; (lhit->y) = y; (lhit->z) = z; didhit = 1;
  6682.                         (cp2.x) = (cp2.x-p1->x)*g + p1->x;
  6683.                         (cp2.y) = (cp2.y-p1->y)*g + p1->y;
  6684.                         (cp2.z) = (cp2.z-p1->z)*g + p1->z;
  6685.                     }
  6686.                 }
  6687.             }
  6688.         }
  6689.     return(didhit);
  6690. }
  6691.  
  6692. // ------------------------ CONVEX 3D HULL CODE BEGINS ------------------------
  6693.  
  6694. #define MAXPOINTS (256 *2) //Leave the *2 here for safety!
  6695. point3d nm[MAXPOINTS*2+2];
  6696. float nmc[MAXPOINTS*2+2];
  6697. long tri[MAXPOINTS*8+8], lnk[MAXPOINTS*8+8], tricnt;
  6698. char umost[VSID*VSID], dmost[VSID*VSID];
  6699.  
  6700. void initetrasid (point3d *pt, long z)
  6701. {
  6702.     long i, j, k;
  6703.     float x0, y0, z0, x1, y1, z1;
  6704.  
  6705.     i = tri[z*4]; j = tri[z*4+1]; k = tri[z*4+2];
  6706.     x0 = pt[i].x-pt[k].x; y0 = pt[i].y-pt[k].y; z0 = pt[i].z-pt[k].z;
  6707.     x1 = pt[j].x-pt[k].x; y1 = pt[j].y-pt[k].y; z1 = pt[j].z-pt[k].z;
  6708.     nm[z].x = y0*z1 - z0*y1;
  6709.     nm[z].y = z0*x1 - x0*z1;
  6710.     nm[z].z = x0*y1 - y0*x1;
  6711.     nmc[z] = nm[z].x*pt[k].x + nm[z].y*pt[k].y + nm[z].z*pt[k].z;
  6712. }
  6713.  
  6714. void inithull3d (point3d *pt, long nump)
  6715. {
  6716.     float px, py, pz;
  6717.     long i, k, s, z, szz, zz, zx, snzz, nzz, zzz, otricnt;
  6718.  
  6719.     tri[0] = 0; tri[4] = 0; tri[8] = 0; tri[12] = 1;
  6720.     tri[1] = 1; tri[2] = 2; initetrasid(pt,0);
  6721.     if (nm[0].x*pt[3].x + nm[0].y*pt[3].y + nm[0].z*pt[3].z >= nmc[0])
  6722.     {
  6723.         tri[1] = 1; tri[2] = 2; lnk[0] = 10; lnk[1] = 14; lnk[2] = 4;
  6724.         tri[5] = 2; tri[6] = 3; lnk[4] = 2; lnk[5] = 13; lnk[6] = 8;
  6725.         tri[9] = 3; tri[10] = 1; lnk[8] = 6; lnk[9] = 12; lnk[10] = 0;
  6726.         tri[13] = 3; tri[14] = 2; lnk[12] = 9; lnk[13] = 5; lnk[14] = 1;
  6727.     }
  6728.     else
  6729.     {
  6730.         tri[1] = 2; tri[2] = 1; lnk[0] = 6; lnk[1] = 12; lnk[2] = 8;
  6731.         tri[5] = 3; tri[6] = 2; lnk[4] = 10; lnk[5] = 13; lnk[6] = 0;
  6732.         tri[9] = 1; tri[10] = 3; lnk[8] = 2; lnk[9] = 14; lnk[10] = 4;
  6733.         tri[13] = 2; tri[14] = 3; lnk[12] = 1; lnk[13] = 5; lnk[14] = 9;
  6734.     }
  6735.     tricnt = 4*4;
  6736.  
  6737.     for(z=0;z<4;z++) initetrasid(pt,z);
  6738.  
  6739.     for(z=4;z<nump;z++)
  6740.     {
  6741.         px = pt[z].x; py = pt[z].y; pz = pt[z].z;
  6742.         for(zz=tricnt-4;zz>=0;zz-=4)
  6743.         {
  6744.             i = (zz>>2);
  6745.             if (nm[i].x*px + nm[i].y*py + nm[i].z*pz >= nmc[i]) continue;
  6746.  
  6747.             s = 0;
  6748.             for(zx=2;zx>=0;zx--)
  6749.             {
  6750.                 i = (lnk[zz+zx]>>2);
  6751.                 s += (nm[i].x*px + nm[i].y*py + nm[i].z*pz < nmc[i]) + s;
  6752.             }
  6753.             if (s == 7) continue;
  6754.  
  6755.             nzz = ((0x4a4>>(s+s))&3); szz = zz; otricnt = tricnt;
  6756.             do
  6757.             {
  6758.                 snzz = nzz;
  6759.                 do
  6760.                 {
  6761.                     zzz = nzz+1; if (zzz >= 3) zzz = 0;
  6762.  
  6763.                         //Insert triangle tricnt: (p0,p1,z)
  6764.                     tri[tricnt+0] = tri[zz+nzz];
  6765.                     tri[tricnt+1] = tri[zz+zzz];
  6766.                     tri[tricnt+2] = z;
  6767.                     initetrasid(pt,tricnt>>2);
  6768.                     k = lnk[zz+nzz]; lnk[tricnt] = k; lnk[k] = tricnt;
  6769.                     lnk[tricnt+1] = tricnt+6;
  6770.                     lnk[tricnt+2] = tricnt-3;
  6771.                     tricnt += 4;
  6772.  
  6773.                         //watch out for loop inside single triangle
  6774.                     if (zzz == snzz) goto endit;
  6775.                     nzz = zzz;
  6776.                 } while (!(s&(1<<zzz)));
  6777.                 do
  6778.                 {
  6779.                     i = zz+nzz;
  6780.                     zz = (lnk[i]&~3);
  6781.                     nzz = (lnk[i]&3)+1; if (nzz == 3) nzz = 0;
  6782.                     s = 0;
  6783.                     for(zx=2;zx>=0;zx--)
  6784.                     {
  6785.                         i = (lnk[zz+zx]>>2);
  6786.                         s += (nm[i].x*px + nm[i].y*py + nm[i].z*pz < nmc[i]) + s;
  6787.                     }
  6788.                 } while (s&(1<<nzz));
  6789.             } while (zz != szz);
  6790. endit:;  lnk[tricnt-3] = otricnt+2; lnk[otricnt+2] = tricnt-3;
  6791.  
  6792.             for(zz=otricnt-4;zz>=0;zz-=4)
  6793.             {
  6794.                 i = (zz>>2);
  6795.                 if (nm[i].x*px + nm[i].y*py + nm[i].z*pz < nmc[i])
  6796.                 {
  6797.                     tricnt -= 4; //Delete triangle zz%
  6798.                     nm[i] = nm[tricnt>>2]; nmc[i] = nmc[tricnt>>2];
  6799.                     for(i=0;i<3;i++)
  6800.                     {
  6801.                         tri[zz+i] = tri[tricnt+i];
  6802.                         lnk[zz+i] = lnk[tricnt+i];
  6803.                         lnk[lnk[zz+i]] = zz+i;
  6804.                     }
  6805.                 }
  6806.             }
  6807.             break;
  6808.         }
  6809.     }
  6810.     tricnt >>= 2;
  6811. }
  6812.  
  6813. static long incmod3[3];
  6814. void tmaphulltrisortho (point3d *pt)
  6815. {
  6816.     point3d *i0, *i1;
  6817.     float r, knmx, knmy, knmc, xinc;
  6818.     long i, k, op, p, pe, y, yi, z, zi, sy, sy1, itop, ibot, damost;
  6819.  
  6820.     for(k=0;k<tricnt;k++)
  6821.     {
  6822.         if (nm[k].z >= 0)
  6823.             { damost = (long)umost; incmod3[0] = 1; incmod3[1] = 2; incmod3[2] = 0; }
  6824.         else
  6825.             { damost = (long)dmost; incmod3[0] = 2; incmod3[1] = 0; incmod3[2] = 1; }
  6826.  
  6827.         itop = (pt[tri[(k<<2)+1]].y < pt[tri[k<<2]].y); ibot = 1-itop;
  6828.               if (pt[tri[(k<<2)+2]].y < pt[tri[(k<<2)+itop]].y) itop = 2;
  6829.         else if (pt[tri[(k<<2)+2]].y > pt[tri[(k<<2)+ibot]].y) ibot = 2;
  6830.  
  6831.             //Pre-calculations
  6832.         if (fabs(nm[k].z) < .000001) r = 0; else r = -65536.0 / nm[k].z;
  6833.         knmx = nm[k].x*r; knmy = nm[k].y*r;
  6834.         //knmc = 65536.0-nmc[k]*r-knmx-knmy;
  6835.         //knmc = -nmc[k]*r-(knmx+knmy)*.5f;
  6836.         knmc = /*65536.0*/  -nmc[k]*r+knmx;
  6837.         ftol(knmx,&zi);
  6838.  
  6839.         i = ibot;
  6840.         do
  6841.         {
  6842.             i1 = &pt[tri[(k<<2)+i]]; ftol(i1->y,&sy1); i = incmod3[i];
  6843.             i0 = &pt[tri[(k<<2)+i]]; ftol(i0->y,&sy); if (sy == sy1) continue;
  6844.             xinc = (i1->x-i0->x)/(i1->y-i0->y);
  6845.             ftol((((float)sy-i0->y)*xinc+i0->x)*65536,&y); ftol(xinc*65536,&yi);
  6846.             for(;sy<sy1;sy++,y+=yi) lastx[sy] = (y>>16);
  6847.         } while (i != itop);
  6848.         do
  6849.         {
  6850.             i0 = &pt[tri[(k<<2)+i]]; ftol(i0->y,&sy); i = incmod3[i];
  6851.             i1 = &pt[tri[(k<<2)+i]]; ftol(i1->y,&sy1); if (sy == sy1) continue;
  6852.             xinc = (i1->x-i0->x)/(i1->y-i0->y);
  6853.             ftol((((float)sy-i0->y)*xinc+i0->x)*65536,&y); ftol(xinc*65536,&yi);
  6854.             op = sy*VSID+damost;
  6855.             for(;sy<sy1;sy++,y+=yi,op+=VSID)
  6856.             {
  6857.                 ftol(knmx*(float)lastx[sy] + knmy*(float)sy + knmc,&z);
  6858.                 pe = (y>>16)+op; p = lastx[sy]+op;
  6859.                 for(;p<pe;p++,z+=zi) *(char *)p = (z>>16);
  6860.             }
  6861.         } while (i != ibot);
  6862.     }
  6863. }
  6864.  
  6865. void sethull3d (point3d *pt, long nump, long dacol, long bakit)
  6866. {
  6867.     void (*modslab)(long *, long, long);
  6868.     float fminx, fminy, fminz, fmaxx, fmaxy, fmaxz;
  6869.     long i, x, y, xs, ys, xe, ye, z0, z1;
  6870.  
  6871.     if (nump > (MAXPOINTS>>1)) nump = (MAXPOINTS>>1); //DANGER!!!
  6872.  
  6873.     fminx = fminy = VSID; fminz = MAXZDIM; fmaxx = fmaxy = fmaxz = 0;
  6874.     for(i=0;i<nump;i++)
  6875.     {
  6876.         pt[i].x = min(max(pt[i].x,0),VSID-1);
  6877.         pt[i].y = min(max(pt[i].y,0),VSID-1);
  6878.         pt[i].z = min(max(pt[i].z,0),MAXZDIM-1);
  6879.  
  6880.         if (pt[i].x < fminx) fminx = pt[i].x;
  6881.         if (pt[i].y < fminy) fminy = pt[i].y;
  6882.         if (pt[i].z < fminz) fminz = pt[i].z;
  6883.         if (pt[i].x > fmaxx) fmaxx = pt[i].x;
  6884.         if (pt[i].y > fmaxy) fmaxy = pt[i].y;
  6885.         if (pt[i].z > fmaxz) fmaxz = pt[i].z;
  6886.     }
  6887.  
  6888.     ftol(fminx,&xs); if (xs < 0) xs = 0;
  6889.     ftol(fminy,&ys); if (ys < 0) ys = 0;
  6890.     ftol(fmaxx,&xe); if (xe >= VSID) xe = VSID-1;
  6891.     ftol(fmaxy,&ye); if (ye >= VSID) ye = VSID-1;
  6892.     vx5.minx = xs; vx5.maxx = xe+1;
  6893.     vx5.miny = ys; vx5.maxy = ye+1;
  6894.     ftol(fminz-.5,&vx5.minz); ftol(fmaxz+.5,&vx5.maxz);
  6895.     if ((xs > xe) || (ys > ye))
  6896.         { if (bakit) voxbackup(xs,ys,xs,ys,bakit); return; }
  6897.     if (bakit) voxbackup(xs,ys,xe,ye,bakit);
  6898.  
  6899.     i = ys*VSID+(xs&~3); x = ((((xe+3)&~3)-(xs&~3))>>2)+1;
  6900.     for(y=ys;y<=ye;y++,i+=VSID)
  6901.         { clearbuf((void *)&umost[i],x,-1); clearbuf((void *)&dmost[i],x,0); }
  6902.  
  6903.     inithull3d(pt,nump);
  6904.     tmaphulltrisortho(pt);
  6905.  
  6906.     if (vx5.colfunc == jitcolfunc) vx5.amount = 0x70707;
  6907.  
  6908.     if (dacol == -1) modslab = delslab; else modslab = insslab;
  6909.  
  6910.     for(y=ys;y<=ye;y++)
  6911.         for(x=xs;x<=xe;x++)
  6912.             modslab(scum2(x,y),(long)umost[y*VSID+x],(long)dmost[y*VSID+x]);
  6913.     scum2finish();
  6914.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  6915. }
  6916.  
  6917. // ------------------------- CONVEX 3D HULL CODE ENDS -------------------------
  6918.  
  6919.     //Old&Slow sector code, but only this one supports the 3D bumpmapping :(
  6920. static void setsectorb (point3d *p, long *point2, long n, float thick, long dacol, long bakit, long bumpmap)
  6921. {
  6922.     point3d norm, p2;
  6923.     float d, f, x0, y0, x1, y1;
  6924.     long i, j, k, got, x, y, z, xs, ys, zs, xe, ye, ze, maxis, ndacol;
  6925.  
  6926.     norm.x = 0; norm.y = 0; norm.z = 0;
  6927.     for(i=0;i<n;i++)
  6928.     {
  6929.         j = point2[i]; k = point2[j];
  6930.         norm.x += (p[i].y-p[j].y)*(p[k].z-p[j].z) - (p[i].z-p[j].z)*(p[k].y-p[j].y);
  6931.         norm.y += (p[i].z-p[j].z)*(p[k].x-p[j].x) - (p[i].x-p[j].x)*(p[k].z-p[j].z);
  6932.         norm.z += (p[i].x-p[j].x)*(p[k].y-p[j].y) - (p[i].y-p[j].y)*(p[k].x-p[j].x);
  6933.     }
  6934.     f = 1.0 / sqrt(norm.x*norm.x + norm.y*norm.y + norm.z*norm.z);
  6935.     norm.x *= f; norm.y *= f; norm.z *= f;
  6936.  
  6937.     if ((fabs(norm.z) >= fabs(norm.x)) && (fabs(norm.z) >= fabs(norm.y)))
  6938.         maxis = 2;
  6939.     else if (fabs(norm.y) > fabs(norm.x))
  6940.         maxis = 1;
  6941.     else
  6942.         maxis = 0;
  6943.  
  6944.     xs = xe = p[0].x;
  6945.     ys = ye = p[0].y;
  6946.     zs = ze = p[0].z;
  6947.     for(i=n-1;i;i--)
  6948.     {
  6949.         if (p[i].x < xs) xs = p[i].x;
  6950.         if (p[i].y < ys) ys = p[i].y;
  6951.         if (p[i].z < zs) zs = p[i].z;
  6952.         if (p[i].x > xe) xe = p[i].x;
  6953.         if (p[i].y > ye) ye = p[i].y;
  6954.         if (p[i].z > ze) ze = p[i].z;
  6955.     }
  6956.     xs = max(xs-thick-bumpmap,0); xe = min(xe+thick+bumpmap,VSID-1);
  6957.     ys = max(ys-thick-bumpmap,0); ye = min(ye+thick+bumpmap,VSID-1);
  6958.     zs = max(zs-thick-bumpmap,0); ze = min(ze+thick+bumpmap,MAXZDIM-1);
  6959.     vx5.minx = xs; vx5.maxx = xe+1;
  6960.     vx5.miny = ys; vx5.maxy = ye+1;
  6961.     vx5.minz = zs; vx5.maxz = ze+1;
  6962.     if ((xs > xe) || (ys > ye) || (zs > ze)) return;
  6963.     if (bakit) voxbackup(xs,ys,xe+1,ye+1,bakit);
  6964.  
  6965.     clearbuf((void *)&templongbuf[zs],ze-zs+1,-3);
  6966.  
  6967.     ndacol = (dacol==-1)-2;
  6968.  
  6969.     for(y=ys;y<=ye;y++)
  6970.         for(x=xs;x<=xe;x++)
  6971.         {
  6972.             got = 0;
  6973.             d = ((float)x-p[0].x)*norm.x + ((float)y-p[0].y)*norm.y + ((float)zs-p[0].z)*norm.z;
  6974.             for(z=zs;z<=ze;z++,d+=norm.z)
  6975.             {
  6976.                 if (bumpmap)
  6977.                 {
  6978.                     if (d < -thick) continue;
  6979.                     p2.x = (float)x - d*norm.x;
  6980.                     p2.y = (float)y - d*norm.y;
  6981.                     p2.z = (float)z - d*norm.z;
  6982.                     if (d > (float)hpngcolfunc(&p2)+thick) continue;
  6983.                 }
  6984.                 else
  6985.                 {
  6986.                     if (fabs(d) > thick) continue;
  6987.                     p2.x = (float)x - d*norm.x;
  6988.                     p2.y = (float)y - d*norm.y;
  6989.                     p2.z = (float)z - d*norm.z;
  6990.                 }
  6991.  
  6992.                 k = 0;
  6993.                 for(i=n-1;i>=0;i--)
  6994.                 {
  6995.                     j = point2[i];
  6996.                     switch(maxis)
  6997.                     {
  6998.                         case 0: x0 = p[i].z-p2.z; x1 = p[j].z-p2.z;
  6999.                                   y0 = p[i].y-p2.y; y1 = p[j].y-p2.y; break;
  7000.                         case 1: x0 = p[i].x-p2.x; x1 = p[j].x-p2.x;
  7001.                                   y0 = p[i].z-p2.z; y1 = p[j].z-p2.z; break;
  7002.                         case 2: x0 = p[i].x-p2.x; x1 = p[j].x-p2.x;
  7003.                                   y0 = p[i].y-p2.y; y1 = p[j].y-p2.y; break;
  7004.                         default: __assume(0); //tells MSVC default can't be reached
  7005.                     }
  7006.                     if (((*(long *)&y0)^(*(long *)&y1)) < 0)
  7007.                     {
  7008.                         if (((*(long *)&x0)^(*(long *)&x1)) >= 0) k ^= (*(long *)&x0);
  7009.                         else { f = (x0*y1-x1*y0); k ^= (*(long *)&f)^(*(long *)&y1); }
  7010.                     }
  7011.                 }
  7012.                 if (k >= 0) continue;
  7013.  
  7014.                 templongbuf[z] = ndacol; got = 1;
  7015.             }
  7016.             if (got)
  7017.             {
  7018.                 scum(x,y,zs,ze+1,templongbuf);
  7019.                 clearbuf((void *)&templongbuf[zs],ze-zs+1,-3);
  7020.             }
  7021.         }
  7022.     scumfinish();
  7023.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  7024. }
  7025.  
  7026.     //This is for ordfillpolygon&splitpoly
  7027. typedef struct { long p, i, t; } raster;
  7028. #define MAXCURS 100 //THIS IS VERY EVIL... FIX IT!!!
  7029. static raster rst[MAXCURS];
  7030. static long slist[MAXCURS];
  7031.  
  7032.     //Code taken from POLYOLD\POLYSPLI.BAS:splitpoly (06/09/2001)
  7033. void splitpoly (float *px, float *py, long *point2, long *bakn,
  7034.                      float x0, float y0, float dx, float dy)
  7035. {
  7036.     long i, j, s2, n, sn, splcnt, z0, z1, z2, z3;
  7037.     float t, t1;
  7038.  
  7039.     n = (*bakn); if (n < 3) return;
  7040.     i = 0; s2 = sn = n; splcnt = 0;
  7041.     do
  7042.     {
  7043.         t1 = (px[i]-x0)*dy - (py[i]-y0)*dx;
  7044.         do
  7045.         {
  7046.             j = point2[i]; point2[i] |= 0x80000000;
  7047.             t = t1; t1 = (px[j]-x0)*dy - (py[j]-y0)*dx;
  7048.             if ((*(long *)&t) < 0)
  7049.                 { px[n] = px[i]; py[n] = py[i]; point2[n] = n+1; n++; }
  7050.             if (((*(long *)&t) ^ (*(long *)&t1)) < 0)
  7051.             {
  7052.                 if ((*(long *)&t) < 0) slist[splcnt++] = n;
  7053.                 t /= (t-t1);
  7054.                 px[n] = (px[j]-px[i])*t + px[i];
  7055.                 py[n] = (py[j]-py[i])*t + py[i];
  7056.                 point2[n] = n+1; n++;
  7057.             }
  7058.             i = j;
  7059.         } while (point2[i] >= 0);
  7060.         if (n > s2) { point2[n-1] = s2; s2 = n; }
  7061.         for(i=sn-1;(i) && (point2[i] < 0);i--);
  7062.     } while (i > 0);
  7063.  
  7064.     if (fabs(dx) > fabs(dy))
  7065.     {
  7066.         for(i=1;i<splcnt;i++)
  7067.         {
  7068.             z0 = slist[i];
  7069.             for(j=0;j<i;j++)
  7070.             {
  7071.                 z1 = point2[z0]; z2 = slist[j]; z3 = point2[z2];
  7072.                 if (fabs(px[z0]-px[z3])+fabs(px[z2]-px[z1]) < fabs(px[z0]-px[z1])+fabs(px[z2]-px[z3]))
  7073.                     { point2[z0] = z3; point2[z2] = z1; }
  7074.             }
  7075.         }
  7076.     }
  7077.     else
  7078.     {
  7079.         for(i=1;i<splcnt;i++)
  7080.         {
  7081.             z0 = slist[i];
  7082.             for(j=0;j<i;j++)
  7083.             {
  7084.                 z1 = point2[z0]; z2 = slist[j]; z3 = point2[z2];
  7085.                 if (fabs(py[z0]-py[z3])+fabs(py[z2]-py[z1]) < fabs(py[z0]-py[z1])+fabs(py[z2]-py[z3]))
  7086.                     { point2[z0] = z3; point2[z2] = z1; }
  7087.             }
  7088.         }
  7089.     }
  7090.  
  7091.     for(i=sn;i<n;i++)
  7092.         { px[i-sn] = px[i]; py[i-sn] = py[i]; point2[i-sn] = point2[i]-sn; }
  7093.     (*bakn) = n-sn;
  7094. }
  7095.  
  7096. void ordfillpolygon (float *px, float *py, long *point2, long n, long day, long xs, long xe, void (*modslab)(long *, long, long))
  7097. {
  7098.     float f;
  7099.     long k, i, z, zz, z0, z1, zx, sx0, sy0, sx1, sy1, sy, nsy, gap, numrst;
  7100.     long np, ni;
  7101.  
  7102.     if (n < 3) return;
  7103.  
  7104.     for(z=0;z<n;z++) slist[z] = z;
  7105.  
  7106.         //Sort points by y's
  7107.     for(gap=(n>>1);gap;gap>>=1)
  7108.         for(z=0;z<n-gap;z++)
  7109.             for(zz=z;zz>=0;zz-=gap)
  7110.             {
  7111.                 if (py[point2[slist[zz]]] <= py[point2[slist[zz+gap]]]) break;
  7112.                 z0 = slist[zz]; slist[zz] = slist[zz+gap]; slist[zz+gap] = z0;
  7113.             }
  7114.  
  7115.     ftol(py[point2[slist[0]]]+.5,&sy); if (sy < xs) sy = xs;
  7116.  
  7117.     numrst = 0; z = 0; n--; //Note: n is local variable!
  7118.     while (z < n)
  7119.     {
  7120.         z1 = slist[z]; z0 = point2[z1];
  7121.         for(zx=0;zx<2;zx++)
  7122.         {
  7123.             ftol(py[z0]+.5,&sy0); ftol(py[z1]+.5,&sy1);
  7124.             if (sy1 > sy0) //Insert raster (z0,z1)
  7125.             {
  7126.                 f = (px[z1]-px[z0]) / (py[z1]-py[z0]);
  7127.                 ftol(((sy-py[z0])*f + px[z0])*65536.0 + 65535.0,&np);
  7128.                 if (sy1-sy0 >= 2) ftol(f*65536.0,&ni); else ni = 0;
  7129.                 k = (np<<1)+ni;
  7130.                 for(i=numrst;i>0;i--)
  7131.                 {
  7132.                     if ((rst[i-1].p<<1)+rst[i-1].i < k) break;
  7133.                     rst[i] = rst[i-1];
  7134.                 }
  7135.                 rst[i].i = ni; rst[i].p = np; rst[i].t = (z0<<16)+z1;
  7136.                 numrst++;
  7137.             }
  7138.             else if (sy1 < sy0) //Delete raster (z1,z0)
  7139.             {
  7140.                 numrst--;
  7141.                 k = (z1<<16)+z0; i = 0;
  7142.                 while ((i < numrst) && (rst[i].t != k)) i++;
  7143.                 while (i < numrst) { rst[i] = rst[i+1]; i++; }
  7144.             }
  7145.             z1 = point2[z0];
  7146.         }
  7147.  
  7148.         z++;
  7149.         ftol(py[point2[slist[z]]]+.5,&nsy); if (nsy > xe) nsy = xe;
  7150.         for(;sy<nsy;sy++)
  7151.             for(i=0;i<numrst;i+=2)
  7152.             {
  7153.                 modslab(scum2(sy,day),max(rst[i].p>>16,0),min(rst[i+1].p>>16,MAXZDIM));
  7154.                 rst[i].p += rst[i].i; rst[i+1].p += rst[i+1].i;
  7155.             }
  7156.     }
  7157. }
  7158.  
  7159.     //Draws a flat polygon
  7160.     //given: p&point2: 3D points, n: # points, thick: thickness, dacol: color
  7161. static float ppx[MAXCURS*4], ppy[MAXCURS*4];
  7162. static long npoint2[MAXCURS*4];
  7163. void setsector (point3d *p, long *point2, long n, float thick, long dacol, long bakit)
  7164. {
  7165.     void (*modslab)(long *, long, long);
  7166.     point3d norm;
  7167.     float f, rnormy, xth, zth, dax, daz, t, t1;
  7168.     long i, j, k, x, y, z, sn, s2, nn, xs, ys, zs, xe, ye, ze;
  7169.  
  7170.     norm.x = 0; norm.y = 0; norm.z = 0;
  7171.     for(i=0;i<n;i++)
  7172.     {
  7173.         j = point2[i]; k = point2[j];
  7174.         norm.x += (p[i].y-p[j].y)*(p[k].z-p[j].z) - (p[i].z-p[j].z)*(p[k].y-p[j].y);
  7175.         norm.y += (p[i].z-p[j].z)*(p[k].x-p[j].x) - (p[i].x-p[j].x)*(p[k].z-p[j].z);
  7176.         norm.z += (p[i].x-p[j].x)*(p[k].y-p[j].y) - (p[i].y-p[j].y)*(p[k].x-p[j].x);
  7177.     }
  7178.     f = 1.0 / sqrt(norm.x*norm.x + norm.y*norm.y + norm.z*norm.z);
  7179.     norm.x *= f; norm.y *= f; norm.z *= f;
  7180.  
  7181.     if (vx5.colfunc == jitcolfunc) vx5.amount = 0x70707;
  7182.     else if ((vx5.colfunc == pngcolfunc) && (vx5.pic) && (vx5.xsiz > 0) && (vx5.ysiz > 0) && (vx5.picmode == 3))
  7183.     {
  7184.             //Find biggest height offset to minimize bounding box size
  7185.         j = k = vx5.pic[0];
  7186.         for(y=vx5.ysiz-1;y>=0;y--)
  7187.         {
  7188.             i = y*(vx5.bpl>>2);
  7189.             for(x=vx5.xsiz-1;x>=0;x--)
  7190.             {
  7191.                 if (vx5.pic[i+x] < j) j = vx5.pic[i+x];
  7192.                 if (vx5.pic[i+x] > k) k = vx5.pic[i+x];
  7193.             }
  7194.         }
  7195.         if ((j^k)&0xff000000) //If high bytes are !=, then use bumpmapping
  7196.         {
  7197.             setsectorb(p,point2,n,thick,dacol,bakit,max(labs(j>>24),labs(k>>24)));
  7198.             return;
  7199.         }
  7200.     }
  7201.  
  7202.     xs = xe = p[0].x;
  7203.     ys = ye = p[0].y;
  7204.     zs = ze = p[0].z;
  7205.     for(i=n-1;i;i--)
  7206.     {
  7207.         if (p[i].x < xs) xs = p[i].x;
  7208.         if (p[i].y < ys) ys = p[i].y;
  7209.         if (p[i].z < zs) zs = p[i].z;
  7210.         if (p[i].x > xe) xe = p[i].x;
  7211.         if (p[i].y > ye) ye = p[i].y;
  7212.         if (p[i].z > ze) ze = p[i].z;
  7213.     }
  7214.     xs = max(xs-thick,0); xe = min(xe+thick,VSID-1);
  7215.     ys = max(ys-thick,0); ye = min(ye+thick,VSID-1);
  7216.     zs = max(zs-thick,0); ze = min(ze+thick,MAXZDIM-1);
  7217.     vx5.minx = xs; vx5.maxx = xe+1;
  7218.     vx5.miny = ys; vx5.maxy = ye+1;
  7219.     vx5.minz = zs; vx5.maxz = ze+1;
  7220.     if ((xs > xe) || (ys > ye) || (zs > ze)) return;
  7221.     if (bakit) voxbackup(xs,ys,xe+1,ye+1,bakit);
  7222.  
  7223.     if (dacol == -1) modslab = delslab; else modslab = insslab;
  7224.  
  7225.     if (fabs(norm.y) >= .001)
  7226.     {
  7227.         rnormy = 1.0 / norm.y;
  7228.         for(y=ys;y<=ye;y++)
  7229.         {
  7230.             nn = n;
  7231.             for(i=0;i<n;i++)
  7232.             {
  7233.                 f = ((float)y-p[i].y) * rnormy;
  7234.                 ppx[i] = norm.z*f + p[i].z;
  7235.                 ppy[i] = norm.x*f + p[i].x;
  7236.                 npoint2[i] = point2[i];
  7237.             }
  7238.             if (fabs(norm.x) > fabs(norm.z))
  7239.             {
  7240.                 splitpoly(ppx,ppy,npoint2,&nn,p[0].z,((p[0].y-(float)y)*norm.y-thick)/norm.x+p[0].x,norm.x,-norm.z);
  7241.                 splitpoly(ppx,ppy,npoint2,&nn,p[0].z,((p[0].y-(float)y)*norm.y+thick)/norm.x+p[0].x,-norm.x,norm.z);
  7242.             }
  7243.             else
  7244.             {
  7245.                 splitpoly(ppx,ppy,npoint2,&nn,((p[0].y-(float)y)*norm.y-thick)/norm.z+p[0].z,p[0].x,norm.x,-norm.z);
  7246.                 splitpoly(ppx,ppy,npoint2,&nn,((p[0].y-(float)y)*norm.y+thick)/norm.z+p[0].z,p[0].x,-norm.x,norm.z);
  7247.             }
  7248.             ordfillpolygon(ppx,ppy,npoint2,nn,y,xs,xe,modslab);
  7249.         }
  7250.     }
  7251.     else
  7252.     {
  7253.         xth = norm.x*thick; zth = norm.z*thick;
  7254.         for(y=ys;y<=ye;y++)
  7255.         {
  7256.             for(z=0;z<n;z++) slist[z] = 0;
  7257.             nn = 0; i = 0; sn = n;
  7258.             do
  7259.             {
  7260.                 s2 = nn; t1 = p[i].y-(float)y;
  7261.                 do
  7262.                 {
  7263.                     j = point2[i]; slist[i] = 1; t = t1; t1 = p[j].y-(float)y;
  7264.                     if (((*(long *)&t) ^ (*(long *)&t1)) < 0)
  7265.                     {
  7266.                         k = ((*(unsigned long *)&t)>>31); t /= (t-t1);
  7267.                         daz = (p[j].z-p[i].z)*t + p[i].z;
  7268.                         dax = (p[j].x-p[i].x)*t + p[i].x;
  7269.                         ppx[nn+k] = daz+zth; ppx[nn+1-k] = daz-zth;
  7270.                         ppy[nn+k] = dax+xth; ppy[nn+1-k] = dax-xth;
  7271.                         npoint2[nn] = nn+1; npoint2[nn+1] = nn+2; nn += 2;
  7272.                     }
  7273.                     i = j;
  7274.                 } while (!slist[i]);
  7275.                 if (nn > s2) { npoint2[nn-1] = s2; s2 = nn; }
  7276.                 for(i=sn-1;(i) && (slist[i]);i--);
  7277.             } while (i);
  7278.             ordfillpolygon(ppx,ppy,npoint2,nn,y,xs,xe,modslab);
  7279.         }
  7280.     }
  7281.     scum2finish();
  7282.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  7283. }
  7284.  
  7285.     //Given: p[>=3]: points 0,1 are the axis of rotation, others make up shape
  7286.     //      numcurs: number of points
  7287.     //        dacol: color
  7288. void setlathe (point3d *p, long numcurs, long dacol, long bakit)
  7289. {
  7290.     point3d norm, ax0, ax1, tp0, tp1;
  7291.     float d, f, x0, y0, x1, y1, px, py, pz;
  7292.     long i, j, cnt, got, x, y, z, xs, ys, zs, xe, ye, ze, maxis, ndacol;
  7293.  
  7294.     norm.x = (p[0].y-p[1].y)*(p[2].z-p[1].z) - (p[0].z-p[1].z)*(p[2].y-p[1].y);
  7295.     norm.y = (p[0].z-p[1].z)*(p[2].x-p[1].x) - (p[0].x-p[1].x)*(p[2].z-p[1].z);
  7296.     norm.z = (p[0].x-p[1].x)*(p[2].y-p[1].y) - (p[0].y-p[1].y)*(p[2].x-p[1].x);
  7297.     f = 1.0 / sqrt(norm.x*norm.x + norm.y*norm.y + norm.z*norm.z);
  7298.     norm.x *= f; norm.y *= f; norm.z *= f;
  7299.  
  7300.     ax0.x = p[1].x-p[0].x; ax0.y = p[1].y-p[0].y; ax0.z = p[1].z-p[0].z;
  7301.     f = 1.0 / sqrt(ax0.x*ax0.x + ax0.y*ax0.y + ax0.z*ax0.z);
  7302.     ax0.x *= f; ax0.y *= f; ax0.z *= f;
  7303.  
  7304.     ax1.x = ax0.y*norm.z - ax0.z*norm.y;
  7305.     ax1.y = ax0.z*norm.x - ax0.x*norm.z;
  7306.     ax1.z = ax0.x*norm.y - ax0.y*norm.x;
  7307.  
  7308.     x0 = 0; //Cylindrical thickness: Perp-dist from line (p[0],p[1])
  7309.     y0 = 0; //Cylindrical min dot product from line (p[0],p[1])
  7310.     y1 = 0; //Cylindrical max dot product from line (p[0],p[1])
  7311.     for(i=numcurs-1;i;i--)
  7312.     {
  7313.         d = (p[i].x-p[0].x)*ax0.x + (p[i].y-p[0].y)*ax0.y + (p[i].z-p[0].z)*ax0.z;
  7314.         if (d < y0) y0 = d;
  7315.         if (d > y1) y1 = d;
  7316.         px = (p[i].x-p[0].x) - d*ax0.x;
  7317.         py = (p[i].y-p[0].y) - d*ax0.y;
  7318.         pz = (p[i].z-p[0].z) - d*ax0.z;
  7319.         f = px*px + py*py + pz*pz;     //Note: f is thickness SQUARED
  7320.         if (f > x0) x0 = f;
  7321.     }
  7322.     x0 = sqrt(x0)+1.0;
  7323.     tp0.x = ax0.x*y0 + p[0].x; tp1.x = ax0.x*y1 + p[0].x;
  7324.     tp0.y = ax0.y*y0 + p[0].y; tp1.y = ax0.y*y1 + p[0].y;
  7325.     tp0.z = ax0.z*y0 + p[0].z; tp1.z = ax0.z*y1 + p[0].z;
  7326.     xs = max(min(tp0.x,tp1.x)-x0,0); xe = min(max(tp0.x,tp1.x)+x0,VSID-1);
  7327.     ys = max(min(tp0.y,tp1.y)-x0,0); ye = min(max(tp0.y,tp1.y)+x0,VSID-1);
  7328.     zs = max(min(tp0.z,tp1.z)-x0,0); ze = min(max(tp0.z,tp1.z)+x0,MAXZDIM-1);
  7329.     vx5.minx = xs; vx5.maxx = xe+1;
  7330.     vx5.miny = ys; vx5.maxy = ye+1;
  7331.     vx5.minz = zs; vx5.maxz = ze+1;
  7332.     if ((xs > xe) || (ys > ye) || (zs > ze)) return;
  7333.     if (bakit) voxbackup(xs,ys,xe,ye,bakit);
  7334.  
  7335.     if ((fabs(norm.z) >= fabs(norm.x)) && (fabs(norm.z) >= fabs(norm.y)))
  7336.         maxis = 2;
  7337.     else if (fabs(norm.y) > fabs(norm.x))
  7338.         maxis = 1;
  7339.     else
  7340.         maxis = 0;
  7341.  
  7342.     clearbuf((void *)&templongbuf[zs],ze-zs+1,-3);
  7343.  
  7344.     if (vx5.colfunc == jitcolfunc) vx5.amount = 0x70707;
  7345.  
  7346.     ndacol = (dacol==-1)-2;
  7347.  
  7348.     for(y=ys;y<=ye;y++)
  7349.         for(x=xs;x<=xe;x++)
  7350.         {
  7351.             got = 0;
  7352.             d = ((float)x-p[0].x)*ax0.x + ((float)y-p[0].y)*ax0.y + ((float)zs-p[0].z)*ax0.z;
  7353.             for(z=zs;z<=ze;z++,d+=ax0.z)
  7354.             {
  7355.                     //Another way: p = sqrt((xyz dot ax1)^2 + (xyz dot norm)^2)
  7356.                 px = ((float)x-p[0].x) - d*ax0.x;
  7357.                 py = ((float)y-p[0].y) - d*ax0.y;
  7358.                 pz = ((float)z-p[0].z) - d*ax0.z;
  7359.                 f = sqrt(px*px + py*py + pz*pz);
  7360.  
  7361.                 px = ax0.x*d + ax1.x*f + p[0].x;
  7362.                 py = ax0.y*d + ax1.y*f + p[0].y;
  7363.                 pz = ax0.z*d + ax1.z*f + p[0].z;
  7364.  
  7365.                 cnt = j = 0;
  7366.                 for(i=numcurs-1;i>=0;i--)
  7367.                 {
  7368.                     switch(maxis)
  7369.                     {
  7370.                         case 0: x0 = p[i].z-pz; x1 = p[j].z-pz;
  7371.                                   y0 = p[i].y-py; y1 = p[j].y-py; break;
  7372.                         case 1: x0 = p[i].x-px; x1 = p[j].x-px;
  7373.                                   y0 = p[i].z-pz; y1 = p[j].z-pz; break;
  7374.                         case 2: x0 = p[i].x-px; x1 = p[j].x-px;
  7375.                                   y0 = p[i].y-py; y1 = p[j].y-py; break;
  7376.                         default: __assume(0); //tells MSVC default can't be reached
  7377.                     }
  7378.                     if (((*(long *)&y0)^(*(long *)&y1)) < 0)
  7379.                     {
  7380.                         if (((*(long *)&x0)^(*(long *)&x1)) >= 0) cnt ^= (*(long *)&x0);
  7381.                         else { f = (x0*y1-x1*y0); cnt ^= (*(long *)&f)^(*(long *)&y1); }
  7382.                     }
  7383.                     j = i;
  7384.                 }
  7385.                 if (cnt >= 0) continue;
  7386.  
  7387.                 templongbuf[z] = ndacol; got = 1;
  7388.             }
  7389.             if (got)
  7390.             {
  7391.                 scum(x,y,zs,ze+1,templongbuf);
  7392.                 clearbuf((void *)&templongbuf[zs],ze-zs+1,-3);
  7393.             }
  7394.         }
  7395.     scumfinish();
  7396.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  7397. }
  7398.  
  7399.     //Given: p[>=1]: centers
  7400.     //   vx5.currad: cutoff value
  7401.     //      numcurs: number of points
  7402.     //        dacol: color
  7403. void setblobs (point3d *p, long numcurs, long dacol, long bakit)
  7404. {
  7405.     float dx, dy, dz, v, nrad;
  7406.     long i, got, x, y, z, xs, ys, zs, xe, ye, ze, ndacol;
  7407.  
  7408.     if (numcurs <= 0) return;
  7409.  
  7410.         //Boundaries are quick hacks - rewrite this code!!!
  7411.     xs = max(p[0].x-64,0); xe = min(p[0].x+64,VSID-1);
  7412.     ys = max(p[0].y-64,0); ye = min(p[0].y+64,VSID-1);
  7413.     zs = max(p[0].z-64,0); ze = min(p[0].z+64,MAXZDIM-1);
  7414.     vx5.minx = xs; vx5.maxx = xe+1;
  7415.     vx5.miny = ys; vx5.maxy = ye+1;
  7416.     vx5.minz = zs; vx5.maxz = ze+1;
  7417.     if ((xs > xe) || (ys > ye) || (zs > ze)) return;
  7418.     if (bakit) voxbackup(xs,ys,xe,ye,bakit);
  7419.  
  7420.     clearbuf((void *)&templongbuf[zs],ze-zs+1,-3);
  7421.  
  7422.     if (vx5.colfunc == jitcolfunc) vx5.amount = 0x70707;
  7423.  
  7424.     ndacol = (dacol==-1)-2;
  7425.  
  7426.     if (cputype&(1<<25))
  7427.     {
  7428.         _asm
  7429.         {
  7430.             mov eax, 256
  7431.             xorps xmm7, xmm7    ;xmm7: 0,0,0,0
  7432.             cvtsi2ss xmm6, eax  ;xmm6: ?,?,?,256
  7433.             movlhps xmm6, xmm6  ;xmm6: ?,256,?,256
  7434.         }
  7435.     }
  7436.  
  7437.     nrad = (float)numcurs / ((float)vx5.currad*(float)vx5.currad + 256.0);
  7438.     for(y=ys;y<=ye;y++)
  7439.         for(x=xs;x<=xe;x++)
  7440.         {
  7441.             if (cputype&(1<<25))
  7442.             {
  7443.                 _asm
  7444.                 {
  7445.                     cvtsi2ss xmm0, x        ;xmm0:?,?,?,x
  7446.                     cvtsi2ss xmm7, y        ;xmm7:0,0,0,y
  7447.                     movlhps xmm0, xmm7      ;xmm0:0,y,?,x
  7448.                     shufps xmm0, xmm0, 0x08 ;xmm0:x,x,y,x
  7449.                 }
  7450.             }
  7451.  
  7452.             got = 0;
  7453.             for(z=zs;z<=ze;z++)
  7454.             {
  7455.                 if (cputype&(1<<25))
  7456.                 {
  7457.                     _asm
  7458.                     {
  7459.                         movhlps xmm3, xmm7       ;xmm3:?,?,0,0
  7460.                         cvtsi2ss xmm7, z         ;xmm7:0,0,0,z
  7461.                         movlhps xmm0, xmm7       ;xmm0:0,z,y,x
  7462.                         mov eax, numcurs
  7463.                         mov edx, p
  7464.                         lea eax, [eax+eax*2-3]
  7465.                  beg: movups xmm1, [edx+eax*4] ;xmm1: ?,pz,py,pz
  7466.                         subps xmm1, xmm0         ;xmm1: ?,dz,dy,dx
  7467.                         mulps xmm1, xmm1         ;xmm1: ?,dzύ,dyύ,dxύ
  7468.                         movhlps xmm6, xmm1       ;xmm6: ?,256,?,dzύ
  7469.                         shufps xmm1, xmm6, 0x84  ;xmm1: 256,dzύ,dyύ,dxύ
  7470.                         movhlps xmm2, xmm1       ;xmm2: ?,?,256,dzύ
  7471.                         addps xmm1, xmm2         ;xmm1: ?,?,dyύ+256,dxύ+dzύ
  7472.                         movss xmm2, xmm1         ;xmm2: ?,?,256,dxύ+dzύ
  7473.                         shufps xmm1, xmm1, 0x1   ;xmm1: dxύ+dzύ,dxύ+dzύ,dxύ+dzύ,dyύ+256
  7474.                         addss xmm1, xmm2         ;xmm1: ?,?,?,dxύ+dyύ+dzύ+256
  7475.                         rcpss xmm1, xmm1         ;xmm1: ?,?,?,1/(dxύ+dyύ+dzύ+256)
  7476.                         addss xmm3, xmm1
  7477.                         sub eax, 3
  7478.                         jnc short beg
  7479.                         movss v, xmm3
  7480.                     }
  7481.                 }
  7482.                 else
  7483.                 {
  7484.                     v = 0;
  7485.                     for(i=numcurs-1;i>=0;i--)
  7486.                     {
  7487.                         dx = p[i].x-(float)x;
  7488.                         dy = p[i].y-(float)y;
  7489.                         dz = p[i].z-(float)z;
  7490.                         v += 1.0f / (dx*dx + dy*dy + dz*dz + 256.0f);
  7491.                     }
  7492.                 }
  7493.                 if (*(long *)&v > *(long *)&nrad) { templongbuf[z] = ndacol; got = 1; }
  7494.             }
  7495.             if (got)
  7496.             {
  7497.                 scum(x,y,zs,ze+1,templongbuf);
  7498.                 clearbuf((void *)&templongbuf[zs],ze-zs+1,-3);
  7499.             }
  7500.         }
  7501.     scumfinish();
  7502.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  7503. }
  7504.  
  7505. //FLOODFILL3D begins --------------------------------------------------------
  7506.  
  7507. #define FILLBUFSIZ 16384 //Use realloc instead!
  7508. typedef struct { unsigned short x, y, z0, z1; } spoint4d; //128K
  7509. static spoint4d fbuf[FILLBUFSIZ];
  7510.  
  7511. long dntil0 (long x, long y, long z)
  7512. {
  7513.     char *v = sptr[y*VSID+x];
  7514.     while (1)
  7515.     {
  7516.         if (z < v[1]) break;
  7517.         if (!v[0]) return(MAXZDIM);
  7518.         v += v[0]*4;
  7519.         if (z < v[3]) return(v[3]);
  7520.     }
  7521.     return(z);
  7522. }
  7523.  
  7524. long dntil1 (long x, long y, long z)
  7525. {
  7526.     char *v = sptr[y*VSID+x];
  7527.     while (1)
  7528.     {
  7529.         if (z <= v[1]) return(v[1]);
  7530.         if (!v[0]) break;
  7531.         v += v[0]*4;
  7532.         if (z < v[3]) break;
  7533.     }
  7534.     return(z);
  7535. }
  7536.  
  7537. long uptil1 (long x, long y, long z)
  7538. {
  7539.     char *v = sptr[y*VSID+x];
  7540.     if (z < v[1]) return(0);
  7541.     while (v[0])
  7542.     {
  7543.         v += v[0]*4;
  7544.         if (z < v[3]) break;
  7545.         if (z < v[1]) return(v[3]);
  7546.     }
  7547.     return(z);
  7548. }
  7549.  
  7550.     //Conducts on air and writes solid
  7551. void setfloodfill3d (long x, long y, long z, long minx, long miny, long minz,
  7552.                                                             long maxx, long maxy, long maxz)
  7553. {
  7554.     long wholemap, j, z0, z1, nz1, i0, i1, (*bakcolfunc)(lpoint3d *);
  7555.     spoint4d a;
  7556.  
  7557.     if (minx < 0) minx = 0;
  7558.     if (miny < 0) miny = 0;
  7559.     if (minz < 0) minz = 0;
  7560.     maxx++; maxy++; maxz++;
  7561.     if (maxx > VSID) maxx = VSID;
  7562.     if (maxy > VSID) maxy = VSID;
  7563.     if (maxz > MAXZDIM) maxz = MAXZDIM;
  7564.     vx5.minx = minx; vx5.maxx = maxx;
  7565.     vx5.miny = miny; vx5.maxy = maxy;
  7566.     vx5.minz = minz; vx5.maxz = maxz;
  7567.     if ((minx >= maxx) || (miny >= maxy) || (minz >= maxz)) return;
  7568.  
  7569.     if ((x < minx) || (x >= maxx) ||
  7570.          (y < miny) || (y >= maxy) ||
  7571.          (z < minz) || (z >= maxz)) return;
  7572.  
  7573.     if ((minx != 0) || (miny != 0) || (minz != 0) || (maxx != VSID) || (maxy != VSID) || (maxz != VSID))
  7574.         wholemap = 0;
  7575.     else wholemap = 1;
  7576.  
  7577.     if (isvoxelsolid(x,y,z)) return;
  7578.  
  7579.     bakcolfunc = vx5.colfunc; vx5.colfunc = curcolfunc;
  7580.  
  7581.     a.x = x; a.z0 = uptil1(x,y,z); if (a.z0 < minz) a.z0 = minz;
  7582.     a.y = y; a.z1 = dntil1(x,y,z+1); if (a.z1 > maxz) a.z1 = maxz;
  7583.     if (((!a.z0) && (wholemap)) || (a.z0 >= a.z1)) { vx5.colfunc = bakcolfunc; return; } //oops! broke free :/
  7584.     insslab(scum2(x,y),a.z0,a.z1); scum2finish();
  7585.     i0 = i1 = 0; goto floodfill3dskip;
  7586.     do
  7587.     {
  7588.         a = fbuf[i0]; i0 = ((i0+1)&(FILLBUFSIZ-1));
  7589. floodfill3dskip:;
  7590.         for(j=3;j>=0;j--)
  7591.         {
  7592.             if (j&1) { x = a.x+(j&2)-1; if ((x < minx) || (x >= maxx)) continue; y = a.y; }
  7593.                  else { y = a.y+(j&2)-1; if ((y < miny) || (y >= maxy)) continue; x = a.x; }
  7594.  
  7595.             if (isvoxelsolid(x,y,a.z0)) { z0 = dntil0(x,y,a.z0); z1 = z0; }
  7596.                                           else { z0 = uptil1(x,y,a.z0); z1 = a.z0; }
  7597.             if ((!z0) && (wholemap)) { vx5.colfunc = bakcolfunc; return; } //oops! broke free :/
  7598.             while (z1 < a.z1)
  7599.             {
  7600.                 z1 = dntil1(x,y,z1);
  7601.  
  7602.                 if (z0 < minz) z0 = minz;
  7603.                 nz1 = z1; if (nz1 > maxz) nz1 = maxz;
  7604.                 if (z0 < nz1)
  7605.                 {
  7606.                     fbuf[i1].x = x; fbuf[i1].y = y;
  7607.                     fbuf[i1].z0 = z0; fbuf[i1].z1 = nz1;
  7608.                     i1 = ((i1+1)&(FILLBUFSIZ-1));
  7609.                     //if (i0 == i1) floodfill stack overflow!
  7610.                     insslab(scum2(x,y),z0,nz1); scum2finish();
  7611.                 }
  7612.                 z0 = dntil0(x,y,z1); z1 = z0;
  7613.             }
  7614.         }
  7615.     } while (i0 != i1);
  7616.  
  7617.     vx5.colfunc = bakcolfunc;
  7618.  
  7619.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,0);
  7620. }
  7621.  
  7622. void hollowfillstart (long x, long y, long z)
  7623. {
  7624.     spoint4d a;
  7625.     char *v;
  7626.     long i, j, z0, z1, i0, i1;
  7627.  
  7628.     a.x = x; a.y = y;
  7629.  
  7630.     v = sptr[y*VSID+x]; j = ((((long)v)-(long)vbuf)>>2); a.z0 = 0;
  7631.     while (1)
  7632.     {
  7633.         a.z1 = (long)(v[1]);
  7634.         if ((a.z0 <= z) && (z < a.z1) && (!(vbit[j>>5]&(1<<j)))) break;
  7635.         if (!v[0]) return;
  7636.         v += v[0]*4; j += 2;
  7637.         a.z0 = (long)(v[3]);
  7638.     }
  7639.     vbit[j>>5] |= (1<<j); //fill a.x,a.y,a.z0<=?<a.z1
  7640.  
  7641.     i0 = i1 = 0; goto floodfill3dskip2;
  7642.     do
  7643.     {
  7644.         a = fbuf[i0]; i0 = ((i0+1)&(FILLBUFSIZ-1));
  7645. floodfill3dskip2:;
  7646.         for(i=3;i>=0;i--)
  7647.         {
  7648.             if (i&1) { x = a.x+(i&2)-1; if ((unsigned long)x >= VSID) continue; y = a.y; }
  7649.                  else { y = a.y+(i&2)-1; if ((unsigned long)y >= VSID) continue; x = a.x; }
  7650.  
  7651.             v = sptr[y*VSID+x]; j = ((((long)v)-(long)vbuf)>>2); z0 = 0;
  7652.             while (1)
  7653.             {
  7654.                 z1 = (long)(v[1]);
  7655.                 if ((z0 < a.z1) && (a.z0 < z1) && (!(vbit[j>>5]&(1<<j))))
  7656.                 {
  7657.                     fbuf[i1].x = x; fbuf[i1].y = y;
  7658.                     fbuf[i1].z0 = z0; fbuf[i1].z1 = z1;
  7659.                     i1 = ((i1+1)&(FILLBUFSIZ-1));
  7660.                     if (i0 == i1) return; //floodfill stack overflow!
  7661.                     vbit[j>>5] |= (1<<j); //fill x,y,z0<=?<z1
  7662.                 }
  7663.                 if (!v[0]) break;
  7664.                 v += v[0]*4; j += 2;
  7665.                 z0 = (long)(v[3]);
  7666.             }
  7667.         }
  7668.     } while (i0 != i1);
  7669. }
  7670.  
  7671.     //hollowfill
  7672. void sethollowfill ()
  7673. {
  7674.     long i, j, l, x, y, z0, z1, *lptr, (*bakcolfunc)(lpoint3d *);
  7675.     char *v;
  7676.  
  7677.     vx5.minx = 0; vx5.maxx = VSID;
  7678.     vx5.miny = 0; vx5.maxy = VSID;
  7679.     vx5.minz = 0; vx5.maxz = MAXZDIM;
  7680.  
  7681.     for(i=0;i<VSID*VSID;i++)
  7682.     {
  7683.         j = ((((long)sptr[i])-(long)vbuf)>>2);
  7684.         for(v=sptr[i];v[0];v+=v[0]*4) { vbit[j>>5] &= ~(1<<j); j += 2; }
  7685.         vbit[j>>5] &= ~(1<<j);
  7686.     }
  7687.  
  7688.     for(y=0;y<VSID;y++)
  7689.         for(x=0;x<VSID;x++)
  7690.             hollowfillstart(x,y,0);
  7691.  
  7692.     bakcolfunc = vx5.colfunc; vx5.colfunc = curcolfunc;
  7693.     i = 0;
  7694.     for(y=0;y<VSID;y++)
  7695.         for(x=0;x<VSID;x++,i++)
  7696.         {
  7697.             j = ((((long)sptr[i])-(long)vbuf)>>2);
  7698.             v = sptr[i]; z0 = MAXZDIM;
  7699.             while (1)
  7700.             {
  7701.                 z1 = (long)(v[1]);
  7702.                 if ((z0 < z1) && (!(vbit[j>>5]&(1<<j))))
  7703.                 {
  7704.                     vbit[j>>5] |= (1<<j);
  7705.                     insslab(scum2(x,y),z0,z1);
  7706.                 }
  7707.                 if (!v[0]) break;
  7708.                 v += v[0]*4; j += 2;
  7709.                 z0 = (long)(v[3]);
  7710.             }
  7711.         }
  7712.     scum2finish();
  7713.     vx5.colfunc = bakcolfunc;
  7714.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,0);
  7715. }
  7716.  
  7717. //FLOODFILL3D ends ----------------------------------------------------------
  7718.  
  7719. #define LPATBUFSIZ 14
  7720. static lpoint2d *patbuf;
  7721. #define LPATHASHSIZ 12
  7722. static lpoint3d *pathashdat;
  7723. static long *pathashead, pathashcnt, pathashmax;
  7724.  
  7725. static void initpathash ()
  7726. {
  7727.     patbuf = (lpoint2d *)radar;
  7728.     pathashead = (long *)(((long)patbuf)+(1<<LPATBUFSIZ)*sizeof(lpoint2d));
  7729.     pathashdat = (lpoint3d *)(((long)pathashead)+((1<<LPATHASHSIZ)*4));
  7730.     pathashmax = ((max((MAXXDIM*MAXYDIM*27)>>1,(VSID+4)*3*256*4)-((1<<LPATBUFSIZ)*sizeof(lpoint2d))-(1<<LPATHASHSIZ)*4)/12);
  7731.     memset(pathashead,-1,(1<<LPATHASHSIZ)*4);
  7732.     pathashcnt = 0;
  7733. }
  7734.  
  7735. static long readpathash (long i)
  7736. {
  7737.     long j = (((i>>LPATHASHSIZ)-i) & ((1<<LPATHASHSIZ)-1));
  7738.     for(j=pathashead[j];j>=0;j=pathashdat[j].x)
  7739.         if (pathashdat[j].y == i) return(pathashdat[j].z);
  7740.     return(-1);
  7741. }
  7742.  
  7743. static void writepathash (long i, long v)
  7744. {
  7745.     long k, j = (((i>>LPATHASHSIZ)-i) & ((1<<LPATHASHSIZ)-1));
  7746.     for(k=pathashead[j];k>=0;k=pathashdat[k].x)
  7747.         if (pathashdat[k].y == i) { pathashdat[k].z = v; return; }
  7748.     pathashdat[pathashcnt].x = pathashead[j]; pathashead[j] = pathashcnt;
  7749.     pathashdat[pathashcnt].y = i;
  7750.     pathashdat[pathashcnt].z = v;
  7751.     pathashcnt++;
  7752. }
  7753.  
  7754. static signed char cdir[26*4] = //sqrt(2) =~ 58/41, sqrt(3) =~ 71/41;
  7755. {
  7756.     -1, 0, 0,41,  1, 0, 0,41,  0,-1, 0,41,  0, 1, 0,41,  0, 0,-1,41,  0, 0, 1,41,
  7757.     -1,-1, 0,58, -1, 1, 0,58, -1, 0,-1,58, -1, 0, 1,58,  0,-1,-1,58,  0,-1, 1,58,
  7758.      1,-1, 0,58,  1, 1, 0,58,  1, 0,-1,58,  1, 0, 1,58,  0, 1,-1,58,  0, 1, 1,58,
  7759.     -1,-1,-1,71, -1,-1, 1,71, -1, 1,-1,71, -1, 1, 1,71,
  7760.      1,-1,-1,71,  1,-1, 1,71,  1, 1,-1,71,  1, 1, 1,71,
  7761. };
  7762.  
  7763. long findpath (long *pathpos, long pathmax, lpoint3d *p1, lpoint3d *p0)
  7764. {
  7765.     long i, j, k, x, y, z, c, nc, xx, yy, zz, bufr, bufw, pcnt;
  7766.  
  7767.     if (!(getcube(p0->x,p0->y,p0->z)&~1))
  7768.     {
  7769.         for(i=5;i>=0;i--)
  7770.         {
  7771.             x = p0->x+(long)cdir[i*4]; y = p0->y+(long)cdir[i*4+1]; z = p0->z+(long)cdir[i*4+2];
  7772.             if (getcube(x,y,z)&~1) { p0->x = x; p0->y = y; p0->z = z; break; }
  7773.         }
  7774.         if (i < 0) return(0);
  7775.     }
  7776.     if (!(getcube(p1->x,p1->y,p1->z)&~1))
  7777.     {
  7778.         for(i=5;i>=0;i--)
  7779.         {
  7780.             x = p1->x+(long)cdir[i*4]; y = p1->y+(long)cdir[i*4+1]; z = p1->z+(long)cdir[i*4+2];
  7781.             if (getcube(x,y,z)&~1) { p1->x = x; p1->y = y; p1->z = z; break; }
  7782.         }
  7783.         if (i < 0) return(0);
  7784.     }
  7785.  
  7786.     initpathash();
  7787.     j = (p0->x*VSID + p0->y)*MAXZDIM+p0->z;
  7788.     patbuf[0].x = j; patbuf[0].y = 0; bufr = 0; bufw = 1;
  7789.     writepathash(j,0);
  7790.     do
  7791.     {
  7792.         j = patbuf[bufr&((1<<LPATBUFSIZ)-1)].x;
  7793.         x = j/(VSID*MAXZDIM); y = ((j/MAXZDIM)&(VSID-1)); z = (j&(MAXZDIM-1));
  7794.         c = patbuf[bufr&((1<<LPATBUFSIZ)-1)].y; bufr++;
  7795.         for(i=0;i<26;i++)
  7796.         {
  7797.             xx = x+(long)cdir[i*4]; yy = y+(long)cdir[i*4+1]; zz = z+(long)cdir[i*4+2];
  7798.             j = (xx*VSID + yy)*MAXZDIM+zz;
  7799.  
  7800.             //nc = c+(long)cdir[i*4+3]; //More accurate but lowers max distance a lot!
  7801.             //if (((k = getcube(xx,yy,zz))&~1) && ((unsigned long)nc < (unsigned long)readpathash(j)))
  7802.  
  7803.             if (((k = getcube(xx,yy,zz))&~1) && (readpathash(j) < 0))
  7804.             {
  7805.                 nc = c+(long)cdir[i*4+3];
  7806.                 if ((xx == p1->x) && (yy == p1->y) && (zz == p1->z)) { c = nc; goto pathfound; }
  7807.                 writepathash(j,nc);
  7808.                 if (pathashcnt >= pathashmax) return(0);
  7809.                 patbuf[bufw&((1<<LPATBUFSIZ)-1)].x = (xx*VSID + yy)*MAXZDIM+zz;
  7810.                 patbuf[bufw&((1<<LPATBUFSIZ)-1)].y = nc; bufw++;
  7811.             }
  7812.         }
  7813.     } while (bufr != bufw);
  7814.  
  7815. pathfound:
  7816.     if (pathmax <= 0) return(0);
  7817.     pathpos[0] = (p1->x*VSID + p1->y)*MAXZDIM+p1->z; pcnt = 1;
  7818.     x = p1->x; y = p1->y; z = p1->z;
  7819.     do
  7820.     {
  7821.         for(i=0;i<26;i++)
  7822.         {
  7823.             xx = x+(long)cdir[i*4]; yy = y+(long)cdir[i*4+1]; zz = z+(long)cdir[i*4+2];
  7824.             nc = c-(long)cdir[i*4+3];
  7825.             if (readpathash((xx*VSID + yy)*MAXZDIM+zz) == nc)
  7826.             {
  7827.                 if (pcnt >= pathmax) return(0);
  7828.                 pathpos[pcnt] = (xx*VSID + yy)*MAXZDIM+zz; pcnt++;
  7829.                 x = xx; y = yy; z = zz; c = nc; break;
  7830.             }
  7831.         }
  7832.     } while (i < 26);
  7833.     if (pcnt >= pathmax) return(0);
  7834.     pathpos[pcnt] = (p0->x*VSID + p0->y)*MAXZDIM+p0->z;
  7835.     return(pcnt+1);
  7836. }
  7837.  
  7838. //---------------------------------------------------------------------
  7839.  
  7840. static unsigned short xyoffs[256][256+1];
  7841. void setkvx (const char *filename, long ox, long oy, long oz, long rot, long bakit)
  7842. {
  7843.     long i, j, x, y, z, xsiz, ysiz, zsiz, longpal[256], zleng, oldz, vis;
  7844.     long d[3], k[9], x0, y0, z0, x1, y1, z1;
  7845.     char ch, typ;
  7846.     FILE *fp;
  7847.  
  7848.     typ = filename[strlen(filename)-3]; if (typ == 'k') typ = 'K';
  7849.  
  7850.     if (!(fp = fopen(filename,"rb"))) return;
  7851.  
  7852.     fseek(fp,-768,SEEK_END);
  7853.     for(i=0;i<255;i++)
  7854.     {
  7855.         longpal[i]  = (((long)fgetc(fp))<<18);
  7856.         longpal[i] += (((long)fgetc(fp))<<10);
  7857.         longpal[i] += (((long)fgetc(fp))<< 2) + 0x80000000;
  7858.     }
  7859.     longpal[255] = 0x7ffffffd;
  7860.  
  7861.     if (typ == 'K') //Load .KVX file
  7862.     {
  7863.         fseek(fp,4,SEEK_SET);
  7864.         fread(&xsiz,4,1,fp);
  7865.         fread(&ysiz,4,1,fp);
  7866.         fread(&zsiz,4,1,fp);
  7867.         fseek(fp,((xsiz+1)<<2)+28,SEEK_SET);
  7868.         for(i=0;i<xsiz;i++) fread(&xyoffs[i][0],(ysiz+1)<<1,1,fp);
  7869.     }
  7870.     else           //Load .VOX file
  7871.     {
  7872.         fseek(fp,0,SEEK_SET);
  7873.         fread(&xsiz,4,1,fp);
  7874.         fread(&ysiz,4,1,fp);
  7875.         fread(&zsiz,4,1,fp);
  7876.     }
  7877.  
  7878.         //rot: low 3 bits for axis negating, high 6 states for axis swapping
  7879.         //k[0], k[3], k[6] are indeces
  7880.         //k[1], k[4], k[7] are xors
  7881.         //k[2], k[5], k[8] are adds
  7882.     switch (rot&~7)
  7883.     {
  7884.         case  0: k[0] = 0; k[3] = 1; k[6] = 2; break; //can use scum!
  7885.         case  8: k[0] = 1; k[3] = 0; k[6] = 2; break; //can use scum!
  7886.         case 16: k[0] = 0; k[3] = 2; k[6] = 1; break;
  7887.         case 24: k[0] = 2; k[3] = 0; k[6] = 1; break;
  7888.         case 32: k[0] = 1; k[3] = 2; k[6] = 0; break;
  7889.         case 40: k[0] = 2; k[3] = 1; k[6] = 0; break;
  7890.         default: __assume(0); //tells MSVC default can't be reached
  7891.     }
  7892.     k[1] = ((rot<<31)>>31);
  7893.     k[4] = ((rot<<30)>>31);
  7894.     k[7] = ((rot<<29)>>31);
  7895.  
  7896.     d[0] = xsiz; d[1] = ysiz; d[2] = zsiz;
  7897.     k[2] = ox-((d[k[0]]>>1)^k[1]);
  7898.     k[5] = oy-((d[k[3]]>>1)^k[4]);
  7899.     k[8] = oz-((d[k[6]]>>1)^k[7]); k[8] -= (d[k[6]]>>1);
  7900.  
  7901.     d[0] = d[1] = d[2] = 0;
  7902.     x0 = x1 = (d[k[0]]^k[1])+k[2];
  7903.     y0 = y1 = (d[k[3]]^k[4])+k[5];
  7904.     z0 = z1 = (d[k[6]]^k[7])+k[8];
  7905.     d[0] = xsiz; d[1] = ysiz; d[2] = zsiz;
  7906.     x0 = min(x0,(d[k[0]]^k[1])+k[2]); x1 = max(x1,(d[k[0]]^k[1])+k[2]);
  7907.     y0 = min(y0,(d[k[3]]^k[4])+k[5]); y1 = max(y1,(d[k[3]]^k[4])+k[5]);
  7908.     z0 = min(z0,(d[k[6]]^k[7])+k[8]); z1 = max(z1,(d[k[6]]^k[7])+k[8]);
  7909.     if (x0 < 1) { i = 1-x0; x0 += i; x1 += i; k[2] += i; }
  7910.     if (y0 < 1) { i = 1-y0; y0 += i; y1 += i; k[5] += i; }
  7911.     if (z0 < 0) { i = 0-z0; z0 += i; z1 += i; k[8] += i; }
  7912.     if (x1 > VSID-2)    { i = VSID-2-x1; x0 += i; x1 += i; k[2] += i; }
  7913.     if (y1 > VSID-2)    { i = VSID-2-y1; y0 += i; y1 += i; k[5] += i; }
  7914.     if (z1 > MAXZDIM-1) { i = MAXZDIM-1-z1; z0 += i; z1 += i; k[8] += i; }
  7915.  
  7916.     vx5.minx = x0; vx5.maxx = x1+1;
  7917.     vx5.miny = y0; vx5.maxy = y1+1;
  7918.     vx5.minz = z0; vx5.maxz = z1+1;
  7919.     if (bakit) voxbackup(x0,y0,x1+1,y1+1,bakit);
  7920.  
  7921.     j = (!(k[3]|(rot&3))); //if (j) { can use scum/scumfinish! }
  7922.  
  7923.     for(x=0;x<xsiz;x++)
  7924.     {
  7925.         d[0] = x;
  7926.         for(y=0;y<ysiz;y++)
  7927.         {
  7928.             d[1] = y;
  7929.             if (k[6] == 2) //can use scum!
  7930.             {
  7931.                 clearbuf((void *)&templongbuf[z0],z1-z0+1,-3);
  7932.                 if (typ == 'K')
  7933.                 {
  7934.                     oldz = -1;
  7935.                     i = xyoffs[d[0]][d[1]+1] - xyoffs[d[0]][d[1]]; if (!i) continue;
  7936.                     while (i > 0)
  7937.                     {
  7938.                         z = fgetc(fp); zleng = fgetc(fp); i -= (zleng+3);
  7939.                         vis = fgetc(fp);
  7940.  
  7941.                         if ((oldz >= 0) && (!(vis&16)))
  7942.                             for(;oldz<z;oldz++)
  7943.                                 templongbuf[(oldz^k[7])+k[8]] = vx5.curcol;
  7944.  
  7945.                         for(;zleng>0;zleng--,z++)
  7946.                             templongbuf[(z^k[7])+k[8]] = longpal[fgetc(fp)];
  7947.                         oldz = z;
  7948.                     }
  7949.                 }
  7950.                 else
  7951.                 {
  7952.                     for(z=0;z<zsiz;z++)
  7953.                         templongbuf[(z^k[7])+k[8]] = longpal[fgetc(fp)];
  7954.                 }
  7955.  
  7956.                 scum((d[k[0]]^k[1])+k[2],(d[k[3]]^k[4])+k[5],z0,z1+1,templongbuf);
  7957.                 if (!j) scumfinish();
  7958.             }
  7959.             else
  7960.             {
  7961.                 if (typ == 'K')
  7962.                 {
  7963.                     oldz = -1;
  7964.                     i = xyoffs[d[0]][d[1]+1] - xyoffs[d[0]][d[1]]; if (!i) continue;
  7965.                     while (i > 0)
  7966.                     {
  7967.                         z = fgetc(fp); zleng = fgetc(fp); i -= (zleng+3);
  7968.                         vis = fgetc(fp);
  7969.  
  7970.                         if ((oldz >= 0) && (!(vis&16)))
  7971.                             for(;oldz<z;oldz++)
  7972.                             {
  7973.                                 d[2] = oldz;
  7974.                                 setcube((d[k[0]]^k[1])+k[2],(d[k[3]]^k[4])+k[5],(d[k[6]]^k[7])+k[8],vx5.curcol);
  7975.                             }
  7976.  
  7977.                         for(;zleng>0;zleng--,z++)
  7978.                         {
  7979.                             ch = fgetc(fp);
  7980.                             d[2] = z;
  7981.                             setcube((d[k[0]]^k[1])+k[2],(d[k[3]]^k[4])+k[5],(d[k[6]]^k[7])+k[8],longpal[ch]);
  7982.                         }
  7983.                         oldz = z;
  7984.                     }
  7985.                 }
  7986.                 else
  7987.                 {
  7988.                     for(z=0;z<zsiz;z++)
  7989.                     {
  7990.                         ch = fgetc(fp);
  7991.                         if (ch != 255)
  7992.                         {
  7993.                             d[2] = z;
  7994.                             setcube((d[k[0]]^k[1])+k[2],(d[k[3]]^k[4])+k[5],(d[k[6]]^k[7])+k[8],longpal[ch]);
  7995.                         }
  7996.                     }
  7997.                 }
  7998.             }
  7999.         }
  8000.     }
  8001.     if (j) scumfinish();
  8002.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,0);
  8003.  
  8004.     fclose(fp);
  8005. }
  8006.  
  8007.     //This here for game programmer only. I would never use it!
  8008. void drawpoint2d (long sx, long sy, long col)
  8009. {
  8010.     if ((unsigned long)sx >= (unsigned long)xres) return;
  8011.     if ((unsigned long)sy >= (unsigned long)yres) return;
  8012.     *(long *)(ylookup[sy]+(sx<<2)+frameplace) = col;
  8013. }
  8014.  
  8015.     //This here for game programmer only. I would never use it!
  8016. void drawpoint3d (float x0, float y0, float z0, long col)
  8017. {
  8018.     float ox, oy, oz, r;
  8019.     long x, y;
  8020.  
  8021.     ox = x0-gipos.x; oy = y0-gipos.y; oz = z0-gipos.z;
  8022.     z0 = ox*gifor.x + oy*gifor.y + oz*gifor.z; if (z0 < SCISDIST) return;
  8023.     r = 1.0f / z0;
  8024.     x0 = (ox*gistr.x + oy*gistr.y + oz*gistr.z)*gihz;
  8025.     y0 = (ox*gihei.x + oy*gihei.y + oz*gihei.z)*gihz;
  8026.  
  8027.     ftol(x0*r + gihx-.5f,&x); if ((unsigned long)x >= (unsigned long)xres) return;
  8028.     ftol(y0*r + gihy-.5f,&y); if ((unsigned long)y >= (unsigned long)yres) return;
  8029.     *(long *)(ylookup[y]+(x<<2)+frameplace) = col;
  8030. }
  8031.  
  8032.     //returns 1 if visible
  8033. long project2d (float x, float y, float z, float *px, float *py, float *sx)
  8034. {
  8035.     float ox, oy, oz;
  8036.  
  8037.     ox = x-gipos.x; oy = y-gipos.y; oz = z-gipos.z;
  8038.     z = ox*gifor.x + oy*gifor.y + oz*gifor.z; if (z < SCISDIST) return(0);
  8039.    
  8040.     z = gihz / z;
  8041.     *px = (ox*gistr.x + oy*gistr.y + oz*gistr.z)*z + gihx;
  8042.     *py = (ox*gihei.x + oy*gihei.y + oz*gihei.z)*z + gihy;
  8043.     *sx = z;  
  8044.     return(1);
  8045. }
  8046.  
  8047. static __int64 mskp255 = 0x00ff00ff00ff00ff;
  8048. static __int64 mskn255 = 0xff01ff01ff01ff01;
  8049. static __int64 rgbmask64 = 0xffffff00ffffff;
  8050.  
  8051.     //(tf,tp,tx,ty,tcx,tcy): Tile source, (tcx&tcy) is texel (<<16) at (sx,sy)
  8052.     //(sx,sy,xz,yz) screen coordinates and x&y zoom, all (<<16)
  8053.     //(black,white): black & white shade scale (ARGB format)
  8054.     //   Note: if alphas of black&white are same, then alpha channel ignored
  8055. void drawtile (long tf, long tp, long tx, long ty, long tcx, long tcy,
  8056.                     long sx, long sy, long xz, long yz, long black, long white)
  8057. {
  8058.     long sx0, sy0, sx1, sy1, x0, y0, x1, y1, x, y, u, v, ui, vi, uu, vv;
  8059.     long p, i, j, a;
  8060.  
  8061.     if (!tf) return;
  8062.     sx0 = sx - mulshr16(tcx,xz); sx1 = sx0 + xz*tx;
  8063.     sy0 = sy - mulshr16(tcy,yz); sy1 = sy0 + yz*ty;
  8064.     x0 = max((sx0+65535)>>16,0); x1 = min((sx1+65535)>>16,xres);
  8065.     y0 = max((sy0+65535)>>16,0); y1 = min((sy1+65535)>>16,yres);
  8066.     ui = shldiv16(65536,xz); u = mulshr16(-sx0,ui);
  8067.     vi = shldiv16(65536,yz); v = mulshr16(-sy0,vi);
  8068.     if (!((black^white)&0xff000000)) //Ignore alpha
  8069.     {
  8070.             //for(y=y0,vv=y*vi+v;y<y1;y++,vv+=vi)
  8071.             //{
  8072.             //   p = ylookup[y] + frameplace; j = (vv>>16)*tp + tf;
  8073.             //   for(x=x0,uu=x*ui+u;x<x1;x++,uu+=ui)
  8074.             //      *(long *)((x<<2)+p) = *(long *)(((uu>>16)<<2) + j);
  8075.             //}
  8076.         if ((xz == 32768) && (yz == 32768))
  8077.         {
  8078.             long plc;
  8079.             for(y=y0,vv=y*vi+v;y<y1;y++,vv+=vi)
  8080.             {
  8081.                 p = ylookup[y] + frameplace;
  8082.                 plc = (((x0*ui+u)>>16)<<2) + (vv>>16)*tp + tf;
  8083.                 _asm
  8084.                 {
  8085.                     push ebx
  8086.                     mov eax, x1
  8087.                     mov ebx, p
  8088.                     lea ebx, [ebx+eax*4]
  8089.                     sub eax, x0
  8090.                     mov ecx, plc
  8091.                     lea ecx, [ecx+eax*8]
  8092.                     mov edx, tp
  8093.                     add edx, ecx
  8094.                     neg eax
  8095.                         ;eax: x0-x1
  8096.                         ;ebx: p + x1*4
  8097.                         ;ecx: plc + (x1-x0)*8
  8098.                         ;edx: plc + (x1-x0)*8 + tp
  8099.       begdthalf:movq mm0, [eax*8+ecx]   ;mm0: A1R1G1B1 A0R0G0B0
  8100.                     pavgb mm0, [eax*8+edx]  ;mm0: A1R1G1B1 A0R0G0B0
  8101.                     pshufw mm1, mm0, 0xe    ;mm1: ???????? A1R1G1B1
  8102.                     pavgb mm0, mm1          ;mm1: ???????? AaRrGgBb
  8103.                     movd [eax*4+ebx], mm0
  8104.                     inc eax
  8105.                     jnz short begdthalf
  8106.                     pop ebx
  8107.                 }
  8108.             }
  8109.             _asm emms
  8110.         }
  8111.         else
  8112.         {
  8113.             long plc = x0*ui+u;
  8114.             for(y=y0,vv=y*vi+v;y<y1;y++,vv+=vi)
  8115.             {
  8116.                 p = ylookup[y] + frameplace; j = (vv>>16)*tp + tf;
  8117.  
  8118.                     //for(x=x0,uu=plc;x<x1;x++,uu+=ui)
  8119.                     //   *(long *)((x<<2)+p) = *(long *)(((uu>>16)<<2) + j);
  8120.                 _asm
  8121.                 {
  8122.                     push ebx
  8123.                     push esi
  8124.                     push edi
  8125.                     mov edi, x1
  8126.                     mov edx, x0
  8127.                     cmp edx, edi
  8128.                     jge short enddtnhalf
  8129.                     mov eax, p
  8130.                     mov esi, ui
  8131.                     mov ecx, plc
  8132.                     mov ebx, j
  8133.                     sub edx, edi
  8134.                     lea edi, [edi*4+eax]
  8135. begdtnhalf:
  8136. #if 0
  8137.                     mov eax, ecx          ;simple loop
  8138.                     shr eax, 16
  8139.                     mov eax, [eax*4+ebx]
  8140.                     add ecx, esi
  8141.                     mov [edx*4+edi], eax
  8142.                     add edx, 1
  8143.                     jnz short begdtnhalf
  8144. #else
  8145.                     lea eax, [ecx+esi]    ;unrolled once loop; uses movntq
  8146.                     shr ecx, 16
  8147.                     add edx, 1
  8148.                     movd mm0, [ecx*4+ebx]
  8149.                     lea ecx, [eax+esi]
  8150.                     jz short preenddtnhalf
  8151.                     shr eax, 16
  8152.                     punpckldq mm0, [eax*4+ebx]
  8153.                     movntq [edx*4+edi-4], mm0
  8154.                     add edx, 1
  8155.                     jnz short begdtnhalf
  8156.                     jmp short enddtnhalf
  8157. preenddtnhalf: movd [edx*4+edi-4], mm0
  8158. #endif
  8159. enddtnhalf:    pop edi
  8160.                     pop esi
  8161.                     pop ebx
  8162.                 }
  8163.             }
  8164.             _asm emms
  8165.         }
  8166.     }
  8167.     else //Use alpha for masking
  8168.     {
  8169.             //Init for black/white code
  8170.         _asm
  8171.         {
  8172.             pxor mm7, mm7
  8173.             movd mm5, white
  8174.             movd mm4, black
  8175.             punpcklbw mm5, mm7   ;mm5: [00Wa00Wr00Wg00Wb]
  8176.             punpcklbw mm4, mm7   ;mm4: [00Ba00Br00Bg00Bb]
  8177.             psubw mm5, mm4       ;mm5: each word range: -255 to 255
  8178.             movq mm0, mm5        ;if (? == -255) ? = -256;
  8179.             movq mm1, mm5        ;if (? ==  255) ? =  256;
  8180.             pcmpeqw mm0, mskp255 ;if (mm0.w[#] == 0x00ff) mm0.w[#] = 0xffff
  8181.             pcmpeqw mm1, mskn255 ;if (mm1.w[#] == 0xff01) mm1.w[#] = 0xffff
  8182.             psubw mm5, mm0
  8183.             paddw mm5, mm1
  8184.             psllw mm5, 4         ;mm5: [-WBa-WBr-WBg-WBb]
  8185.             movq mm6, rgbmask64
  8186.         }
  8187.         for(y=y0,vv=y*vi+v;y<y1;y++,vv+=vi)
  8188.         {
  8189.             p = ylookup[y] + frameplace; j = (vv>>16)*tp + tf;
  8190.             for(x=x0,uu=x*ui+u;x<x1;x++,uu+=ui)
  8191.             {
  8192.                 i = *(long *)(((uu>>16)<<2) + j);
  8193.  
  8194.                 _asm
  8195.                 {
  8196.                         ;                (mm5)              (mm4)
  8197.                         ;i.a = i.a*(white.a-black.a)/256 + black.a
  8198.                         ;i.r = i.r*(white.r-black.r)/256 + black.r
  8199.                         ;i.g = i.g*(white.g-black.g)/256 + black.g
  8200.                         ;i.b = i.b*(white.b-black.b)/256 + black.b
  8201.                     movd mm0, i           ;mm1: [00000000AaRrGgBb]
  8202.                     punpcklbw mm0, mm7    ;mm1: [00Aa00Rr00Gg00Bb]
  8203.                     psllw mm0, 4          ;mm1: [0Aa00Rr00Gg00Bb0]
  8204.                     pmulhw mm0, mm5       ;mm1: [--Aa--Rr--Gg--Bb]
  8205.                     paddw mm0, mm4        ;mm1: [00Aa00Rr00Gg00Bb]
  8206.                     movq mm1, mm0
  8207.                     packuswb mm0, mm0     ;mm1: [AaRrGgBbAaRrGgBb]
  8208.                     movd i, mm0
  8209.                 }
  8210.  
  8211.                     //a = (((unsigned long)i)>>24);
  8212.                     //if (!a) continue;
  8213.                     //if (a == 255) { *(long *)((x<<2)+p) = i; continue; }
  8214.                 if ((unsigned long)(i+0x1000000) < 0x2000000)
  8215.                 {
  8216.                     if (i < 0) *(long *)((x<<2)+p) = i;
  8217.                     continue;
  8218.                 }
  8219.                 _asm
  8220.                 {
  8221.                     mov eax, x            ;mm0 = (mm1-mm0)*a + mm0
  8222.                     mov edx, p
  8223.                     lea eax, [eax*4+edx]
  8224.                     movd mm0, [eax]       ;mm0: [00000000AaRrGgBb]
  8225.                     ;movd mm1, i           ;mm1: [00000000AaRrGgBb]
  8226.                     pand mm0, mm6         ;zero alpha from screen pixel
  8227.                     punpcklbw mm0, mm7    ;mm0: [00Aa00Rr00Gg00Bb]
  8228.                     ;punpcklbw mm1, mm7    ;mm1: [00Aa00Rr00Gg00Bb]
  8229.                     psubw mm1, mm0        ;mm1: [--Aa--Rr--Gg--Bb] range:+-255
  8230.                     psllw mm1, 4          ;mm1: [-Aa0-Rr0-Gg0-Bb0]
  8231.                     pshufw mm2, mm1, 0xff ;mm2: [-Aa0-Aa0-Aa0-Aa0]
  8232.                     pmulhw mm1, mm2
  8233.                     ;mov edx, a            ;alphalookup[i] = i*0x001000100010;
  8234.                     ;pmulhw mm1, alphalookup[edx*8]
  8235.                     paddw mm0, mm1
  8236.                     packuswb mm0, mm0
  8237.                     movd [eax], mm0
  8238.                 }
  8239.             }
  8240.         }
  8241.         _asm emms
  8242.     }
  8243. }
  8244.  
  8245. void drawline2d (float x1, float y1, float x2, float y2, long col)
  8246. {
  8247.     float dx, dy, fxresm1, fyresm1;
  8248.     long i, j, incr, ie;
  8249.  
  8250.     dx = x2-x1; dy = y2-y1; if ((dx == 0) && (dy == 0)) return;
  8251.     fxresm1 = (float)xres-.5; fyresm1 = (float)yres-.5;
  8252.     if (x1 >= fxresm1) { if (x2 >= fxresm1) return; y1 += (fxresm1-x1)*dy/dx; x1 = fxresm1; }
  8253.     else if (x1 < 0) { if (x2 < 0) return; y1 += (0-x1)*dy/dx; x1 = 0; }
  8254.     if (x2 >= fxresm1) { y2 += (fxresm1-x2)*dy/dx; x2 = fxresm1; }
  8255.     else if (x2 < 0) { y2 += (0-x2)*dy/dx; x2 = 0; }
  8256.     if (y1 >= fyresm1) { if (y2 >= fyresm1) return; x1 += (fyresm1-y1)*dx/dy; y1 = fyresm1; }
  8257.     else if (y1 < 0) { if (y2 < 0) return; x1 += (0-y1)*dx/dy; y1 = 0; }
  8258.     if (y2 >= fyresm1) { x2 += (fyresm1-y2)*dx/dy; y2 = fyresm1; }
  8259.     else if (y2 < 0) { x2 += (0-y2)*dx/dy; y2 = 0; }
  8260.  
  8261.     if (fabs(dx) >= fabs(dy))
  8262.     {
  8263.         if (x2 > x1) { ftol(x1,&i); ftol(x2,&ie); } else { ftol(x2,&i); ftol(x1,&ie); }
  8264.         if (i < 0) i = 0; if (ie >= xres) ie = xres-1;
  8265.         ftol(1048576.0*dy/dx,&incr); ftol(y1*1048576.0+((float)i+.5f-x1)*incr,&j);
  8266.         for(;i<=ie;i++,j+=incr)
  8267.             if ((unsigned long)(j>>20) < (unsigned long)yres)
  8268.                 *(long *)(ylookup[j>>20]+(i<<2)+frameplace) = col;
  8269.     }
  8270.     else
  8271.     {
  8272.         if (y2 > y1) { ftol(y1,&i); ftol(y2,&ie); } else { ftol(y2,&i); ftol(y1,&ie); }
  8273.         if (i < 0) i = 0; if (ie >= yres) ie = yres-1;
  8274.         ftol(1048576.0*dx/dy,&incr); ftol(x1*1048576.0+((float)i+.5f-y1)*incr,&j);
  8275.         for(;i<=ie;i++,j+=incr)
  8276.             if ((unsigned long)(j>>20) < (unsigned long)xres)
  8277.                 *(long *)(ylookup[i]+((j>>18)&~3)+frameplace) = col;
  8278.     }
  8279. }
  8280.  
  8281. #if (USEZBUFFER == 1)
  8282. void drawline2dclip (float x1, float y1, float x2, float y2, float rx0, float ry0, float rz0, float rx1, float ry1, float rz1, long col)
  8283. {
  8284.     float dx, dy, fxresm1, fyresm1, Za, Zb, Zc, z;
  8285.     long i, j, incr, ie, p;
  8286.  
  8287.     dx = x2-x1; dy = y2-y1; if ((dx == 0) && (dy == 0)) return;
  8288.     fxresm1 = (float)xres-.5; fyresm1 = (float)yres-.5;
  8289.     if (x1 >= fxresm1) { if (x2 >= fxresm1) return; y1 += (fxresm1-x1)*dy/dx; x1 = fxresm1; }
  8290.     else if (x1 < 0) { if (x2 < 0) return; y1 += (0-x1)*dy/dx; x1 = 0; }
  8291.     if (x2 >= fxresm1) { y2 += (fxresm1-x2)*dy/dx; x2 = fxresm1; }
  8292.     else if (x2 < 0) { y2 += (0-x2)*dy/dx; x2 = 0; }
  8293.     if (y1 >= fyresm1) { if (y2 >= fyresm1) return; x1 += (fyresm1-y1)*dx/dy; y1 = fyresm1; }
  8294.     else if (y1 < 0) { if (y2 < 0) return; x1 += (0-y1)*dx/dy; y1 = 0; }
  8295.     if (y2 >= fyresm1) { x2 += (fyresm1-y2)*dx/dy; y2 = fyresm1; }
  8296.     else if (y2 < 0) { x2 += (0-y2)*dx/dy; y2 = 0; }
  8297.  
  8298.     if (fabs(dx) >= fabs(dy))
  8299.     {
  8300.             //Original equation: (rz1*t+rz0) / (rx1*t+rx0) = gihz/(sx-gihx)
  8301.         Za = gihz*(rx0*rz1 - rx1*rz0); Zb = rz1; Zc = -gihx*rz1 - gihz*rx1;
  8302.  
  8303.         if (x2 > x1) { ftol(x1,&i); ftol(x2,&ie); } else { ftol(x2,&i); ftol(x1,&ie); }
  8304.         if (i < 0) i = 0; if (ie >= xres) ie = xres-1;
  8305.         ftol(1048576.0*dy/dx,&incr); ftol(y1*1048576.0+((float)i+.5f-x1)*incr,&j);
  8306.         for(;i<=ie;i++,j+=incr)
  8307.             if ((unsigned long)(j>>20) < (unsigned long)yres)
  8308.             {
  8309.                 p = ylookup[j>>20]+(i<<2)+frameplace;
  8310.                 z = Za / ((float)i*Zb + Zc);
  8311.                 if (*(long *)&z >= *(long *)(p+zbufoff)) continue;
  8312.                 *(long *)(p+zbufoff) = *(long *)&z;
  8313.                 *(long *)p = col;
  8314.             }
  8315.     }
  8316.     else
  8317.     {
  8318.         Za = gihz*(ry0*rz1 - ry1*rz0); Zb = rz1; Zc = -gihy*rz1 - gihz*ry1;
  8319.  
  8320.         if (y2 > y1) { ftol(y1,&i); ftol(y2,&ie); } else { ftol(y2,&i); ftol(y1,&ie); }
  8321.         if (i < 0) i = 0; if (ie >= yres) ie = yres-1;
  8322.         ftol(1048576.0*dx/dy,&incr); ftol(x1*1048576.0+((float)i+.5f-y1)*incr,&j);
  8323.         for(;i<=ie;i++,j+=incr)
  8324.             if ((unsigned long)(j>>20) < (unsigned long)xres)
  8325.             {
  8326.                 p = ylookup[i]+((j>>18)&~3)+frameplace;
  8327.                 z = Za / ((float)i*Zb + Zc);
  8328.                 if (*(long *)&z >= *(long *)(p+zbufoff)) continue;
  8329.                 *(long *)(p+zbufoff) = *(long *)&z;
  8330.                 *(long *)p = col;
  8331.             }
  8332.     }
  8333. }
  8334. #endif
  8335.  
  8336. void drawline3d (float x0, float y0, float z0, float x1, float y1, float z1, long col)
  8337. {
  8338.     float ox, oy, oz, r;
  8339.  
  8340.     ox = x0-gipos.x; oy = y0-gipos.y; oz = z0-gipos.z;
  8341.     x0 = ox*gistr.x + oy*gistr.y + oz*gistr.z;
  8342.     y0 = ox*gihei.x + oy*gihei.y + oz*gihei.z;
  8343.     z0 = ox*gifor.x + oy*gifor.y + oz*gifor.z;
  8344.  
  8345.     ox = x1-gipos.x; oy = y1-gipos.y; oz = z1-gipos.z;
  8346.     x1 = ox*gistr.x + oy*gistr.y + oz*gistr.z;
  8347.     y1 = ox*gihei.x + oy*gihei.y + oz*gihei.z;
  8348.     z1 = ox*gifor.x + oy*gifor.y + oz*gifor.z;
  8349.  
  8350.     if (z0 < SCISDIST)
  8351.     {
  8352.         if (z1 < SCISDIST) return;
  8353.         r = (SCISDIST-z0)/(z1-z0); z0 = SCISDIST;
  8354.         x0 += (x1-x0)*r; y0 += (y1-y0)*r;
  8355.     }
  8356.     else if (z1 < SCISDIST)
  8357.     {
  8358.         r = (SCISDIST-z1)/(z1-z0); z1 = SCISDIST;
  8359.         x1 += (x1-x0)*r; y1 += (y1-y0)*r;
  8360.     }
  8361.  
  8362.     ox = gihz/z0;
  8363.     oy = gihz/z1;
  8364.  
  8365. #if (USEZBUFFER == 1)
  8366.     if (!(col&0xff000000))
  8367.         drawline2dclip(x0*ox+gihx,y0*ox+gihy,x1*oy+gihx,y1*oy+gihy,x0,y0,z0,x1-x0,y1-y0,z1-z0,col);
  8368.     else
  8369.         drawline2d(x0*ox+gihx,y0*ox+gihy,x1*oy+gihx,y1*oy+gihy,col&0xffffff);
  8370. #else
  8371.     drawline2d(x0*ox+gihx,y0*ox+gihy,x1*oy+gihx,y1*oy+gihy,col);
  8372. #endif
  8373. }
  8374.  
  8375.     //If radius is negative, then it uses Z-buffering
  8376. void drawspherefill (float ox, float oy, float oz, float bakrad, long col)
  8377. {
  8378.     float a, b, c, d, e, f, g, h, t, cxcx, cycy, Za, Zb, Zc, ysq;
  8379.     float r2a, rr2a, nb, nbi, isq, isqi, isqii, cx, cy, cz, rad;
  8380.     long sx1, sy1, sx2, sy2, p, sx;
  8381.  
  8382.     rad = fabs(bakrad);
  8383. #if (USEZBUFFER == 0)
  8384.     bakrad = rad;
  8385. #endif
  8386.  
  8387.     ox -= gipos.x; oy -= gipos.y; oz -= gipos.z;
  8388.     cz = ox*gifor.x + oy*gifor.y + oz*gifor.z; if (cz < SCISDIST) return;
  8389.     cx = ox*gistr.x + oy*gistr.y + oz*gistr.z;
  8390.     cy = ox*gihei.x + oy*gihei.y + oz*gihei.z;
  8391.  
  8392.         //3D Sphere projection (see spherast.txt for derivation) (13 multiplies)
  8393.     cxcx = cx*cx; cycy = cy*cy; g = rad*rad - cxcx - cycy - cz*cz;
  8394.     a = g + cxcx; if (!a) return;
  8395.     b = cx*cy; b += b;
  8396.     c = g + cycy;
  8397.     f = gihx*cx + gihy*cy - gihz*cz;
  8398.     d = -cx*f - gihx*g; d += d;
  8399.     e = -cy*f - gihy*g; e += e;
  8400.     f = f*f + g*(gihx*gihx+gihy*gihy+gihz*gihz);
  8401.  
  8402.         //isq = (b*b-4*a*c)yύ + (2*b*d-4*a*e)y + (d*d-4*a*f) = 0
  8403.     Za = b*b - a*c*4; if (!Za) return;
  8404.     Zb = b*d*2 - a*e*4;
  8405.     Zc = d*d - a*f*4;
  8406.     ysq = Zb*Zb - Za*Zc*4; if (ysq <= 0) return;
  8407.     t = sqrt(ysq); //fsqrtasm(&ysq,&t);
  8408.     h = .5f / Za;
  8409.     ftol((-Zb+t)*h,&sy1); if (sy1 < 0) sy1 = 0;
  8410.     ftol((-Zb-t)*h,&sy2); if (sy2 > yres) sy2 = yres;
  8411.     if (sy1 >= sy2) return;
  8412.     r2a = .5f / a; rr2a = r2a*r2a;
  8413.     nbi = -b*r2a; nb = nbi*(float)sy1-d*r2a;
  8414.     h = Za*(float)sy1; isq = ((float)sy1*(h+Zb)+Zc)*rr2a;
  8415.     isqi = (h+h+Za+Zb)*rr2a; isqii = Za*rr2a*2;
  8416.  
  8417.     p = ylookup[sy1]+frameplace;
  8418.     sy2 = ylookup[sy2]+frameplace;
  8419. #if (USEZBUFFER == 1)
  8420.     if ((*(long *)&bakrad) >= 0)
  8421.     {
  8422. #endif
  8423.         while (1)  //(a)xύ + (b*y+d)x + (c*y*y+e*y+f) = 0
  8424.         {
  8425.             t = sqrt(isq); //fsqrtasm(&isq,&t);
  8426.             ftol(nb-t,&sx1); if (sx1 < 0) sx1 = 0;
  8427.             ftol(nb+t,&sx2);
  8428.             sx2 = min(sx2,xres)-sx1;
  8429.             if (sx2 > 0) clearbuf((void *)((sx1<<2)+p),sx2,col);
  8430.             p += bytesperline; if (p >= sy2) return;
  8431.             isq += isqi; isqi += isqii; nb += nbi;
  8432.         }
  8433. #if (USEZBUFFER == 1)
  8434.     }
  8435.     else
  8436.     {     //Use Z-buffering
  8437.  
  8438.         if (ofogdist >= 0) //If fog enabled...
  8439.         {
  8440.             ftol(sqrt(ox*ox + oy*oy),&sx); //Use cylindrical x-y distance for fog
  8441.             if (sx > 2047) sx = 2047;
  8442.             sx = (long)(*(short *)&foglut[sx]);
  8443.             col = ((((( vx5.fogcol     &255)-( col     &255))*sx)>>15)    ) +
  8444.                     ((((((vx5.fogcol>> 8)&255)-((col>> 8)&255))*sx)>>15)<< 8) +
  8445.                     ((((((vx5.fogcol>>16)&255)-((col>>16)&255))*sx)>>15)<<16) + col;
  8446.         }
  8447.  
  8448.         while (1)  //(a)xύ + (b*y+d)x + (c*y*y+e*y+f) = 0
  8449.         {
  8450.             t = sqrt(isq); //fsqrtasm(&isq,&t);
  8451.             ftol(nb-t,&sx1); if (sx1 < 0) sx1 = 0;
  8452.             ftol(nb+t,&sx2);
  8453.             if (sx2 > xres) sx2 = xres;
  8454.             for(sx=sx1;sx<sx2;sx++)
  8455.                 if (*(long *)&cz < *(long *)(p+(sx<<2)+zbufoff))
  8456.                 {
  8457.                     *(long *)(p+(sx<<2)+zbufoff) = *(long *)&cz;
  8458.                     *(long *)(p+(sx<<2)) = col;
  8459.                 }
  8460.             sy1++;
  8461.             p += bytesperline; if (p >= sy2) return;
  8462.             isq += isqi; isqi += isqii; nb += nbi;
  8463.         }
  8464.     }
  8465. #endif
  8466. }
  8467.  
  8468. void drawpicinquad (long rpic, long rbpl, long rxsiz, long rysiz,
  8469.                           long wpic, long wbpl, long wxsiz, long wysiz,
  8470.                           float x0, float y0, float x1, float y1,
  8471.                           float x2, float y2, float x3, float y3)
  8472. {
  8473.     float px[4], py[4], k0, k1, k2, k3, k4, k5, k6, k7, k8;
  8474.     float t, u, v, dx, dy, l0, l1, m0, m1, m2, n0, n1, n2, r;
  8475.     long i, j, k, l, imin, imax, sx, sxe, sy, sy1, dd, uu, vv, ddi, uui, vvi;
  8476.     long x, xi, *p, *pe, uvmax, iu, iv;
  8477.  
  8478.     px[0] = x0; px[1] = x1; px[2] = x2; px[3] = x3;
  8479.     py[0] = y0; py[1] = y1; py[2] = y2; py[3] = y3;
  8480.  
  8481.         //This code projects 4 point2D's into a t,u,v screen-projection matrix
  8482.         //
  8483.         //Derivation: (given 4 known (sx,sy,kt,ku,kv) pairs, solve for k0-k8)
  8484.         //   kt = k0*sx + k1*sy + k2
  8485.         //   ku = k3*sx + k4*sy + k5
  8486.         //   kv = k6*sx + k7*sy + k8
  8487.         //0 = (k3*x0 + k4*y0 + k5) / (k0*x0 + k1*y0 + k2) / rxsiz
  8488.         //0 = (k6*x0 + k7*y0 + k8) / (k0*x0 + k1*y0 + k2) / rysiz
  8489.         //1 = (k3*x1 + k4*y1 + k5) / (k0*x1 + k1*y1 + k2) / rxsiz
  8490.         //0 = (k6*x1 + k7*y1 + k8) / (k0*x1 + k1*y1 + k2) / rysiz
  8491.         //1 = (k3*x2 + k4*y2 + k5) / (k0*x2 + k1*y2 + k2) / rxsiz
  8492.         //1 = (k6*x2 + k7*y2 + k8) / (k0*x2 + k1*y2 + k2) / rysiz
  8493.         //0 = (k3*x3 + k4*y3 + k5) / (k0*x3 + k1*y3 + k2) / rxsiz
  8494.         //1 = (k6*x3 + k7*y3 + k8) / (k0*x3 + k1*y3 + k2) / rysiz
  8495.         //   40*, 28+, 1~, 30W
  8496.     k3 = y3 - y0; k4 = x0 - x3; k5 = x3*y0 - x0*y3;
  8497.     k6 = y0 - y1; k7 = x1 - x0; k8 = x0*y1 - x1*y0;
  8498.     n0 = x2*y3 - x3*y2; n1 = x3*y1 - x1*y3; n2 = x1*y2 - x2*y1;
  8499.     l0 = k6*x2 + k7*y2 + k8;
  8500.     l1 = k3*x2 + k4*y2 + k5;
  8501.     t = n0 + n1 + n2; dx = (float)rxsiz*t*l0; dy = (float)rysiz*t*l1;
  8502.     t = l0*l1;
  8503.     l0 *= (k3*x1 + k4*y1 + k5);
  8504.     l1 *= (k6*x3 + k7*y3 + k8);
  8505.     m0 = l1 - t; m1 = l0 - l1; m2 = t - l0;
  8506.     k0 = m0*y1 + m1*y2 + m2*y3;
  8507.     k1 = -(m0*x1 + m1*x2 + m2*x3);
  8508.     k2 = n0*l0 + n1*t + n2*l1;
  8509.     k3 *= dx; k4 *= dx; k5 *= dx;
  8510.     k6 *= dy; k7 *= dy; k8 *= dy;
  8511.  
  8512.         //Make sure k's are in good range for conversion to integers...
  8513.     t = fabs(k0);
  8514.     if (fabs(k1) > t) t = fabs(k1);
  8515.     if (fabs(k2) > t) t = fabs(k2);
  8516.     if (fabs(k3) > t) t = fabs(k3);
  8517.     if (fabs(k4) > t) t = fabs(k4);
  8518.     if (fabs(k5) > t) t = fabs(k5);
  8519.     if (fabs(k6) > t) t = fabs(k6);
  8520.     if (fabs(k7) > t) t = fabs(k7);
  8521.     if (fabs(k8) > t) t = fabs(k8);
  8522.     t = -268435456.0 / t;
  8523.     k0 *= t; k1 *= t; k2 *= t;
  8524.     k3 *= t; k4 *= t; k5 *= t;
  8525.     k6 *= t; k7 *= t; k8 *= t;
  8526.     ftol(k0,&ddi);
  8527.  
  8528.     imin = 0; imax = 0;
  8529.     for(i=1;i<4;i++)
  8530.     {
  8531.         if (py[i] < py[imin]) imin = i;
  8532.         if (py[i] > py[imax]) imax = i;
  8533.     }
  8534.  
  8535.     uvmax = (rysiz-1)*rbpl + (rxsiz<<2);
  8536.  
  8537.     i = imax;
  8538.     do
  8539.     {
  8540.         j = ((i+1)&3);
  8541.             //offset would normally be -.5, but need to bias by +1.0
  8542.         ftol(py[j]+.5,&sy); if (sy < 0) sy = 0;
  8543.         ftol(py[i]+.5,&sy1); if (sy1 > wysiz) sy1 = wysiz;
  8544.         if (sy1 > sy)
  8545.         {
  8546.             ftol((px[i]-px[j])*4096.0/(py[i]-py[j]),&xi);
  8547.             ftol(((float)sy-py[j])*(float)xi + px[j]*4096.0 + 4096.0,&x);
  8548.             for(;sy<sy1;sy++,x+=xi) lastx[sy] = (x>>12);
  8549.         }
  8550.         i = j;
  8551.     } while (i != imin);
  8552.     do
  8553.     {
  8554.         j = ((i+1)&3);
  8555.             //offset would normally be -.5, but need to bias by +1.0
  8556.         ftol(py[i]+.5,&sy); if (sy < 0) sy = 0;
  8557.         ftol(py[j]+.5,&sy1); if (sy1 > wysiz) sy1 = wysiz;
  8558.         if (sy1 > sy)
  8559.         {
  8560.             ftol((px[j]-px[i])*4096.0/(py[j]-py[i]),&xi);
  8561.             ftol(((float)sy-py[i])*(float)xi + px[i]*4096.0 + 4096.0,&x);
  8562.             for(;sy<sy1;sy++,x+=xi)
  8563.             {
  8564.                 sx = lastx[sy]; if (sx < 0) sx = 0;
  8565.                 sxe = (x>>12); if (sxe > wxsiz) sxe = wxsiz;
  8566.                 if (sx >= sxe) continue;
  8567.                 t = k0*(float)sx + k1*(float)sy + k2; r = 1.0 / t;
  8568.                 u = k3*(float)sx + k4*(float)sy + k5; ftol(u*r-.5,&iu);
  8569.                 v = k6*(float)sx + k7*(float)sy + k8; ftol(v*r-.5,&iv);
  8570.                 ftol(t,&dd);
  8571.                 ftol((float)iu*k0 - k3,&uui); ftol((float)iu*t - u,&uu);
  8572.                 ftol((float)iv*k0 - k6,&vvi); ftol((float)iv*t - v,&vv);
  8573.                 if (k3*t < u*k0) k =    -4; else { uui = -(uui+ddi); uu = -(uu+dd); k =    4; }
  8574.                 if (k6*t < v*k0) l = -rbpl; else { vvi = -(vvi+ddi); vv = -(vv+dd); l = rbpl; }
  8575.                 iu = iv*rbpl + (iu<<2);
  8576.                 p  = (long *)(sy*wbpl+(sx<<2)+wpic);
  8577.                 pe = (long *)(sy*wbpl+(sxe<<2)+wpic);
  8578.                 do
  8579.                 {
  8580.                     if ((unsigned long)iu < uvmax) p[0] = *(long *)(rpic+iu);
  8581.                     dd += ddi;
  8582.                     uu += uui; while (uu < 0) { iu += k; uui -= ddi; uu -= dd; }
  8583.                     vv += vvi; while (vv < 0) { iu += l; vvi -= ddi; vv -= dd; }
  8584.                     p++;
  8585.                 } while (p < pe);
  8586.             }
  8587.         }
  8588.         i = j;
  8589.     } while (i != imax);
  8590. }
  8591.  
  8592. __declspec(align(16)) static float dpqdistlut[MAXXDIM];
  8593. __declspec(align(16)) static float dpqmulval[4] = {0,1,2,3}, dpqfour[4] = {4,4,4,4};
  8594. __declspec(align(8)) static float dpq3dn[4];
  8595. void drawpolyquad (long rpic, long rbpl, long rxsiz, long rysiz,
  8596.                          float x0, float y0, float z0, float u0, float v0,
  8597.                          float x1, float y1, float z1, float u1, float v1,
  8598.                          float x2, float y2, float z2, float u2, float v2,
  8599.                          float x3, float y3, float z3)
  8600. {
  8601.     point3d fp, fp2;
  8602.     float px[6], py[6], pz[6], pu[6], pv[6], px2[4], py2[4], pz2[4], pu2[4], pv2[4];
  8603.     float f, t, u, v, r, nx, ny, nz, ox, oy, oz, scaler;
  8604.     float dx, dy, db, ux, uy, ub, vx, vy, vb;
  8605.     long i, j, k, l, imin, imax, sx, sxe, sy, sy1;
  8606.     long x, xi, *p, *pe, uvmax, iu, iv, n;
  8607.     long dd, uu, vv, ddi, uui, vvi, distlutoffs;
  8608.  
  8609.     px2[0] = x0; py2[0] = y0; pz2[0] = z0; pu2[0] = u0; pv2[0] = v0;
  8610.     px2[1] = x1; py2[1] = y1; pz2[1] = z1; pu2[1] = u1; pv2[1] = v1;
  8611.     px2[2] = x2; py2[2] = y2; pz2[2] = z2; pu2[2] = u2; pv2[2] = v2;
  8612.     px2[3] = x3; py2[3] = y3; pz2[3] = z3;
  8613.  
  8614.         //Calculate U-V coordinate of 4th point on quad (based on 1st 3)
  8615.     nx = (y1-y0)*(z2-z0) - (z1-z0)*(y2-y0);
  8616.     ny = (z1-z0)*(x2-x0) - (x1-x0)*(z2-z0);
  8617.     nz = (x1-x0)*(y2-y0) - (y1-y0)*(x2-x0);
  8618.     if ((fabs(nx) > fabs(ny)) && (fabs(nx) > fabs(nz)))
  8619.     {     //(y1-y0)*u + (y2-y0)*v = (y3-y0)
  8620.             //(z1-z0)*u + (z2-z0)*v = (z3-z0)
  8621.         f = 1/nx;
  8622.         u = ((y3-y0)*(z2-z0) - (z3-z0)*(y2-y0))*f;
  8623.         v = ((y1-y0)*(z3-z0) - (z1-z0)*(y3-y0))*f;
  8624.     }
  8625.     else if (fabs(ny) > fabs(nz))
  8626.     {     //(x1-x0)*u + (x2-x0)*v = (x3-x0)
  8627.             //(z1-z0)*u + (z2-z0)*v = (z3-z0)
  8628.         f = -1/ny;
  8629.         u = ((x3-x0)*(z2-z0) - (z3-z0)*(x2-x0))*f;
  8630.         v = ((x1-x0)*(z3-z0) - (z1-z0)*(x3-x0))*f;
  8631.     }
  8632.     else
  8633.     {     //(x1-x0)*u + (x2-x0)*v = (x3-x0)
  8634.             //(y1-y0)*u + (y2-y0)*v = (y3-y0)
  8635.         f = 1/nz;
  8636.         u = ((x3-x0)*(y2-y0) - (y3-y0)*(x2-x0))*f;
  8637.         v = ((x1-x0)*(y3-y0) - (y1-y0)*(x3-x0))*f;
  8638.     }
  8639.     pu2[3] = (u1-u0)*u + (u2-u0)*v + u0;
  8640.     pv2[3] = (v1-v0)*u + (v2-v0)*v + v0;
  8641.  
  8642.  
  8643.     for(i=4-1;i>=0;i--) //rotation
  8644.     {
  8645.         fp.x = px2[i]-gipos.x; fp.y = py2[i]-gipos.y; fp.z = pz2[i]-gipos.z;
  8646.         px2[i] = fp.x*gistr.x + fp.y*gistr.y + fp.z*gistr.z;
  8647.         py2[i] = fp.x*gihei.x + fp.y*gihei.y + fp.z*gihei.z;
  8648.         pz2[i] = fp.x*gifor.x + fp.y*gifor.y + fp.z*gifor.z;
  8649.     }
  8650.  
  8651.         //Clip to SCISDIST plane
  8652.     n = 0;
  8653.     for(i=0;i<4;i++)
  8654.     {
  8655.         j = ((i+1)&3);
  8656.         if (pz2[i] >= SCISDIST) { px[n] = px2[i]; py[n] = py2[i]; pz[n] = pz2[i]; pu[n] = pu2[i]; pv[n] = pv2[i]; n++; }
  8657.         if ((pz2[i] >= SCISDIST) != (pz2[j] >= SCISDIST))
  8658.         {
  8659.             f = (SCISDIST-pz2[i])/(pz2[j]-pz2[i]);
  8660.             px[n] = (px2[j]-px2[i])*f + px2[i];
  8661.             py[n] = (py2[j]-py2[i])*f + py2[i];
  8662.             pz[n] = SCISDIST;
  8663.             pu[n] = (pu2[j]-pu2[i])*f + pu2[i];
  8664.             pv[n] = (pv2[j]-pv2[i])*f + pv2[i]; n++;
  8665.         }
  8666.     }
  8667.     if (n < 3) return;
  8668.  
  8669.     for(i=n-1;i>=0;i--) //projection
  8670.     {
  8671.         pz[i] = 1/pz[i]; f = pz[i]*gihz;
  8672.         px[i] = px[i]*f + gihx;
  8673.         py[i] = py[i]*f + gihy;
  8674.     }
  8675.  
  8676.         //General equations:
  8677.         //pz[i] = (px[i]*gdx + py[i]*gdy + gdo)
  8678.         //pu[i] = (px[i]*gux + py[i]*guy + guo)/pz[i]
  8679.         //pv[i] = (px[i]*gvx + py[i]*gvy + gvo)/pz[i]
  8680.         //
  8681.         //px[0]*gdx + py[0]*gdy + 1*gdo = pz[0]
  8682.         //px[1]*gdx + py[1]*gdy + 1*gdo = pz[1]
  8683.         //px[2]*gdx + py[2]*gdy + 1*gdo = pz[2]
  8684.         //
  8685.         //px[0]*gux + py[0]*guy + 1*guo = pu[0]*pz[0] (pu[i] premultiplied by pz[i] above)
  8686.         //px[1]*gux + py[1]*guy + 1*guo = pu[1]*pz[1]
  8687.         //px[2]*gux + py[2]*guy + 1*guo = pu[2]*pz[2]
  8688.         //
  8689.         //px[0]*gvx + py[0]*gvy + 1*gvo = pv[0]*pz[0] (pv[i] premultiplied by pz[i] above)
  8690.         //px[1]*gvx + py[1]*gvy + 1*gvo = pv[1]*pz[1]
  8691.         //px[2]*gvx + py[2]*gvy + 1*gvo = pv[2]*pz[2]
  8692.     pu[0] *= pz[0]; pu[1] *= pz[1]; pu[2] *= pz[2];
  8693.     pv[0] *= pz[0]; pv[1] *= pz[1]; pv[2] *= pz[2];
  8694.     ox = py[1]-py[2]; oy = py[2]-py[0]; oz = py[0]-py[1];
  8695.     r = 1.0 / (ox*px[0] + oy*px[1] + oz*px[2]);
  8696.     dx = (ox*pz[0] + oy*pz[1] + oz*pz[2])*r;
  8697.     ux = (ox*pu[0] + oy*pu[1] + oz*pu[2])*r;
  8698.     vx = (ox*pv[0] + oy*pv[1] + oz*pv[2])*r;
  8699.     ox = px[2]-px[1]; oy = px[0]-px[2]; oz = px[1]-px[0];
  8700.     dy = (ox*pz[0] + oy*pz[1] + oz*pz[2])*r;
  8701.     uy = (ox*pu[0] + oy*pu[1] + oz*pu[2])*r;
  8702.     vy = (ox*pv[0] + oy*pv[1] + oz*pv[2])*r;
  8703.     db = pz[0] - px[0]*dx - py[0]*dy;
  8704.     ub = pu[0] - px[0]*ux - py[0]*uy;
  8705.     vb = pv[0] - px[0]*vx - py[0]*vy;
  8706.  
  8707. #if 1
  8708.         //Make sure k's are in good range for conversion to integers...
  8709.     t = fabs(ux);
  8710.     if (fabs(uy) > t) t = fabs(uy);
  8711.     if (fabs(ub) > t) t = fabs(ub);
  8712.     if (fabs(vx) > t) t = fabs(vx);
  8713.     if (fabs(vy) > t) t = fabs(vy);
  8714.     if (fabs(vb) > t) t = fabs(vb);
  8715.     if (fabs(dx) > t) t = fabs(dx);
  8716.     if (fabs(dy) > t) t = fabs(dy);
  8717.     if (fabs(db) > t) t = fabs(db);
  8718.     scaler = -268435456.0 / t;
  8719.     ux *= scaler; uy *= scaler; ub *= scaler;
  8720.     vx *= scaler; vy *= scaler; vb *= scaler;
  8721.     dx *= scaler; dy *= scaler; db *= scaler;
  8722.     ftol(dx,&ddi);
  8723.     uvmax = (rysiz-1)*rbpl + (rxsiz<<2);
  8724.  
  8725.     scaler = 1.f/scaler; t = dx*scaler;
  8726.     if (cputype&(1<<25))
  8727.     {
  8728.         _asm //SSE
  8729.         {
  8730.             movss xmm6, t         ;xmm6: -,-,-,dx*scaler
  8731.             shufps xmm6, xmm6, 0  ;xmm6: dx*scaler,dx*scaler,dx*scaler,dx*scaler
  8732.             movaps xmm7, xmm6     ;xmm7: dx*scaler,dx*scaler,dx*scaler,dx*scaler
  8733.             mulps xmm6, dpqmulval ;xmm6: dx*scaler*3,dx*scaler*2,dx*scaler*1,0
  8734.             mulps xmm7, dpqfour   ;xmm7: dx*scaler*4,dx*scaler*4,dx*scaler*4,dx*scaler*4
  8735.         }
  8736.     }
  8737.     else { dpq3dn[0] = 0; dpq3dn[1] = t; dpq3dn[2] = dpq3dn[3] = t+t; } //3DNow!
  8738. #endif
  8739.  
  8740.     imin = (py[1]<py[0]); imax = 1-imin;
  8741.     for(i=n-1;i>1;i--)
  8742.     {
  8743.         if (py[i] < py[imin]) imin = i;
  8744.         if (py[i] > py[imax]) imax = i;
  8745.     }
  8746.  
  8747.     i = imax;
  8748.     do
  8749.     {
  8750.         j = i+1; if (j >= n) j = 0;
  8751.             //offset would normally be -.5, but need to bias by +1.0
  8752.         ftol(py[j]+.5,&sy); if (sy < 0) sy = 0;
  8753.         ftol(py[i]+.5,&sy1); if (sy1 > yres) sy1 = yres;
  8754.         if (sy1 > sy)
  8755.         {
  8756.             ftol((px[i]-px[j])*4096.0/(py[i]-py[j]),&xi);
  8757.             ftol(((float)sy-py[j])*(float)xi + px[j]*4096.0 + 4096.0,&x);
  8758.             for(;sy<sy1;sy++,x+=xi) lastx[sy] = (x>>12);
  8759.         }
  8760.         i = j;
  8761.     } while (i != imin);
  8762.     do
  8763.     {
  8764.         j = i+1; if (j >= n) j = 0;
  8765.             //offset would normally be -.5, but need to bias by +1.0
  8766.         ftol(py[i]+.5,&sy); if (sy < 0) sy = 0;
  8767.         ftol(py[j]+.5,&sy1); if (sy1 > yres) sy1 = yres;
  8768.         if (sy1 > sy)
  8769.         {
  8770.             ftol((px[j]-px[i])*4096.0/(py[j]-py[i]),&xi);
  8771.             ftol(((float)sy-py[i])*(float)xi + px[i]*4096.0 + 4096.0,&x);
  8772.             for(;sy<sy1;sy++,x+=xi)
  8773.             {
  8774.                 sx = lastx[sy]; if (sx < 0) sx = 0;
  8775.                 sxe = (x>>12); if (sxe > xres) sxe = xres;
  8776.                 if (sx >= sxe) continue;
  8777.                 p  = (long *)(sy*bytesperline+(sx<<2)+frameplace);
  8778.                 pe = (long *)(sy*bytesperline+(sxe<<2)+frameplace);
  8779. #if 0
  8780.                     //Brute force
  8781.                 do
  8782.                 {
  8783.                     f = 1.f/(dx*(float)sx + dy*(float)sy + db);
  8784.                     if (f < *(float *)(((long)p)+zbufoff))
  8785.                     {
  8786.                         *(float *)(((long)p)+zbufoff) = f;
  8787.                         ftol((ux*(float)sx + uy*(float)sy + ub)*f-.5,&iu);
  8788.                         ftol((vx*(float)sx + vy*(float)sy + vb)*f-.5,&iv);
  8789.                         if ((unsigned long)iu >= rxsiz) iu = 0;
  8790.                         if ((unsigned long)iv >= rysiz) iv = 0;
  8791.                         p[0] = *(long *)(iv*rbpl+(iu<<2)+rpic);
  8792.                     }
  8793.                     p++; sx++;
  8794.                 } while (p < pe);
  8795. #else
  8796.                     //Optimized (in C) hyperbolic texture-mapping (Added Z-buffer using SSE/3DNow! for recip's)
  8797.                 t = dx*(float)sx + dy*(float)sy + db; r = 1.0 / t;
  8798.                 u = ux*(float)sx + uy*(float)sy + ub; ftol(u*r-.5,&iu);
  8799.                 v = vx*(float)sx + vy*(float)sy + vb; ftol(v*r-.5,&iv);
  8800.                 ftol(t,&dd);
  8801.                 ftol((float)iu*dx - ux,&uui); ftol((float)iu*t - u,&uu);
  8802.                 ftol((float)iv*dx - vx,&vvi); ftol((float)iv*t - v,&vv);
  8803.                 if (ux*t < u*dx) k =    -4; else { uui = -(uui+ddi); uu = -(uu+dd); k =    4; }
  8804.                 if (vx*t < v*dx) l = -rbpl; else { vvi = -(vvi+ddi); vv = -(vv+dd); l = rbpl; }
  8805.                 iu = iv*rbpl + (iu<<2);
  8806.  
  8807.                 t *= scaler;
  8808.                 _asm
  8809.                 {
  8810.                     mov ecx, sxe
  8811.                     sub ecx, sx
  8812.                     xor eax, eax
  8813.                     lea ecx, [ecx*4]
  8814.                     sub eax, ecx
  8815.                     add ecx, offset dpqdistlut
  8816.  
  8817.                     test cputype, 1 shl 25
  8818.                     jz short dpqpre3dn
  8819.  
  8820.                     movss xmm0, t ;dd+ddi*3 dd+ddi*2 dd+ddi*1 dd+ddi*0
  8821.                     shufps xmm0, xmm0, 0
  8822.                     addps xmm0, xmm6
  8823.      dpqbegsse: rcpps xmm1, xmm0
  8824.                     addps xmm0, xmm7
  8825.                     movaps [eax+ecx], xmm1
  8826.                     add eax, 16
  8827.                     jl short dpqbegsse
  8828.                     jmp short dpqendit
  8829.  
  8830.      dpqpre3dn: movd mm0, t ;dd+ddi*1 dd+ddi*0
  8831.                     punpckldq mm0, mm0
  8832.                     pfadd mm0, dpq3dn[0]
  8833.                     movq mm7, dpq3dn[8]
  8834.      dpqbeg3dn: pswapd mm2, mm0
  8835.                     pfrcp mm1, mm0     ;mm1: 1/mm0l 1/mm0l
  8836.                     pfrcp mm2, mm2     ;mm2: 1/mm0h 1/mm0h
  8837.                     punpckldq mm1, mm2 ;mm1: 1/mm0h 1/mm0l
  8838.                     pfadd mm0, mm7
  8839.                     movq [eax+ecx], mm1
  8840.                     add eax, 8
  8841.                     jl short dpqbeg3dn
  8842.                     femms
  8843.       dpqendit:
  8844.                 }
  8845.                 distlutoffs = ((long)dpqdistlut)-((long)p);
  8846.                 do
  8847.                 {
  8848. #if (USEZBUFFER != 0)
  8849.                     if (*(long *)(((long)p)+zbufoff) > *(long *)(((long)p)+distlutoffs))
  8850.                     {
  8851.                         *(long *)(((long)p)+zbufoff) = *(long *)(((long)p)+distlutoffs);
  8852. #endif
  8853.                         if ((unsigned long)iu < uvmax) p[0] = *(long *)(rpic+iu);
  8854. #if (USEZBUFFER != 0)
  8855.                     }
  8856. #endif
  8857.                     dd += ddi;
  8858.                     uu += uui; while (uu < 0) { iu += k; uui -= ddi; uu -= dd; }
  8859.                     vv += vvi; while (vv < 0) { iu += l; vvi -= ddi; vv -= dd; }
  8860.                     p++;
  8861.                 } while (p < pe);
  8862. #endif
  8863.             }
  8864.         }
  8865.         i = j;
  8866.     } while (i != imax);
  8867. }
  8868.  
  8869. //------------------------- SXL parsing code begins --------------------------
  8870.  
  8871. static char *sxlbuf = 0;
  8872. static long sxlparspos, sxlparslen;
  8873.  
  8874. long loadsxl (const char *sxlnam, char **vxlnam, char **skynam, char **globst)
  8875. {
  8876.     long j, k, m, n;
  8877.  
  8878.         //NOTE: MUST buffer file because insertsprite uses kz file code :/
  8879.     if (!kzopen(sxlnam)) return(0);
  8880.     sxlparslen = kzfilelength();
  8881.     if (sxlbuf) { free(sxlbuf); sxlbuf = 0; }
  8882.     if (!(sxlbuf = (char *)malloc(sxlparslen))) return(0);
  8883.     kzread(sxlbuf,sxlparslen);
  8884.     kzclose();
  8885.  
  8886.     j = n = 0;
  8887.  
  8888.         //parse vxlnam
  8889.     (*vxlnam) = &sxlbuf[j];
  8890.     while ((sxlbuf[j]!=13)&&(sxlbuf[j]!=10) && (j < sxlparslen)) j++; sxlbuf[j++] = 0;
  8891.     while (((sxlbuf[j]==13)||(sxlbuf[j]==10)) && (j < sxlparslen)) j++;
  8892.  
  8893.         //parse skynam
  8894.     (*skynam) = &sxlbuf[j];
  8895.     while ((sxlbuf[j]!=13)&&(sxlbuf[j]!=10) && (j < sxlparslen)) j++; sxlbuf[j++] = 0;
  8896.     while (((sxlbuf[j]==13)||(sxlbuf[j]==10)) && (j < sxlparslen)) j++;
  8897.  
  8898.         //parse globst
  8899.     m = n = j; (*globst) = &sxlbuf[n];
  8900.     while (((sxlbuf[j] == ' ') || (sxlbuf[j] == 9)) && (j < sxlparslen))
  8901.     {
  8902.         j++;
  8903.         while ((sxlbuf[j]!=13) && (sxlbuf[j]!=10) && (j < sxlparslen)) sxlbuf[n++] = sxlbuf[j++];
  8904.         sxlbuf[n++] = 13; j++;
  8905.         while (((sxlbuf[j]==13) || (sxlbuf[j]==10)) && (j < sxlparslen)) j++;
  8906.     }
  8907.     if (n > m) sxlbuf[n-1] = 0; else (*globst) = &nullst;
  8908.  
  8909.         //Count number of sprites in .SXL file (helpful for GAME)
  8910.     sxlparspos = j;
  8911.     return(1);
  8912. }
  8913.  
  8914. char *parspr (vx5sprite *spr, char **userst)
  8915. {
  8916.     float f;
  8917.     long j, k, m, n;
  8918.     char *namptr;
  8919.  
  8920.     j = sxlparspos; //unnecessary temp variable (to shorten code)
  8921.  
  8922.         //Automatically free temp sxlbuf when done reading sprites
  8923.     if (((j+2 < sxlparslen) && (sxlbuf[j] == 'e') && (sxlbuf[j+1] == 'n') && (sxlbuf[j+2] == 'd') &&
  8924.         ((j+3 == sxlparslen) || (sxlbuf[j+3] == 13) || (sxlbuf[j+3] == 10))) || (j > sxlparslen))
  8925.         return(0);
  8926.  
  8927.         //parse kv6name
  8928.     for(k=j;(sxlbuf[k]!=',') && (k < sxlparslen);k++); sxlbuf[k] = 0;
  8929.     namptr = &sxlbuf[j]; j = k+1;
  8930.  
  8931.         //parse 12 floats
  8932.     for(m=0;m<12;m++)
  8933.     {
  8934.         if (m < 11) { for(k=j;(sxlbuf[k]!=',') && (k < sxlparslen);k++); }
  8935.         else { for(k=j;(sxlbuf[k]!=13) && (sxlbuf[k]!=10) && (k < sxlparslen);k++); }
  8936.  
  8937.         sxlbuf[k] = 0; f = atof(&sxlbuf[j]); j = k+1;
  8938.         switch(m)
  8939.         {
  8940.             case  0: spr->p.x = f; break;
  8941.             case  1: spr->p.y = f; break;
  8942.             case  2: spr->p.z = f; break;
  8943.             case  3: spr->s.x = f; break;
  8944.             case  4: spr->s.y = f; break;
  8945.             case  5: spr->s.z = f; break;
  8946.             case  6: spr->h.x = f; break;
  8947.             case  7: spr->h.y = f; break;
  8948.             case  8: spr->h.z = f; break;
  8949.             case  9: spr->f.x = f; break;
  8950.             case 10: spr->f.y = f; break;
  8951.             case 11: spr->f.z = f; break;
  8952.             default: __assume(0); //tells MSVC default can't be reached
  8953.         }
  8954.     }
  8955.     while (((sxlbuf[j]==13) || (sxlbuf[j]==10)) && (j < sxlparslen)) j++;
  8956.  
  8957.     spr->flags = 0;
  8958.  
  8959.         //parse userst
  8960.     m = n = j; (*userst) = &sxlbuf[n];
  8961.     while (((sxlbuf[j] == ' ') || (sxlbuf[j] == 9)) && (j < sxlparslen))
  8962.     {
  8963.         j++;
  8964.         while ((sxlbuf[j]!=13) && (sxlbuf[j]!=10) && (j < sxlparslen)) sxlbuf[n++] = sxlbuf[j++];
  8965.         sxlbuf[n++] = 13; j++;
  8966.         while (((sxlbuf[j]==13) || (sxlbuf[j]==10)) && (j < sxlparslen)) j++;
  8967.     }
  8968.     if (n > m) sxlbuf[n-1] = 0; else (*userst) = &nullst;
  8969.  
  8970.     sxlparspos = j; //unnecessary temp variable (for short code)
  8971.     return(namptr);
  8972. }
  8973.  
  8974. //--------------------------  Name hash code begins --------------------------
  8975.  
  8976.     //khashbuf format: (used by getkv6/getkfa to avoid duplicate loads)
  8977.     //[long index to next hash or -1][pointer to struct][char type]string[\0]
  8978.     //[long index to next hash or -1][pointer to struct][chat type]string[\0]
  8979.     //...
  8980.     //type:0 = kv6data
  8981.     //type:1 = kfatype
  8982. #define KHASHINITSIZE 8192
  8983. static char *khashbuf = 0;
  8984. static long khashead[256], khashpos = 0, khashsiz = 0;
  8985.  
  8986. char *getkfilname (long namoff) { return(&khashbuf[namoff]); }
  8987.  
  8988.     //Returns: 0,retptr=-1: Error! (bad filename or out of memory)
  8989.     //         0,retptr>=0: Not in hash; new name allocated, valid index
  8990.     //         1,retptr>=0: Already in hash, valid index
  8991.     //   Uses a 256-entry hash to compare names very quickly.
  8992. static long inkhash (const char *filnam, long *retind)
  8993. {
  8994.     long i, j, hashind;
  8995.  
  8996.     (*retind) = -1;
  8997.  
  8998.     if (!filnam) return(0);
  8999.     j = strlen(filnam); if (!j) return(0);
  9000.     j += 10;
  9001.     if (khashpos+j > khashsiz) //Make sure string fits in khashbuf
  9002.     {
  9003.         i = khashsiz; do { i <<= 1; } while (khashpos+j > i);
  9004.         if (!(khashbuf = (char *)realloc(khashbuf,i))) return(0);
  9005.         khashsiz = i;
  9006.     }
  9007.  
  9008.         //Copy filename to avoid destroying original string
  9009.         //Also, calculate hash index (which hopefully is uniformly random :)
  9010.     strcpy(&khashbuf[khashpos+9],filnam);
  9011.     for(i=khashpos+9,hashind=0;khashbuf[i];i++)
  9012.     {
  9013.         if ((khashbuf[i] >= 'a') && (khashbuf[i] <= 'z')) khashbuf[i] -= 32;
  9014.         if (khashbuf[i] == '/') khashbuf[i] = '\\';
  9015.         hashind = (khashbuf[i] - hashind*3);
  9016.     }
  9017.     hashind %= (sizeof(khashead)/sizeof(khashead[0]));
  9018.  
  9019.         //Find if string is already in hash...
  9020.     for(i=khashead[hashind];i>=0;i=(*(long *)&khashbuf[i]))
  9021.         if (!strcmp(&khashbuf[i+9],&khashbuf[khashpos+9]))
  9022.             { (*retind) = i; return(1); } //Early out: already in hash
  9023.  
  9024.     (*retind) = khashpos;
  9025.     *(long *)&khashbuf[khashpos] = khashead[hashind];
  9026.     *(long *)&khashbuf[khashpos+4] = 0; //Set to 0 just in case load fails
  9027.     khashead[hashind] = khashpos; khashpos += j;
  9028.     return(0);
  9029. }
  9030.  
  9031. //-------------------------- KV6 sprite code begins --------------------------
  9032.  
  9033. //EQUIVEC code begins -----------------------------------------------------
  9034. point3d univec[256];
  9035. __declspec(align(8)) short iunivec[256][4];
  9036.  
  9037. typedef struct
  9038. {
  9039.     float fibx[45], fiby[45];
  9040.     float azval[20], zmulk, zaddk;
  9041.     long fib[47], aztop, npoints;
  9042. } equivectyp;
  9043. static equivectyp equivec;
  9044.  
  9045. #ifdef _MSC_VER
  9046.  
  9047. static _inline long dmulshr0 (long a, long d, long s, long t)
  9048. {
  9049.     _asm
  9050.     {
  9051.         mov eax, a
  9052.         imul d
  9053.         mov ecx, eax
  9054.         mov eax, s
  9055.         imul t
  9056.         add eax, ecx
  9057.     }
  9058. }
  9059.  
  9060. #endif
  9061.  
  9062. void equiind2vec (long i, float *x, float *y, float *z)
  9063. {
  9064.     float r;
  9065.     (*z) = (float)i*equivec.zmulk + equivec.zaddk; r = sqrt(1.f - (*z)*(*z));
  9066.     fcossin((float)i*(GOLDRAT*PI*2),x,y); (*x) *= r; (*y) *= r;
  9067. }
  9068.  
  9069.     //Very fast; good quality
  9070. long equivec2indmem (float x, float y, float z)
  9071. {
  9072.     long b, i, j, k, bestc;
  9073.     float xy, zz, md, d;
  9074.  
  9075.     xy = atan2(y,x); //atan2 is 150 clock cycles!
  9076.     j = ((*(long *)&z)&0x7fffffff);
  9077.     bestc = equivec.aztop;
  9078.     do
  9079.     {
  9080.         if (j < *(long *)&equivec.azval[bestc]) break;
  9081.         bestc--;
  9082.     } while (bestc);
  9083.  
  9084.     zz = z + 1.f;
  9085.     ftol(equivec.fibx[bestc]*xy + equivec.fiby[bestc]*zz - .5,&i);
  9086.     bestc++;
  9087.     ftol(equivec.fibx[bestc]*xy + equivec.fiby[bestc]*zz - .5,&j);
  9088.  
  9089.     k = dmulshr0(equivec.fib[bestc+2],i,equivec.fib[bestc+1],j);
  9090.     if ((unsigned long)k < equivec.npoints)
  9091.     {
  9092.         md = univec[k].x*x + univec[k].y*y + univec[k].z*z;
  9093.         j = k;
  9094.     } else md = -2.f;
  9095.     b = bestc+3;
  9096.     do
  9097.     {
  9098.         i = equivec.fib[b] + k;
  9099.         if ((unsigned long)i < equivec.npoints)
  9100.         {
  9101.             d = univec[i].x*x + univec[i].y*y + univec[i].z*z;
  9102.             if (*(long *)&d > *(long *)&md) { md = d; j = i; }
  9103.         }
  9104.         b--;
  9105.     } while (b != bestc);
  9106.     return(j);
  9107. }
  9108.  
  9109. void equivecinit (long n)
  9110. {
  9111.     float t0, t1;
  9112.     long z;
  9113.  
  9114.         //Init constants for ind2vec
  9115.     equivec.npoints = n;
  9116.     equivec.zmulk = 2 / (float)n; equivec.zaddk = equivec.zmulk*.5 - 1.0;
  9117.  
  9118.         //equimemset
  9119.     for(z=n-1;z>=0;z--)
  9120.         equiind2vec(z,&univec[z].x,&univec[z].y,&univec[z].z);
  9121.     if (n&1) //Hack for when n=255 and want a <0,0,0> vector
  9122.         { univec[n].x = univec[n].y = univec[n].z = 0; }
  9123.  
  9124.         //Init Fibonacci table
  9125.     equivec.fib[0] = 0; equivec.fib[1] = 1;
  9126.     for(z=2;z<47;z++) equivec.fib[z] = equivec.fib[z-2]+equivec.fib[z-1];
  9127.  
  9128.         //Init fibx/y LUT
  9129.     t0 = .5 / PI; t1 = (float)n * -.5;
  9130.     for(z=0;z<45;z++)
  9131.     {
  9132.         t0 = -t0; equivec.fibx[z] = (float)equivec.fib[z+2]*t0;
  9133.         t1 = -t1; equivec.fiby[z] = ((float)equivec.fib[z+2]*GOLDRAT - (float)equivec.fib[z])*t1;
  9134.     }
  9135.  
  9136.     t0 = 1 / ((float)n * PI);
  9137.     for(equivec.aztop=0;equivec.aztop<20;equivec.aztop++)
  9138.     {
  9139.         t1 = 1 - (float)equivec.fib[(equivec.aztop<<1)+6]*t0; if (t1 < 0) break;
  9140.         equivec.azval[equivec.aztop+1] = sqrt(t1);
  9141.     }
  9142. }
  9143.  
  9144. //EQUIVEC code ends -------------------------------------------------------
  9145.  
  9146. static long umulmip[9] = {0,4294967295,2147483648,1431655765,1073741824,
  9147.                                   858993459,715827882,613566756,536870912};
  9148. kv6data *genmipkv6 (kv6data *kv6)
  9149. {
  9150.     kv6data *nkv6;
  9151.     kv6voxtype *v0[2], *vs[4], *ve[4], *voxptr;
  9152.     unsigned short *xyptr, *xyi2, *sxyi2;
  9153.     long i, j, x, y, z, xs, ys, zs, xysiz, n, oxn, oxyn, *xptr;
  9154.     long xx, yy, zz, r, g, b, vis, npix, sxyi2i, darand = 0;
  9155.     char vecbuf[8];
  9156.  
  9157.     if ((!kv6) || (kv6->lowermip)) return(0);
  9158.  
  9159.     xs = ((kv6->xsiz+1)>>1); ys = ((kv6->ysiz+1)>>1); zs = ((kv6->zsiz+1)>>1);
  9160.     if ((xs < 2) || (ys < 2) || (zs < 2)) return(0);
  9161.     xysiz = ((((xs*ys)<<1)+3)&~3);
  9162.     i = sizeof(kv6data) + (xs<<2) + xysiz + kv6->numvoxs*sizeof(kv6voxtype);
  9163.     nkv6 = (kv6data *)malloc(i);
  9164.     if (!nkv6) return(0);
  9165.  
  9166.     kv6->lowermip = nkv6;
  9167.     nkv6->xsiz = xs;
  9168.     nkv6->ysiz = ys;
  9169.     nkv6->zsiz = zs;
  9170.     nkv6->xpiv = kv6->xpiv*.5;
  9171.     nkv6->ypiv = kv6->ypiv*.5;
  9172.     nkv6->zpiv = kv6->zpiv*.5;
  9173.     nkv6->namoff = 0;
  9174.     nkv6->lowermip = 0;
  9175.  
  9176.     xptr = (long *)(((long)nkv6) + sizeof(kv6data));
  9177.     xyptr = (unsigned short *)(((long)xptr) + (xs<<2));
  9178.     voxptr = (kv6voxtype *)(((long)xyptr) + xysiz);
  9179.     n = 0;
  9180.  
  9181.     v0[0] = kv6->vox; sxyi2 = kv6->ylen; sxyi2i = (kv6->ysiz<<1);
  9182.     for(x=0;x<xs;x++)
  9183.     {
  9184.         v0[1] = v0[0]+kv6->xlen[x<<1];
  9185.  
  9186.             //vs: start pointer of each of the 4 columns
  9187.             //ve: end pointer of each of the 4 columns
  9188.         vs[0] = v0[0]; vs[2] = v0[1];
  9189.  
  9190.         xyi2 = sxyi2; sxyi2 += sxyi2i;
  9191.  
  9192.         oxn = n;
  9193.         for(y=0;y<ys;y++)
  9194.         {
  9195.             oxyn = n;
  9196.  
  9197.             ve[0] = vs[1] = vs[0]+xyi2[0];
  9198.             if ((x<<1)+1 < kv6->xsiz) { ve[2] = vs[3] = vs[2]+xyi2[kv6->ysiz]; }
  9199.             if ((y<<1)+1 < kv6->ysiz)
  9200.             {
  9201.                 ve[1] = vs[1]+xyi2[1];
  9202.                 if ((x<<1)+1 < kv6->xsiz) ve[3] = vs[3]+xyi2[kv6->ysiz+1];
  9203.             }
  9204.             xyi2 += 2;
  9205.  
  9206.             while (1)
  9207.             {
  9208.                 z = 0x7fffffff;
  9209.                 for(i=3;i>=0;i--)
  9210.                     if ((vs[i] < ve[i]) && (vs[i]->z < z)) z = vs[i]->z;
  9211.                 if (z == 0x7fffffff) break;
  9212.  
  9213.                 z |= 1;
  9214.  
  9215.                 r = g = b = vis = npix = 0;
  9216.                 for(i=3;i>=0;i--)
  9217.                     for(zz=z-1;zz<=z;zz++)
  9218.                     {
  9219.                         if ((vs[i] >= ve[i]) || (vs[i]->z > zz)) continue;
  9220.                         r += (vs[i]->col&0xff00ff); //MMX-style trick!
  9221.                         g += (vs[i]->col&  0xff00);
  9222.                         //b += (vs[i]->col&    0xff);
  9223.                         vis |= vs[i]->vis;
  9224.                         vecbuf[npix] = vs[i]->dir;
  9225.                         npix++; vs[i]++;
  9226.                     }
  9227.  
  9228.                 if (npix)
  9229.                 {
  9230.                     if (n >= kv6->numvoxs) return(0); //Don't let it crash!
  9231.  
  9232.                     i = umulmip[npix]; j = (npix>>1);
  9233.                     voxptr[n].col = (umulshr32(r+(j<<16),i)&0xff0000) +
  9234.                                          (umulshr32(g+(j<< 8),i)&  0xff00) +
  9235.                                          (umulshr32((r&0xfff)+ j     ,i));
  9236.                     voxptr[n].z = (z>>1);
  9237.                     voxptr[n].vis = vis;
  9238.                     voxptr[n].dir = vecbuf[umulshr32(darand,npix)]; darand += i;
  9239.                     n++;
  9240.                 }
  9241.             }
  9242.             xyptr[0] = n-oxyn; xyptr++;
  9243.             vs[0] = ve[1]; vs[2] = ve[3];
  9244.         }
  9245.         xptr[x] = n-oxn;
  9246.         if ((x<<1)+1 >= kv6->xsiz) break; //Avoid read page fault
  9247.         v0[0] = v0[1]+kv6->xlen[(x<<1)+1];
  9248.     }
  9249.  
  9250.     nkv6->leng = sizeof(kv6data) + (xs<<2) + xysiz + n*sizeof(kv6voxtype);
  9251.     nkv6 = (kv6data *)realloc(nkv6,nkv6->leng); if (!nkv6) return(0);
  9252.     nkv6->xlen = (unsigned long *)(((long)nkv6) + sizeof(kv6data));
  9253.     nkv6->ylen = (unsigned short *)(((long)nkv6->xlen) + (xs<<2));
  9254.     nkv6->vox = (kv6voxtype *)(((long)nkv6->ylen) + xysiz);
  9255.     nkv6->numvoxs = n;
  9256.     kv6->lowermip = nkv6;
  9257.     return(nkv6);
  9258. }
  9259.  
  9260. void savekv6 (const char *filnam, kv6data *kv)
  9261. {
  9262.     FILE *fil;
  9263.     long i;
  9264.  
  9265.     if (fil = fopen(filnam,"wb"))
  9266.     {
  9267.         i = 0x6c78764b; fwrite(&i,4,1,fil); //Kvxl
  9268.         fwrite(&kv->xsiz,4,1,fil); fwrite(&kv->ysiz,4,1,fil); fwrite(&kv->zsiz,4,1,fil);
  9269.         fwrite(&kv->xpiv,4,1,fil); fwrite(&kv->ypiv,4,1,fil); fwrite(&kv->zpiv,4,1,fil);
  9270.         fwrite(&kv->numvoxs,4,1,fil);
  9271.         fwrite(kv->vox,kv->numvoxs*sizeof(kv6voxtype),1,fil);
  9272.         fwrite(kv->xlen,kv->xsiz*sizeof(long),1,fil);
  9273.         fwrite(kv->ylen,kv->xsiz*kv->ysiz*sizeof(short),1,fil);
  9274.         fclose(fil);
  9275.     }
  9276. }
  9277.  
  9278.     //NOTE: should make this inline to getkv6!
  9279. static kv6data *loadkv6 (const char *filnam)
  9280. {
  9281.     FILE *fil;
  9282.     kv6data tk, *newkv6;
  9283.     long i;
  9284.  
  9285.     if (!kzopen(filnam))
  9286.     {
  9287.             //File not found, but allocate a structure anyway
  9288.             //   so it can keep track of the filename
  9289.         if (!(newkv6 = (kv6data *)malloc(sizeof(kv6data)))) return(0);
  9290.         newkv6->leng = sizeof(kv6data);
  9291.         newkv6->xsiz = newkv6->ysiz = newkv6->zsiz = 0;
  9292.         newkv6->xpiv = newkv6->ypiv = newkv6->zpiv = 0;
  9293.         newkv6->numvoxs = 0;
  9294.         newkv6->namoff = 0;
  9295.         newkv6->lowermip = 0;
  9296.         newkv6->vox = (kv6voxtype *)(((long)newkv6)+sizeof(kv6data));
  9297.         newkv6->xlen = (unsigned long *)newkv6->vox;
  9298.         newkv6->ylen = (unsigned short *)newkv6->xlen;
  9299.         return(newkv6);
  9300.     }
  9301.  
  9302.     kzread((void *)&tk,32);
  9303.  
  9304.     i = tk.numvoxs*sizeof(kv6voxtype) + tk.xsiz*4 + tk.xsiz*tk.ysiz*2;
  9305.     newkv6 = (kv6data *)malloc(i+sizeof(kv6data));
  9306.     if (!newkv6) { kzclose(); return(0); }
  9307.     if (((long)newkv6)&3) evilquit("getkv6 malloc not 32-bit aligned!");
  9308.  
  9309.     newkv6->leng = i+sizeof(kv6data);
  9310.     memcpy(&newkv6->xsiz,&tk.xsiz,28);
  9311.     newkv6->namoff = 0;
  9312.     newkv6->lowermip = 0;
  9313.     newkv6->vox = (kv6voxtype *)(((long)newkv6)+sizeof(kv6data));
  9314.     newkv6->xlen = (unsigned long *)(((long)newkv6->vox)+tk.numvoxs*sizeof(kv6voxtype));
  9315.     newkv6->ylen = (unsigned short *)(((long)newkv6->xlen) + tk.xsiz*4);
  9316.  
  9317.     kzread((void *)newkv6->vox,i);
  9318.     kzclose();
  9319.     return(newkv6);
  9320. }
  9321.  
  9322.     //Cover-up function for LOADKV6: returns a pointer to the loaded kv6data
  9323.     //   structure. Loads file only if not already loaded before with getkv6.
  9324. kv6data *getkv6 (const char *filnam)
  9325. {
  9326.     kv6data *kv6ptr;
  9327.     long i;
  9328.  
  9329.     if (inkhash(filnam,&i)) return(*(kv6data **)&khashbuf[i+4]);
  9330.     if (i == -1) return(0);
  9331.  
  9332.     if (kv6ptr = loadkv6((char *)&khashbuf[i+9]))
  9333.         kv6ptr->namoff = i+9; //Must use offset for ptr->name conversion
  9334.  
  9335.     *(kv6data **)&khashbuf[i+4] = kv6ptr;
  9336.     *(char *)&khashbuf[i+8] = 0; //0 for KV6
  9337.     return(kv6ptr);
  9338. }
  9339.  
  9340. #ifdef __cplusplus
  9341. extern "C" {
  9342. #endif
  9343.  
  9344. extern void *caddasm;
  9345. #define cadd4 ((point4d *)&caddasm)
  9346. extern void *ztabasm;
  9347. #define ztab4 ((point4d *)&ztabasm)
  9348. extern short qsum0[4], qsum1[4], qbplbpp[4];
  9349. extern long kv6frameplace, kv6bytesperline;
  9350. extern float scisdist;
  9351. extern __int64 kv6colmul[256], kv6coladd[256];
  9352.  
  9353. char ptfaces16[43][8] =
  9354. {
  9355.     0, 0, 0,  0,  0, 0, 0,0,  4, 0,32,96, 64, 0,32,0,  4,16,80,112,48, 16,80,0,  0,0,0,0,0,0,0,0,
  9356.     4,64,96,112, 80,64,96,0,  6, 0,32,96,112,80,64,0,  6,16,80, 64,96,112,48,0,  0,0,0,0,0,0,0,0,
  9357.     4, 0,16, 48, 32, 0,16,0,  6, 0,16,48, 32,96,64,0,  6, 0,16, 80,112,48,32,0,  0,0,0,0,0,0,0,0,
  9358.     0, 0, 0,  0,  0, 0, 0,0,  0, 0, 0, 0,  0, 0, 0,0,  0, 0, 0,  0,  0, 0, 0,0,  0,0,0,0,0,0,0,0,
  9359.     4, 0,64, 80, 16, 0,64,0,  6, 0,32,96, 64,80,16,0,  6, 0,64, 80,112,48,16,0,  0,0,0,0,0,0,0,0,
  9360.     6, 0,64, 96,112,80,16,0,  6, 0,32,96,112,80,16,0,  6, 0,64, 96,112,48,16,0,  0,0,0,0,0,0,0,0,
  9361.     6, 0,64, 80, 16,48,32,0,  6,16,48,32, 96,64,80,0,  6, 0,64, 80,112,48,32,0,  0,0,0,0,0,0,0,0,
  9362.     0, 0, 0,  0,  0, 0, 0,0,  0, 0, 0, 0,  0, 0, 0,0,  0, 0, 0,  0,  0, 0, 0,0,  0,0,0,0,0,0,0,0,
  9363.     4,32,48,112, 96,32,48,0,  6, 0,32,48,112,96,64,0,  6,16,80,112, 96,32,48,0,  0,0,0,0,0,0,0,0,
  9364.     6,32,48,112, 80,64,96,0,  6, 0,32,48,112,80,64,0,  6,16,80, 64, 96,32,48,0,  0,0,0,0,0,0,0,0,
  9365.     6, 0,16, 48,112,96,32,0,  6, 0,16,48,112,96,64,0,  6, 0,16, 80,112,96,32,0,
  9366. };
  9367.  
  9368. void drawboundcubesseinit ();
  9369. void drawboundcubesse (kv6voxtype *, long);
  9370. void drawboundcube3dninit ();
  9371. void drawboundcube3dn (kv6voxtype *, long);
  9372.  
  9373. #ifdef __cplusplus
  9374. }
  9375. #endif
  9376.  
  9377. //static void initboundcubescr (long dafram, long dabpl, long x, long y, long dabpp)
  9378. //{
  9379. //   qsum1[3] = qsum1[1] = 0x7fff-y; qsum1[2] = qsum1[0] = 0x7fff-x;
  9380. //   qbplbpp[1] = dabpl; qbplbpp[0] = ((dabpp+7)>>3);
  9381. //   kv6frameplace = dafram; kv6bytesperline = dabpl;
  9382. //}
  9383.  
  9384. static __declspec(align(8)) short lightlist[MAXLIGHTS+1][4];
  9385. static __int64 all32767 = 0x7fff7fff7fff7fff;
  9386.  
  9387. static void updatereflects (vx5sprite *spr)
  9388. {
  9389.     __int64 fogmul;
  9390.     point3d tp;
  9391.     float f, g, h, fx, fy, fz;
  9392.     long i, j;
  9393.  
  9394. #if 0
  9395.     KV6 lighting calculations for: fog, white, black, intens(normal dot product), black currently not supported!
  9396.  
  9397.     long vx5.kv6black = 0x000000, vx5.kv6white = 0x808080;
  9398.     long nw.r = vx5.kv6white.r-vx5.kv6black.r, nb.r = vx5.kv6black.r*2;
  9399.     long nw.g = vx5.kv6white.g-vx5.kv6black.g, nb.g = vx5.kv6black.g*2;
  9400.     long nw.b = vx5.kv6white.b-vx5.kv6black.b, nb.b = vx5.kv6black.b*2;
  9401.     col.r = mulshr7(col.r,nw.r)+nb.r; col.r = mulshr7(col.r,intens); col.r += mulshr15(fogcol.r-col.r,fogmul);
  9402.     col.g = mulshr7(col.g,nw.g)+nb.g; col.g = mulshr7(col.g,intens); col.g += mulshr15(fogcol.g-col.g,fogmul);
  9403.     col.b = mulshr7(col.b,nw.b)+nb.b; col.b = mulshr7(col.b,intens); col.b += mulshr15(fogcol.b-col.b,fogmul);
  9404.  
  9405.     col.r = ((col.r*intens*nw.r*(32767-fogmul))>>29) +
  9406.               ((      intens*nb.r*(32767-fogmul))>>22) + ((fogcol.r*fogmul)>>15);
  9407.     col.g = ((col.g*intens*nw.g*(32767-fogmul))>>29) +
  9408.               ((      intens*nb.g*(32767-fogmul))>>22) + ((fogcol.g*fogmul)>>15);
  9409.     col.b = ((col.b*intens*nw.b*(32767-fogmul))>>29) +
  9410.               ((      intens*nb.b*(32767-fogmul))>>22) + ((fogcol.b*fogmul)>>15);
  9411. #endif
  9412.  
  9413.         //Use cylindrical x-y distance for fog
  9414.     if (ofogdist >= 0)
  9415.     {
  9416.         ftol(sqrt((spr->p.x-gipos.x)*(spr->p.x-gipos.x) + (spr->p.y-gipos.y)*(spr->p.y-gipos.y)),&i);
  9417.         if (i > 2047) i = 2047;
  9418.         fogmul = foglut[i];
  9419.  
  9420. #if 0
  9421.         i = (long)(*(short *)&fogmul);
  9422.         ((short *)kv6coladd)[0] = (short)((((long)(((short *)&fogcol)[0]))*i)>>1);
  9423.         ((short *)kv6coladd)[1] = (short)((((long)(((short *)&fogcol)[1]))*i)>>1);
  9424.         ((short *)kv6coladd)[2] = (short)((((long)(((short *)&fogcol)[2]))*i)>>1);
  9425. #else
  9426.         _asm
  9427.         {
  9428.             movq mm0, fogcol
  9429.             paddd mm0, mm0
  9430.             pmulhuw mm0, fogmul
  9431.             movq kv6coladd[0], mm0
  9432.             emms
  9433.         }
  9434. #endif
  9435.     } else { fogmul = 0I64; kv6coladd[0] = 0I64; }
  9436.  
  9437.     if (spr->flags&1)
  9438.     {
  9439.         //((short *)kv6colmul)[0] = 0x010001000100;                                        //Do (nothing)
  9440.           ((short *)kv6colmul)[0] = (short)((vx5.kv6col&255)<<1);                          //Do     white
  9441.         //((short *)kv6colmul)[0] = (short)((32767-(short)fogmul)>>7);                     //Do fog
  9442.         //((short *)kv6colmul)[0] = (short)(((32767-(short)fogmul)*(vx5.kv6col&255))>>14); //Do fog&white
  9443.  
  9444.         ((short *)kv6colmul)[1] = ((short *)kv6colmul)[0];
  9445.         ((short *)kv6colmul)[2] = ((short *)kv6colmul)[0];
  9446.         ((short *)kv6colmul)[3] = 0;
  9447.         for(i=1;i<256;i++) kv6colmul[i] = kv6colmul[0];
  9448.         return;
  9449.     }
  9450.  
  9451.     if (vx5.lightmode < 2)
  9452.     {
  9453.         fx = 1.0; fy = 1.0; fz = 1.0;
  9454.         tp.x = spr->s.x*fx + spr->s.y*fy + spr->s.z*fz;
  9455.         tp.y = spr->h.x*fx + spr->h.y*fy + spr->h.z*fz;
  9456.         tp.z = spr->f.x*fx + spr->f.y*fy + spr->f.z*fz;
  9457.  
  9458.         f = 64.0 / sqrt(tp.x*tp.x + tp.y*tp.y + tp.z*tp.z);
  9459.  
  9460.             //for(i=255;i>=0;i--)
  9461.             //{
  9462.             //   ftol(univec[i].x*tp.x + univec[i].y*tp.y + univec[i].z*tp.z,&j);
  9463.             //   j = (lbound0(j+128,255)<<8);
  9464.             //   ((unsigned short *)(&kv6colmul[i]))[0] = j;
  9465.             //   ((unsigned short *)(&kv6colmul[i]))[1] = j;
  9466.             //   ((unsigned short *)(&kv6colmul[i]))[2] = j;
  9467.             //}
  9468.         g = ((float)((((long)fogmul)&32767)^32767))*(16.f*8.f/65536.f);
  9469.         if (!(((vx5.kv6col&0xffff)<<8)^(vx5.kv6col&0xffff00))) //Cool way to check if R==G==B :)
  9470.         {
  9471.             g *= ((float)(vx5.kv6col&255))/256.f;
  9472.                 //This case saves 1 MMX multiply per iteration
  9473.             f *= g;
  9474.             lightlist[0][0] = (short)(tp.x*f);
  9475.             lightlist[0][1] = (short)(tp.y*f);
  9476.             lightlist[0][2] = (short)(tp.z*f);
  9477.             lightlist[0][3] = (short)(g*128.f);
  9478.             _asm
  9479.             {
  9480.                 movq mm6, lightlist[0]
  9481.                 mov ecx, 255*8
  9482.   nolighta: movq mm0, iunivec[ecx]
  9483.                 movq mm1, iunivec[ecx-8]
  9484.                 pmaddwd mm0, mm6 ;mm0: [tp.a*iunivec.a + tp.z*iunivec.z][tp.y*iunivec.y + tp.x*iunivec.x]
  9485.                 pmaddwd mm1, mm6
  9486.                 pshufw mm2, mm0, 0x4e  ;Before: mm0: [ 0 ][ a ][   ][   ][ 0 ][ b ][   ][   ]
  9487.                 pshufw mm3, mm1, 0x4e
  9488.                 paddd mm0, mm2
  9489.                 paddd mm1, mm3
  9490.                 pshufw mm0, mm0, 0x55
  9491.                 pshufw mm1, mm1, 0x55  ;After:  mm0: [   ][   ][   ][a+b][   ][a+b][   ][a+b]
  9492.                 movq kv6colmul[ecx], mm0
  9493.                 movq kv6colmul[ecx-8], mm1
  9494.                 sub ecx, 2*8
  9495.                 jnc short nolighta
  9496.             }
  9497.         }
  9498.         else
  9499.         {
  9500.             f *= g;
  9501.             lightlist[0][0] = (short)(tp.x*f);
  9502.             lightlist[0][1] = (short)(tp.y*f);
  9503.             lightlist[0][2] = (short)(tp.z*f);
  9504.             lightlist[0][3] = (short)(g*128.f);
  9505.             _asm
  9506.             {
  9507.                 punpcklbw mm5, vx5.kv6col
  9508.                 movq mm6, lightlist[0]
  9509.                 mov ecx, 255*8
  9510.   nolightb: movq mm0, iunivec[ecx]
  9511.                 movq mm1, iunivec[ecx-8]
  9512.                 pmaddwd mm0, mm6 ;mm0: [tp.a*iunivec.a + tp.z*iunivec.z][tp.y*iunivec.y + tp.x*iunivec.x]
  9513.                 pmaddwd mm1, mm6
  9514.                 pshufw mm2, mm0, 0x4e ;Before: mm0: [ 0 ][ a ][   ][   ][ 0 ][ b ][   ][   ]
  9515.                 pshufw mm3, mm1, 0x4e
  9516.                 paddd mm0, mm2
  9517.                 paddd mm1, mm3
  9518.                 pshufw mm0, mm0, 0x55
  9519.                 pshufw mm1, mm1, 0x55 ;After:  mm0: [   ][   ][   ][a+b][   ][a+b][   ][a+b]
  9520.                 pmulhuw mm0, mm5
  9521.                 pmulhuw mm1, mm5
  9522.                 movq kv6colmul[ecx], mm0
  9523.                 movq kv6colmul[ecx-8], mm1
  9524.                 sub ecx, 2*8
  9525.                 jnc short nolightb
  9526.             }
  9527.         }
  9528.         //NOTE: emms not necessary!
  9529.     }
  9530.     else
  9531.     {
  9532.         point3d sprs, sprh, sprf;
  9533.         float ff, gg, hh;
  9534.         long k, lightcnt;
  9535.  
  9536.             //WARNING: this only works properly for orthonormal matrices!
  9537.         f = 1.0 / sqrt(spr->s.x*spr->s.x + spr->s.y*spr->s.y + spr->s.z*spr->s.z);
  9538.         sprs.x = spr->s.x*f; sprs.y = spr->s.y*f; sprs.z = spr->s.z*f;
  9539.         f = 1.0 / sqrt(spr->h.x*spr->h.x + spr->h.y*spr->h.y + spr->h.z*spr->h.z);
  9540.         sprh.x = spr->h.x*f; sprh.y = spr->h.y*f; sprh.z = spr->h.z*f;
  9541.         f = 1.0 / sqrt(spr->f.x*spr->f.x + spr->f.y*spr->f.y + spr->f.z*spr->f.z);
  9542.         sprf.x = spr->f.x*f; sprf.y = spr->f.y*f; sprf.z = spr->f.z*f;
  9543.  
  9544.         hh = ((float)((((long)fogmul)&32767)^32767))/65536.f * 2.f;
  9545.  
  9546.  
  9547.             //Find which lights are close enough to affect sprite.
  9548.         lightcnt = 0;
  9549.         for(i=vx5.numlights-1;i>=0;i--)
  9550.         {
  9551.             fx = vx5.lightsrc[i].p.x-(spr->p.x);
  9552.             fy = vx5.lightsrc[i].p.y-(spr->p.y);
  9553.             fz = vx5.lightsrc[i].p.z-(spr->p.z);
  9554.             gg = fx*fx + fy*fy + fz*fz; ff = vx5.lightsrc[i].r2;
  9555.             if (*(long *)&gg < *(long *)&ff)
  9556.             {
  9557.                 f = sqrt(ff); g = sqrt(gg);
  9558.                 //h = (16.0/(sqrt(gg)*gg) - 16.0/(sqrt(ff)*ff))*vx5.lightsrc[i].sc;
  9559.                 h = (f*ff - g*gg)/(f*ff*g*gg) * vx5.lightsrc[i].sc*16.0;
  9560.                 if (g*h > 4096.0) h = 4096.0/g; //Max saturation clipping
  9561.                 h *= hh;
  9562.                 lightlist[lightcnt][0] = (short)((fx*sprs.x + fy*sprs.y + fz*sprs.z)*h);
  9563.                 lightlist[lightcnt][1] = (short)((fx*sprh.x + fy*sprh.y + fz*sprh.z)*h);
  9564.                 lightlist[lightcnt][2] = (short)((fx*sprf.x + fy*sprf.y + fz*sprf.z)*h);
  9565.                 lightlist[lightcnt][3] = 0;
  9566.                 lightcnt++;
  9567.             }
  9568.         }
  9569.  
  9570.         fx = 0.0; fy = 0.5; fz = 1.0;
  9571.  
  9572.             //tp.x = (sprs.x*fx + sprs.y*fy + sprs.z*fz)*16.0;
  9573.             //tp.y = (sprh.x*fx + sprh.y*fy + sprh.z*fz)*16.0;
  9574.             //tp.z = (sprf.x*fx + sprf.y*fy + sprf.z*fz)*16.0;
  9575.             //for(i=255;i>=0;i--)
  9576.             //{
  9577.             //   f = tp.x*univec[i].x + tp.y*univec[i].y + tp.z*univec[i].z + 48;
  9578.             //   for(k=lightcnt-1;k>=0;k--)
  9579.             //   {
  9580.             //      h = lightlist[k].x*univec[i].x + lightlist[k].y*univec[i].y + lightlist[k].z*univec[i].z;
  9581.             //      if (*(long *)&h < 0) f -= h;
  9582.             //   }
  9583.             //   if (f > 255) f = 255;
  9584.             //   ftol(f,&j); j <<= 8;
  9585.             //   ((unsigned short *)(&kv6colmul[i]))[0] = j;
  9586.             //   ((unsigned short *)(&kv6colmul[i]))[1] = j;
  9587.             //   ((unsigned short *)(&kv6colmul[i]))[2] = j;
  9588.             //}
  9589.         hh *= 16*16.f*8.f/2.f;
  9590.         lightlist[lightcnt][0] = (short)((sprs.x*fx + sprs.y*fy + sprs.z*fz)*hh);
  9591.         lightlist[lightcnt][1] = (short)((sprh.x*fx + sprh.y*fy + sprh.z*fz)*hh);
  9592.         lightlist[lightcnt][2] = (short)((sprf.x*fx + sprf.y*fy + sprf.z*fz)*hh);
  9593.         lightlist[lightcnt][3] = (short)(hh*(48/16.0));
  9594.         _asm
  9595.         {
  9596.             punpcklbw mm5, vx5.kv6col
  9597.             pxor mm6, mm6
  9598.             mov edx, lightcnt
  9599.             shl edx, 3
  9600.             mov ecx, 255*8
  9601. beglig:  movq mm3, iunivec[ecx]   ;mm3: 256 u[i].z*256 u[i].y*256 u[i].x*256
  9602.             mov eax, edx
  9603.             movq mm0, lightlist[edx] ;mm0: 48*256,0 tp.z*256 tp.y*256 tp.x*256
  9604.             pmaddwd mm0, mm3
  9605.             pshufw mm2, mm0, 0x4e
  9606.             paddd mm0, mm2
  9607.             sub eax, 8
  9608.             js short endlig
  9609. beglig2: movq mm1, lightlist[eax] ;mm1: 0 tp.z*256 tp.y*256 tp.x*256
  9610.             pmaddwd mm1, mm3
  9611.             pshufw mm2, mm1, 0x4e
  9612.             paddd mm1, mm2
  9613.             pminsw mm1, mm6          ;16-bits is ugly, but ok here
  9614.             psubd mm0, mm1
  9615.             sub eax, 8
  9616.             jns short beglig2        ;mm0: 00 II ii ii 00 II ii ii
  9617. endlig:  pshufw mm0, mm0, 0x55    ;mm0: 00 II 00 II 00 II 00 II
  9618.             pmulhuw mm0, mm5
  9619.             movq kv6colmul[ecx], mm0
  9620.             sub ecx, 8
  9621.             jnc short beglig
  9622.         }
  9623.         //NOTE: emms not necessary!
  9624.     }
  9625. }
  9626.  
  9627. #ifdef _MSC_VER
  9628.  
  9629. static _inline void movps (point4d *dest, point4d *src)
  9630. {
  9631.     _asm
  9632.     {
  9633.         mov eax, src
  9634.         movaps xmm7, [eax]
  9635.         mov eax, dest
  9636.         movaps [eax], xmm7
  9637.     }
  9638. }
  9639.  
  9640. static _inline void intss (point4d *dest, long src)
  9641. {
  9642.     _asm
  9643.     {
  9644.         mov eax, dest
  9645.         cvtsi2ss xmm7, src
  9646.         shufps xmm7, xmm7, 0
  9647.         movaps [eax], xmm7
  9648.     }
  9649. }
  9650.  
  9651. static _inline void addps (point4d *sum, point4d *a, point4d *b)
  9652. {
  9653.     _asm
  9654.     {
  9655.         mov eax, a
  9656.         movaps xmm7, [eax]
  9657.         mov eax, b
  9658.         addps xmm7, [eax]
  9659.         mov eax, sum
  9660.         movaps [eax], xmm7
  9661.     }
  9662. }
  9663.  
  9664. static _inline void mulps (point4d *sum, point4d *a, point4d *b)
  9665. {
  9666.     _asm
  9667.     {
  9668.         mov eax, a
  9669.         movaps xmm7, [eax]
  9670.         mov eax, b
  9671.         mulps xmm7, [eax]
  9672.         mov eax, sum
  9673.         movaps [eax], xmm7
  9674.     }
  9675. }
  9676.  
  9677. static _inline void subps (point4d *sum, point4d *a, point4d *b)
  9678. {
  9679.     _asm
  9680.     {
  9681.         mov eax, a
  9682.         movaps xmm7, [eax]
  9683.         mov eax, b
  9684.         subps xmm7, [eax]
  9685.         mov eax, sum
  9686.         movaps [eax], xmm7
  9687.     }
  9688. }
  9689.  
  9690. static _inline void minps (point4d *sum, point4d *a, point4d *b)
  9691. {
  9692.     _asm
  9693.     {
  9694.         mov eax, a
  9695.         movaps xmm7, [eax]
  9696.         mov eax, b
  9697.         minps xmm7, [eax]
  9698.         mov eax, sum
  9699.         movaps [eax], xmm7
  9700.     }
  9701. }
  9702.  
  9703. static _inline void maxps (point4d *sum, point4d *a, point4d *b)
  9704. {
  9705.     _asm
  9706.     {
  9707.         mov eax, a
  9708.         movaps xmm7, [eax]
  9709.         mov eax, b
  9710.         maxps xmm7, [eax]
  9711.         mov eax, sum
  9712.         movaps [eax], xmm7
  9713.     }
  9714. }
  9715.  
  9716. static _inline void movps_3dn (point4d *dest, point4d *src)
  9717. {
  9718.     _asm
  9719.     {
  9720.         mov eax, src
  9721.         movq mm0, [eax]
  9722.         movq mm1, [eax+8]
  9723.         mov eax, dest
  9724.         movq [eax], mm0
  9725.         movq [eax+8], mm1
  9726.     }
  9727. }
  9728.  
  9729. static _inline void intss_3dn (point4d *dest, long src)
  9730. {
  9731.     _asm
  9732.     {
  9733.         mov eax, dest
  9734.         movd mm0, src
  9735.         pi2fd mm0, mm0
  9736.         punpckldq mm0, mm0
  9737.         movq [eax], mm0
  9738.         movq [eax+8], mm0
  9739.     }
  9740. }
  9741.  
  9742. static _inline void addps_3dn (point4d *sum, point4d *a, point4d *b)
  9743. {
  9744.     _asm
  9745.     {
  9746.         mov eax, a
  9747.         movq mm0, [eax]
  9748.         movq mm1, [eax+8]
  9749.         mov eax, b
  9750.         pfadd mm0, [eax]
  9751.         pfadd mm1, [eax+8]
  9752.         mov eax, sum
  9753.         movq [eax], mm0
  9754.         movq [eax+8], mm1
  9755.     }
  9756. }
  9757.  
  9758. static _inline void mulps_3dn (point4d *sum, point4d *a, point4d *b)
  9759. {
  9760.     _asm
  9761.     {
  9762.         mov eax, a
  9763.         movq mm0, [eax]
  9764.         movq mm1, [eax+8]
  9765.         mov eax, b
  9766.         pfmul mm0, [eax]
  9767.         pfmul mm1, [eax+8]
  9768.         mov eax, sum
  9769.         movq [eax], mm0
  9770.         movq [eax+8], mm1
  9771.     }
  9772. }
  9773.  
  9774. static _inline void subps_3dn (point4d *sum, point4d *a, point4d *b)
  9775. {
  9776.     _asm
  9777.     {
  9778.         mov eax, a
  9779.         movq mm0, [eax]
  9780.         movq mm1, [eax+8]
  9781.         mov eax, b
  9782.         pfsub mm0, [eax]
  9783.         pfsub mm1, [eax+8]
  9784.         mov eax, sum
  9785.         movq [eax], mm0
  9786.         movq [eax+8], mm1
  9787.     }
  9788. }
  9789.  
  9790. static _inline void minps_3dn (point4d *sum, point4d *a, point4d *b)
  9791. {
  9792.     _asm
  9793.     {
  9794.         mov eax, a
  9795.         movq mm0, [eax]
  9796.         movq mm1, [eax+8]
  9797.         mov eax, b
  9798.         pfmin mm0, [eax]
  9799.         pfmin mm1, [eax+8]
  9800.         mov eax, sum
  9801.         movq [eax], mm0
  9802.         movq [eax+8], mm1
  9803.     }
  9804. }
  9805.  
  9806. static _inline void maxps_3dn (point4d *sum, point4d *a, point4d *b)
  9807. {
  9808.     _asm
  9809.     {
  9810.         mov eax, a
  9811.         movq mm0, [eax]
  9812.         movq mm1, [eax+8]
  9813.         mov eax, b
  9814.         pfmax mm0, [eax]
  9815.         pfmax mm1, [eax+8]
  9816.         mov eax, sum
  9817.         movq [eax], mm0
  9818.         movq [eax+8], mm1
  9819.     }
  9820. }
  9821.  
  9822. #endif
  9823.  
  9824. #define DRAWBOUNDCUBELINE(const) \
  9825.     for(;v0<=v1 && v0->z<inz;v0++) drawboundcubesse(v0,const+0x20);\
  9826.     for(;v0<=v1 && v1->z>inz;v1--) drawboundcubesse(v1,const+0x10);\
  9827.                           if (v0 == v1) drawboundcubesse(v1,const+0x00);
  9828.  
  9829. #define DRAWBOUNDCUBELINE_3DN(const) \
  9830.     for(;v0<=v1 && v0->z<inz;v0++) drawboundcube3dn(v0,const+0x20);\
  9831.     for(;v0<=v1 && v1->z>inz;v1--) drawboundcube3dn(v1,const+0x10);\
  9832.                           if (v0 == v1) drawboundcube3dn(v1,const+0x00);
  9833.  
  9834.     //Code taken from renderboundcube of SLAB6D (Pentium III version :)
  9835. #define MAXZSIZ 1024
  9836. static void kv6draw (vx5sprite *spr)
  9837. {
  9838.     point4d *r0, *r1, *r2;
  9839.     kv6voxtype *xv, *yv, *v0, *v1;
  9840.     kv6data *kv;
  9841.     point3d ts, th, tf;
  9842.     point3d npos, nstr, nhei, nfor, tp, tp2;
  9843.     float f;
  9844.     long x, y, z, inx, iny, inz, nxplanemin, nxplanemax;
  9845.     unsigned short *ylenptr;
  9846.  
  9847.     kv = spr->voxnum; if (!kv) return;
  9848.  
  9849.     z = 0; //Quick & dirty estimation of distance
  9850.     ftol((spr->p.x-gipos.x)*gifor.x + (spr->p.y-gipos.y)*gifor.y + (spr->p.z-gipos.z)*gifor.z,&y);
  9851.     while ((kv->lowermip) && (y >= vx5.kv6mipfactor)) { kv = kv->lowermip; z++; y >>= 1; }
  9852.     if (!z)
  9853.     {
  9854.         nxplanemin = vx5.xplanemin; nxplanemax = vx5.xplanemax;
  9855.         ts = spr->s; th = spr->h; tf = spr->f;
  9856.     }
  9857.     else
  9858.     {
  9859.         nxplanemin = (vx5.xplanemin>>z);
  9860.         nxplanemax = (vx5.xplanemax>>z); f = (float)(1<<z);
  9861.         ts.x = spr->s.x*f; ts.y = spr->s.y*f; ts.z = spr->s.z*f;
  9862.         th.x = spr->h.x*f; th.y = spr->h.y*f; th.z = spr->h.z*f;
  9863.         tf.x = spr->f.x*f; tf.y = spr->f.y*f; tf.z = spr->f.z*f;
  9864.     }
  9865.  
  9866.         //View frustrum culling (72*,63+,12fabs,4cmp)
  9867.     tp2.x = ((float)kv->xsiz)*.5; tp.x = tp2.x - kv->xpiv;
  9868.     tp2.y = ((float)kv->ysiz)*.5; tp.y = tp2.y - kv->ypiv;
  9869.     tp2.z = ((float)kv->zsiz)*.5; tp.z = tp2.z - kv->zpiv;
  9870.     npos.x = tp.x*ts.x + tp.y*th.x + tp.z*tf.x + (spr->p.x-gipos.x);
  9871.     npos.y = tp.x*ts.y + tp.y*th.y + tp.z*tf.y + (spr->p.y-gipos.y);
  9872.     npos.z = tp.x*ts.z + tp.y*th.z + tp.z*tf.z + (spr->p.z-gipos.z);
  9873.     nstr.x = ts.x*tp2.x; nstr.y = ts.y*tp2.x; nstr.z = ts.z*tp2.x;
  9874.     nhei.x = th.x*tp2.y; nhei.y = th.y*tp2.y; nhei.z = th.z*tp2.y;
  9875.     nfor.x = tf.x*tp2.z; nfor.y = tf.y*tp2.z; nfor.z = tf.z*tp2.z;
  9876.     for(z=3;z>=0;z--) //72*,63+
  9877.     {
  9878.             //movaps xmm0, nx4      mulaps xmm0, ginor[0].x(dup 4)
  9879.             //movaps xmm1, ny4      mulaps xmm1, ginor[0].y(dup 4)
  9880.             //movaps xmm2, nz4      mulaps xmm2, ginor[0].z(dup 4)
  9881.             //addps xmm0, xmm1      addps xmm0, xmm2
  9882.             //andps xmm0, [0x7fffffff7fffffff7fffffffffffffff]
  9883.             //movhlps xmm1, xmm0    addps xmm0, xmm1
  9884.             //shufps xmm1, xmm0, 1  addss xmm0, xmm1
  9885.             //ucomiss xmm0, [0x0]   jnz retfunc
  9886.         if (fabs(nstr.x*ginor[z].x + nstr.y*ginor[z].y + nstr.z*ginor[z].z) +
  9887.              fabs(nhei.x*ginor[z].x + nhei.y*ginor[z].y + nhei.z*ginor[z].z) +
  9888.              fabs(nfor.x*ginor[z].x + nfor.y*ginor[z].y + nfor.z*ginor[z].z) +
  9889.                     npos.x*ginor[z].x + npos.y*ginor[z].y + npos.z*ginor[z].z < 0) return;
  9890.     }
  9891. #if 0   //There are bugs when some vertices are behind ifor plane
  9892.     x = xres; y = xres; inx = 0; iny = 0;
  9893.     for(z=7;z>=0;z--) //This is useful for debugging.
  9894.     {
  9895.         tp.x = -kv->xpiv; if (z&1) tp.x += (float)kv->xsiz;
  9896.         tp.y = -kv->ypiv; if (z&2) tp.y += (float)kv->ysiz;
  9897.         tp.z = -kv->zpiv; if (z&4) tp.z += (float)kv->zsiz;
  9898.         drawspherefill(tp.x*ts.x+tp.y*th.x+tp.z*tf.x+spr->p.x,
  9899.                             tp.x*ts.y+tp.y*th.y+tp.z*tf.y+spr->p.y,
  9900.                             tp.x*ts.z+tp.y*th.z+tp.z*tf.z+spr->p.z,.5,0xf08040);
  9901.         tp2.x = tp.x*ts.x+tp.y*th.x+tp.z*tf.x+spr->p.x-gipos.x;
  9902.         tp2.y = tp.x*ts.y+tp.y*th.y+tp.z*tf.y+spr->p.y-gipos.y;
  9903.         tp2.z = tp.x*ts.z+tp.y*th.z+tp.z*tf.z+spr->p.z-gipos.z;
  9904.         tp.z = tp2.x*gifor.x + tp2.y*gifor.y + tp2.z*gifor.z; if (tp.z < 2) continue;
  9905.         tp.x = tp2.x*gistr.x + tp2.y*gistr.y + tp2.z*gistr.z;
  9906.         tp.y = tp2.x*gihei.x + tp2.y*gihei.y + tp2.z*gihei.z;
  9907.         ftol(tp.x*gihz/tp.z + gihx,&inz);
  9908.         if (inz < x) x = inz;
  9909.         if (inz > inx) inx = inz;
  9910.         ftol(tp.y*gihz/tp.z+gihy,&inz);
  9911.         if (inz < y) y = inz;
  9912.         if (inz > iny) iny = inz;
  9913.     }
  9914.     if (x < 0) x = 0;
  9915.     if (inx > xres) inx = xres;
  9916.     if (y < 0) y = 0;
  9917.     if (iny > yres) iny = yres;
  9918.     if (x < inx)
  9919.         for(inz=y;inz<iny;inz++)
  9920.             clearbuf((void *)(ylookup[inz]+(x<<2)+frameplace),inx-x,0L);
  9921. #endif
  9922.  
  9923. #if (USEZBUFFER == 0)
  9924.     lpoint3d lp;
  9925.     if (!cansee(&gipos,&spr->p,&lp)) return; //Very crappy Z-buffer!
  9926. #endif
  9927.  
  9928.     r0 = &ztab4[MAXZSIZ]; r1 = &ztab4[MAXZSIZ+1]; r2 = &ztab4[MAXZSIZ+2];
  9929.  
  9930.         //Rotate sprite from world to screen coordinates:
  9931.     mat2(&gixs,&giys,&gizs,&giadd, &ts,&th,&tf,&spr->p, &nstr,&nhei,&nfor,&npos);
  9932.     npos.x -= (kv->xpiv*nstr.x + kv->ypiv*nhei.x + kv->zpiv*nfor.x);
  9933.     npos.y -= (kv->xpiv*nstr.y + kv->ypiv*nhei.y + kv->zpiv*nfor.y);
  9934.     npos.z -= (kv->xpiv*nstr.z + kv->ypiv*nhei.z + kv->zpiv*nfor.z);
  9935.  
  9936.         //Find split point by using Cramer's rule
  9937.         //Must use Cramer's rule for non-orthonormal input matrices
  9938.     tp.x = nhei.y*nfor.z - nfor.y*nhei.z;
  9939.     tp.y = nfor.y*nstr.z - nstr.y*nfor.z;
  9940.     tp.z = nstr.y*nhei.z - nhei.y*nstr.z;
  9941.     f = nstr.x*tp.x + nhei.x*tp.y + nfor.x*tp.z;
  9942.     if (f != 0)
  9943.     {
  9944.         f = -1.0f / f;
  9945.         tp2.x = npos.y*nfor.z - nfor.y*npos.z;
  9946.         tp2.y = nhei.y*npos.z - npos.y*nhei.z;
  9947.         tp2.z = npos.y*nstr.z - nstr.y*npos.z;
  9948.         inx = (npos.x*tp.x - nhei.x*tp2.x - nfor.x*tp2.y)*f;
  9949.         iny = (npos.x*tp.y + nstr.x*tp2.x - nfor.x*tp2.z)*f;
  9950.         inz = (npos.x*tp.z + nstr.x*tp2.y + nhei.x*tp2.z)*f;
  9951.     }
  9952.     else { inx = iny = inz = -1; }
  9953.     inx = lbound(inx,-1,kv->xsiz);
  9954.     iny = lbound(iny,-1,kv->ysiz);
  9955.     inz = lbound(inz,-1,kv->zsiz);
  9956.  
  9957.     f = nhei.x; nhei.x = nfor.x; nfor.x = -f;
  9958.     f = nhei.y; nhei.y = nfor.y; nfor.y = -f;
  9959.     f = nhei.z; nhei.z = nfor.z; nfor.z = -f;
  9960.  
  9961.     if (kv->zsiz >= MAXZSIZ) return; //HACK TO PREVENT CRASHES FOR NOW... FIX!
  9962.     qsum0[2] = qsum0[0] = 0x7fff-(xres-(long)gihx);
  9963.     qsum0[3] = qsum0[1] = 0x7fff-(yres-(long)gihy);
  9964.  
  9965.         //r1->x = nstr.z; r1->y = nhei.z; r1->z = nfor.z;
  9966.         //minps(r1,r1,&ztab4[0]); //&ztab4[0] always 0
  9967.         //scisdist = -(r1->x + r1->y + r1->z);
  9968.     scisdist = 0;
  9969.     if (*(long *)&nstr.z < 0) scisdist -= nstr.z;
  9970.     if (*(long *)&nhei.z < 0) scisdist -= nhei.z;
  9971.     if (*(long *)&nfor.z < 0) scisdist -= nfor.z;
  9972.  
  9973.     cadd4[1].x = nstr.x*gihz; cadd4[1].y = nstr.y*gihz; cadd4[1].z = cadd4[1].z2 = nstr.z;
  9974.     cadd4[2].x = nhei.x*gihz; cadd4[2].y = nhei.y*gihz; cadd4[2].z = cadd4[2].z2 = nhei.z;
  9975.     cadd4[4].x = nfor.x*gihz; cadd4[4].y = nfor.y*gihz; cadd4[4].z = cadd4[4].z2 = nfor.z;
  9976.           r1->x = npos.x*gihz;      r1->y = npos.y*gihz;      r1->z =      r1->z2 = npos.z;
  9977.  
  9978.     updatereflects(spr);
  9979.     //No more 8087 code after here!!! ----------------------------------------
  9980.  
  9981.     if (cputype&(1<<25))
  9982.     {
  9983.         addps(&cadd4[3],&cadd4[1],&cadd4[2]);
  9984.         addps(&cadd4[5],&cadd4[1],&cadd4[4]);
  9985.         addps(&cadd4[6],&cadd4[2],&cadd4[4]);
  9986.         addps(&cadd4[7],&cadd4[3],&cadd4[4]);
  9987.  
  9988.         for(z=1;z<kv->zsiz;z++) addps(&ztab4[z],&ztab4[z-1],&cadd4[2]);
  9989.         intss(r2,-kv->ysiz); mulps(r2,r2,&cadd4[4]);
  9990.  
  9991.         subps(r1,r1,&cadd4[4]); //ANNOYING HACK!!!
  9992.  
  9993.         _asm
  9994.         {
  9995.             movq mm6, qsum0
  9996.             movq mm7, qsum1
  9997.         }
  9998.  
  9999.         xv = kv->vox; ylenptr = kv->ylen;
  10000.         for(x=0;x<inx;x++,ylenptr+=kv->ysiz)
  10001.         {
  10002.             if ((x < nxplanemin) || (x >= nxplanemax))
  10003.                 { xv += kv->xlen[x]; addps(r1,r1,&cadd4[1]); continue; }
  10004.             yv = xv+kv->xlen[x]; movps(r0,r1);
  10005.             for(y=0;y<iny;y++)
  10006.             {
  10007.                 v0 = xv; xv += ylenptr[y]; v1 = xv-1;
  10008.                 DRAWBOUNDCUBELINE(0xa)
  10009.                 subps(r0,r0,&cadd4[4]);
  10010.             }
  10011.             xv = yv;
  10012.             addps(r0,r1,r2);
  10013.             addps(r1,r1,&cadd4[1]);
  10014.             for(y=kv->ysiz-1;y>iny;y--)
  10015.             {
  10016.                 addps(r0,r0,&cadd4[4]);
  10017.                 v1 = yv-1; yv -= ylenptr[y]; v0 = yv;
  10018.                 DRAWBOUNDCUBELINE(0x6)
  10019.             }
  10020.             if ((unsigned long)iny < (unsigned long)kv->ysiz)
  10021.             {
  10022.                 addps(r0,r0,&cadd4[4]);
  10023.                 v1 = yv-1; yv -= ylenptr[y]; v0 = yv;
  10024.                 DRAWBOUNDCUBELINE(0x2)
  10025.             }
  10026.         }
  10027.         xv = &kv->vox[kv->numvoxs]; ylenptr = &kv->ylen[(kv->xsiz-1)*kv->ysiz];
  10028.         intss(r0,kv->xsiz-x); mulps(r0,r0,&cadd4[1]); addps(r1,r1,r0);
  10029.         for(x=kv->xsiz-1;x>inx;x--,ylenptr-=kv->ysiz)
  10030.         {
  10031.             if ((x < nxplanemin) || (x >= nxplanemax))
  10032.                 { xv -= kv->xlen[x]; subps(r1,r1,&cadd4[1]); continue; }
  10033.             yv = xv-kv->xlen[x];
  10034.             subps(r1,r1,&cadd4[1]);
  10035.             addps(r0,r1,r2);
  10036.             for(y=kv->ysiz-1;y>iny;y--)
  10037.             {
  10038.                 addps(r0,r0,&cadd4[4]);
  10039.                 v1 = xv-1; xv -= ylenptr[y]; v0 = xv;
  10040.                 DRAWBOUNDCUBELINE(0x5)
  10041.             }
  10042.             xv = yv; movps(r0,r1);
  10043.             for(y=0;y<iny;y++)
  10044.             {
  10045.                 v0 = yv; yv += ylenptr[y]; v1 = yv-1;
  10046.                 DRAWBOUNDCUBELINE(0x9)
  10047.                 subps(r0,r0,&cadd4[4]);
  10048.             }
  10049.             if ((unsigned long)iny < (unsigned long)kv->ysiz)
  10050.             {
  10051.                 v0 = yv; yv += ylenptr[y]; v1 = yv-1;
  10052.                 DRAWBOUNDCUBELINE(0x1)
  10053.             }
  10054.         }
  10055.         if ((unsigned long)inx < (unsigned long)kv->xsiz)
  10056.         {
  10057.             if ((x < nxplanemin) || (x >= nxplanemax)) { { _asm emms } return; }
  10058.             yv = xv-kv->xlen[x];
  10059.             subps(r1,r1,&cadd4[1]);
  10060.             addps(r0,r1,r2);
  10061.             for(y=kv->ysiz-1;y>iny;y--)
  10062.             {
  10063.                 addps(r0,r0,&cadd4[4]);
  10064.                 v1 = xv-1; xv -= ylenptr[y]; v0 = xv;
  10065.                 DRAWBOUNDCUBELINE(0x4)
  10066.             }
  10067.             xv = yv; movps(r0,r1);
  10068.             for(y=0;y<iny;y++)
  10069.             {
  10070.                 v0 = yv; yv += ylenptr[y]; v1 = yv-1;
  10071.                 DRAWBOUNDCUBELINE(0x8)
  10072.                 subps(r0,r0,&cadd4[4]);
  10073.             }
  10074.             if ((unsigned long)iny < (unsigned long)kv->ysiz)
  10075.             {
  10076.                 v0 = yv; yv += ylenptr[y]; v1 = yv-1;
  10077.                 DRAWBOUNDCUBELINE(0x0)
  10078.             }
  10079.         }
  10080.     }
  10081.     else
  10082.     {
  10083.         addps_3dn(&cadd4[3],&cadd4[1],&cadd4[2]);
  10084.         addps_3dn(&cadd4[5],&cadd4[1],&cadd4[4]);
  10085.         addps_3dn(&cadd4[6],&cadd4[2],&cadd4[4]);
  10086.         addps_3dn(&cadd4[7],&cadd4[3],&cadd4[4]);
  10087.  
  10088.         for(z=1;z<kv->zsiz;z++) addps_3dn(&ztab4[z],&ztab4[z-1],&cadd4[2]);
  10089.         intss_3dn(r2,-kv->ysiz); mulps_3dn(r2,r2,&cadd4[4]);
  10090.  
  10091.         subps_3dn(r1,r1,&cadd4[4]); //ANNOYING HACK!!!
  10092.  
  10093.         _asm
  10094.         {
  10095.             movq mm6, qsum0
  10096.             movq mm7, qsum1
  10097.         }
  10098.  
  10099.         xv = kv->vox; ylenptr = kv->ylen;
  10100.         for(x=0;x<inx;x++,ylenptr+=kv->ysiz)
  10101.         {
  10102.             if ((x < nxplanemin) || (x >= nxplanemax))
  10103.                 { xv += kv->xlen[x]; addps_3dn(r1,r1,&cadd4[1]); continue; }
  10104.             yv = xv+kv->xlen[x]; movps_3dn(r0,r1);
  10105.             for(y=0;y<iny;y++)
  10106.             {
  10107.                 v0 = xv; xv += ylenptr[y]; v1 = xv-1;
  10108.                 DRAWBOUNDCUBELINE_3DN(0xa)
  10109.                 subps_3dn(r0,r0,&cadd4[4]);
  10110.             }
  10111.             xv = yv;
  10112.             addps_3dn(r0,r1,r2);
  10113.             addps_3dn(r1,r1,&cadd4[1]);
  10114.             for(y=kv->ysiz-1;y>iny;y--)
  10115.             {
  10116.                 addps_3dn(r0,r0,&cadd4[4]);
  10117.                 v1 = yv-1; yv -= ylenptr[y]; v0 = yv;
  10118.                 DRAWBOUNDCUBELINE_3DN(0x6)
  10119.             }
  10120.             if ((unsigned long)iny < (unsigned long)kv->ysiz)
  10121.             {
  10122.                 addps_3dn(r0,r0,&cadd4[4]);
  10123.                 v1 = yv-1; yv -= ylenptr[y]; v0 = yv;
  10124.                 DRAWBOUNDCUBELINE_3DN(0x2)
  10125.             }
  10126.         }
  10127.         xv = &kv->vox[kv->numvoxs]; ylenptr = &kv->ylen[(kv->xsiz-1)*kv->ysiz];
  10128.         intss_3dn(r0,kv->xsiz-x); mulps_3dn(r0,r0,&cadd4[1]); addps_3dn(r1,r1,r0);
  10129.         for(x=kv->xsiz-1;x>inx;x--,ylenptr-=kv->ysiz)
  10130.         {
  10131.             if ((x < nxplanemin) || (x >= nxplanemax))
  10132.                 { xv -= kv->xlen[x]; subps_3dn(r1,r1,&cadd4[1]); continue; }
  10133.             yv = xv-kv->xlen[x];
  10134.             subps_3dn(r1,r1,&cadd4[1]);
  10135.             addps_3dn(r0,r1,r2);
  10136.             for(y=kv->ysiz-1;y>iny;y--)
  10137.             {
  10138.                 addps_3dn(r0,r0,&cadd4[4]);
  10139.                 v1 = xv-1; xv -= ylenptr[y]; v0 = xv;
  10140.                 DRAWBOUNDCUBELINE_3DN(0x5)
  10141.             }
  10142.             xv = yv; movps_3dn(r0,r1);
  10143.             for(y=0;y<iny;y++)
  10144.             {
  10145.                 v0 = yv; yv += ylenptr[y]; v1 = yv-1;
  10146.                 DRAWBOUNDCUBELINE_3DN(0x9)
  10147.                 subps_3dn(r0,r0,&cadd4[4]);
  10148.             }
  10149.             if ((unsigned long)iny < (unsigned long)kv->ysiz)
  10150.             {
  10151.                 v0 = yv; yv += ylenptr[y]; v1 = yv-1;
  10152.                 DRAWBOUNDCUBELINE_3DN(0x1)
  10153.             }
  10154.         }
  10155.         if ((unsigned long)inx < (unsigned long)kv->xsiz)
  10156.         {
  10157.             if ((x < nxplanemin) || (x >= nxplanemax)) { { _asm emms } return; }
  10158.             yv = xv-kv->xlen[x];
  10159.             subps_3dn(r1,r1,&cadd4[1]);
  10160.             addps_3dn(r0,r1,r2);
  10161.             for(y=kv->ysiz-1;y>iny;y--)
  10162.             {
  10163.                 addps_3dn(r0,r0,&cadd4[4]);
  10164.                 v1 = xv-1; xv -= ylenptr[y]; v0 = xv;
  10165.                 DRAWBOUNDCUBELINE_3DN(0x4)
  10166.             }
  10167.             xv = yv; movps_3dn(r0,r1);
  10168.             for(y=0;y<iny;y++)
  10169.             {
  10170.                 v0 = yv; yv += ylenptr[y]; v1 = yv-1;
  10171.                 DRAWBOUNDCUBELINE_3DN(0x8)
  10172.                 subps_3dn(r0,r0,&cadd4[4]);
  10173.             }
  10174.             if ((unsigned long)iny < (unsigned long)kv->ysiz)
  10175.             {
  10176.                 v0 = yv; yv += ylenptr[y]; v1 = yv-1;
  10177.                 DRAWBOUNDCUBELINE_3DN(0x0)
  10178.             }
  10179.         }
  10180.     }
  10181.     _asm emms
  10182. }
  10183.  
  10184. #endif
  10185.  
  10186. //-------------------------- KFA sprite code begins --------------------------
  10187.  
  10188. static kv6voxtype *getvptr (kv6data *kv, long x, long y)
  10189. {
  10190.     kv6voxtype *v;
  10191.     long i, j;
  10192.  
  10193.     v = kv->vox;
  10194.     if ((x<<1) < kv->xsiz) { for(i=0         ;i< x;i++) v += kv->xlen[i]; }
  10195.     else { v += kv->numvoxs; for(i=kv->xsiz-1;i>=x;i--) v -= kv->xlen[i]; }
  10196.     j = x*kv->ysiz;
  10197.     if ((y<<1) < kv->ysiz) { for(i=0         ;i< y;i++) v += kv->ylen[j+i]; }
  10198.     else { v += kv->xlen[x]; for(i=kv->ysiz-1;i>=y;i--) v -= kv->ylen[j+i]; }
  10199.     return(v);
  10200. }
  10201.  
  10202. #define VFIFSIZ 16384 //SHOULDN'T BE STATIC ALLOCATION!!!
  10203. static long vfifo[VFIFSIZ];
  10204. static void floodsucksprite (vx5sprite *spr, kv6data *kv, long ox, long oy,
  10205.                                       kv6voxtype *v0, kv6voxtype *v1)
  10206. {
  10207.     kv6voxtype *v, *ve, *ov, *v2, *v3;
  10208.     kv6data *kv6;
  10209.     long i, j, x, y, z, x0, y0, z0, x1, y1, z1, n, vfif0, vfif1;
  10210.  
  10211.     x0 = x1 = ox; y0 = y1 = oy; z0 = v0->z; z1 = v1->z;
  10212.  
  10213.     n = (((long)v1)-((long)v0))/sizeof(kv6voxtype)+1;
  10214.     v1->vis &= ~64;
  10215.  
  10216.     vfifo[0] = ox; vfifo[1] = oy;
  10217.     vfifo[2] = (long)v0; vfifo[3] = (long)v1;
  10218.     vfif0 = 0; vfif1 = 4;
  10219.  
  10220.     while (vfif0 < vfif1)
  10221.     {
  10222.         i = (vfif0&(VFIFSIZ-1)); vfif0 += 4;
  10223.         ox = vfifo[i]; oy = vfifo[i+1];
  10224.         v0 = (kv6voxtype *)vfifo[i+2]; v1 = (kv6voxtype *)vfifo[i+3];
  10225.  
  10226.         if (ox < x0) x0 = ox;
  10227.         if (ox > x1) x1 = ox;
  10228.         if (oy < y0) y0 = oy;
  10229.         if (oy > y1) y1 = oy;
  10230.         if (v0->z < z0) z0 = v0->z;
  10231.         if (v1->z > z1) z1 = v1->z;
  10232.         for(v=v0;v<=v1;v++) v->vis |= 128; //Mark as part of current piece
  10233.  
  10234.         for(j=0;j<4;j++)
  10235.         {
  10236.             switch(j)
  10237.             {
  10238.                 case 0: x = ox-1; y = oy; break;
  10239.                 case 1: x = ox+1; y = oy; break;
  10240.                 case 2: x = ox; y = oy-1; break;
  10241.                 case 3: x = ox; y = oy+1; break;
  10242.                 default: __assume(0); //tells MSVC default can't be reached
  10243.             }
  10244.             if ((unsigned long)x >= kv->xsiz) continue;
  10245.             if ((unsigned long)y >= kv->ysiz) continue;
  10246.  
  10247.             v = getvptr(kv,x,y);
  10248.             for(ve=&v[kv->ylen[x*kv->ysiz+y]];v<ve;v++)
  10249.             {
  10250.                 if (v->vis&16) ov = v;
  10251.                 if (((v->vis&(64+32)) == 64+32) && (v0->z <= v->z) && (v1->z >= ov->z))
  10252.                 {
  10253.                     i = (vfif1&(VFIFSIZ-1)); vfif1 += 4;
  10254.                     if (vfif1-vfif0 >= VFIFSIZ) //FIFO Overflow... make entire object 1 piece :/
  10255.                     {
  10256.                         for(i=kv->numvoxs-1;i>=0;i--)
  10257.                         {
  10258.                             if ((kv->vox[i].vis&(64+32)) == 64+32) { v1 = &kv->vox[i]; v1->vis &= ~64; }
  10259.                             if (kv->vox[i].vis&16) for(v=&kv->vox[i];v<=v1;v++) kv->vox[i].vis |= 128;
  10260.                         }
  10261.                         x0 = y0 = z0 = 0; x1 = kv->xsiz; y1 = kv->ysiz; z1 = kv->zsiz; n = kv->numvoxs;
  10262.                         goto floodsuckend;
  10263.                     }
  10264.                     vfifo[i] = x; vfifo[i+1] = y;
  10265.                     vfifo[i+2] = (long)ov; vfifo[i+3] = (long)v;
  10266.                     n += (((long)v)-((long)ov))/sizeof(kv6voxtype)+1;
  10267.                     v->vis &= ~64;
  10268.                 }
  10269.             }
  10270.         }
  10271.     }
  10272.     x1++; y1++; z1++;
  10273. floodsuckend:;
  10274.  
  10275.     i = sizeof(kv6data) + n*sizeof(kv6voxtype) + (x1-x0)*4 + (x1-x0)*(y1-y0)*2;
  10276.     if (!(kv6 = (kv6data *)malloc(i))) return;
  10277.     kv6->leng = i;
  10278.     kv6->xsiz = x1-x0;
  10279.     kv6->ysiz = y1-y0;
  10280.     kv6->zsiz = z1-z0;
  10281.     kv6->xpiv = 0; //Set limb pivots to 0 - don't need it twice!
  10282.     kv6->ypiv = 0;
  10283.     kv6->zpiv = 0;
  10284.     kv6->numvoxs = n;
  10285.     kv6->namoff = 0;
  10286.     kv6->lowermip = 0;
  10287.     kv6->vox = (kv6voxtype *)(((long)kv6)+sizeof(kv6data));
  10288.     kv6->xlen = (unsigned long *)(((long)kv6->vox)+n*sizeof(kv6voxtype));
  10289.     kv6->ylen = (unsigned short *)(((long)kv6->xlen)+(x1-x0)*4);
  10290.  
  10291.         //Extract sub-KV6 to newly allocated kv6data
  10292.     v3 = kv6->vox; n = 0;
  10293.     for(x=0,v=kv->vox;x<x0;x++) v += kv->xlen[x];
  10294.     for(;x<x1;x++)
  10295.     {
  10296.         v2 = v; ox = n;
  10297.         for(y=0;y<y0;y++) v += kv->ylen[x*kv->ysiz+y];
  10298.         for(;y<y1;y++)
  10299.         {
  10300.             oy = n;
  10301.             for(ve=&v[kv->ylen[x*kv->ysiz+y]];v<ve;v++)
  10302.                 if (v->vis&128)
  10303.                 {
  10304.                     v->vis &= ~128;
  10305.                     (*v3) = (*v);
  10306.                     v3->z -= z0;
  10307.                     v3++; n++;
  10308.                 }
  10309.             kv6->ylen[(x-x0)*(y1-y0)+(y-y0)] = n-oy;
  10310.         }
  10311.         kv6->xlen[x-x0] = n-ox;
  10312.         v = v2+kv->xlen[x];
  10313.     }
  10314.  
  10315.     spr->p.x = x0-kv->xpiv;
  10316.     spr->p.y = y0-kv->ypiv;
  10317.     spr->p.z = z0-kv->zpiv;
  10318.     spr->s.x = 1; spr->s.y = 0; spr->s.z = 0;
  10319.     spr->h.x = 0; spr->h.y = 1; spr->h.z = 0;
  10320.     spr->f.x = 0; spr->f.y = 0; spr->f.z = 1;
  10321.     spr->voxnum = kv6;
  10322.     spr->flags = 0;
  10323. }
  10324.  
  10325. static char *stripdir (char *filnam)
  10326. {
  10327.     long i, j;
  10328.     for(i=0,j=-1;filnam[i];i++)
  10329.         if ((filnam[i] == '/') || (filnam[i] == '\\')) j = i;
  10330.     return(&filnam[j+1]);
  10331. }
  10332.  
  10333. static void kfasorthinge (hingetype *h, long nh, long *hsort)
  10334. {
  10335.     long i, j, n;
  10336.  
  10337.         //First pass: stick hinges with parent=-1 at end
  10338.     n = nh; j = 0;
  10339.     for(i=n-1;i>=0;i--)
  10340.     {
  10341.         if (h[i].parent < 0) hsort[--n] = i;
  10342.                              else hsort[j++] = i;
  10343.     }
  10344.         //Finish accumulation (n*log(n) if tree is perfectly balanced)
  10345.     while (n > 0)
  10346.     {
  10347.         i--; if (i < 0) i = n-1;
  10348.         j = hsort[i];
  10349.         if (h[h[j].parent].parent < 0)
  10350.         {
  10351.             h[j].parent = -2-h[j].parent; n--;
  10352.             hsort[i] = hsort[n]; hsort[n] = j;
  10353.         }
  10354.     }
  10355.         //Restore parents to original values
  10356.     for(i=nh-1;i>=0;i--) h[i].parent = -2-h[i].parent;
  10357. }
  10358.  
  10359.     //Returns a pointer to the loaded kfatype structure.
  10360.     //Loads data only if not already loaded before with getkfa
  10361. kfatype *getkfa (const char *kfanam)
  10362. {
  10363.     kfatype *kfa;
  10364.     kv6voxtype *v, *ov, *ve;
  10365.     kv6data *kv;
  10366.     long i, j, x, y;
  10367.     char *cptr, snotbuf[MAX_PATH];
  10368.  
  10369.     if (inkhash(kfanam,&i)) return(*(kfatype **)&khashbuf[i+4]);
  10370.     if (i == -1) return(0);
  10371.  
  10372.     if (!(kfa = (kfatype *)malloc(sizeof(kfatype)))) return(0);
  10373.     memset(kfa,0,sizeof(kfatype));
  10374.  
  10375.     kfa->namoff = i+9; //Must use offset for ptr->name conversion
  10376.     *(kfatype **)&khashbuf[i+4] = kfa;
  10377.     *(char *)&khashbuf[i+8] = 1; //1 for KFA
  10378.  
  10379.     if (!kzopen(kfanam)) return(0);
  10380.     kzread(&i,4); if (i != 0x6b6c774b) { kzclose(); return(0); } //Kwlk
  10381.     kzread(&i,4); strcpy(snotbuf,kfanam); cptr = stripdir(snotbuf);
  10382.     kzread(cptr,i); cptr[i] = 0;
  10383.     kzread(&kfa->numhin,4);
  10384.  
  10385.         //Actual allocation for ->spr is numspr, which is <= numhin!
  10386.     if (!(kfa->spr = (vx5sprite *)malloc(kfa->numhin*sizeof(vx5sprite)))) { kzclose(); return(0); }
  10387.  
  10388.     if (!(kfa->hinge = (hingetype *)malloc(kfa->numhin*sizeof(hingetype)))) { kzclose(); return(0); }
  10389.     kzread(kfa->hinge,kfa->numhin*sizeof(hingetype));
  10390.  
  10391.     kzread(&kfa->numfrm,4);
  10392.     if (!(kfa->frmval = (short *)malloc(kfa->numfrm*kfa->numhin*2))) { kzclose(); return(0); }
  10393.     kzread(kfa->frmval,kfa->numfrm*kfa->numhin*2);
  10394.  
  10395.     kzread(&kfa->seqnum,4);
  10396.     if (!(kfa->seq = (seqtyp *)malloc(kfa->seqnum*sizeof(seqtyp)))) { kzclose(); return(0); }
  10397.     kzread(kfa->seq,kfa->seqnum*sizeof(seqtyp));
  10398.  
  10399.     kzclose();
  10400.  
  10401.         //MUST load the associated KV6 AFTER the kzclose :/
  10402.     kfa->numspr = 0;
  10403.     kv = getkv6(snotbuf); if (!kv) return(0);
  10404.     kfa->basekv6 = kv;
  10405.     if (!kv->numvoxs) return(0);
  10406.     v = kv->vox;
  10407.     for(x=kv->numvoxs-1;x>=0;x--) v[x].vis |= ((v[x].vis&32)<<1);
  10408.     for(x=0;x<kv->xsiz;x++)
  10409.         for(y=0;y<kv->ysiz;y++)
  10410.             for(ve=&v[kv->ylen[x*kv->ysiz+y]];v<ve;v++)
  10411.             {
  10412.                 if (v->vis&16) ov = v;
  10413.                 if ((v->vis&(64+32)) == 64+32)
  10414.                 {
  10415.                     floodsucksprite(&kfa->spr[kfa->numspr],kv,x,y,ov,v);
  10416.                     kfa->numspr++;
  10417.                 }
  10418.             }
  10419.  
  10420.     kfa->hingesort = (long *)malloc(kfa->numhin*4);
  10421.     kfasorthinge(kfa->hinge,kfa->numhin,kfa->hingesort);
  10422.  
  10423.         //Remember position offsets of limbs with no parent in hinge[?].p[0]
  10424.     for(i=(kfa->numhin)-1;i>=0;i--)
  10425.     {
  10426.         j = kfa->hingesort[i]; if (j >= kfa->numspr) continue;
  10427.         if (kfa->hinge[j].parent < 0)
  10428.         {
  10429.             kfa->hinge[j].p[0].x = -kfa->spr[j].p.x;
  10430.             kfa->hinge[j].p[0].y = -kfa->spr[j].p.y;
  10431.             kfa->hinge[j].p[0].z = -kfa->spr[j].p.z;
  10432.         }
  10433.     }
  10434.  
  10435.     return(kfa);
  10436. }
  10437.  
  10438. void getspr (vx5sprite *s, const char *filnam)
  10439. {
  10440.     long i;
  10441.  
  10442.     if (!filnam) return;
  10443.     i = strlen(filnam); if (!i) return;
  10444.  
  10445.     if ((filnam[i-1] == 'A') || (filnam[i-1] == 'a'))
  10446.         { s->kfaptr = getkfa(filnam); s->flags = 2; s->kfatim = 0; }
  10447.     else if (filnam[i-1] == '6')
  10448.         { s->voxnum = getkv6(filnam); s->flags = 0; }
  10449. }
  10450.  
  10451.     //Given vector a, returns b&c that makes (a,b,c) orthonormal
  10452. void genperp (point3d *a, point3d *b, point3d *c)
  10453. {
  10454.     float t;
  10455.  
  10456.     if ((a->x == 0) && (a->y == 0) && (a->z == 0))
  10457.         { b->x = 0; b->y = 0; b->z = 0; return; }
  10458.     if ((fabs(a->x) < fabs(a->y)) && (fabs(a->x) < fabs(a->z)))
  10459.         { t = 1.0 / sqrt(a->y*a->y + a->z*a->z); b->x = 0; b->y = a->z*t; b->z = -a->y*t; }
  10460.     else if (fabs(a->y) < fabs(a->z))
  10461.         { t = 1.0 / sqrt(a->x*a->x + a->z*a->z); b->x = -a->z*t; b->y = 0; b->z = a->x*t; }
  10462.     else
  10463.         { t = 1.0 / sqrt(a->x*a->x + a->y*a->y); b->x = a->y*t; b->y = -a->x*t; b->z = 0; }
  10464.     c->x = a->y*b->z - a->z*b->y;
  10465.     c->y = a->z*b->x - a->x*b->z;
  10466.     c->z = a->x*b->y - a->y*b->x;
  10467. }
  10468.  
  10469.     //A * B = C, find A   36*, 27ρ
  10470.     //[asx ahx agx aox][bsx bhx bgx box]   [csx chx cgx cox]
  10471.     //[asy ahy agy aoy][bsy bhy bgy boy] = [csy chy cgy coy]
  10472.     //[asz ahz agz aoz][bsz bhz bgz boz]   [csz chz cgz coz]
  10473.     //[  0   0   0   1][  0   0   0   1]   [  0   0   0   1]
  10474. void mat0 (point3d *as, point3d *ah, point3d *ag, point3d *ao,
  10475.               point3d *bs, point3d *bh, point3d *bg, point3d *bo,
  10476.               point3d *cs, point3d *ch, point3d *cg, point3d *co)
  10477. {
  10478.     point3d ts, th, tg, to;
  10479.     ts.x = bs->x*cs->x + bh->x*ch->x + bg->x*cg->x;
  10480.     ts.y = bs->x*cs->y + bh->x*ch->y + bg->x*cg->y;
  10481.     ts.z = bs->x*cs->z + bh->x*ch->z + bg->x*cg->z;
  10482.     th.x = bs->y*cs->x + bh->y*ch->x + bg->y*cg->x;
  10483.     th.y = bs->y*cs->y + bh->y*ch->y + bg->y*cg->y;
  10484.     th.z = bs->y*cs->z + bh->y*ch->z + bg->y*cg->z;
  10485.     tg.x = bs->z*cs->x + bh->z*ch->x + bg->z*cg->x;
  10486.     tg.y = bs->z*cs->y + bh->z*ch->y + bg->z*cg->y;
  10487.     tg.z = bs->z*cs->z + bh->z*ch->z + bg->z*cg->z;
  10488.     to.x = co->x - bo->x*ts.x - bo->y*th.x - bo->z*tg.x;
  10489.     to.y = co->y - bo->x*ts.y - bo->y*th.y - bo->z*tg.y;
  10490.     to.z = co->z - bo->x*ts.z - bo->y*th.z - bo->z*tg.z;
  10491.     (*as) = ts; (*ah) = th; (*ag) = tg; (*ao) = to;
  10492. }
  10493.  
  10494.     //A * B = C, find B   36*, 27ρ
  10495.     //[asx ahx agx aox][bsx bhx bgx box]   [csx chx cgx cox]
  10496.     //[asy ahy agy aoy][bsy bhy bgy boy] = [csy chy cgy coy]
  10497.     //[asz ahz agz aoz][bsz bhz bgz boz]   [csz chz cgz coz]
  10498.     //[  0   0   0   1][  0   0   0   1]   [  0   0   0   1]
  10499. void mat1 (point3d *as, point3d *ah, point3d *ag, point3d *ao,
  10500.               point3d *bs, point3d *bh, point3d *bg, point3d *bo,
  10501.               point3d *cs, point3d *ch, point3d *cg, point3d *co)
  10502. {
  10503.     point3d ts, th, tg, to;
  10504.     float x = co->x-ao->x, y = co->y-ao->y, z = co->z-ao->z;
  10505.     ts.x = cs->x*as->x + cs->y*as->y + cs->z*as->z;
  10506.     ts.y = cs->x*ah->x + cs->y*ah->y + cs->z*ah->z;
  10507.     ts.z = cs->x*ag->x + cs->y*ag->y + cs->z*ag->z;
  10508.     th.x = ch->x*as->x + ch->y*as->y + ch->z*as->z;
  10509.     th.y = ch->x*ah->x + ch->y*ah->y + ch->z*ah->z;
  10510.     th.z = ch->x*ag->x + ch->y*ag->y + ch->z*ag->z;
  10511.     tg.x = cg->x*as->x + cg->y*as->y + cg->z*as->z;
  10512.     tg.y = cg->x*ah->x + cg->y*ah->y + cg->z*ah->z;
  10513.     tg.z = cg->x*ag->x + cg->y*ag->y + cg->z*ag->z;
  10514.     to.x = as->x*x + as->y*y + as->z*z;
  10515.     to.y = ah->x*x + ah->y*y + ah->z*z;
  10516.     to.z = ag->x*x + ag->y*y + ag->z*z;
  10517.     (*bs) = ts; (*bh) = th; (*bg) = tg; (*bo) = to;
  10518. }
  10519.  
  10520.     //A * B = C, find C   36*, 27ρ
  10521.     //[asx ahx afx aox][bsx bhx bfx box]   [csx chx cfx cox]
  10522.     //[asy ahy afy aoy][bsy bhy bfy boy] = [csy chy cfy coy]
  10523.     //[asz ahz afz aoz][bsz bhz bfz boz]   [csz chz cfz coz]
  10524.     //[  0   0   0   1][  0   0   0   1]   [  0   0   0   1]
  10525. void mat2 (point3d *a_s, point3d *a_h, point3d *a_f, point3d *a_o,
  10526.               point3d *b_s, point3d *b_h, point3d *b_f, point3d *b_o,
  10527.               point3d *c_s, point3d *c_h, point3d *c_f, point3d *c_o)
  10528. {
  10529.     if (cputype&(1<<25))
  10530.     {
  10531.         _asm
  10532.         {
  10533.             mov eax, b_s
  10534.             mov edx, b_h
  10535.             movups xmm0, [eax]      ;xmm0:   -  bs.z bs.y bs.x
  10536.             movups xmm4, [edx]      ;xmm4:   -  bh.z bh.y bh.x
  10537.             mov eax, b_f
  10538.             mov edx, b_o
  10539.             movups xmm6, [eax]      ;xmm6:   -  bf.z bf.y bf.x
  10540.             movups xmm3, [edx]      ;xmm3:   -  bo.z bo.y bo.x
  10541.  
  10542.             mov eax, a_s
  10543.             mov edx, a_h
  10544.  
  10545.             movaps xmm2, xmm0       ;xmm2:   -  bs.z bs.y bs.x
  10546.             movaps xmm5, xmm6       ;xmm5:   -  bf.z bf.y bf.x
  10547.             unpcklps xmm0, xmm4     ;xmm0: bh.y bs.y bh.x bs.x
  10548.             unpcklps xmm6, xmm3     ;xmm6: bo.y bf.y bo.x bf.x
  10549.             movhlps xmm1, xmm0      ;xmm1:   -    -  bh.y bs.y
  10550.             movhlps xmm7, xmm6      ;xmm7:   -    -  bo.y bf.y
  10551.             unpckhps xmm2, xmm4     ;xmm2:   -    -  bh.z bs.z
  10552.             unpckhps xmm5, xmm3     ;xmm5:   -    -  bo.z bf.z
  10553.             movlhps xmm0, xmm6      ;xmm0: bo.x bf.x bh.x bs.x
  10554.             movlhps xmm1, xmm7      ;xmm1: bo.y bf.y bh.y bs.y
  10555.             movlhps xmm2, xmm5      ;xmm2: bo.z bf.z bh.z bs.z
  10556.  
  10557.             movss xmm3, [eax]
  10558.             shufps xmm3, xmm3, 0
  10559.             movss xmm4, [eax+4]
  10560.             shufps xmm4, xmm4, 0
  10561.             movss xmm5, [eax+8]
  10562.             shufps xmm5, xmm5, 0
  10563.             mulps xmm3, xmm0
  10564.             mulps xmm4, xmm0
  10565.             mulps xmm5, xmm0
  10566.  
  10567.             mov eax, a_f
  10568.  
  10569.             movss xmm6, [edx]
  10570.             shufps xmm6, xmm6, 0
  10571.             movss xmm7, [edx+4]
  10572.             shufps xmm7, xmm7, 0
  10573.             movss xmm0, [edx+8]
  10574.             shufps xmm0, xmm0, 0
  10575.             mulps xmm6, xmm1
  10576.             mulps xmm7, xmm1
  10577.             mulps xmm0, xmm1
  10578.             addps xmm3, xmm6
  10579.             addps xmm4, xmm7
  10580.             addps xmm5, xmm0
  10581.  
  10582.             mov edx, c_s
  10583.  
  10584.             movss xmm6, [eax]
  10585.             shufps xmm6, xmm6, 0
  10586.             movss xmm7, [eax+4]
  10587.             shufps xmm7, xmm7, 0
  10588.             movss xmm0, [eax+8]
  10589.             shufps xmm0, xmm0, 0
  10590.             mulps xmm6, xmm2
  10591.             mulps xmm7, xmm2
  10592.             mulps xmm0, xmm2
  10593.             addps xmm3, xmm6        ;xmm3: to.x tf.x th.x ts.x
  10594.             addps xmm4, xmm7        ;xmm4: to.y tf.y th.y ts.y
  10595.             addps xmm5, xmm0        ;xmm5: to.z tf.z th.z ts.z
  10596.  
  10597.             mov eax, c_f
  10598.  
  10599.             movss [edx], xmm3
  10600.             movhlps xmm0, xmm3
  10601.             movss [edx+4], xmm4
  10602.             movhlps xmm1, xmm4
  10603.             movss [edx+8], xmm5
  10604.             movhlps xmm2, xmm5
  10605.             mov edx, c_h
  10606.             movss [eax], xmm0
  10607.             movss [eax+4], xmm1
  10608.             movss [eax+8], xmm2
  10609.             shufps xmm3, xmm3, 0xb1 ;xmm3:   -  to.x   -  th.x
  10610.             shufps xmm4, xmm4, 0xb1 ;xmm4:   -  to.y   -  th.y
  10611.             shufps xmm5, xmm5, 0xb1 ;xmm5:   -  to.z   -  th.z
  10612.             mov eax, a_o
  10613.             movss [edx], xmm3
  10614.             movss [edx+4], xmm4
  10615.             movss [edx+8], xmm5
  10616.             mov edx, c_o
  10617.             movhlps xmm0, xmm3
  10618.             addss xmm0, [eax]
  10619.             movhlps xmm1, xmm4
  10620.             addss xmm1, [eax+4]
  10621.             movhlps xmm2, xmm5
  10622.             addss xmm2, [eax+8]
  10623.             movss [edx], xmm0
  10624.             movss [edx+4], xmm1
  10625.             movss [edx+8], xmm2
  10626.         }
  10627.     }
  10628.     else
  10629.     {
  10630.         point3d ts, th, tf, to;
  10631.         ts.x = a_s->x*b_s->x + a_h->x*b_s->y + a_f->x*b_s->z;
  10632.         ts.y = a_s->y*b_s->x + a_h->y*b_s->y + a_f->y*b_s->z;
  10633.         ts.z = a_s->z*b_s->x + a_h->z*b_s->y + a_f->z*b_s->z;
  10634.         th.x = a_s->x*b_h->x + a_h->x*b_h->y + a_f->x*b_h->z;
  10635.         th.y = a_s->y*b_h->x + a_h->y*b_h->y + a_f->y*b_h->z;
  10636.         th.z = a_s->z*b_h->x + a_h->z*b_h->y + a_f->z*b_h->z;
  10637.         tf.x = a_s->x*b_f->x + a_h->x*b_f->y + a_f->x*b_f->z;
  10638.         tf.y = a_s->y*b_f->x + a_h->y*b_f->y + a_f->y*b_f->z;
  10639.         tf.z = a_s->z*b_f->x + a_h->z*b_f->y + a_f->z*b_f->z;
  10640.         to.x = a_s->x*b_o->x + a_h->x*b_o->y + a_f->x*b_o->z + a_o->x;
  10641.         to.y = a_s->y*b_o->x + a_h->y*b_o->y + a_f->y*b_o->z + a_o->y;
  10642.         to.z = a_s->z*b_o->x + a_h->z*b_o->y + a_f->z*b_o->z + a_o->z;
  10643.         (*c_s) = ts; (*c_h) = th; (*c_f) = tf; (*c_o) = to;
  10644.     }
  10645. }
  10646.  
  10647. static void setlimb (kfatype *kfa, long i, long p, long trans_type, short val)
  10648. {
  10649.     point3d ps, ph, pf, pp;
  10650.     point3d qs, qh, qf, qp;
  10651.     float r[2];
  10652.  
  10653.         //Generate orthonormal matrix in world space for child limb
  10654.     qp = kfa->hinge[i].p[0]; qs = kfa->hinge[i].v[0]; genperp(&qs,&qh,&qf);
  10655.  
  10656.     switch (trans_type)
  10657.     {
  10658.         case 0: //Hinge rotate!
  10659.             //fcossin(((float)val)*(PI/32768.0),&c,&s);
  10660.             ucossin(((long)val)<<16,r);
  10661.             ph = qh; pf = qf;
  10662.             qh.x = ph.x*r[0] - pf.x*r[1]; qf.x = ph.x*r[1] + pf.x*r[0];
  10663.             qh.y = ph.y*r[0] - pf.y*r[1]; qf.y = ph.y*r[1] + pf.y*r[0];
  10664.             qh.z = ph.z*r[0] - pf.z*r[1]; qf.z = ph.z*r[1] + pf.z*r[0];
  10665.             break;
  10666.         default: __assume(0); //tells MSVC default can't be reached
  10667.     }
  10668.  
  10669.         //Generate orthonormal matrix in world space for parent limb
  10670.     pp = kfa->hinge[i].p[1]; ps = kfa->hinge[i].v[1]; genperp(&ps,&ph,&pf);
  10671.  
  10672.         //mat0(rotrans, loc_velcro, par_velcro)
  10673.     mat0(&qs,&qh,&qf,&qp, &qs,&qh,&qf,&qp, &ps,&ph,&pf,&pp);
  10674.         //mat2(par, rotrans, parent * par_velcro * (loc_velcro x rotrans)^-1)
  10675.     mat2(&kfa->spr[p].s,&kfa->spr[p].h,&kfa->spr[p].f,&kfa->spr[p].p,
  10676.           &qs,&qh,&qf,&qp,
  10677.           &kfa->spr[i].s,&kfa->spr[i].h,&kfa->spr[i].f,&kfa->spr[i].p);
  10678. }
  10679.  
  10680.     //Uses binary search to find sequence index at time "tim"
  10681. static long kfatime2seq (kfatype *kfa, long tim)
  10682. {
  10683.     long i, a, b;
  10684.  
  10685.     for(a=0,b=(kfa->seqnum)-1;b-a>=2;)
  10686.         { i = ((a+b)>>1); if (tim >= kfa->seq[i].tim) a = i; else b = i; }
  10687.     return(a);
  10688. }
  10689.  
  10690. void animsprite (vx5sprite *s, long ti)
  10691. {
  10692.     kfatype *kfa;
  10693.     long i, j, k, x, y, z, zz, trat;
  10694.     long trat2, z0, zz0, frm0;
  10695.  
  10696.     if (!(s->flags&2)) return;
  10697.     kfa = s->kfaptr; if (!kfa) return;
  10698.  
  10699.     z = kfatime2seq(kfa,s->kfatim);
  10700.     while (ti > 0)
  10701.     {
  10702.         z++; if (z >= kfa->seqnum) break;
  10703.         i = kfa->seq[z].tim-s->kfatim; if (i <= 0) break;
  10704.         if (i > ti) { s->kfatim += ti; break; }
  10705.         ti -= i;
  10706.         zz = ~kfa->seq[z].frm; if (zz >= 0) { if (z == zz) break; z = zz; }
  10707.         s->kfatim = kfa->seq[z].tim;
  10708.     }
  10709.  
  10710. // --------------------------------------------------------------------------
  10711.  
  10712.     z = kfatime2seq(kfa,s->kfatim); zz = z+1;
  10713.     if ((zz < kfa->seqnum) && (kfa->seq[zz].frm != ~zz))
  10714.     {
  10715.         trat = kfa->seq[zz].tim-kfa->seq[z].tim;
  10716.         if (trat) trat = shldiv16(s->kfatim-kfa->seq[z].tim,trat);
  10717.         i = kfa->seq[zz].frm; if (i < 0) zz = kfa->seq[~i].frm; else zz = i;
  10718.     } else trat = 0;
  10719.     z = kfa->seq[z].frm;
  10720.     if (z < 0)
  10721.     {
  10722.         z0 = kfatime2seq(kfa,s->okfatim); zz0 = z0+1;
  10723.         if ((zz0 < kfa->seqnum) && (kfa->seq[zz0].frm != ~zz0))
  10724.         {
  10725.             trat2 = kfa->seq[zz0].tim-kfa->seq[z0].tim;
  10726.             if (trat2) trat2 = shldiv16(s->okfatim-kfa->seq[z0].tim,trat2);
  10727.             i = kfa->seq[zz0].frm; if (i < 0) zz0 = kfa->seq[~i].frm; else zz0 = i;
  10728.         } else trat2 = 0;
  10729.         z0 = kfa->seq[z0].frm; if (z0 < 0) { z0 = zz0; trat2 = 0; }
  10730.     } else trat2 = -1;
  10731.  
  10732.     for(i=(kfa->numhin)-1;i>=0;i--)
  10733.     {
  10734.         if (kfa->hinge[i].parent < 0) continue;
  10735.  
  10736.         if (trat2 < 0) frm0 = (long)kfa->frmval[z*(kfa->numhin)+i];
  10737.         else
  10738.         {
  10739.             frm0 = (long)kfa->frmval[z0*(kfa->numhin)+i];
  10740.             if (trat2 > 0)
  10741.             {
  10742.                 x = (((long)(kfa->frmval[zz0*(kfa->numhin)+i]-frm0))&65535);
  10743.                 if (kfa->hinge[i].vmin == kfa->hinge[i].vmax) x = ((x<<16)>>16);
  10744.                 else if ((((long)(kfa->frmval[zz0*(kfa->numhin)+i]-kfa->hinge[i].vmin))&65535) <
  10745.                             (((long)(frm0-kfa->hinge[i].vmin))&65535))
  10746.                     x -= 65536;
  10747.                 frm0 += mulshr16(x,trat2);
  10748.             }
  10749.         }
  10750.         if (trat > 0)
  10751.         {
  10752.             x = (((long)(kfa->frmval[zz*(kfa->numhin)+i]-frm0))&65535);
  10753.             if (kfa->hinge[i].vmin == kfa->hinge[i].vmax) x = ((x<<16)>>16);
  10754.             else if ((((long)(kfa->frmval[zz*(kfa->numhin)+i]-kfa->hinge[i].vmin))&65535) <
  10755.                         (((long)(frm0-kfa->hinge[i].vmin))&65535))
  10756.                 x -= 65536;
  10757.             frm0 += mulshr16(x,trat);
  10758.         }
  10759.         vx5.kfaval[i] = frm0;
  10760.     }
  10761. }
  10762.  
  10763. static void kfadraw (vx5sprite *s)
  10764. {
  10765.     point3d tp;
  10766.     kfatype *kfa;
  10767.     long i, j, k;
  10768.  
  10769.     kfa = s->kfaptr; if (!kfa) return;
  10770.  
  10771.     for(i=(kfa->numhin)-1;i>=0;i--)
  10772.     {
  10773.         j = kfa->hingesort[i]; k = kfa->hinge[j].parent;
  10774.         if (k >= 0) setlimb(kfa,j,k,kfa->hinge[j].htype,vx5.kfaval[j]);
  10775.         else
  10776.         {
  10777.             kfa->spr[j].s = s->s;
  10778.             kfa->spr[j].h = s->h;
  10779.             kfa->spr[j].f = s->f;
  10780.             //kfa->spr[j].p = s->p;
  10781.             tp.x = kfa->hinge[j].p[0].x;
  10782.             tp.y = kfa->hinge[j].p[0].y;
  10783.             tp.z = kfa->hinge[j].p[0].z;
  10784.             kfa->spr[j].p.x = s->p.x - tp.x*s->s.x - tp.y*s->h.x - tp.z*s->f.x;
  10785.             kfa->spr[j].p.y = s->p.y - tp.x*s->s.y - tp.y*s->h.y - tp.z*s->f.y;
  10786.             kfa->spr[j].p.z = s->p.z - tp.x*s->s.z - tp.y*s->h.z - tp.z*s->f.z;
  10787.         }
  10788.         if (j < kfa->numspr) kv6draw(&kfa->spr[j]);
  10789.     }
  10790. }
  10791.  
  10792. //--------------------------- KFA sprite code ends ---------------------------
  10793.  
  10794. void drawsprite (vx5sprite *spr)
  10795. {
  10796.     if (spr->flags&4) return;
  10797.     if (!(spr->flags&2)) kv6draw(spr); else kfadraw(spr);
  10798. }
  10799.  
  10800. #if 0
  10801.  
  10802. void setkv6 (vx5sprite *spr)
  10803. {
  10804.     point3d r0, r1;
  10805.     long x, y, vx, vy, vz;
  10806.     kv6data *kv;
  10807.     kv6voxtype *v, *ve;
  10808.  
  10809.     if (spr->flags&2) return;
  10810.     kv = spr->voxnum; if (!kv) return;
  10811.  
  10812.     vx5.minx = ?; vx5.maxx = ?+1;
  10813.     vx5.miny = ?; vx5.maxy = ?+1;
  10814.     vx5.minz = ?; vx5.maxz = ?+1;
  10815.  
  10816.     v = kv->vox; //.01 is to fool rounding so they aren't all even numbers
  10817.     r0.x = spr->p.x - kv->xpiv*spr->s.x - kv->ypiv*spr->h.x - kv->zpiv*spr->f.x - .01;
  10818.     r0.y = spr->p.y - kv->xpiv*spr->s.y - kv->ypiv*spr->h.y - kv->zpiv*spr->f.y - .01;
  10819.     r0.z = spr->p.z - kv->xpiv*spr->s.z - kv->ypiv*spr->h.z - kv->zpiv*spr->f.z - .01;
  10820.     vx5.colfunc = curcolfunc;
  10821.     for(x=0;x<kv->xsiz;x++)
  10822.     {
  10823.         r1 = r0;
  10824.         for(y=0;y<kv->ysiz;y++)
  10825.         {
  10826.             for(ve=&v[kv->ylen[x*kv->ysiz+y]];v<ve;v++)
  10827.             {
  10828.                 ftol(spr->f.x*v->z + r1.x,&vx);
  10829.                 ftol(spr->f.y*v->z + r1.y,&vy);
  10830.                 ftol(spr->f.z*v->z + r1.z,&vz);
  10831.                 vx5.curcol = ((v->col&0xffffff)|0x80000000);
  10832.                 setcube(vx,vy,vz,-2);
  10833.             }
  10834.             r1.x += spr->h.x; r1.y += spr->h.y; r1.z += spr->h.z;
  10835.         }
  10836.         r0.x += spr->s.x; r0.y += spr->s.y; r0.z += spr->s.z;
  10837.     }
  10838. }
  10839.  
  10840. #else
  10841.  
  10842. #ifdef _MSC_VER
  10843.  
  10844.     //dmulshr22 = ((a*b + c*d)>>22)
  10845. static _inline long dmulshr22 (long a, long b, long c, long d)
  10846. {
  10847.     _asm
  10848.     {
  10849.         mov eax, a
  10850.         imul b
  10851.         mov ecx, eax
  10852.         push edx
  10853.         mov eax, c
  10854.         imul d
  10855.         add eax, ecx
  10856.         pop ecx
  10857.         adc edx, ecx
  10858.         shrd eax, edx, 22
  10859.     }
  10860. }
  10861.  
  10862.  
  10863. #endif
  10864.  
  10865. static kv6data *gfrezkv;
  10866. static lpoint3d gfrezx, gfrezy, gfrezz, gfrezp;
  10867. static signed char gkv6colx[27] = {0,  0, 0, 0, 0, 1,-1, -1,-1,-1,-1, 0, 0, 0, 0, 1, 1, 1, 1,  1, 1, 1, 1,-1,-1,-1,-1};
  10868. static signed char gkv6coly[27] = {0,  0, 0, 1,-1, 0, 0,  0, 0,-1, 1, 1, 1,-1,-1, 0, 0,-1, 1,  1, 1,-1,-1, 1, 1,-1,-1};
  10869. static signed char gkv6colz[27] = {0,  1,-1, 0, 0, 0, 0, -1, 1, 0, 0, 1,-1, 1,-1, 1,-1, 0, 0,  1,-1, 1,-1, 1,-1, 1,-1};
  10870. long kv6colfunc (lpoint3d *p)
  10871. {
  10872.     kv6voxtype *v0, *v1, *v, *ve;
  10873.     long i, j, k, x, y, z, ox, oy, nx, ny, nz, mind, d;
  10874.  
  10875.     x = ((p->x*gfrezx.x + p->y*gfrezy.x + p->z*gfrezz.x + gfrezp.x)>>16);
  10876.     y = ((p->x*gfrezx.y + p->y*gfrezy.y + p->z*gfrezz.y + gfrezp.y)>>16);
  10877.     z = ((p->x*gfrezx.z + p->y*gfrezy.z + p->z*gfrezz.z + gfrezp.z)>>16);
  10878.     x = lbound0(x,gfrezkv->xsiz-1);
  10879.     y = lbound0(y,gfrezkv->ysiz-1);
  10880.     z = lbound0(z,gfrezkv->zsiz-1);
  10881.  
  10882.         //Process x
  10883.     v0 = gfrezkv->vox;
  10884.     if ((x<<1) < gfrezkv->xsiz) { ox = oy = j = 0; }
  10885.     else { v0 += gfrezkv->numvoxs; ox = gfrezkv->xsiz; oy = gfrezkv->ysiz; j = ox*oy; }
  10886.     v1 = v0;
  10887.  
  10888.     for(k=0;k<27;k++)
  10889.     {
  10890.         nx = ((long)gkv6colx[k])+x; if ((unsigned long)nx >= gfrezkv->xsiz) continue;
  10891.         ny = ((long)gkv6coly[k])+y; if ((unsigned long)ny >= gfrezkv->ysiz) continue;
  10892.         nz = ((long)gkv6colz[k])+z; if ((unsigned long)nz >= gfrezkv->zsiz) continue;
  10893.  
  10894.         if (nx != ox)
  10895.         {
  10896.             while (nx > ox) { v0 += gfrezkv->xlen[ox]; ox++; j += gfrezkv->ysiz; }
  10897.             while (nx < ox) { ox--; v0 -= gfrezkv->xlen[ox]; j -= gfrezkv->ysiz; }
  10898.             if ((ny<<1) < gfrezkv->ysiz) { oy = 0; v1 = v0; }
  10899.             else { oy = gfrezkv->ysiz; v1 = v0+gfrezkv->xlen[nx]; }
  10900.         }
  10901.         if (ny != oy)
  10902.         {
  10903.             while (ny > oy) { v1 += gfrezkv->ylen[j+oy]; oy++; }
  10904.             while (ny < oy) { oy--; v1 -= gfrezkv->ylen[j+oy]; }
  10905.         }
  10906.  
  10907.             //Process z
  10908.         for(v=v1,ve=&v1[gfrezkv->ylen[j+ny]];v<ve;v++)
  10909.             if (v->z == nz) return(v->col);
  10910.     }
  10911.  
  10912.         //Use brute force when all else fails.. :/
  10913.     v = gfrezkv->vox; mind = 0x7fffffff;
  10914.     for(nx=0;nx<gfrezkv->xsiz;nx++)
  10915.         for(ny=0;ny<gfrezkv->ysiz;ny++)
  10916.             for(ve=&v[gfrezkv->ylen[nx*gfrezkv->ysiz+ny]];v<ve;v++)
  10917.             {
  10918.                 d = labs(x-nx)+labs(y-ny)+labs(z-v->z);
  10919.                 if (d < mind) { mind = d; k = v->col; }
  10920.             }
  10921.     return(k);
  10922. }
  10923.  
  10924. static void kv6colfuncinit (vx5sprite *spr, float det)
  10925. {
  10926.     point3d tp, tp2;
  10927.     float f;
  10928.  
  10929.     gfrezkv = spr->voxnum; if (!gfrezkv) { vx5.colfunc = curcolfunc; return; }
  10930.  
  10931.     tp2.x = gfrezkv->xpiv + .5;
  10932.     tp2.y = gfrezkv->ypiv + .5;
  10933.     tp2.z = gfrezkv->zpiv + .5;
  10934.     tp.x = spr->p.x - spr->s.x*tp2.x - spr->h.x*tp2.y - spr->f.x*tp2.z;
  10935.     tp.y = spr->p.y - spr->s.y*tp2.x - spr->h.y*tp2.y - spr->f.y*tp2.z;
  10936.     tp.z = spr->p.z - spr->s.z*tp2.x - spr->h.z*tp2.y - spr->f.z*tp2.z;
  10937.  
  10938.         //spr->s.x*x + spr->h.x*y + spr->f.x*z = np.x; //Solve for x,y,z
  10939.         //spr->s.y*x + spr->h.y*y + spr->f.y*z = np.y;
  10940.         //spr->s.z*x + spr->h.z*y + spr->f.z*z = np.z;
  10941.     f = 65536.0 / det;
  10942.  
  10943.     tp2.x = (spr->h.y*spr->f.z - spr->h.z*spr->f.y)*f; ftol(tp2.x,&gfrezx.x);
  10944.     tp2.y = (spr->h.z*spr->f.x - spr->h.x*spr->f.z)*f; ftol(tp2.y,&gfrezy.x);
  10945.     tp2.z = (spr->h.x*spr->f.y - spr->h.y*spr->f.x)*f; ftol(tp2.z,&gfrezz.x);
  10946.     ftol(-tp.x*tp2.x - tp.y*tp2.y - tp.z*tp2.z,&gfrezp.x); gfrezp.x += 32767;
  10947.  
  10948.     tp2.x = (spr->f.y*spr->s.z - spr->f.z*spr->s.y)*f; ftol(tp2.x,&gfrezx.y);
  10949.     tp2.y = (spr->f.z*spr->s.x - spr->f.x*spr->s.z)*f; ftol(tp2.y,&gfrezy.y);
  10950.     tp2.z = (spr->f.x*spr->s.y - spr->f.y*spr->s.x)*f; ftol(tp2.z,&gfrezz.y);
  10951.     ftol(-tp.x*tp2.x - tp.y*tp2.y - tp.z*tp2.z,&gfrezp.y); gfrezp.y += 32767;
  10952.  
  10953.     tp2.x = (spr->s.y*spr->h.z - spr->s.z*spr->h.y)*f; ftol(tp2.x,&gfrezx.z);
  10954.     tp2.y = (spr->s.z*spr->h.x - spr->s.x*spr->h.z)*f; ftol(tp2.y,&gfrezy.z);
  10955.     tp2.z = (spr->s.x*spr->h.y - spr->s.y*spr->h.x)*f; ftol(tp2.z,&gfrezz.z);
  10956.     ftol(-tp.x*tp2.x - tp.y*tp2.y - tp.z*tp2.z,&gfrezp.z); gfrezp.z += 32768;
  10957. }
  10958.  
  10959. #define LSC3 8 //2 for testing, 8 is normal
  10960. typedef struct
  10961. {
  10962.     long xo, yo, zo, xu, yu, zu, xv, yv, zv, d, msk, pzi;
  10963.     long xmino, ymino, xmaxo, ymaxo, xusc, yusc, xvsc, yvsc;
  10964. } gfrezt;
  10965. static gfrezt gfrez[6];
  10966. typedef struct { char z[2]; long n; } slstype;
  10967. void setkv6 (vx5sprite *spr, long dacol)
  10968. {
  10969.     point3d tp, tp2; float f, det;
  10970.     long i, j, k, x, y, z, c, d, x0, y0, z0, x1, y1, z1, xi, yi, zi;
  10971.     long xo, yo, zo, xu, yu, zu, xv, yv, zv, stu, stv, tu, tv;
  10972.     long xx, yy, xmin, xmax, ymin, ymax, isrhs, ihxi, ihyi, ihzi, syshpit;
  10973.     long isx, isy, isz, ihx, ihy, ihz, ifx, ify, ifz, iox, ioy, ioz;
  10974.     long sx, sy, sx0, sy0, sz0, rx, ry, rz, pz, dcnt, dcnt2, vismask, xysiz;
  10975.     long bx0, by0, bz0, bx1, by1, bz1, *lptr, *shead, shpit, scnt, sstop;
  10976.     gfrezt *gf;
  10977.     slstype *slst;
  10978.     kv6data *kv;
  10979.     kv6voxtype *v0, *v1, *v2, *v3;
  10980.     void (*modslab)(long *, long, long);
  10981.  
  10982.     if (spr->flags&2) return;
  10983.     kv = spr->voxnum; if (!kv) return;
  10984.  
  10985.         //Calculate top-left-up corner in VXL world coordinates
  10986.     tp.x = kv->xpiv + .5;
  10987.     tp.y = kv->ypiv + .5;
  10988.     tp.z = kv->zpiv + .5;
  10989.     tp2.x = spr->p.x - spr->s.x*tp.x - spr->h.x*tp.y - spr->f.x*tp.z;
  10990.     tp2.y = spr->p.y - spr->s.y*tp.x - spr->h.y*tp.y - spr->f.y*tp.z;
  10991.     tp2.z = spr->p.z - spr->s.z*tp.x - spr->h.z*tp.y - spr->f.z*tp.z;
  10992.  
  10993.         //Get bounding x-y box of entire freeze area:
  10994.     bx0 = VSID; by0 = VSID; bz0 = MAXZDIM; bx1 = 0; by1 = 0; bz1 = 0;
  10995.     for(z=kv->zsiz;z>=0;z-=kv->zsiz)
  10996.         for(y=kv->ysiz;y>=0;y-=kv->ysiz)
  10997.             for(x=kv->xsiz;x>=0;x-=kv->xsiz)
  10998.             {
  10999.                 ftol(spr->s.x*(float)x + spr->h.x*(float)y + spr->f.x*(float)z + tp2.x,&i);
  11000.                 if (i < bx0) bx0 = i;
  11001.                 if (i > bx1) bx1 = i;
  11002.                 ftol(spr->s.y*(float)x + spr->h.y*(float)y + spr->f.y*(float)z + tp2.y,&i);
  11003.                 if (i < by0) by0 = i;
  11004.                 if (i > by1) by1 = i;
  11005.                 ftol(spr->s.z*(float)x + spr->h.z*(float)y + spr->f.z*(float)z + tp2.z,&i);
  11006.                 if (i < bz0) bz0 = i;
  11007.                 if (i > bz1) bz1 = i;
  11008.             }
  11009.     bx0 -= 2; if (bx0 < 0) bx0 = 0;
  11010.     by0 -= 2; if (by0 < 0) by0 = 0;
  11011.     bz0 -= 2; if (bz0 < 0) bz0 = 0;
  11012.     bx1 += 2; if (bx1 > VSID) bx1 = VSID;
  11013.     by1 += 2; if (by1 > VSID) by1 = VSID;
  11014.     bz1 += 2; if (bz1 > MAXZDIM) bz1 = MAXZDIM;
  11015.     vx5.minx = bx0; vx5.maxx = bx1;
  11016.     vx5.miny = by0; vx5.maxy = by1;
  11017.     vx5.minz = bz0; vx5.maxz = bz1;
  11018.  
  11019.     shpit = bx1-bx0; i = (by1-by0)*shpit*sizeof(shead[0]);
  11020.         //Make sure to use array that's big enough: umost is 1MB
  11021.     shead = (long *)(((long)umost) - (by0*shpit+bx0)*sizeof(shead[0]));
  11022.     slst = (slstype *)(((long)umost)+i);
  11023.     scnt = 1; sstop = (sizeof(umost)-i)/sizeof(slstype);
  11024.     memset(umost,0,i);
  11025.  
  11026.     f = (float)(1<<LSC3);
  11027.     ftol(spr->s.x*f,&isx); ftol(spr->s.y*f,&isy); ftol(spr->s.z*f,&isz);
  11028.     ftol(spr->h.x*f,&ihx); ftol(spr->h.y*f,&ihy); ftol(spr->h.z*f,&ihz);
  11029.     ftol(spr->f.x*f,&ifx); ftol(spr->f.y*f,&ify); ftol(spr->f.z*f,&ifz);
  11030.     ftol(tp2.x*f,&iox);
  11031.     ftol(tp2.y*f,&ioy);
  11032.     ftol(tp2.z*f,&ioz);
  11033.  
  11034.         //Determine whether sprite is RHS(1) or LHS(0)
  11035.     det = (spr->h.y*spr->f.z - spr->h.z*spr->f.y)*spr->s.x +
  11036.             (spr->h.z*spr->f.x - spr->h.x*spr->f.z)*spr->s.y +
  11037.             (spr->h.x*spr->f.y - spr->h.y*spr->f.x)*spr->s.z;
  11038.     if ((*(long *)&det) > 0) isrhs = 1;
  11039.     else if ((*(long *)&det) < 0) isrhs = 0;
  11040.     else return;
  11041.  
  11042.     xi = (((ifx*ihy-ihx*ify)>>31)|1);
  11043.     yi = (((isx*ify-ifx*isy)>>31)|1);
  11044.     zi = (((ihx*isy-isx*ihy)>>31)|1);
  11045.     if (xi > 0) { x0 = 0; x1 = kv->xsiz; } else { x0 = kv->xsiz-1; x1 = -1; }
  11046.     if (yi > 0) { y0 = 0; y1 = kv->ysiz; } else { y0 = kv->ysiz-1; y1 = -1; }
  11047.     if (zi > 0) { z0 = 0; z1 = kv->zsiz; } else { z0 = kv->zsiz-1; z1 = -1; }
  11048.  
  11049.     vismask = (zi<<3)+24 + (yi<<1)+6 + (xi>>1)+2;
  11050.  
  11051.     dcnt = 0;
  11052.     for(j=2;j;j--)
  11053.     {
  11054.         dcnt2 = dcnt;
  11055.         vismask = ~vismask;
  11056.         for(i=1;i<64;i+=i)
  11057.         {
  11058.             if (!(vismask&i)) continue;
  11059.  
  11060.             if (i&0x15) { xo = yo = zo = 0; }
  11061.             else if (i == 2) { xo = isx; yo = isy; zo = isz; }
  11062.             else if (i == 8) { xo = ihx; yo = ihy; zo = ihz; }
  11063.             else             { xo = ifx; yo = ify; zo = ifz; }
  11064.  
  11065.                   if (i&3)  { xu = ihx; yu = ihy; zu = ihz; xv = ifx; yv = ify; zv = ifz; }
  11066.             else if (i&12) { xu = isx; yu = isy; zu = isz; xv = ifx; yv = ify; zv = ifz; }
  11067.             else           { xu = isx; yu = isy; zu = isz; xv = ihx; yv = ihy; zv = ihz; }
  11068.  
  11069.             if ((yu < 0) || ((!yu) && (xu < 0)))
  11070.                 { xo += xu; yo += yu; zo += zu; xu = -xu; yu = -yu; zu = -zu; }
  11071.             if ((yv < 0) || ((!yv) && (xv < 0)))
  11072.                 { xo += xv; yo += yv; zo += zv; xv = -xv; yv = -yv; zv = -zv; }
  11073.             d = xv*yu - xu*yv; if (!d) continue;
  11074.             if (d < 0)
  11075.             {
  11076.                 k = xu; xu = xv; xv = k;
  11077.                 k = yu; yu = yv; yv = k;
  11078.                 k = zu; zu = zv; zv = k; d = -d;
  11079.             }
  11080.             xmin = ymin = xmax = ymax = 0;
  11081.             if (xu < 0) xmin += xu; else xmax += xu;
  11082.             if (yu < 0) ymin += yu; else ymax += yu;
  11083.             if (xv < 0) xmin += xv; else xmax += xv;
  11084.             if (yv < 0) ymin += yv; else ymax += yv;
  11085.  
  11086.             gf = &gfrez[dcnt];
  11087.             gf->xo = xo; gf->yo = yo; gf->zo = zo;
  11088.             gf->xu = xu; gf->yu = yu;
  11089.             gf->xv = xv; gf->yv = yv;
  11090.             gf->xmino = xmin; gf->ymino = ymin;
  11091.             gf->xmaxo = xmax; gf->ymaxo = ymax;
  11092.             gf->xusc = (xu<<LSC3); gf->yusc = (yu<<LSC3);
  11093.             gf->xvsc = (xv<<LSC3); gf->yvsc = (yv<<LSC3);
  11094.             gf->d = d; gf->msk = i;
  11095.  
  11096.             f = 1.0 / (float)d;
  11097.             ftol(((float)gf->yusc * (float)zv - (float)gf->yvsc * (float)zu) * f,&gf->pzi);
  11098.             f *= 4194304.0;
  11099.             ftol((float)zu*f,&gf->zu);
  11100.             ftol((float)zv*f,&gf->zv);
  11101.  
  11102.             dcnt++;
  11103.         }
  11104.     }
  11105.  
  11106.     ihxi = ihx*yi;
  11107.     ihyi = ihy*yi;
  11108.     ihzi = ihz*yi;
  11109.  
  11110.     if (xi < 0) v0 = kv->vox+kv->numvoxs; else v0 = kv->vox;
  11111.     for(x=x0;x!=x1;x+=xi)
  11112.     {
  11113.         i = (long)kv->xlen[x];
  11114.         if (xi < 0) v0 -= i;
  11115.         if (yi < 0) v1 = v0+i; else v1 = v0;
  11116.         if (xi >= 0) v0 += i;
  11117.         xysiz = x*kv->ysiz;
  11118.         sx0 = isx*x + ihx*y0 + iox;
  11119.         sy0 = isy*x + ihy*y0 + ioy;
  11120.         sz0 = isz*x + ihz*y0 + ioz;
  11121.         for(y=y0;y!=y1;y+=yi)
  11122.         {
  11123.             i = (long)kv->ylen[xysiz+y];
  11124.             if (yi < 0) v1 -= i;
  11125.             if (zi < 0) { v2 = v1+i-1; v3 = v1-1; }
  11126.                      else { v2 = v1; v3 = v1+i; }
  11127.             if (yi >= 0) v1 += i;
  11128.             while (v2 != v3)
  11129.             {
  11130.                 z = v2->z; //c = v2->col;
  11131.                 rx = ifx*z + sx0;
  11132.                 ry = ify*z + sy0;
  11133.                 rz = ifz*z + sz0;
  11134.                 for(i=0;i<dcnt;i++)
  11135.                 {
  11136.                     gf = &gfrez[i]; if (!(v2->vis&gf->msk)) continue;
  11137.                     xo = gf->xo + rx;
  11138.                     yo = gf->yo + ry;
  11139.                     zo = gf->zo + rz;
  11140.                     xmin = ((gf->xmino + xo)>>LSC3); if (xmin < 0) xmin = 0;
  11141.                     ymin = ((gf->ymino + yo)>>LSC3); if (ymin < 0) ymin = 0;
  11142.                     xmax = ((gf->xmaxo + xo)>>LSC3)+1; if (xmax > VSID) xmax = VSID;
  11143.                     ymax = ((gf->ymaxo + yo)>>LSC3)+1; if (ymax > VSID) ymax = VSID;
  11144.                     xx = (xmin<<LSC3) - xo;
  11145.                     yy = (ymin<<LSC3) - yo;
  11146.                     stu = yy*gf->xu - xx*gf->yu;
  11147.                     stv = yy*gf->xv - xx*gf->yv - gf->d;
  11148.                     syshpit = ymin*shpit;
  11149.                     for(sy=ymin;sy<ymax;sy++,syshpit+=shpit)
  11150.                     {
  11151.                         tu = stu; stu += gf->xusc;
  11152.                         tv = stv; stv += gf->xvsc;
  11153.                         sx = xmin;
  11154.                         while ((tu&tv) >= 0)
  11155.                         {
  11156.                             sx++; if (sx >= xmax) goto freezesprcont;
  11157.                             tu -= gf->yusc; tv -= gf->yvsc;
  11158.                         }
  11159.                         tu = ~tu; tv += gf->d;
  11160.                         pz = dmulshr22(tu,gf->zv,tv,gf->zu) + zo; j = syshpit+sx;
  11161.                         tu -= gf->d; tv = ~tv;
  11162.                         while ((tu&tv) < 0)
  11163.                         {
  11164.                             if (i < dcnt2)
  11165.                             {
  11166.                                 if (scnt >= sstop) return; //OUT OF BUFFER SPACE!
  11167.                                 slst[scnt].z[0] = (char)lbound0(pz>>LSC3,255);
  11168.                                 slst[scnt].n = shead[j]; shead[j] = scnt; scnt++;
  11169.                             }
  11170.                             else slst[shead[j]].z[1] = (char)lbound0(pz>>LSC3,255);
  11171.                             tu += gf->yusc; tv += gf->yvsc; pz += gf->pzi; j++;
  11172.                         }
  11173. freezesprcont:;
  11174.                     }
  11175.                 }
  11176.                 v2 += zi;
  11177.             }
  11178.             sx0 += ihxi; sy0 += ihyi; sz0 += ihzi;
  11179.         }
  11180.     }
  11181.  
  11182.     if (dacol == -1) modslab = delslab; else modslab = insslab;
  11183.  
  11184.     if (vx5.colfunc == kv6colfunc) kv6colfuncinit(spr,det);
  11185.  
  11186.     j = by0*shpit+bx0;
  11187.     for(sy=by0;sy<by1;sy++)
  11188.         for(sx=bx0;sx<bx1;sx++,j++)
  11189.         {
  11190.             i = shead[j]; if (!i) continue;
  11191.             lptr = scum2(sx,sy);
  11192.             do
  11193.             {
  11194.                 modslab(lptr,(long)slst[i].z[isrhs],(long)slst[i].z[isrhs^1]);
  11195.                 i = slst[i].n;
  11196.             } while (i);
  11197.         }
  11198.     scum2finish();
  11199.     updatebbox(vx5.minx,vx5.miny,vx5.minz,vx5.maxx,vx5.maxy,vx5.maxz,dacol);
  11200. }
  11201.  
  11202. #endif
  11203.  
  11204.     //Sprite structure is already allocated
  11205.     //kv6, vox, xlen, ylen are all malloced in here!
  11206. long meltsphere (vx5sprite *spr, lpoint3d *hit, long hitrad)
  11207. {
  11208.     long i, j, x, y, z, xs, ys, zs, xe, ye, ze, sq, z0, z1;
  11209.     long oxvoxs, oyvoxs, numvoxs, cx, cy, cz, cw;
  11210.     float f, ff;
  11211.     kv6data *kv;
  11212.     kv6voxtype *voxptr;
  11213.     unsigned long *xlenptr;
  11214.     unsigned short *ylenptr;
  11215.  
  11216.     xs = max(hit->x-hitrad,0); xe = min(hit->x+hitrad,VSID-1);
  11217.     ys = max(hit->y-hitrad,0); ye = min(hit->y+hitrad,VSID-1);
  11218.     zs = max(hit->z-hitrad,0); ze = min(hit->z+hitrad,MAXZDIM-1);
  11219.     if ((xs > xe) || (ys > ye) || (zs > ze)) return(0);
  11220.  
  11221.     if (hitrad >= SETSPHMAXRAD-1) hitrad = SETSPHMAXRAD-2;
  11222.  
  11223.     tempfloatbuf[0] = 0.0f;
  11224. #if 0
  11225.         //Totally unoptimized
  11226.     for(i=1;i<=hitrad;i++) tempfloatbuf[i] = pow((float)i,vx5.curpow);
  11227. #else
  11228.     tempfloatbuf[1] = 1.0f;
  11229.     for(i=2;i<=hitrad;i++)
  11230.     {
  11231.         if (!factr[i][0]) tempfloatbuf[i] = exp(logint[i]*vx5.curpow);
  11232.         else tempfloatbuf[i] = tempfloatbuf[factr[i][0]]*tempfloatbuf[factr[i][1]];
  11233.     }
  11234. #endif
  11235.     *(long *)&tempfloatbuf[hitrad+1] = 0x7f7fffff; //3.4028235e38f; //Highest float
  11236.  
  11237. // ---------- Need to know how many voxels to allocate... SLOW!!! :( ----------
  11238.     cx = cy = cz = 0; //Centroid
  11239.     cw = 0;       //Weight (1 unit / voxel)
  11240.     numvoxs = 0;
  11241.     sq = 0; //pow(fabs(x-hit->x),vx5.curpow) + "y + "z < pow(vx5.currad,vx5.curpow)
  11242.     for(x=xs;x<=xe;x++)
  11243.     {
  11244.         ff = tempfloatbuf[hitrad]-tempfloatbuf[labs(x-hit->x)];
  11245.         for(y=ys;y<=ye;y++)
  11246.         {
  11247.             f = ff-tempfloatbuf[labs(y-hit->y)];
  11248.             if (*(long *)&f > 0) //WARNING: make sure to always write ylenptr!
  11249.             {
  11250.                 while (*(long *)&tempfloatbuf[sq] <  *(long *)&f) sq++;
  11251.                 while (*(long *)&tempfloatbuf[sq] >= *(long *)&f) sq--;
  11252.                 z0 = max(hit->z-sq,zs); z1 = min(hit->z+sq+1,ze);
  11253.                 for(z=z0;z<z1;z++)
  11254.                 {
  11255.                     i = getcube(x,y,z); //0:air, 1:unexposed solid, 2:vbuf col ptr
  11256.                     if (i)
  11257.                     {
  11258.                         cx += (x-hit->x); cy += (y-hit->y); cz += (z-hit->z); cw++;
  11259.                     }
  11260.                     if ((i == 0) || ((i == 1) && (1))) continue; //not_on_border))) continue; //FIX THIS!!!
  11261.                     numvoxs++;
  11262.                 }
  11263.             }
  11264.         }
  11265.     }
  11266.     if (numvoxs <= 0) return(0); //No voxels found!
  11267. // ---------------------------------------------------------------------------
  11268.  
  11269.     f = 1.0 / (float)cw; //Make center of sprite the centroid
  11270.     spr->p.x = (float)hit->x + (float)cx*f;
  11271.     spr->p.y = (float)hit->y + (float)cy*f;
  11272.     spr->p.z = (float)hit->z + (float)cz*f;
  11273.     spr->s.x = 1.f; spr->h.x = 0.f; spr->f.x = 0.f;
  11274.     spr->s.y = 0.f; spr->h.y = 1.f; spr->f.y = 0.f;
  11275.     spr->s.z = 0.f; spr->h.z = 0.f; spr->f.z = 1.f;
  11276.  
  11277.     x = xe-xs+1; y = ye-ys+1; z = ze-zs+1;
  11278.  
  11279.     j = sizeof(kv6data) + numvoxs*sizeof(kv6voxtype) + x*4 + x*y*2;
  11280.     i = (long)malloc(j); if (!i) return(0); if (i&3) { free((void *)i); return(0); }
  11281.     spr->voxnum = kv = (kv6data *)i; spr->flags = 0;
  11282.     kv->leng = j;
  11283.     kv->xsiz = x;
  11284.     kv->ysiz = y;
  11285.     kv->zsiz = z;
  11286.     kv->xpiv = spr->p.x - xs;
  11287.     kv->ypiv = spr->p.y - ys;
  11288.     kv->zpiv = spr->p.z - zs;
  11289.     kv->numvoxs = numvoxs;
  11290.     kv->namoff = 0;
  11291.     kv->lowermip = 0;
  11292.     kv->vox = (kv6voxtype *)((long)spr->voxnum+sizeof(kv6data));
  11293.     kv->xlen = (unsigned long *)(((long)kv->vox)+numvoxs*sizeof(kv6voxtype));
  11294.     kv->ylen = (unsigned short *)(((long)kv->xlen) + kv->xsiz*4);
  11295.  
  11296.     voxptr = kv->vox; numvoxs = 0;
  11297.     xlenptr = kv->xlen; oxvoxs = 0;
  11298.     ylenptr = kv->ylen; oyvoxs = 0;
  11299.  
  11300.     sq = 0; //pow(fabs(x-hit->x),vx5.curpow) + "y + "z < pow(vx5.currad,vx5.curpow)
  11301.     for(x=xs;x<=xe;x++)
  11302.     {
  11303.         ff = tempfloatbuf[hitrad]-tempfloatbuf[labs(x-hit->x)];
  11304.         for(y=ys;y<=ye;y++)
  11305.         {
  11306.             f = ff-tempfloatbuf[labs(y-hit->y)];
  11307.             if (*(long *)&f > 0) //WARNING: make sure to always write ylenptr!
  11308.             {
  11309.                 while (*(long *)&tempfloatbuf[sq] <  *(long *)&f) sq++;
  11310.                 while (*(long *)&tempfloatbuf[sq] >= *(long *)&f) sq--;
  11311.                 z0 = max(hit->z-sq,zs); z1 = min(hit->z+sq+1,ze);
  11312.                 for(z=z0;z<z1;z++)
  11313.                 {
  11314.                     i = getcube(x,y,z); //0:air, 1:unexposed solid, 2:vbuf col ptr
  11315.                     if ((i == 0) || ((i == 1) && (1))) continue; //not_on_border))) continue; //FIX THIS!!!
  11316.                     voxptr[numvoxs].col = lightvox(*(long *)i);
  11317.                     voxptr[numvoxs].z = z-zs;
  11318.                     voxptr[numvoxs].vis = 63; //FIX THIS!!!
  11319.                     voxptr[numvoxs].dir = 0; //FIX THIS!!!
  11320.                     numvoxs++;
  11321.                 }
  11322.             }
  11323.             *ylenptr++ = numvoxs-oyvoxs; oyvoxs = numvoxs;
  11324.         }
  11325.         *xlenptr++ = numvoxs-oxvoxs; oxvoxs = numvoxs;
  11326.     }
  11327.     return(cw);
  11328. }
  11329.  
  11330.     //Sprite structure is already allocated
  11331.     //kv6, vox, xlen, ylen are all malloced in here!
  11332. long meltspans (vx5sprite *spr, vspans *lst, long lstnum, lpoint3d *offs)
  11333. {
  11334.     float f;
  11335.     long i, j, x, y, z, xs, ys, zs, xe, ye, ze, z0, z1;
  11336.     long ox, oy, oxvoxs, oyvoxs, numvoxs, cx, cy, cz, cw;
  11337.     kv6data *kv;
  11338.     kv6voxtype *voxptr;
  11339.     unsigned long *xlenptr;
  11340.     unsigned short *ylenptr;
  11341.  
  11342.     if (lstnum <= 0) return(0);
  11343. // ---------- Need to know how many voxels to allocate... SLOW!!! :( ----------
  11344.     cx = cy = cz = 0; //Centroid
  11345.     cw = 0;       //Weight (1 unit / voxel)
  11346.     numvoxs = 0;
  11347.     xs = xe = ((long)lst[0].x)+offs->x;
  11348.     ys = ((long)lst[       0].y)+offs->y;
  11349.     ye = ((long)lst[lstnum-1].y)+offs->y;
  11350.     zs = ze = ((long)lst[0].z0)+offs->z;
  11351.     for(j=0;j<lstnum;j++)
  11352.     {
  11353.         x = ((long)lst[j].x)+offs->x;
  11354.         y = ((long)lst[j].y)+offs->y; if ((x|y)&(~(VSID-1))) continue;
  11355.               if (x < xs) xs = x;
  11356.         else if (x > xe) xe = x;
  11357.         z0 = ((long)lst[j].z0)+offs->z;   if (z0 < 0) z0 = 0;
  11358.         z1 = ((long)lst[j].z1)+offs->z+1; if (z1 > MAXZDIM) z1 = MAXZDIM;
  11359.         if (z0 < zs) zs = z0;
  11360.         if (z1 > ze) ze = z1;
  11361.         for(z=z0;z<z1;z++) //getcube too SLOW... FIX THIS!!!
  11362.         {
  11363.             i = getcube(x,y,z); //0:air, 1:unexposed solid, 2:vbuf col ptr
  11364.             if (i) { cx += x-offs->x; cy += y-offs->y; cz += z-offs->z; cw++; }
  11365.             if (i&~1) numvoxs++;
  11366.         }
  11367.     }
  11368.     if (numvoxs <= 0) return(0); //No voxels found!
  11369. // ---------------------------------------------------------------------------
  11370.  
  11371.     f = 1.0 / (float)cw; //Make center of sprite the centroid
  11372.     spr->p.x = (float)offs->x + (float)cx*f;
  11373.     spr->p.y = (float)offs->y + (float)cy*f;
  11374.     spr->p.z = (float)offs->z + (float)cz*f;
  11375.     spr->x.x = 0.f; spr->y.x = 1.f; spr->z.x = 0.f;
  11376.     spr->x.y = 1.f; spr->y.y = 0.f; spr->z.y = 0.f;
  11377.     spr->x.z = 0.f; spr->y.z = 0.f; spr->z.z = 1.f;
  11378.  
  11379.     x = xe-xs+1; y = ye-ys+1; z = ze-zs;
  11380.  
  11381.     j = sizeof(kv6data) + numvoxs*sizeof(kv6voxtype) + y*4 + x*y*2;
  11382.     i = (long)malloc(j); if (!i) return(0); if (i&3) { free((void *)i); return(0); }
  11383.     spr->voxnum = kv = (kv6data *)i; spr->flags = 0;
  11384.     kv->leng = j;
  11385.     kv->xsiz = y;
  11386.     kv->ysiz = x;
  11387.     kv->zsiz = z;
  11388.     kv->xpiv = spr->p.y - ys;
  11389.     kv->ypiv = spr->p.x - xs;
  11390.     kv->zpiv = spr->p.z - zs;
  11391.     kv->numvoxs = numvoxs;
  11392.     kv->namoff = 0;
  11393.     kv->lowermip = 0;
  11394.     kv->vox = (kv6voxtype *)((long)spr->voxnum+sizeof(kv6data));
  11395.     kv->xlen = (unsigned long *)(((long)kv->vox)+numvoxs*sizeof(kv6voxtype));
  11396.     kv->ylen = (unsigned short *)(((long)kv->xlen) + kv->xsiz*4);
  11397.  
  11398.     voxptr = kv->vox; numvoxs = 0;
  11399.     xlenptr = kv->xlen; oxvoxs = 0;
  11400.     ylenptr = kv->ylen; oyvoxs = 0;
  11401.     ox = xs; oy = ys;
  11402.     for(j=0;j<lstnum;j++)
  11403.     {
  11404.         x = ((long)lst[j].x)+offs->x;
  11405.         y = ((long)lst[j].y)+offs->y; if ((x|y)&(~(VSID-1))) continue;
  11406.         while ((ox != x) || (oy != y))
  11407.         {
  11408.             *ylenptr++ = numvoxs-oyvoxs; oyvoxs = numvoxs; ox++;
  11409.             if (ox > xe)
  11410.             {
  11411.                 *xlenptr++ = numvoxs-oxvoxs; oxvoxs = numvoxs;
  11412.                 ox = xs; oy++;
  11413.             }
  11414.         }
  11415.         z0 = ((long)lst[j].z0)+offs->z;   if (z0 < 0) z0 = 0;
  11416.         z1 = ((long)lst[j].z1)+offs->z+1; if (z1 > MAXZDIM) z1 = MAXZDIM;
  11417.         for(z=z0;z<z1;z++) //getcube TOO SLOW... FIX THIS!!!
  11418.         {
  11419.             i = getcube(x,y,z); //0:air, 1:unexposed solid, 2:vbuf col ptr
  11420.             if (!(i&~1)) continue;
  11421.             voxptr[numvoxs].col = lightvox(*(long *)i);
  11422.             voxptr[numvoxs].z = z-zs;
  11423.  
  11424.             voxptr[numvoxs].vis = 63; //FIX THIS!!!
  11425.             //if (!isvoxelsolid(x-1,y,z)) voxptr[numvoxs].vis |= 1;
  11426.             //if (!isvoxelsolid(x+1,y,z)) voxptr[numvoxs].vis |= 2;
  11427.             //if (!isvoxelsolid(x,y-1,z)) voxptr[numvoxs].vis |= 4;
  11428.             //if (!isvoxelsolid(x,y+1,z)) voxptr[numvoxs].vis |= 8;
  11429.             //if (!isvoxelsolid(x,y,z-1)) voxptr[numvoxs].vis |= 16;
  11430.             //if (!isvoxelsolid(x,y,z+1)) voxptr[numvoxs].vis |= 32;
  11431.  
  11432.             voxptr[numvoxs].dir = 0; //FIX THIS!!!
  11433.             numvoxs++;
  11434.         }
  11435.     }
  11436.     while (1)
  11437.     {
  11438.         *ylenptr++ = numvoxs-oyvoxs; oyvoxs = numvoxs; ox++;
  11439.         if (ox > xe)
  11440.         {
  11441.             *xlenptr++ = numvoxs-oxvoxs; oxvoxs = numvoxs;
  11442.             ox = xs; oy++; if (oy > ye) break;
  11443.         }
  11444.     }
  11445.     return(cw);
  11446. }
  11447.  
  11448. static void setlighting (long x0, long y0, long z0, long x1, long y1, long z1, long lval)
  11449. {
  11450.     long i, x, y;
  11451.     char *v;
  11452.  
  11453.     x0 = max(x0,0); x1 = min(x1,VSID);
  11454.     y0 = max(y0,0); y1 = min(y1,VSID);
  11455.     z0 = max(z0,0); z1 = min(z1,MAXZDIM);
  11456.  
  11457.     lval <<= 24;
  11458.  
  11459.         //Set 4th byte of colors to full intensity
  11460.     for(y=y0;y<y1;y++)
  11461.         for(x=x0;x<x1;x++)
  11462.         {
  11463.             for(v=sptr[y*VSID+x];v[0];v+=v[0]*4)
  11464.                 for(i=1;i<v[0];i++)
  11465.                     (*(long *)&v[i<<2]) = (((*(long *)&v[i<<2])&0xffffff)|lval);
  11466.             for(i=1;i<=v[2]-v[1]+1;i++)
  11467.                 (*(long *)&v[i<<2]) = (((*(long *)&v[i<<2])&0xffffff)|lval);
  11468.         }
  11469. }
  11470.  
  11471.     //Updates Lighting, Mip-mapping, and Floating objects list
  11472. typedef struct { long x0, y0, z0, x1, y1, z1, csgdel; } bboxtyp;
  11473. #define BBOXSIZ 256
  11474. static bboxtyp bbox[BBOXSIZ];
  11475. static long bboxnum = 0;
  11476. void updatevxl ()
  11477. {
  11478.     long i;
  11479.  
  11480.     for(i=bboxnum-1;i>=0;i--)
  11481.     {
  11482.         if (vx5.lightmode)
  11483.             updatelighting(bbox[i].x0,bbox[i].y0,bbox[i].z0,bbox[i].x1,bbox[i].y1,bbox[i].z1);
  11484.         if (vx5.vxlmipuse > 1)
  11485.             genmipvxl(bbox[i].x0,bbox[i].y0,bbox[i].x1,bbox[i].y1);
  11486.         if ((vx5.fallcheck) && (bbox[i].csgdel))
  11487.             checkfloatinbox(bbox[i].x0,bbox[i].y0,bbox[i].z0,bbox[i].x1,bbox[i].y1,bbox[i].z1);
  11488.     }
  11489.     bboxnum = 0;
  11490. }
  11491.  
  11492. void updatebbox (long x0, long y0, long z0, long x1, long y1, long z1, long csgdel)
  11493. {
  11494.     long i;
  11495.  
  11496.     if ((x0 >= x1) || (y0 >= y1) || (z0 >= z1)) return;
  11497.     for(i=bboxnum-1;i>=0;i--)
  11498.     {
  11499.         if ((x0 >= bbox[i].x1) || (bbox[i].x0 >= x1)) continue;
  11500.         if ((y0 >= bbox[i].y1) || (bbox[i].y0 >= y1)) continue;
  11501.         if ((z0 >= bbox[i].z1) || (bbox[i].z0 >= z1)) continue;
  11502.         if (bbox[i].x0 < x0) x0 = bbox[i].x0;
  11503.         if (bbox[i].y0 < y0) y0 = bbox[i].y0;
  11504.         if (bbox[i].z0 < z0) z0 = bbox[i].z0;
  11505.         if (bbox[i].x1 > x1) x1 = bbox[i].x1;
  11506.         if (bbox[i].y1 > y1) y1 = bbox[i].y1;
  11507.         if (bbox[i].z1 > z1) z1 = bbox[i].z1;
  11508.         csgdel |= bbox[i].csgdel;
  11509.         bboxnum--; bbox[i] = bbox[bboxnum];
  11510.     }
  11511.     bbox[bboxnum].x0 = x0; bbox[bboxnum].x1 = x1;
  11512.     bbox[bboxnum].y0 = y0; bbox[bboxnum].y1 = y1;
  11513.     bbox[bboxnum].z0 = z0; bbox[bboxnum].z1 = z1;
  11514.     bbox[bboxnum].csgdel = csgdel; bboxnum++;
  11515.     if (bboxnum >= BBOXSIZ) updatevxl();
  11516. }
  11517.  
  11518. static long lightlst[MAXLIGHTS];
  11519. static float lightsub[MAXLIGHTS];
  11520.     //Re-calculates lighting byte #4 of all voxels inside bounding box
  11521. void updatelighting (long x0, long y0, long z0, long x1, long y1, long z1)
  11522. {
  11523.     point3d tp;
  11524.     float f, g, h, fx, fy, fz;
  11525.     long i, j, x, y, z, sz0, sz1, offs, cstat, lightcnt;
  11526.     long x2, y2, x3, y3;
  11527.     char *v;
  11528.  
  11529.     if (!vx5.lightmode) return;
  11530.     xbsox = -17;
  11531.  
  11532.     x0 = max(x0-ESTNORMRAD,0); x1 = min(x1+ESTNORMRAD,VSID);
  11533.     y0 = max(y0-ESTNORMRAD,0); y1 = min(y1+ESTNORMRAD,VSID);
  11534.     z0 = max(z0-ESTNORMRAD,0); z1 = min(z1+ESTNORMRAD,MAXZDIM);
  11535.  
  11536.     x2 = x0; y2 = y0;
  11537.     x3 = x1; y3 = y1;
  11538.     for(y0=y2;y0<y3;y0=y1)
  11539.     {
  11540.         y1 = min(y0+64,y3);  //"justfly -" (256 lights): +1024:41sec 512:29 256:24 128:22 64:21 32:21 16:21
  11541.         for(x0=x2;x0<x3;x0=x1)
  11542.         {
  11543.             x1 = min(x0+64,x3);
  11544.  
  11545.  
  11546.             if (vx5.lightmode == 2)
  11547.             {
  11548.                 lightcnt = 0; //Find which lights are close enough to affect rectangle
  11549.                 for(i=vx5.numlights-1;i>=0;i--)
  11550.                 {
  11551.                     ftol(vx5.lightsrc[i].p.x,&x);
  11552.                     ftol(vx5.lightsrc[i].p.y,&y);
  11553.                     ftol(vx5.lightsrc[i].p.z,&z);
  11554.                     if (x < x0) x -= x0; else if (x > x1) x -= x1; else x = 0;
  11555.                     if (y < y0) y -= y0; else if (y > y1) y -= y1; else y = 0;
  11556.                     if (z < z0) z -= z0; else if (z > z1) z -= z1; else z = 0;
  11557.                     f = vx5.lightsrc[i].r2;
  11558.                     if ((float)(x*x+y*y+z*z) < f)
  11559.                     {
  11560.                         lightlst[lightcnt] = i;
  11561.                         lightsub[lightcnt] = 1/(sqrt(f)*f);
  11562.                         lightcnt++;
  11563.                     }
  11564.                 }
  11565.             }
  11566.  
  11567.             for(y=y0;y<y1;y++)
  11568.                 for(x=x0;x<x1;x++)
  11569.                 {
  11570.                     v = sptr[y*VSID+x]; cstat = 0;
  11571.                     while (1)
  11572.                     {
  11573.                         if (!cstat)
  11574.                         {
  11575.                             sz0 = ((long)v[1]); sz1 = ((long)v[2])+1; offs = 7-(sz0<<2);
  11576.                             cstat = 1;
  11577.                         }
  11578.                         else
  11579.                         {
  11580.                             sz0 = ((long)v[2])-((long)v[1])-((long)v[0])+2;
  11581.                             if (!v[0]) break; v += v[0]*4;
  11582.                             sz1 = ((long)v[3]); sz0 += sz1; offs = 3-(sz1<<2);
  11583.                             cstat = 0;
  11584.                         }
  11585.                         if (z0 > sz0) sz0 = z0;
  11586.                         if (z1 < sz1) sz1 = z1;
  11587.                         if (vx5.lightmode < 2)
  11588.                         {
  11589.                             for(z=sz0;z<sz1;z++)
  11590.                             {
  11591.                                 estnorm(x,y,z,&tp);
  11592.                                 ftol((tp.y*.5+tp.z)*64.f+103.5f,&i);
  11593.                                 v[(z<<2)+offs] = *(char *)&i;
  11594.                             }
  11595.                         }
  11596.                         else
  11597.                         {
  11598.                             for(z=sz0;z<sz1;z++)
  11599.                             {
  11600.                                 estnorm(x,y,z,&tp);
  11601.                                 f = (tp.y*.5+tp.z)*16+47.5;
  11602.                                 for(i=lightcnt-1;i>=0;i--)
  11603.                                 {
  11604.                                     j = lightlst[i];
  11605.                                     fx = vx5.lightsrc[j].p.x-(float)x;
  11606.                                     fy = vx5.lightsrc[j].p.y-(float)y;
  11607.                                     fz = vx5.lightsrc[j].p.z-(float)z;
  11608.                                     h = tp.x*fx+tp.y*fy+tp.z*fz; if (*(long *)&h >= 0) continue;
  11609.                                     g = fx*fx+fy*fy+fz*fz; if (g >= vx5.lightsrc[j].r2) continue;
  11610.  
  11611.                                         //g = 1.0/(g*sqrt(g))-lightsub[i]; //1.0/g;
  11612.                                     if (cputype&(1<<25))
  11613.                                     {
  11614.                                         _asm
  11615.                                         {
  11616.                                             movss xmm0, g        ;xmm0=g
  11617.                                             rcpss xmm1, xmm0     ;xmm1=1/g
  11618.                                             rsqrtss xmm0, xmm0   ;xmm0=1/sqrt(g)
  11619.                                             mulss xmm1, xmm0     ;xmm1=1/(g*sqrt(g))
  11620.                                             mov eax, i
  11621.                                             subss xmm1, lightsub[eax*4]
  11622.                                             movss g, xmm1
  11623.                                         }
  11624.                                     }
  11625.                                     else
  11626.                                     {
  11627.                                         _asm
  11628.                                         {
  11629.                                             movd mm0, g
  11630.                                             pfrcp mm1, mm0
  11631.                                             pfrsqrt mm0, mm0
  11632.                                             pfmul mm0, mm1
  11633.                                             mov eax, i
  11634.                                             pfsub mm0, lightsub[eax*4]
  11635.                                             movd g, xmm0
  11636.                                             femms
  11637.                                         }
  11638.                                     }
  11639.                                     f -= g*h*vx5.lightsrc[j].sc;
  11640.                                 }
  11641.                                 if (*(long *)&f > 0x437f0000) f = 255; //0x437f0000 is 255.0
  11642.                                 ftol(f,&i);
  11643.                                 v[(z<<2)+offs] = *(char *)&i;
  11644.                             }
  11645.                         }
  11646.                     }
  11647.                 }
  11648.         }
  11649.     }
  11650. }
  11651.  
  11652. //float detection & falling code begins --------------------------------------
  11653. //How to use this section of code:
  11654. //Step 1: Call checkfloatinbox after every "deleting" set* call
  11655. //Step 2: Call dofalls(); at a constant rate in movement code
  11656.  
  11657.     //Adds all slabs inside box (inclusive) to "float check" list
  11658. void checkfloatinbox (long x0, long y0, long z0, long x1, long y1, long z1)
  11659. {
  11660.     long x, y;
  11661.     char *ov, *v;
  11662.  
  11663.     if (flchkcnt >= FLCHKSIZ) return;
  11664.  
  11665.         //Make all off-by-1 hacks in other code unnecessary
  11666.     x0 = max(x0-1,0); x1 = min(x1+1,VSID);
  11667.     y0 = max(y0-1,0); y1 = min(y1+1,VSID);
  11668.     z0 = max(z0-1,0); z1 = min(z1+1,MAXZDIM);
  11669.  
  11670.         //Add local box's slabs to flchk list - checked in next dofalls()
  11671.     for(y=y0;y<y1;y++)
  11672.         for(x=x0;x<x1;x++)
  11673.         {
  11674.             v = sptr[y*VSID+x];
  11675.             while (1)
  11676.             {
  11677.                 ov = v; if ((z1 <= v[1]) || (!v[0])) break;
  11678.                 v += v[0]*4; if (z0 >= v[3]) continue;
  11679.                 flchk[flchkcnt].x = x;
  11680.                 flchk[flchkcnt].y = y;
  11681.                 flchk[flchkcnt].z = ov[1];
  11682.                 flchkcnt++; if (flchkcnt >= FLCHKSIZ) return;
  11683.             }
  11684.         }
  11685. }
  11686.  
  11687. void isnewfloatingadd (long f)
  11688. {
  11689.     long v = (((f>>(LOGHASHEAD+3))-(f>>3)) & ((1<<LOGHASHEAD)-1));
  11690.     vlst[vlstcnt].b = hhead[v]; hhead[v] = vlstcnt;
  11691.     vlst[vlstcnt].v = f; vlstcnt++;
  11692. }
  11693.  
  11694. long isnewfloatingot (long f)
  11695. {
  11696.     long v = hhead[((f>>(LOGHASHEAD+3))-(f>>3)) & ((1<<LOGHASHEAD)-1)];
  11697.     while (1)
  11698.     {
  11699.         if (v < 0) return(-1);
  11700.         if (vlst[v].v == f) return(v);
  11701.         v = vlst[v].b;
  11702.     }
  11703. }
  11704.  
  11705.     //removes a & adds b while preserving index; used only by meltfall(...)
  11706.     //Must do nothing if 'a' not in hash
  11707. void isnewfloatingchg (long a, long b)
  11708. {
  11709.     long ov, v, i, j;
  11710.  
  11711.     i = (((a>>(LOGHASHEAD+3))-(a>>3)) & ((1<<LOGHASHEAD)-1));
  11712.     j = (((b>>(LOGHASHEAD+3))-(b>>3)) & ((1<<LOGHASHEAD)-1));
  11713.  
  11714.     v = hhead[i]; ov = -1;
  11715.     while (v >= 0)
  11716.     {
  11717.         if (vlst[v].v == a)
  11718.         {
  11719.             vlst[v].v = b; if (i == j) return;
  11720.             if (ov < 0) hhead[i] = vlst[v].b; else vlst[ov].b = vlst[v].b;
  11721.             vlst[v].b = hhead[j]; hhead[j] = v;
  11722.             return;
  11723.         }
  11724.         ov = v; v = vlst[v].b;
  11725.     }
  11726. }
  11727.  
  11728. long isnewfloating (flstboxtype *flb)
  11729. {
  11730.     float f;
  11731.     lpoint3d p, cen;
  11732.     long i, j, nx, ny, z0, z1, fend, ovlstcnt, mass;
  11733.     char *v, *ov;
  11734.  
  11735.     p.x = flb->chk.x; p.y = flb->chk.y; p.z = flb->chk.z;
  11736.     v = sptr[p.y*VSID+p.x];
  11737.     while (1)
  11738.     {
  11739.         ov = v;
  11740.         if ((p.z < v[1]) || (!v[0])) return(0);
  11741.         v += v[0]*4;
  11742.         if (p.z < v[3]) break;
  11743.     }
  11744.  
  11745.     if (isnewfloatingot((long)ov) >= 0) return(0);
  11746.     ovlstcnt = vlstcnt;
  11747.     isnewfloatingadd((long)ov);
  11748.     if (vlstcnt >= VLSTSIZ) return(0); //EVIL HACK TO PREVENT CRASH!
  11749.  
  11750.         //Init: centroid, mass, bounding box
  11751.     cen = p; mass = 1;
  11752.     flb->x0 = p.x-1; flb->y0 = p.y-1; flb->z0 = p.z-1;
  11753.     flb->x1 = p.x+1; flb->y1 = p.y+1; flb->z1 = p.z+1;
  11754.  
  11755.     fend = 0;
  11756.     while (1)
  11757.     {
  11758.         z0 = ov[1];         if (z0 < flb->z0) flb->z0 = z0;
  11759.         z1 = ov[ov[0]*4+3]; if (z1 > flb->z1) flb->z1 = z1;
  11760.  
  11761.         i = z1-z0;
  11762.         cen.x += p.x*i;
  11763.         cen.y += p.y*i;
  11764.         cen.z += (((z0+z1)*i)>>1); //sum(z0 to z1-1)
  11765.         mass += i;
  11766.  
  11767.         for(i=0;i<8;i++) //26-connectivity
  11768.         {
  11769.             switch(i)
  11770.             {
  11771.                 case 0: nx = p.x-1; ny = p.y  ; if (nx < flb->x0) flb->x0 = nx; break;
  11772.                 case 1: nx = p.x  ; ny = p.y-1; if (ny < flb->y0) flb->y0 = ny; break;
  11773.                 case 2: nx = p.x+1; ny = p.y  ; if (nx > flb->x1) flb->x1 = nx; break;
  11774.                 case 3: nx = p.x  ; ny = p.y+1; if (ny > flb->y1) flb->y1 = ny; break;
  11775.                 case 4: nx = p.x-1; ny = p.y-1; break;
  11776.                 case 5: nx = p.x+1; ny = p.y-1; break;
  11777.                 case 6: nx = p.x-1; ny = p.y+1; break;
  11778.                 case 7: nx = p.x+1; ny = p.y+1; break;
  11779.                 default: __assume(0); //tells MSVC default can't be reached
  11780.             }
  11781.             if ((unsigned long)(nx|ny) >= VSID) continue;
  11782.  
  11783.             v = sptr[ny*VSID+nx];
  11784.             while (1)
  11785.             {
  11786.                 if (!v[0])
  11787.                 {
  11788.                     if (v[1] <= z1) return(0);  //This MUST be <=, (not <) !!!
  11789.                     break;
  11790.                 }
  11791.                 ov = v; v += v[0]*4; //NOTE: this is a 'different' ov
  11792.                 if ((ov[1] > z1) || (z0 > v[3])) continue; //26-connectivity
  11793.                 j = isnewfloatingot((long)ov);
  11794.                 if (j < 0)
  11795.                 {
  11796.                     isnewfloatingadd((long)ov);
  11797.                     if (vlstcnt >= VLSTSIZ) return(0); //EVIL HACK TO PREVENT CRASH!
  11798.                     fstk[fend].x = nx; fstk[fend].y = ny; fstk[fend].z = (long)ov;
  11799.                     fend++; if (fend >= FSTKSIZ) return(0); //EVIL HACK TO PREVENT CRASH!
  11800.                     continue;
  11801.                 }
  11802.                 if ((unsigned long)j < ovlstcnt) return(0);
  11803.             }
  11804.         }
  11805.  
  11806.         if (!fend)
  11807.         {
  11808.             flb->i0 = ovlstcnt;
  11809.             flb->i1 = vlstcnt;
  11810.             flb->mass = mass; f = 1.0 / (float)mass;
  11811.             flb->centroid.x = (float)cen.x*f;
  11812.             flb->centroid.y = (float)cen.y*f;
  11813.             flb->centroid.z = (float)cen.z*f;
  11814.             return(1);
  11815.         }
  11816.         fend--;
  11817.         p.x = fstk[fend].x; p.y = fstk[fend].y; ov = (char *)fstk[fend].z;
  11818.     }
  11819. }
  11820.  
  11821. void startfalls ()
  11822. {
  11823.     long i, z;
  11824.  
  11825.         //This allows clear to be MUCH faster when there isn't much falling
  11826.     if (vlstcnt < ((1<<LOGHASHEAD)>>1))
  11827.     {
  11828.         for(i=vlstcnt-1;i>=0;i--)
  11829.         {
  11830.             z = vlst[i].v;
  11831.             hhead[((z>>(LOGHASHEAD+3))-(z>>3)) & ((1<<LOGHASHEAD)-1)] = -1;
  11832.         }
  11833.     }
  11834.     else { for(z=0;z<(1<<LOGHASHEAD);z++) hhead[z] = -1; }
  11835.  
  11836.         //Float detection...
  11837.         //flstcnt[].i0/i1 tell which parts of vlst are floating
  11838.     vlstcnt = 0;
  11839.  
  11840.         //Remove any current pieces that are no longer floating
  11841.     for(i=vx5.flstnum-1;i>=0;i--)
  11842.         if (!isnewfloating(&vx5.flstcnt[i])) //Modifies flstcnt,vlst[],vlstcnt
  11843.             vx5.flstcnt[i] = vx5.flstcnt[--vx5.flstnum]; //onground, so delete flstcnt[i]
  11844.  
  11845.         //Add new floating pieces (while space is left on flstcnt)
  11846.     if (vx5.flstnum < FLPIECES)
  11847.         for(i=flchkcnt-1;i>=0;i--)
  11848.         {
  11849.             vx5.flstcnt[vx5.flstnum].chk = flchk[i];
  11850.             if (isnewfloating(&vx5.flstcnt[vx5.flstnum])) //Modifies flstcnt,vlst[],vlstcnt
  11851.             {
  11852.                 vx5.flstcnt[vx5.flstnum].userval = -1; //New piece: let game programmer know
  11853.                 vx5.flstnum++; if (vx5.flstnum >= FLPIECES) break;
  11854.             }
  11855.         }
  11856.     flchkcnt = 0;
  11857. }
  11858.  
  11859.     //Call 0 or 1 times (per flstcnt) between startfalls&finishfalls
  11860. void dofall (long i)
  11861. {
  11862.     long j, z;
  11863.     char *v;
  11864.  
  11865.         //Falling code... call this function once per piece
  11866.     vx5.flstcnt[i].chk.z++;
  11867.     for(z=vx5.flstcnt[i].i1-1;z>=vx5.flstcnt[i].i0;z--)
  11868.     {
  11869.         v = (char *)vlst[z].v; v[1]++; v[2]++;
  11870.         v = &v[v[0]*4];
  11871.         v[3]++;
  11872.         if ((v[3] == v[1]) && (vx5.flstcnt[i].i1 >= 0))
  11873.         {
  11874.             j = isnewfloatingot((long)v);
  11875.                 //Make sure it's not part of the same floating object
  11876.             if ((j < vx5.flstcnt[i].i0) || (j >= vx5.flstcnt[i].i1))
  11877.                 vx5.flstcnt[i].i1 = -1; //Mark flstcnt[i] for scum2 fixup
  11878.         }
  11879.     }
  11880.  
  11881.     if (vx5.vxlmipuse > 1)
  11882.     {
  11883.         long x0, y0, x1, y1;
  11884.         x0 = max(vx5.flstcnt[i].x0,0); x1 = min(vx5.flstcnt[i].x1+1,VSID);
  11885.         y0 = max(vx5.flstcnt[i].y0,0); y1 = min(vx5.flstcnt[i].y1+1,VSID);
  11886.         //FIX ME!!!
  11887.         //if ((x1 > x0) && (y1 > y0)) genmipvxl(x0,y0,x1,y1); //Don't replace with bbox!
  11888.     }
  11889. }
  11890.  
  11891.     //Sprite structure is already allocated
  11892.     //kv6, vox, xlen, ylen are all malloced in here!
  11893. long meltfall (vx5sprite *spr, long fi, long delvxl)
  11894. {
  11895.     long i, j, k, x, y, z, xs, ys, zs, xe, ye, ze;
  11896.     long oxvoxs, oyvoxs, numvoxs;
  11897.     char *v, *ov, *nv;
  11898.     kv6data *kv;
  11899.     kv6voxtype *voxptr;
  11900.     unsigned long *xlenptr;
  11901.     unsigned short *ylenptr;
  11902.  
  11903.     if (vx5.flstcnt[fi].i1 < 0) return(0);
  11904.  
  11905.     xs = max(vx5.flstcnt[fi].x0,0); xe = min(vx5.flstcnt[fi].x1,VSID-1);
  11906.     ys = max(vx5.flstcnt[fi].y0,0); ye = min(vx5.flstcnt[fi].y1,VSID-1);
  11907.     zs = max(vx5.flstcnt[fi].z0,0); ze = min(vx5.flstcnt[fi].z1,MAXZDIM-1);
  11908.     if ((xs > xe) || (ys > ye) || (zs > ze)) return(0);
  11909.  
  11910.         //Need to know how many voxels to allocate... SLOW :(
  11911.     numvoxs = vx5.flstcnt[fi].i0-vx5.flstcnt[fi].i1;
  11912.     for(i=vx5.flstcnt[fi].i0;i<vx5.flstcnt[fi].i1;i++)
  11913.         numvoxs += ((char *)vlst[i].v)[0];
  11914.     if (numvoxs <= 0) return(0); //No voxels found!
  11915.  
  11916.     spr->p = vx5.flstcnt[fi].centroid;
  11917.     spr->s.x = 1.f; spr->h.x = 0.f; spr->f.x = 0.f;
  11918.     spr->s.y = 0.f; spr->h.y = 1.f; spr->f.y = 0.f;
  11919.     spr->s.z = 0.f; spr->h.z = 0.f; spr->f.z = 1.f;
  11920.  
  11921.     x = xe-xs+1; y = ye-ys+1; z = ze-zs+1;
  11922.  
  11923.     j = sizeof(kv6data) + numvoxs*sizeof(kv6voxtype) + x*4 + x*y*2;
  11924.     i = (long)malloc(j); if (!i) return(0); if (i&3) { free((void *)i); return(0); }
  11925.     spr->voxnum = kv = (kv6data *)i; spr->flags = 0;
  11926.     kv->leng = j;
  11927.     kv->xsiz = x;
  11928.     kv->ysiz = y;
  11929.     kv->zsiz = z;
  11930.     kv->xpiv = spr->p.x - xs;
  11931.     kv->ypiv = spr->p.y - ys;
  11932.     kv->zpiv = spr->p.z - zs;
  11933.     kv->numvoxs = numvoxs;
  11934.     kv->namoff = 0;
  11935.     kv->lowermip = 0;
  11936.     kv->vox = (kv6voxtype *)((long)spr->voxnum+sizeof(kv6data));
  11937.     kv->xlen = (unsigned long *)(((long)kv->vox)+numvoxs*sizeof(kv6voxtype));
  11938.     kv->ylen = (unsigned short *)(((long)kv->xlen) + kv->xsiz*4);
  11939.  
  11940.     voxptr = kv->vox; numvoxs = 0;
  11941.     xlenptr = kv->xlen; oxvoxs = 0;
  11942.     ylenptr = kv->ylen; oyvoxs = 0;
  11943.  
  11944.     for(x=xs;x<=xe;x++)
  11945.     {
  11946.         for(y=ys;y<=ye;y++)
  11947.         {
  11948.             for(v=sptr[y*VSID+x];v[0];v=nv)
  11949.             {
  11950.                 nv = v+v[0]*4;
  11951.  
  11952.                 i = isnewfloatingot((long)v);
  11953.                 if (((unsigned long)i >= vx5.flstcnt[fi].i1) || (i < vx5.flstcnt[fi].i0))
  11954.                     continue;
  11955.  
  11956.                 for(z=v[1];z<=v[2];z++)
  11957.                 {
  11958.                     voxptr[numvoxs].col = lightvox(*(long *)&v[((z-v[1])<<2)+4]);
  11959.                     voxptr[numvoxs].z = z-zs;
  11960.  
  11961.                     voxptr[numvoxs].vis = 0; //OPTIMIZE THIS!!!
  11962.                     if (!isvoxelsolid(x-1,y,z)) voxptr[numvoxs].vis |= 1;
  11963.                     if (!isvoxelsolid(x+1,y,z)) voxptr[numvoxs].vis |= 2;
  11964.                     if (!isvoxelsolid(x,y-1,z)) voxptr[numvoxs].vis |= 4;
  11965.                     if (!isvoxelsolid(x,y+1,z)) voxptr[numvoxs].vis |= 8;
  11966.                     //if (z == v[1]) voxptr[numvoxs].vis |= 16;
  11967.                     //if (z == nv[3]-1) voxptr[numvoxs].vis |= 32;
  11968.                     if (!isvoxelsolid(x,y,z-1)) voxptr[numvoxs].vis |= 16;
  11969.                     if (!isvoxelsolid(x,y,z+1)) voxptr[numvoxs].vis |= 32;
  11970.  
  11971.                     voxptr[numvoxs].dir = 0; //FIX THIS!!!
  11972.                     numvoxs++;
  11973.                 }
  11974.                 for(z=nv[3]+v[2]-v[1]-v[0]+2;z<nv[3];z++)
  11975.                 {
  11976.                     voxptr[numvoxs].col = lightvox(*(long *)&nv[(z-nv[3])<<2]);
  11977.                     voxptr[numvoxs].z = z-zs;
  11978.  
  11979.                     voxptr[numvoxs].vis = 0; //OPTIMIZE THIS!!!
  11980.                     if (!isvoxelsolid(x-1,y,z)) voxptr[numvoxs].vis |= 1;
  11981.                     if (!isvoxelsolid(x+1,y,z)) voxptr[numvoxs].vis |= 2;
  11982.                     if (!isvoxelsolid(x,y-1,z)) voxptr[numvoxs].vis |= 4;
  11983.                     if (!isvoxelsolid(x,y+1,z)) voxptr[numvoxs].vis |= 8;
  11984.                     //if (z == v[1]) voxptr[numvoxs].vis |= 16;
  11985.                     //if (z == nv[3]-1) voxptr[numvoxs].vis |= 32;
  11986.                     if (!isvoxelsolid(x,y,z-1)) voxptr[numvoxs].vis |= 16;
  11987.                     if (!isvoxelsolid(x,y,z+1)) voxptr[numvoxs].vis |= 32;
  11988.  
  11989.                     voxptr[numvoxs].dir = 0; //FIX THIS!!!
  11990.                     numvoxs++;
  11991.                 }
  11992.  
  11993. #if 0
  11994.                 if (delvxl) //Quick&dirty dealloc from VXL (bad for holes!)
  11995.                 {
  11996.                         //invalidate current vptr safely
  11997.                     isnewfloatingchg((long)v,0);
  11998.  
  11999.                     k = nv-v; //perform slng(nv) and adjust vlst at same time
  12000.                     for(ov=nv;ov[0];ov+=ov[0]*4)
  12001.                         isnewfloatingchg((long)ov,((long)ov)-k);
  12002.  
  12003.                     j = (long)ov-(long)nv+(ov[2]-ov[1]+1)*4+4;
  12004.  
  12005.                         //shift end of RLE column up
  12006.                     v[0] = nv[0]; v[1] = nv[1]; v[2] = nv[2];
  12007.                     for(i=4;i<j;i+=4) *(long *)&v[i] = *(long *)&nv[i];
  12008.  
  12009.                         //remove end of RLE column from vbit
  12010.                     i = ((((long)(&v[i]))-(long)vbuf)>>2); j = (k>>2)+i;
  12011. #if 0
  12012.                     while (i < j) { vbit[i>>5] &= ~(1<<i); i++; }
  12013. #else
  12014.                     if (!((j^i)&~31))
  12015.                         vbit[i>>5] &= ~(p2m[j&31]^p2m[i&31]);
  12016.                     else
  12017.                     {
  12018.                         vbit[i>>5] &=   p2m[i&31];  i >>= 5;
  12019.                         vbit[j>>5] &= (~p2m[j&31]); j >>= 5;
  12020.                         for(j--;j>i;j--) vbit[j] = 0;
  12021.                     }
  12022. #endif
  12023.                     nv = v;
  12024.                 }
  12025. #endif
  12026.             }
  12027.             *ylenptr++ = numvoxs-oyvoxs; oyvoxs = numvoxs;
  12028.         }
  12029.         *xlenptr++ = numvoxs-oxvoxs; oxvoxs = numvoxs;
  12030.     }
  12031.  
  12032.     if (delvxl)
  12033.         for(x=xs;x<=xe;x++)
  12034.             for(y=ys;y<=ye;y++)
  12035.                 for(v=sptr[y*VSID+x];v[0];v=nv)
  12036.                 {
  12037.                     nv = v+v[0]*4;
  12038.  
  12039.                     i = isnewfloatingot((long)v);
  12040.                     if (((unsigned long)i >= vx5.flstcnt[fi].i1) || (i < vx5.flstcnt[fi].i0))
  12041.                         continue;
  12042.  
  12043.                         //Quick&dirty dealloc from VXL (bad for holes!)
  12044.  
  12045.                         //invalidate current vptr safely
  12046.                     isnewfloatingchg((long)v,0);
  12047.  
  12048.                     k = nv-v; //perform slng(nv) and adjust vlst at same time
  12049.                     for(ov=nv;ov[0];ov+=ov[0]*4)
  12050.                         isnewfloatingchg((long)ov,((long)ov)-k);
  12051.  
  12052.                     j = (long)ov-(long)nv+(ov[2]-ov[1]+1)*4+4;
  12053.  
  12054.                         //shift end of RLE column up
  12055.                     v[0] = nv[0]; v[1] = nv[1]; v[2] = nv[2];
  12056.                     for(i=4;i<j;i+=4) *(long *)&v[i] = *(long *)&nv[i];
  12057.  
  12058.                         //remove end of RLE column from vbit
  12059.                     i = ((((long)(&v[i]))-(long)vbuf)>>2); j = (k>>2)+i;
  12060. #if 0
  12061.                     while (i < j) { vbit[i>>5] &= ~(1<<i); i++; }
  12062. #else
  12063.                     if (!((j^i)&~31))
  12064.                         vbit[i>>5] &= ~(p2m[j&31]^p2m[i&31]);
  12065.                     else
  12066.                     {
  12067.                         vbit[i>>5] &=   p2m[i&31];  i >>= 5;
  12068.                         vbit[j>>5] &= (~p2m[j&31]); j >>= 5;
  12069.                         for(j--;j>i;j--) vbit[j] = 0;
  12070.                     }
  12071. #endif
  12072.                     nv = v;
  12073.                 }
  12074.  
  12075.     vx5.flstcnt[fi].i1 = -2; //Mark flstcnt[i] invalid; no scum2 fixup
  12076.  
  12077.     if (vx5.vxlmipuse > 1) genmipvxl(xs,ys,xe+1,ye+1);
  12078.  
  12079.     return(vx5.flstcnt[fi].mass);
  12080. }
  12081.  
  12082. void finishfalls ()
  12083. {
  12084.     long i, x, y;
  12085.  
  12086.         //Scum2 box fixup: refreshes rle voxel data inside a bounding rectangle
  12087.     for(i=vx5.flstnum-1;i>=0;i--)
  12088.         if (vx5.flstcnt[i].i1 < 0)
  12089.         {
  12090.             if (vx5.flstcnt[i].i1 == -1)
  12091.             {
  12092.                 for(y=vx5.flstcnt[i].y0;y<=vx5.flstcnt[i].y1;y++)
  12093.                     for(x=vx5.flstcnt[i].x0;x<=vx5.flstcnt[i].x1;x++)
  12094.                         scum2(x,y);
  12095.                 scum2finish();
  12096.                 updatebbox(vx5.flstcnt[i].x0,vx5.flstcnt[i].y0,vx5.flstcnt[i].z0,vx5.flstcnt[i].x1,vx5.flstcnt[i].y1,vx5.flstcnt[i].z1,0);
  12097.             }
  12098.             vx5.flstcnt[i] = vx5.flstcnt[--vx5.flstnum]; //onground, so delete flstcnt[i]
  12099.         }
  12100. }
  12101.  
  12102. //float detection & falling code ends ----------------------------------------
  12103.  
  12104. //----------------------------------------------------------------------------
  12105.  
  12106. void voxsetframebuffer (long p, long b, long x, long y)
  12107. {
  12108.     long i;
  12109.  
  12110.     frameplace = p;
  12111.     if (x > MAXXDIM) x = MAXXDIM; //This sucks, but it crashes without it
  12112.     if (y > MAXYDIM) y = MAXYDIM;
  12113.  
  12114.         //Set global variables used by kv6draw's PIII asm (drawboundcube)
  12115.     qsum1[3] = qsum1[1] = 0x7fff-y; qsum1[2] = qsum1[0] = 0x7fff-x;
  12116.     kv6bytesperline = qbplbpp[1] = b; qbplbpp[0] = 4;
  12117.     kv6frameplace = p - (qsum1[0]*qbplbpp[0] + qsum1[1]*qbplbpp[1]);
  12118.  
  12119.     if ((b != ylookup[1]) || (x != xres) || (y != yres))
  12120.     {
  12121.         bytesperline = b; xres = x; yres = y; xres4 = (xres<<2);
  12122.         ylookup[0] = 0; for(i=0;i<yres;i++) ylookup[i+1] = ylookup[i]+bytesperline;
  12123.         //gihx = gihz = (float)xres*.5f; gihy = (float)yres*.5f; //BAD!!!
  12124. #if (USEZBUFFER == 1)
  12125.         if ((ylookup[yres]+256 > zbuffersiz) || (!zbuffermem))  //Increase Z buffer size if too small
  12126.         {
  12127.             if (zbuffermem) { free(zbuffermem); zbuffermem = 0; }
  12128.             zbuffersiz = ylookup[yres]+256;
  12129.             if (!(zbuffermem = (long *)malloc(zbuffersiz))) evilquit("voxsetframebuffer: allocation too big");
  12130.         }
  12131. #endif
  12132.     }
  12133. #if (USEZBUFFER == 1)
  12134.         //zbuffer aligns its memory to the same pixel boundaries as the screen!
  12135.         //WARNING: Pentium 4's L2 cache has severe slowdowns when 65536-64 <= (zbufoff&65535) < 64
  12136.     zbufoff = (((((long)zbuffermem)-frameplace-128)+255)&~255)+128;
  12137. #endif
  12138.     uurend = &uurendmem[((frameplace&4)^(((long)uurendmem)&4))>>2];
  12139.  
  12140.     if (vx5.fogcol >= 0)
  12141.     {
  12142.         fogcol = (((__int64)(vx5.fogcol&0xff0000))<<16) +
  12143.                     (((__int64)(vx5.fogcol&0x00ff00))<< 8) +
  12144.                     (((__int64)(vx5.fogcol&0x0000ff))    );
  12145.  
  12146.         if (vx5.maxscandist > 2047) vx5.maxscandist = 2047;
  12147.         if ((vx5.maxscandist != ofogdist) && (vx5.maxscandist > 0))
  12148.         {
  12149.             ofogdist = vx5.maxscandist;
  12150.  
  12151.             //foglut[?>>20] = min(?*32767/vx5.maxscandist,32767)
  12152. #if 0
  12153.             long j, k, l;
  12154.             j = 0; l = 0x7fffffff/vx5.maxscandist;
  12155.             for(i=0;i<2048;i++)
  12156.             {
  12157.                 k = (j>>16); j += l;
  12158.                 if (k < 0) break;
  12159.                 foglut[i] = (((__int64)k)<<32)+(((__int64)k)<<16)+((__int64)k);
  12160.             }
  12161.             while (i < 2048) foglut[i++] = all32767;
  12162. #else
  12163.             i = 0x7fffffff/vx5.maxscandist;
  12164.             _asm
  12165.             {
  12166.                 xor eax, eax
  12167.                 mov ecx, -2048*8
  12168.                 mov edx, i
  12169. fogbeg:     movd mm0, eax
  12170.                 add eax, edx
  12171.                 jo short fogend
  12172.                 pshufw mm0, mm0, 0x55
  12173.                 movq foglut[ecx+2048*8], mm0
  12174.                 add ecx, 8
  12175.                 js short fogbeg
  12176.                 jmp short fogend2
  12177. fogend:     movq mm0, all32767
  12178. fogbeg2:    movq foglut[ecx+2048*8], mm0
  12179.                 add ecx, 8
  12180.                 js short fogbeg2
  12181. fogend2:    emms
  12182.             }
  12183. #endif
  12184.         }
  12185.     } else ofogdist = -1;
  12186.  
  12187.     if (cputype&(1<<25)) drawboundcubesseinit(); else drawboundcube3dninit();
  12188. }
  12189.  
  12190. //------------------------ Simple PNG OUT code begins ------------------------
  12191. FILE *pngofil;
  12192. long pngoxplc, pngoyplc, pngoxsiz, pngoysiz;
  12193. unsigned long pngocrc, pngoadcrc;
  12194.  
  12195. #ifdef _MSC_VER
  12196.  
  12197. static _inline unsigned long bswap (unsigned long a)
  12198. {
  12199.     _asm
  12200.     {
  12201.         mov eax, a
  12202.         bswap eax
  12203.     }
  12204. }
  12205.  
  12206. #endif
  12207.  
  12208. long crctab32[256];  //SEE CRC32.C
  12209. #define updatecrc32(c,crc) crc=(crctab32[(crc^c)&255]^(((unsigned)crc)>>8))
  12210. #define updateadl32(c,crc) \
  12211. {  c += (crc&0xffff); if (c   >= 65521) c   -= 65521; \
  12212.     crc = (crc>>16)+c; if (crc >= 65521) crc -= 65521; \
  12213.     crc = (crc<<16)+c; \
  12214. } \
  12215.  
  12216. void fputbytes (unsigned long v, long n)
  12217.     { for(;n;v>>=8,n--) { fputc(v,pngofil); updatecrc32(v,pngocrc); } }
  12218.  
  12219. void pngoutopenfile (const char *fnam, long xsiz, long ysiz)
  12220. {
  12221.     long i, j, k;
  12222.     char a[40];
  12223.  
  12224.     pngoxsiz = xsiz; pngoysiz = ysiz; pngoxplc = pngoyplc = 0;
  12225.     for(i=255;i>=0;i--)
  12226.     {
  12227.         k = i; for(j=8;j;j--) k = ((unsigned long)k>>1)^((-(k&1))&0xedb88320);
  12228.         crctab32[i] = k;
  12229.     }
  12230.     pngofil = fopen(fnam,"wb");
  12231.     *(long *)&a[0] = 0x474e5089; *(long *)&a[4] = 0x0a1a0a0d;
  12232.     *(long *)&a[8] = 0x0d000000; *(long *)&a[12] = 0x52444849;
  12233.     *(long *)&a[16] = bswap(xsiz); *(long *)&a[20] = bswap(ysiz);
  12234.     *(long *)&a[24] = 0x00000208; *(long *)&a[28] = 0;
  12235.     for(i=12,j=-1;i<29;i++) updatecrc32(a[i],j);
  12236.     *(long *)&a[29] = bswap(j^-1);
  12237.     fwrite(a,37,1,pngofil);
  12238.     pngocrc = 0xffffffff; pngoadcrc = 1;
  12239.     fputbytes(0x54414449,4); fputbytes(0x0178,2);
  12240. }
  12241.  
  12242. void pngoutputpixel (long rgbcol)
  12243. {
  12244.     long a[4];
  12245.  
  12246.     if (!pngoxplc)
  12247.     {
  12248.         fputbytes(pngoyplc==pngoysiz-1,1);
  12249.         fputbytes(((pngoxsiz*3+1)*0x10001)^0xffff0000,4);
  12250.         fputbytes(0,1); a[0] = 0; updateadl32(a[0],pngoadcrc);
  12251.     }
  12252.     fputbytes(bswap(rgbcol<<8),3);
  12253.     a[0] = (rgbcol>>16)&255; updateadl32(a[0],pngoadcrc);
  12254.     a[0] = (rgbcol>> 8)&255; updateadl32(a[0],pngoadcrc);
  12255.     a[0] = (rgbcol    )&255; updateadl32(a[0],pngoadcrc);
  12256.     pngoxplc++; if (pngoxplc < pngoxsiz) return;
  12257.     pngoxplc = 0; pngoyplc++; if (pngoyplc < pngoysiz) return;
  12258.     fputbytes(bswap(pngoadcrc),4);
  12259.     a[0] = bswap(pngocrc^-1); a[1] = 0; a[2] = 0x444e4549; a[3] = 0x826042ae;
  12260.     fwrite(a,1,16,pngofil);
  12261.     a[0] = bswap(ftell(pngofil)-(33+8)-16);
  12262.     fseek(pngofil,33,SEEK_SET); fwrite(a,1,4,pngofil);
  12263.     fclose(pngofil);
  12264. }
  12265. //------------------------- Simple PNG OUT code ends -------------------------
  12266.  
  12267. long screencapture32bit (const char *fname)
  12268. {
  12269.     long p, x, y;
  12270.  
  12271.     pngoutopenfile(fname,xres,yres);
  12272.     p = frameplace;
  12273.     for(y=0;y<yres;y++,p+=bytesperline)
  12274.         for(x=0;x<xres;x++)
  12275.             pngoutputpixel(*(long *)(p+(x<<2)));
  12276.  
  12277.     return(0);
  12278. }
  12279.  
  12280.     //Captures all direction onto an un-wrapped cube
  12281. long surroundcapture32bit (dpoint3d *pos, const char *fname, long boxsiz)
  12282. {
  12283.     lpoint3d hit;
  12284.     dpoint3d d;
  12285.     long x, y, hboxsiz, *hind, hdir;
  12286.     float f;
  12287.  
  12288.     //Picture layout:
  12289.     //   ΫΫΫΫΫΫϊϊϊϊ
  12290.     //   ϊϊϊϊΫΫΫΫΫΫ
  12291.  
  12292.     f = 2.0 / (float)boxsiz; hboxsiz = (boxsiz>>1);
  12293.     pngoutopenfile(fname,boxsiz*5,boxsiz*2);
  12294.     for(y=-hboxsiz;y<hboxsiz;y++)
  12295.     {
  12296.         for(x=-hboxsiz;x<hboxsiz;x++) //(1,1,-1) - (-1,1,1)
  12297.         {
  12298.             d.x = -(x+.5)*f; d.y = 1; d.z = (y+.5)*f;
  12299.             hitscan(pos,&d,&hit,&hind,&hdir);
  12300.             if (hind) pngoutputpixel(lightvox(*hind)); else pngoutputpixel(0);
  12301.         }
  12302.         for(x=-hboxsiz;x<hboxsiz;x++) //(-1,1,-1) - (-1,-1,1)
  12303.         {
  12304.             d.x = -1; d.y = -(x+.5)*f; d.z = (y+.5)*f;
  12305.             hitscan(pos,&d,&hit,&hind,&hdir);
  12306.             if (hind) pngoutputpixel(lightvox(*hind)); else pngoutputpixel(0);
  12307.         }
  12308.         for(x=-hboxsiz;x<hboxsiz;x++) //(-1,-1,-1) - (1,-1,1)
  12309.         {
  12310.             d.x = (x+.5)*f; d.y = -1; d.z = (y+.5)*f;
  12311.             hitscan(pos,&d,&hit,&hind,&hdir);
  12312.             if (hind) pngoutputpixel(lightvox(*hind)); else pngoutputpixel(0);
  12313.         }
  12314.         for(x=(boxsiz<<1);x>0;x--) pngoutputpixel(0);
  12315.     }
  12316.     for(y=-hboxsiz;y<hboxsiz;y++)
  12317.     {
  12318.         for(x=(boxsiz<<1);x>0;x--) pngoutputpixel(0);
  12319.         for(x=-hboxsiz;x<hboxsiz;x++) //(-1,-1,1) - (1,1,1)
  12320.         {
  12321.             d.x = (x+.5)*f; d.y = (y+.5)*f; d.z = 1;
  12322.             hitscan(pos,&d,&hit,&hind,&hdir);
  12323.             if (hind) pngoutputpixel(lightvox(*hind)); else pngoutputpixel(0);
  12324.         }
  12325.         for(x=-hboxsiz;x<hboxsiz;x++) //(1,-1,1) - (1,1,-1)
  12326.         {
  12327.             d.x = 1; d.y = (y+.5)*f; d.z = -(x+.5)*f;
  12328.             hitscan(pos,&d,&hit,&hind,&hdir);
  12329.             if (hind) pngoutputpixel(lightvox(*hind)); else pngoutputpixel(0);
  12330.         }
  12331.         for(x=-hboxsiz;x<hboxsiz;x++) //(1,-1,-1) - (-1,1,-1)
  12332.         {
  12333.             d.x = -(x+.5)*f; d.y = (y+.5)*f; d.z = -1;
  12334.             hitscan(pos,&d,&hit,&hind,&hdir);
  12335.             if (hind) pngoutputpixel(lightvox(*hind)); else pngoutputpixel(0);
  12336.         }
  12337.     }
  12338.     return(0);
  12339. }
  12340.  
  12341. static _inline long testflag (long c)
  12342. {
  12343.     _asm
  12344.     {
  12345.         mov ecx, c
  12346.         pushfd
  12347.         pop eax
  12348.         mov edx, eax
  12349.         xor eax, ecx
  12350.         push eax
  12351.         popfd
  12352.         pushfd
  12353.         pop eax
  12354.         xor eax, edx
  12355.         mov eax, 1
  12356.         jne menostinx
  12357.         xor eax, eax
  12358.         menostinx:
  12359.     }
  12360. }
  12361.  
  12362. static _inline void cpuid (long a, long *s)
  12363. {
  12364.     _asm
  12365.     {
  12366.         push ebx
  12367.         push esi
  12368.         mov eax, a
  12369.         cpuid
  12370.         mov esi, s
  12371.         mov dword ptr [esi+0], eax
  12372.         mov dword ptr [esi+4], ebx
  12373.         mov dword ptr [esi+8], ecx
  12374.         mov dword ptr [esi+12], edx
  12375.         pop esi
  12376.         pop ebx
  12377.     }
  12378. }
  12379.  
  12380.     //Bit numbers of return value:
  12381.     //0:FPU, 4:RDTSC, 15:CMOV, 22:MMX+, 23:MMX, 25:SSE, 26:SSE2, 30:3DNow!+, 31:3DNow!
  12382. static long getcputype ()
  12383. {
  12384.     long i, cpb[4], cpid[4];
  12385.     if (!testflag(0x200000)) return(0);
  12386.     cpuid(0,cpid); if (!cpid[0]) return(0);
  12387.     cpuid(1,cpb); i = (cpb[3]&~((1<<22)|(1<<30)|(1<<31)));
  12388.     cpuid(0x80000000,cpb);
  12389.     if (((unsigned long)cpb[0]) > 0x80000000)
  12390.     {
  12391.         cpuid(0x80000001,cpb);
  12392.         i |= (cpb[3]&(1<<31));
  12393.         if (!((cpid[1]^0x68747541)|(cpid[3]^0x69746e65)|(cpid[2]^0x444d4163))) //AuthenticAMD
  12394.             i |= (cpb[3]&((1<<22)|(1<<30)));
  12395.     }
  12396.     if (i&(1<<25)) i |= (1<<22); //SSE implies MMX+ support
  12397.     return(i);
  12398. }
  12399.  
  12400. #if 0
  12401.   //This doesn't speed it up and it only makes it crash on some computers :/
  12402. static _inline void fixsse ()
  12403. {
  12404.     static long asm32;
  12405.     _asm
  12406.     {
  12407.         stmxcsr [asm32]  ;Default is:0x1f80
  12408.         or asm32, 0x8040 ;enable ftz&daz to prevent slow denormals!
  12409.         ldmxcsr [asm32]
  12410.     }
  12411. }
  12412. #endif
  12413.  
  12414. void freekv6 (kv6data *kv6)
  12415. {
  12416.     if (kv6->lowermip) freekv6(kv6->lowermip); //NOTE: dangerous - recursive!
  12417.     free((void *)kv6);
  12418. }
  12419.  
  12420. void uninitvoxlap ()
  12421. {
  12422.     if (sxlbuf) { free(sxlbuf); sxlbuf = 0; }
  12423.  
  12424.     if (vbuf) { free(vbuf); vbuf = 0; }
  12425.     if (vbit) { free(vbit); vbit = 0; }
  12426.  
  12427.     if (khashbuf)
  12428.     {     //Free all KV6&KFA on hash list
  12429.         long i, j;
  12430.         kfatype *kfp;
  12431.         for(i=0;i<khashpos;i+=strlen(&khashbuf[i+9])+10)
  12432.         {
  12433.             switch (khashbuf[i+8])
  12434.             {
  12435.                 case 0: //KV6
  12436.                     freekv6(*(kv6data **)&khashbuf[i+4]);
  12437.                     break;
  12438.                 case 1: //KFA
  12439.                     kfp = *(kfatype **)&khashbuf[i+4];
  12440.                     if (!kfp) continue;
  12441.                     if (kfp->seq) free((void *)kfp->seq);
  12442.                     if (kfp->frmval) free((void *)kfp->frmval);
  12443.                     if (kfp->hingesort) free((void *)kfp->hingesort);
  12444.                     if (kfp->hinge) free((void *)kfp->hinge);
  12445.                     if (kfp->spr)
  12446.                     {
  12447.                         for(j=kfp->numspr-1;j>=0;j--)
  12448.                             if (kfp->spr[j].voxnum)
  12449.                                 freekv6((kv6data *)kfp->spr[j].voxnum);
  12450.                         free((void *)kfp->spr);
  12451.                     }
  12452.                     free((void *)kfp);
  12453.                     break;
  12454.                 default: __assume(0); //tells MSVC default can't be reached
  12455.             }
  12456.         }
  12457.         free(khashbuf); khashbuf = 0; khashpos = khashsiz = 0;
  12458.     }
  12459.  
  12460.     if (skylng) { free((void *)skylng); skylng = 0; }
  12461.     if (skylat) { free((void *)skylat); skylat = 0; }
  12462.     if (skypic) { free((void *)skypic); skypic = skyoff = 0; }
  12463.  
  12464.     if (vx5.pic) { free(vx5.pic); vx5.pic = 0; }
  12465. #if (USEZBUFFER == 1)
  12466.     if (zbuffermem) { free(zbuffermem); zbuffermem = 0; }
  12467. #endif
  12468.     if (radarmem) { free(radarmem); radarmem = 0; radar = 0; }
  12469. }
  12470.  
  12471. long initvoxlap ()
  12472. {
  12473.     __int64 q;
  12474.     long i, j, k, z, zz;
  12475.     float f, ff;
  12476.  
  12477.     v5_asm_dep_unlock();
  12478.  
  12479.     cputype = getcputype();
  12480.         //CPU Must have: FPU,RDTSC,CMOV,MMX,MMX+
  12481.     if ((cputype&((1<<0)|(1<<4)|(1<<15)|(1<<22)|(1<<23))) !=
  12482.                      ((1<<0)|(1<<4)|(1<<15)|(1<<22)|(1<<23))) return(-1);
  12483.         //CPU UNSUPPORTED!
  12484.     if ((!(cputype&(1<<25))) && //SSE
  12485.         (!((cputype&((1<<30)|(1<<31))) == ((1<<30)|(1<<31))))) //3DNow!+
  12486.         return(-1);
  12487.     //if (cputype&(1<<25)) fixsse(); //SSE
  12488.  
  12489.       //WARNING: xres&yres are local to VOXLAP5.C so don't rely on them here!
  12490.     if (!(radarmem = (long *)malloc(max((((MAXXDIM*MAXYDIM*27)>>1)+7)&~7,(VSID+4)*3*SCPITCH*4+8))))
  12491.         return(-1);
  12492.     radar = (long *)((((long)radarmem)+7)&~7);
  12493.  
  12494.     for(i=0;i<32;i++) { xbsflor[i] = (-1<<i); xbsceil[i] = ~xbsflor[i]; }
  12495.  
  12496.         //Setsphere precalculations (factr[] tables) (Derivation in POWCALC.BAS)
  12497.         //   if (!factr[z][0]) z's prime else factr[z][0]*factr[z][1] == z
  12498.     factr[2][0] = 0; i = 1; j = 9; k = 0;
  12499.     for(z=3;z<SETSPHMAXRAD;z+=2)
  12500.     {
  12501.         if (z == j) { j += (i<<2)+12; i += 2; }
  12502.         factr[z][0] = 0; factr[k][1] = z;
  12503.         for(zz=3;zz<=i;zz=factr[zz][1])
  12504.             if (!(z%zz)) { factr[z][0] = zz; factr[z][1] = z/zz; break; }
  12505.         if (!factr[z][0]) k = z;
  12506.         factr[z+1][0] = ((z+1)>>1); factr[z+1][1] = 2;
  12507.     }
  12508.     for(z=1;z<SETSPHMAXRAD;z++) logint[z] = log((double)z);
  12509.  
  12510. #if (ESTNORMRAD == 2)
  12511.         //LUT for ESTNORM
  12512.     fsqrecip[0] = 0.f; fsqrecip[1] = 1.f;
  12513.     fsqrecip[2] = (float)(1.f/sqrt(2.f)); fsqrecip[3] = (float)1.f/sqrt(3.f);
  12514.     for(z=4,i=3;z<sizeof(fsqrecip)/sizeof(fsqrecip[0]);z+=6) //fsqrecip[z] = 1/sqrt(z);
  12515.     {
  12516.         fsqrecip[z+0] = fsqrecip[(z+0)>>1]*fsqrecip[2];
  12517.         fsqrecip[z+2] = fsqrecip[(z+2)>>1]*fsqrecip[2];
  12518.         fsqrecip[z+4] = fsqrecip[(z+4)>>1]*fsqrecip[2];
  12519.         fsqrecip[z+5] = fsqrecip[i]*fsqrecip[3]; i += 2;
  12520.  
  12521.         f = (fsqrecip[z+0]+fsqrecip[z+2])*.5f;
  12522.         if (z <= 22) f = (1.5f-(.5f*((float)(z+1))) * f*f)*f;
  12523.         fsqrecip[z+1] = (1.5f-(.5f*((float)(z+1))) * f*f)*f;
  12524.  
  12525.         f = (fsqrecip[z+2]+fsqrecip[z+4])*.5f;
  12526.         if (z <= 22) f = (1.5f-(.5f*((float)(z+3))) * f*f)*f;
  12527.         fsqrecip[z+3] = (1.5f-(.5f*((float)(z+3))) * f*f)*f;
  12528.     }
  12529. #endif
  12530.  
  12531.         //Lookup table to save 1 divide for gline()
  12532.     for(i=1;i<CMPRECIPSIZ;i++) cmprecip[i] = CMPPREC/(float)i;
  12533.  
  12534.         //Flashscan equal-angle compare table
  12535.     for(i=0;i<(1<<LOGFLASHVANG)*8;i++)
  12536.     {
  12537.         if (!(i&((1<<LOGFLASHVANG)-1)))
  12538.             j = (gfclookup[i>>LOGFLASHVANG]<<4)+8 - (1<<LOGFLASHVANG)*64;
  12539.         gfc[i].y = j; j += 64*2;
  12540.         ftol(sqrt((1<<(LOGFLASHVANG<<1))*64.f*64.f-gfc[i].y*gfc[i].y),&gfc[i].x);
  12541.     }
  12542.  
  12543.         //Init norm flash variables:
  12544.     ff = (float)GSIZ*.5f; // /(1);
  12545.     for(z=1;z<(GSIZ>>1);z++)
  12546.     {
  12547.         ffxptr = &ffx[(z+1)*z-1];
  12548.         f = ff; ff = (float)GSIZ*.5f/((float)z+1);
  12549.         for(zz=-z;zz<=z;zz++)
  12550.         {
  12551.             if (zz <= 0) i = (long)(((float)zz-.5f)*f); else i = (long)(((float)zz-.5f)*ff);
  12552.             if (zz >= 0) j = (long)(((float)zz+.5f)*f); else j = (long)(((float)zz+.5f)*ff);
  12553.             ffxptr[zz].x = (unsigned short)max(i+(GSIZ>>1),0);
  12554.             ffxptr[zz].y = (unsigned short)min(j+(GSIZ>>1),GSIZ);
  12555.         }
  12556.     }
  12557.     for(i=0;i<=25*5;i+=5) xbsbuf[i] = 0x00000000ffffffff;
  12558.     for(z=0;z<32;z++) { p2c[z] = (1<<z); p2m[z] = p2c[z]-1; }
  12559.  
  12560.         //Drawtile lookup table:
  12561.     //q = 0;
  12562.     //for(i=0;i<256;i++) { alphalookup[i] = q; q += 0x1000100010; }
  12563.  
  12564.         //Initialize univec normals (for KV6 lighting)
  12565.     equivecinit(255);
  12566.     //for(i=0;i<255;i++)
  12567.     //{
  12568.     //   univec[i].z = ((float)((i<<1)-254))/255.0;
  12569.     //   f = sqrt(1.0 - univec[i].z*univec[i].z);
  12570.     //   fcossin((float)i*(GOLDRAT*PI*2),&univec[i].x,&univec[i].y);
  12571.     //   univec[i].x *= f; univec[i].y *= f;
  12572.     //}
  12573.     //univec[255].x = univec[255].y = univec[255].z = 0;
  12574.     for(i=0;i<256;i++)
  12575.     {
  12576.         iunivec[i][0] = (short)(univec[i].x*4096.0);
  12577.         iunivec[i][1] = (short)(univec[i].y*4096.0);
  12578.         iunivec[i][2] = (short)(univec[i].z*4096.0);
  12579.         iunivec[i][3] = 4096;
  12580.     }
  12581.     ucossininit();
  12582.  
  12583.     memset(mixn,0,sizeof(mixn));
  12584.  
  12585.         //Initialize hash table for getkv6()
  12586.     memset(khashead,-1,sizeof(khashead));
  12587.     if (!(khashbuf = (char *)malloc(KHASHINITSIZE))) return(-1);
  12588.     khashsiz = KHASHINITSIZE;
  12589.  
  12590.     vx5.anginc = 1; //Higher=faster (1:full,2:half)
  12591.     vx5.sideshademode = 0; setsideshades(0,0,0,0,0,0);
  12592.     vx5.mipscandist = 128;
  12593.     vx5.maxscandist = 256; //must be <= 2047
  12594.     vx5.colfunc = curcolfunc; //This prevents omission bugs from crashing voxlap5
  12595.     vx5.curcol = 0x80804c33;
  12596.     vx5.currad = 8;
  12597.     vx5.curhei = 0;
  12598.     vx5.curpow = 2.0;
  12599.     vx5.amount = 0x70707;
  12600.     vx5.pic = 0;
  12601.     vx5.cliphitnum = 0;
  12602.     vx5.xplanemin = 0;
  12603.     vx5.xplanemax = 0x7fffffff;
  12604.     vx5.flstnum = 0;
  12605.     vx5.lightmode = 0;
  12606.     vx5.numlights = 0;
  12607.     vx5.kv6mipfactor = 96;
  12608.     vx5.kv6col = 0x808080;
  12609.     vx5.vxlmipuse = 1;
  12610.     vx5.fogcol = -1;
  12611.     vx5.fallcheck = 0;
  12612.  
  12613.     gmipnum = 0;
  12614.  
  12615.     return(0);
  12616. }
  12617.  
  12618. #if 0 //ndef _WIN32
  12619.     long i, j, k, l;
  12620.     char *v;
  12621.  
  12622.     j = k = l = 0;
  12623.     for(i=0;i<VSID*VSID;i++)
  12624.     {
  12625.         for(v=sptr[i];v[0];v+=v[0]*4) { j++; k += v[2]-v[1]+1; l += v[0]-1; }
  12626.         k += v[2]-v[1]+1; l += v[2]-v[1]+1;
  12627.     }
  12628.  
  12629.     printf("VOXLAP5 programmed by Ken Silverman (www.advsys.net/ken)\n");
  12630.     printf("Please DO NOT DISTRIBUTE! If this leaks, I will not be happy.\n\n");
  12631.     //printf("This copy licensed to:  \n\n");
  12632.     printf("Memory statistics upon exit: (all numbers in bytes)");
  12633.     printf("\n");
  12634.     if (screen) printf("   screen: %8ld\n",imageSize);
  12635.     printf("    radar: %8ld\n",max((((MAXXDIM*MAXYDIM*27)>>1)+7)&~7,(VSID+4)*3*SCPITCH*4+8));
  12636.     printf("  bacsptr: %8ld\n",sizeof(bacsptr));
  12637.     printf("     sptr: %8ld\n",(VSID*VSID)<<2);
  12638.     printf("     vbuf: %8ld(%8ld)\n",(j+VSID*VSID+l)<<2,VOXSIZ);
  12639.     printf("     vbit: %8ld(%8ld)\n",VOXSIZ>>5);
  12640.     printf("\n");
  12641.     printf("vbuf head: %8ld\n",(j+VSID*VSID)<<2);
  12642.     printf("vbuf cols: %8ld\n",l<<2);
  12643.     printf("     fcol: %8ld\n",k<<2);
  12644.     printf("     ccol: %8ld\n",(l-k)<<2);
  12645.     printf("\n");
  12646.     printf("%.2f bytes/column\n",(float)((j+VSID*VSID+l)<<2)/(float)(VSID*VSID));
  12647. #endif
  12648.  
  12649.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement