home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Peter's Final Project / src / engine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-10  |  10.6 KB  |  514 lines  |  [TEXT/KAHL]

  1. /*
  2.  *  Peter's Final Project -- A texture mapping demonstration
  3.  *  © 1995, Peter Mattis
  4.  *
  5.  *  E-mail:
  6.  *  petm@soda.csua.berkeley.edu
  7.  *
  8.  *  Snail-mail:
  9.  *   Peter Mattis
  10.  *   557 Fort Laramie Dr.
  11.  *   Sunnyvale, CA 94087
  12.  *
  13.  *  Avaible from:
  14.  *  http://www.csua.berkeley.edu/~petm/final.html
  15.  *
  16.  *  This program is free software; you can redistribute it and/or modify
  17.  *  it under the terms of the GNU General Public License as published by
  18.  *  the Free Software Foundation; either version 2 of the License, or
  19.  *  (at your option) any later version.
  20.  *
  21.  *  This program is distributed in the hope that it will be useful,
  22.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  23.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24.  *  GNU General Public License for more details.
  25.  *
  26.  *  You should have received a copy of the GNU General Public License
  27.  *  along with this program; if not, write to the Free Software
  28.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29.  */
  30.  
  31. #include <assert.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34.  
  35. #include "collision.h"
  36. #include "computer.h"
  37. #include "engine.h"
  38. #include "matrix.vector.h"
  39. #include "maze.h"
  40. #include "object.h"
  41. #include "render.h"
  42. #include "scan.h"
  43. #include "sector.h"
  44. #include "sys.stuff.h"
  45. #include "timer.h"
  46. #include "world.h"
  47.  
  48. /*
  49.  * Declare the functions private to this module.
  50.  */
  51.  
  52. void do_engine_refresh (void);
  53. void do_move_objects (OBJECTS);
  54. void do_move_my_object (OBJECT);
  55. void do_object_movement (OBJECT);
  56.  
  57. /*
  58.  * Define some values for key encoding.
  59.  */
  60.  
  61. static const short LEFT = 0x1;
  62. static const short RIGHT = 0x2;
  63. static const short UP = 0x4;
  64. static const short DOWN = 0x8;
  65.  
  66. /*
  67.  * Define some movement values.
  68.  * The maximum values are to make sure no one
  69.  *  moves to fast.
  70.  */
  71.  
  72. static const NUM TURN_STEP = NUM_ONE * 0.07;
  73. static const NUM TURN_MAX = NUM_ONE * 0.25;
  74. static const NUM TURN_MIN = NUM_ONE * 0.01;
  75.  
  76. static const NUM MOVE_STEP = NUM_ONE * 0.10;
  77. static const NUM MOVE_MAX = NUM_ONE * 0.25;
  78. static const NUM MOVE_MIN = NUM_ONE * 0.01;
  79.  
  80. /*
  81.  * A global debug variable. Not really used much now.
  82.  */
  83. short debug_level = 0;
  84.  
  85. /*
  86.  * Lots of private variables. 
  87.  */
  88.  
  89. static long keys = 0;
  90. static TIMER frame_timer;
  91. static TIMER global_timer;
  92. static long frame_count;
  93.  
  94. static short maze_size = 15;
  95. static char *server_name = NULL;
  96. static char *wall_texture_name = NULL;
  97. static char *floor_texture_name = NULL;
  98. static char *ceiling_texture_name = NULL;
  99.  
  100. static MAZE maze;
  101. static WORLD world;
  102. static OBJECT view = NULL;
  103. static OBJECT player = NULL;
  104. static OBJECT enemy = NULL;
  105. static OBJECTS objects = NULL;
  106.  
  107. /*
  108.  * Set the maze size.
  109.  */
  110.  
  111. void
  112. do_set_maze_size (size)
  113.     short size;
  114. {
  115.     maze_size = size;
  116. }
  117.  
  118. /*
  119.  * Set the wall texture.
  120.  */
  121.  
  122. void
  123. do_set_wall_texture (name)
  124.     char *name;
  125. {
  126.     wall_texture_name = name;
  127. }
  128.  
  129. /*
  130.  * Set the floor texture.
  131.  */
  132.  
  133. void
  134. do_set_floor_texture (name)
  135.     char *name;
  136. {
  137.     floor_texture_name = name;
  138. }
  139.  
  140. /*
  141.  * Set the ceiling texture.
  142.  */
  143.  
  144. void
  145. do_set_ceiling_texture (name)
  146.     char *name;
  147. {
  148.     ceiling_texture_name = name;
  149. }
  150.  
  151. /*
  152.  * Set the debug level.
  153.  */
  154.  
  155. void
  156. do_set_debug_level (state)
  157.     short state;
  158. {
  159.     debug_level = state;
  160. }
  161.  
  162. /*
  163.  * Initialize the engine.
  164.  */
  165.  
  166. void
  167. do_engine_init ()
  168. {
  169.     /*
  170.      * Initialize the scan converter.
  171.      */
  172.     scan_init ();
  173.  
  174.     /*
  175.      * Make and initialize the maze. The third
  176.      *  value is the random seed value.
  177.      */ 
  178.     maze = make_maze ();
  179.     maze_init (maze, maze_size, 0);
  180.  
  181.     /*
  182.      * Print and ascii description of the maze.
  183.      */
  184.     if (debug_level >= 1)
  185.         maze_describe (maze);
  186.  
  187.     /*
  188.      * Make and initialize the world form the maze.
  189.      */
  190.     world = make_world ();
  191.     world_from_maze (world, maze, wall_texture_name, floor_texture_name, ceiling_texture_name);
  192.  
  193.     /*
  194.      * Make the user controlled player.
  195.      */
  196.     player = make_object ();
  197.     set_object_id (player, 1);
  198.     set_object_radius (player, my_float_to_num (0.36));
  199.     set_object_red (player, my_float_to_num (1));
  200.     set_object_green (player, my_float_to_num (0));
  201.     set_object_blue (player, my_float_to_num (0));
  202.     set_object_move (player, (void *) do_move_my_object);
  203.  
  204.     set_object_pos_x (player, my_float_to_num (1.0));
  205.     set_object_pos_y (player, my_float_to_num (1.0));
  206.     set_object_pos_z (player, my_float_to_num (2.5));
  207.  
  208.     set_object_dir_x (player, my_float_to_num (0.0));
  209.     set_object_dir_y (player, my_float_to_num (0.0));
  210.     set_object_dir_z (player, my_float_to_num (1.0));
  211.  
  212.     object_update_camera (player);
  213.     set_object_sector (player, maze_element_sector (maze, 2, 1));
  214.     sector_objects (object_sector (player)) = objects_add_object (
  215.     sector_objects (object_sector (player)), player);
  216.     object_sectors (player) = sectors_add_sector (object_sectors (player), 
  217.     object_sector (player));
  218.     objects = objects_add_object (objects, player);
  219.  
  220.     /*
  221.      * Make the computer controlled player.
  222.      */
  223.     enemy = make_object ();
  224.     set_object_id (enemy, 1);
  225.     set_object_radius (enemy, my_float_to_num (0.36));
  226.     set_object_red (enemy, my_float_to_num (0));
  227.     set_object_green (enemy, my_float_to_num (0));
  228.     set_object_blue (enemy, my_float_to_num (1));
  229.  
  230.     set_object_data (enemy, player);
  231.     set_object_move (enemy, (void *) computer_move);
  232.  
  233.     set_object_pos_x (enemy, my_float_to_num (1.0));
  234.     set_object_pos_y (enemy, my_float_to_num (1.0));
  235.     set_object_pos_z (enemy, my_float_to_num (1.0));
  236.  
  237.     set_object_dir_x (enemy, my_float_to_num (0.0));
  238.     set_object_dir_y (enemy, my_float_to_num (0.0));
  239.     set_object_dir_z (enemy, my_float_to_num (-1.0));
  240.  
  241.     object_update_camera (enemy);
  242.     set_object_sector (enemy, maze_element_sector (maze, 1, 1));
  243.     sector_objects (object_sector (enemy)) = objects_add_object (
  244.     sector_objects (object_sector (enemy)), enemy);
  245.     object_sectors (enemy) = sectors_add_sector (object_sectors (enemy), 
  246.     object_sector (enemy));
  247.     objects = objects_add_object (objects, enemy);
  248.  
  249.     /*
  250.      * Tie the view to the computer controlled player.
  251.      */
  252.     view = enemy;
  253.  
  254.     /*
  255.      * Create the various timers and initialize the frame count.
  256.      */
  257.     frame_timer = make_timer ();
  258.     global_timer = make_timer ();
  259.     frame_count = 0;
  260. }
  261.  
  262. /*
  263.  * Exit the engine.
  264.  */
  265.  
  266. void
  267. do_engine_exit ()
  268. {
  269.     /*
  270.      * Stop the global timer.
  271.      */
  272.     timer_stop (global_timer);
  273.  
  274.     /*
  275.      * Print memory debugging information.
  276.      */
  277.     if (debug_level >= 1)
  278.     {
  279.         printf ("Face memory usage: %d k\n", face_mem_usage () /1024);
  280.         printf ("Sector memory usage: %d k\n", sector_mem_usage () /1024);
  281.         printf ("Average fps: %0.4f\n", frame_count /timer_elapsed (global_timer));
  282.     }
  283.  
  284.     /*
  285.      * Free stuff.
  286.      */
  287.     free_timer (frame_timer);
  288.     free_timer (global_timer);
  289.     free_maze (maze);
  290.     free_world (world);
  291.     free_object (player);
  292.     free_object (enemy);
  293. }
  294.  
  295. /*
  296.  * Display a single frame.
  297.  * This involves moving the objects and then
  298.  *  refreshing the display.
  299.  */
  300.  
  301. void
  302. do_engine_frame ()
  303. {
  304.     do_move_objects (objects);
  305.     do_engine_refresh ();
  306. }
  307.  
  308. /*
  309.  * Refresh the display.
  310.  */
  311.  
  312. void
  313. do_engine_refresh ()
  314. {
  315.     /*
  316.      * Start the global timer if this is the first frame.
  317.      */
  318.     if (frame_count == 0)
  319.         timer_start (global_timer);
  320.     
  321.     /*
  322.      * Increment the frame count.
  323.      */
  324.     frame_count++;
  325.  
  326.     if (debug_level >= 2)
  327.         timer_start (frame_timer);
  328.  
  329.     /*
  330.      * Clear the frame buffer. This doesn't really need
  331.      *  to be done since we'll be drawing over every single
  332.      *  pixel.
  333.      */
  334. /*
  335.     do_set_color (1);
  336.     do_clear_frame_buffer ();
  337. */
  338.  
  339.     /*
  340.      * Render the world from the current view. Then
  341.      *  update the screen.
  342.      */
  343.     do_render_world (view);
  344.     do_update_screen ();
  345.  
  346.     if (debug_level >= 2)
  347.     {
  348.         timer_stop (frame_timer);
  349.         printf ("fps: %0.4f\n", 1.0 /timer_elapsed (frame_timer));
  350.     }
  351. }
  352.  
  353. /*
  354.  * Handle key presses. We'll simply encode them so 
  355.  *  that we can keep track of which keys are currently
  356.  *  down.
  357.  */
  358.  
  359. void
  360. do_engine_key (key, down)
  361.     long key;
  362.     short down;
  363. {
  364.     if (down)
  365.     {
  366.         /*
  367.          * The key was pressed so "or" it in with the
  368.          *  rest of them.
  369.          */
  370.         if (key == LEFT_KEY)
  371.             keys |= LEFT;
  372.         else if (key == RIGHT_KEY)
  373.             keys |= RIGHT;
  374.         else if (key == UP_KEY)
  375.             keys |= UP;
  376.         else if (key == DOWN_KEY)
  377.             keys |= DOWN;
  378.         else if (key == TAB_KEY)
  379.         {
  380.             /*
  381.              * Switch the view if the tab key was pressed.
  382.              */
  383.              view = (view == player) ? enemy : player;
  384.         }
  385.     }
  386.     else
  387.     {
  388.         /*
  389.          * The key was released so "and-not" it with the
  390.          *  rest of them.
  391.          */
  392.         if (key == LEFT_KEY)
  393.             keys &= ~LEFT;
  394.         else if (key == RIGHT_KEY)
  395.             keys &= ~RIGHT;
  396.         else if (key == UP_KEY)
  397.             keys &= ~UP;
  398.         else if (key == DOWN_KEY)
  399.             keys &= ~DOWN;
  400.     }
  401. }
  402.  
  403. /*
  404.  * Move the objects.
  405.  */
  406.  
  407. void
  408. do_move_objects (objs)
  409.     OBJECTS objs;
  410. {
  411.     OBJECT obj;
  412.  
  413.     /*
  414.      * Simply call the corresponding move function
  415.      *  for every object. Then use "do_object_movement"
  416.      *  to actually move the object and do collision
  417.      *  detection.
  418.      */
  419.     while (objs)
  420.     {
  421.         obj = objects_first (objs);
  422.         objs = objects_rest (objs);
  423.  
  424.         if (object_move (obj))
  425.             (*object_move (obj)) (obj);
  426.         do_object_movement (obj);
  427.     }
  428. }
  429.  
  430. /*
  431.  * User controlled movement.
  432.  */
  433.  
  434. void
  435. do_move_my_object (o)
  436.     OBJECT o;
  437. {
  438.     /*
  439.      * Simply add to the appropriate velocities.
  440.      */
  441.      
  442.     if (keys & LEFT)
  443.         set_object_dir_vel (o, object_dir_vel (o) + TURN_STEP);
  444.     if (keys & RIGHT)
  445.         set_object_dir_vel (o, object_dir_vel (o) - TURN_STEP);
  446.     if (keys & UP)
  447.         set_object_pos_vel (o, object_pos_vel (o) + MOVE_STEP);
  448.     if (keys & DOWN)
  449.         set_object_pos_vel (o, object_pos_vel (o) - MOVE_STEP);
  450. }
  451.  
  452. /*
  453.  * Move an object based on its velocities.
  454.  */
  455.  
  456. void
  457. do_object_movement (o)
  458.     OBJECT o;
  459. {
  460.     VECTOR temp_vector;
  461.     MATRIX temp_matrix;
  462.  
  463.     /*
  464.      * Make sure the object isn't moving too fast.
  465.      */
  466.     if (object_dir_vel (o) > TURN_MAX)
  467.         set_object_dir_vel (o, TURN_MAX);
  468.     if (object_dir_vel (o) < -TURN_MAX)
  469.         set_object_dir_vel (o, -TURN_MAX);
  470.     if (object_pos_vel (o) > MOVE_MAX)
  471.         set_object_pos_vel (o, MOVE_MAX);
  472.     if (object_pos_vel (o) < -MOVE_MAX)
  473.         set_object_pos_vel (o, -MOVE_MAX);
  474.  
  475.     /*
  476.      * Perform object rotation.
  477.      */
  478.     vector_copy (object_dir (o), temp_vector);
  479.     matrix_rotate_y (temp_matrix, object_dir_vel (o));
  480.     matrix_vector (temp_matrix, temp_vector, object_dir (o));
  481.  
  482.     /*
  483.      * Perform object movement.
  484.      */
  485.     vector_copy (object_pos (o), temp_vector);
  486.     vector_x (temp_vector) += my_mul (object_dir_x (o), object_pos_vel (o));
  487.     vector_y (temp_vector) += my_mul (object_dir_y (o), object_pos_vel (o));
  488.     vector_z (temp_vector) += my_mul (object_dir_z (o), object_pos_vel (o));
  489.     vector_w (temp_vector) = 1;
  490.  
  491.     /*
  492.      * Reduce the velocities to simulate drag.
  493.      */
  494.     set_object_dir_vel (o, my_div (object_dir_vel (o), object_dir_drag (o)));
  495.     set_object_pos_vel (o, my_div (object_pos_vel (o), object_pos_drag (o)));
  496.  
  497.     /*
  498.      * If the object actually moved (rotation doesn't count),
  499.      *  then perform collision detection.
  500.      */
  501.     if ((vector_x (temp_vector) != object_dir_x (o)) ||
  502.         (vector_y (temp_vector) != object_dir_y (o)) ||
  503.         (vector_z (temp_vector) != object_dir_z (o)))
  504.     {
  505.         collision (o, object_pos (o), temp_vector);
  506.         vector_copy (temp_vector, object_pos (o));
  507.     }
  508.  
  509.     /*
  510.      * Update the objects camera.
  511.      */
  512.     object_update_camera (o);
  513. }
  514.