home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 1 / PC Actual CD 01.iso / share / dos / demos / planets / source.lzh / MAKEGUSH.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-29  |  10.3 KB  |  342 lines

  1.  
  2. /*
  3.  *  MAKEGUSH.C
  4.  *
  5.  *  (Simon Hern, 1994)
  6.  *
  7.  *  Generate some Gush data for the Bouncing Planets demo
  8.  *
  9.  *  Asks for desired planet radius and orientation (as two rotations)
  10.  *
  11.  *  The Gush is written to the file GUSH.DAT
  12.  *  The data is in compiled form, i.e., executable code
  13.  *  Four interlaced Mode X slices are used, with vectors to them at
  14.  *   data offsets 1, 4, 7, and 10
  15.  *  The first byte of the gush is the planet's radius
  16.  *  The slices 'return far' on completion
  17.  *  Gush assumes that:  ES:DI is the top left corner of the image on screen
  18.  *                      DS:SI is the start of the expanded Xion array
  19.  *  Gush data cannot be longer than 64k (size depends on RHO value)
  20.  *
  21.  *  GUSHCODE.ASM provides an interface to gush data for the C language
  22.  *
  23.  */
  24.  
  25.  
  26. #include <math.h>
  27. #include <stdio.h>
  28. #include <alloc.h>
  29.  
  30. /* XLib v06 */
  31. #include <xfileio.h>
  32.  
  33. /* Local definitions (notably RHO: the surface resolution) */
  34. #include "planet.h"
  35.  
  36.  
  37.  
  38. /* Viewing distance for perspective */
  39. #define DIST 2000.0
  40.  
  41. /* Largest planet radius possible (restricted by segment size) */
  42. #define MAX_RADIUS 64
  43.  
  44. /* Value to mark unused parts of grid (both xm and ym values) */
  45. #define NOT_USED 255
  46.  
  47. /* File to write data to */
  48. #define GUSH_FILE "GUSH.DAT"
  49.  
  50. /* Screen width (a quarter of this according to Mode X) */
  51. #define SCR_WIDTH 320
  52.  
  53. /* Machine code */
  54. #define JMP 0xE9        /* 'jump near relative' */
  55. #define ADD_DI_B1 0x83  /* 'add byte to DI' byte 1 */
  56. #define ADD_DI_B2 0xC7  /* 'add byte to DI' byte 2 */
  57. #define ADD_DI_W1 0x81  /* 'add word to DI' byte 1 */
  58. #define ADD_DI_W2 0xC7  /* 'add word to DI' byte 2 */
  59. #define STOSB 0xAA      /* 'store AL at DI and inc DI' */
  60. #define STOSW 0xAB      /* 'store AX at DI and inc DI' */
  61. #define MOV_AL_1 0x8A   /* 'get AL relative to SI' byte 1 */
  62. #define MOV_AL_2 0x84   /* 'get AL relative to SI' byte 2 */
  63. #define MOV_AH_1 0x8A   /* 'get AH relative to SI' byte 1 */
  64. #define MOV_AH_2 0xA4   /* 'get AH relative to SI' byte 2 */
  65. #define RETF 0xCB       /* 'far return' */
  66.  
  67.  
  68.  
  69. /* Structure for values to be stored at each point in the grid */
  70. typedef struct {
  71.     unsigned char xm;
  72.     unsigned char ym;   /* 'char' suitable for RHO up to 128 */
  73. } GridVals;
  74.  
  75.  
  76.  
  77. /* Save data from 'far' array (up to 65535 bytes) */
  78. int far_save(char * fname, char far * data, unsigned len);
  79.  
  80.  
  81.  
  82. void main() {
  83.  
  84.  
  85.   /* The Grid: Image of the planet; results of calculations (Square Gush) */
  86.     GridVals grid[2*MAX_RADIUS][2*MAX_RADIUS];
  87.  
  88.   /* The Gush: Compiled code for drawing a planet */
  89.     unsigned char far * gush;
  90.  
  91.  
  92.  
  93.   /* Stage 1 variables */
  94.  
  95.     int radius;  /* Visible radius of planet (in pixels) */
  96.     double r;  /* Actual radius of planet */
  97.  
  98.     int theta, phi;  /* Rotation angles */
  99.     double cth, sth, cph, sph;  /* cos and sin of theta and phi */
  100.  
  101.     unsigned gridx, gridy;  /* Current position in grid */
  102.     double xs, ys;          /* Screen coords relative to screen centre */
  103.     double xp, yp, zp;      /* 3D coords of point on planet surface */
  104.     double xt, yt, zt;      /* 3D coords after twist and turn */
  105.     int xm, ym;             /* Map coords */
  106.  
  107.     double zs, k, alpha, beta, w;  /* Temporary values */
  108.  
  109.  
  110.  
  111.   /* Stage 2 variables */
  112.  
  113.     unsigned int i;       /* Index into gush object */
  114.     unsigned int start;   /* Start of current slice of gush */
  115.     int slice;            /* Slices 0-3 for Mode X convenience */
  116.     unsigned int blanks;  /* Number of pixels to hop over */
  117.     int got_one;          /* Flags presence of first half of a pair */
  118.     unsigned int source;  /* Address to grab value from */
  119.  
  120.  
  121.  
  122.   /* Request radius and angles */
  123.  
  124.     printf("\nPlanet radius (max %d): ", MAX_RADIUS);
  125.     scanf("%d", &radius);
  126.     printf("\nBackward tilt in degrees (phi): ");
  127.     scanf("%d", &phi);
  128.     printf("\nClockwise turn in degrees (theta): ");
  129.     scanf("%d", &theta);
  130.  
  131.     /* The radius can't be too large or the gush overflows the 64k barrier */
  132.     if ( radius > MAX_RADIUS || radius < 4 ) radius = MAX_RADIUS / 2;
  133.     /* I'm insisting that the radius be a multiple of 4. There's no real */
  134.     /* reason for this as far as I can see, it's just that the one time */
  135.     /* I tried an odd radius the program glitched. So there. */
  136.     radius = radius & 0xFFFC;
  137.  
  138.     phi = phi % 360;
  139.     theta = theta % 360;
  140.     printf("\nRadius = %d, ", radius);
  141.     printf("Phi = %d, Theta = %d\n\n", phi, theta);
  142.  
  143.     r = DIST * radius / sqrt( DIST*DIST + radius*radius );
  144.     cth = cos( (double)theta * PI/180 );
  145.     sth = sin( (double)theta * PI/180 );
  146.     cph = cos( (double)phi * PI/180 );
  147.     sph = sin( (double)phi * PI/180 );
  148.  
  149.  
  150.  
  151.   /* Stage 1: Fill in the grid */
  152.   /* (Do lots of sums. Grid points either hold results or are left blank) */
  153.  
  154.     printf("Calculating %d lines\n", 2*radius);
  155.  
  156.     for( gridy=0, ys=radius-0.5 ; gridy < 2*radius ; gridy++, ys-- ) {
  157.         for( gridx=0, xs=0.5-radius ; gridx < 2*radius ; gridx++, xs++ ) {
  158.  
  159.             zs = sqrt( xs*xs + ys*ys );
  160.             if ( zs > radius ) {
  161.                 /* Not a point in the planet image */
  162.                 xm = NOT_USED;
  163.                 ym = NOT_USED;
  164.             } else {
  165.  
  166.                 k = ( DIST*DIST -
  167.                         sqrt( DIST*DIST*( r*r - zs*zs ) + r*r*zs*zs ) )
  168.                     / ( DIST*DIST + zs*zs );
  169.                 yp = k * ys;
  170.                 xp = k * xs;
  171.                 zp = sqrt( r*r - xp*xp - yp*yp );
  172.  
  173.                 xt = xp*cth - yp*sth*cph + zp*sth*sph;
  174.                 yt = xp*sth + yp*cth*cph - zp*cth*sph;
  175.                 zt = yp*sph + zp*cph;
  176.  
  177.                 if ( yt > r ) yt = r;
  178.                 if ( yt < -r ) yt = -r;
  179.                 w = sqrt( r*r - yt*yt );
  180.                 alpha = acos( yt/r );
  181.  
  182.                 if ( xt > w ) xt = w;
  183.                 if ( xt < -w ) xt = -w;
  184.                 beta = acos( - xt/w );
  185.  
  186.                 xm = (int) ( beta * RHO/PI );
  187.                 if ( xm == RHO ) xm--;
  188.                 ym = (int) ( alpha * RHO/PI );
  189.                 if ( ym == RHO ) ym--;
  190.  
  191.                 if ( zt < 0 ) xm = 2*RHO - 1 - xm;
  192.  
  193.             }
  194.  
  195.             grid[gridy][gridx].xm = (unsigned char)xm;
  196.             grid[gridy][gridx].ym = (unsigned char)ym;
  197.         }
  198.  
  199.         printf("   Line: %d\r", gridy);
  200.     }
  201.  
  202.  
  203.  
  204.   /* Stage 2: Compile grid to gush */
  205.   /* (Move through the grid, generating point plotting machine code) */
  206.  
  207.     printf("Compiling data\n");
  208.  
  209.     gush = (unsigned char far *)farmalloc(65535L);
  210.     if ( gush == NULL ) {
  211.         printf("ERROR: Run out of memory\n");
  212.         exit(1);
  213.     }
  214.  
  215.     /* First byte is the radius */
  216.     gush[0] = (unsigned char)radius;
  217.  
  218.     /* Then 12 bytes of vectors to slices */
  219.     gush[1] = gush[4] = gush[7] = gush[10] = JMP;
  220.  
  221.     start = 13;  /* After vectors */
  222.     for ( slice = 0 ; slice < 4 ; slice++ ) {
  223.  
  224.         i = start;
  225.         blanks = 0;
  226.         got_one = 0;
  227.         for ( gridy = 0 ; gridy < 2*radius ; gridy++ ) {
  228.             for ( gridx = slice ; gridx < 2*radius ; gridx+=4 ) {
  229.  
  230.                 xm = grid[gridy][gridx].xm;
  231.                 ym = grid[gridy][gridx].ym;
  232.  
  233.                 if ( xm == NOT_USED && ym == NOT_USED ) {
  234.  
  235.                     /* Skip over this point */
  236.                     blanks++;
  237.  
  238.                 } else {
  239.  
  240.                     if ( blanks ) {
  241.                         /* Any points outstanding? */
  242.                         if ( got_one ) {
  243.                             gush[i++] = STOSB;
  244.                             got_one = 0;
  245.                         }
  246.  
  247.                         /* Move screen pointer on some */
  248.                         if ( blanks <= 127 ) {
  249.                             /* Add byte value */
  250.                             gush[i++] = ADD_DI_B1;
  251.                             gush[i++] = ADD_DI_B2;
  252.                             gush[i++] = blanks;
  253.                         } else {
  254.                             /* Add word value */
  255.                             gush[i++] = ADD_DI_W1;
  256.                             gush[i++] = ADD_DI_W2;
  257.                             gush[i++] = blanks & 0xFF;
  258.                             gush[i++] = blanks >> 8;
  259.                         }
  260.                         blanks = 0;
  261.                     }
  262.  
  263.                     /* Calculate source address */
  264.                     source = xm + 4*RHO*(unsigned)ym;
  265.  
  266.                     /* And write the code */
  267.                     if ( got_one ) {
  268.                         /* Second half of a pair */
  269.                         gush[i++] = MOV_AH_1;
  270.                         gush[i++] = MOV_AH_2;
  271.                         gush[i++] = source & 0xFF;
  272.                         gush[i++] = source >> 8;
  273.                         gush[i++] = STOSW;
  274.                         got_one = 0;
  275.                     } else {
  276.                         /* First half of a pair */
  277.                         gush[i++] = MOV_AL_1;
  278.                         gush[i++] = MOV_AL_2;
  279.                         gush[i++] = source & 0xFF;
  280.                         gush[i++] = source >> 8;
  281.                         got_one = 1;
  282.                     }
  283.  
  284.                 }
  285.  
  286.                 /* Check i not about to got out of bounds */
  287.                 if ( i > 65500 ) {
  288.                     printf("Sorry, run out of space for gush\n"
  289.                            "Try a smaller planet radius\n");
  290.                     exit(0);
  291.                 }
  292.  
  293.             } /* for ( gridx ) */
  294.  
  295.             /* Around edge of screen */
  296.             blanks += ( SCR_WIDTH - 2*radius ) / 4;
  297.  
  298.         } /* for ( gridy ) */
  299.  
  300.         /* Just one left? */
  301.         if ( got_one ) gush[i++] = STOSB;
  302.  
  303.         gush[i++] = RETF;
  304.  
  305.         /* Line up vectors */
  306.         gush[3*slice+2] = ( start - slice*3 - 4 ) & 0xFF;
  307.         gush[3*slice+3] = ( start - slice*3 - 4 ) >> 8;
  308.         start = i;
  309.  
  310.     } /* for ( slice ) */
  311.  
  312.  
  313.  
  314.     /* Output gush to file */
  315.     if ( ! far_save(GUSH_FILE, gush, i) ) {
  316.         printf("ERROR: Cannot create %s\n", GUSH_FILE);
  317.         exit(1);
  318.     }
  319.  
  320.     printf("\nData saved to %s, length %.0f bytes\n", GUSH_FILE, (double)i);
  321.  
  322.     farfree((void far *)gush);
  323.  
  324. }
  325.  
  326.  
  327.  
  328. /* Function to save data from 'far' array (up to 65535 bytes) */
  329.  
  330. int far_save(char * fname, char far * data, unsigned len) {
  331.     int fout;
  332.  
  333.     fout = f_open(fname, F_WRONLY);
  334.     if ( fout == FILE_ERR ) return 0;
  335.  
  336.     f_writefar(fout, data, len);
  337.  
  338.     f_close(fout);
  339.     return 1;
  340. }
  341.  
  342.