home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / Source / GPCHAP16 / GPDUMB2.CPP < prev    next >
C/C++ Source or Header  |  2002-05-01  |  45KB  |  1,729 lines

  1. // GPDUMB2.CPP - Game Engine Part II
  2.  
  3. // INCLUDES ///////////////////////////////////////////////
  4.  
  5. #define WIN32_LEAN_AND_MEAN  
  6. //#define INITGUID
  7.  
  8. #include <windows.h>   // include important windows stuff
  9. #include <windowsx.h> 
  10. #include <mmsystem.h>
  11. #include <objbase.h>
  12. #include <iostream.h> // include important C/C++ stuff
  13. #include <conio.h>
  14. #include <stdlib.h>
  15. #include <malloc.h>
  16. #include <memory.h>
  17. #include <string.h>
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20. #include <math.h>
  21. #include <io.h>
  22. #include <fcntl.h>
  23.  
  24. #include <ddraw.h>  // directX includes
  25. #include <dsound.h>
  26. #include <dinput.h>
  27. #include "gpdumb1.h"
  28. #include "gpdumb2.h"
  29.  
  30. // DEFINES ////////////////////////////////////////////////
  31.  
  32. // TYPES //////////////////////////////////////////////////
  33.  
  34. // PROTOTYPES /////////////////////////////////////////////
  35.  
  36. // EXTERNALS /////////////////////////////////////////////
  37.  
  38. extern HWND main_window_handle;     // access to main window handle in main module
  39.  
  40. // GLOBALS ////////////////////////////////////////////////
  41.  
  42. // directsound stuff
  43. LPDIRECTSOUND        lpds;           // directsound interface pointer
  44. DSBUFFERDESC        dsbd;           // directsound description
  45. DSCAPS                dscaps;         // directsound caps
  46. HRESULT                dsresult;       // general directsound result
  47. DSBCAPS                dsbcaps;        // directsound buffer caps
  48. LPDIRECTSOUNDBUFFER    lpdsbprimary;   // the primary mixing buffer
  49. pcm_sound            sound_fx[MAX_SOUNDS];    // the array of secondary sound buffers
  50.  
  51. WAVEFORMATEX        pcmwf;          // generic waveformat structure
  52.  
  53. // directinput globals
  54. LPDIRECTINPUT8       lpdi      = NULL;    // dinput object
  55. LPDIRECTINPUTDEVICE8 lpdikey   = NULL;    // dinput keyboard
  56. LPDIRECTINPUTDEVICE8 lpdimouse = NULL;    // dinput mouse
  57. LPDIRECTINPUTDEVICE8 lpdijoy   = NULL;    // dinput joystick 
  58. GUID                 joystickGUID;        // guid for main joystick
  59. char                 joyname[80];         // name of joystick
  60.  
  61. // these contain the target records for all di input packets
  62. UCHAR keyboard_state[256]; // contains keyboard state table
  63. DIMOUSESTATE mouse_state;  // contains state of mouse
  64. DIJOYSTATE joy_state;      // contains state of joystick
  65. int joystick_found = 0;    // tracks if joystick was found and inited
  66.  
  67. // FUNCTIONS //////////////////////////////////////////////
  68.  
  69. int Load_VOC(char *filename)
  70. {
  71. // this function loads a .voc file, sets up the directsound buffer and loads the data
  72. // into memory, the function returns the id number of the sound
  73.  
  74. int    sound_id = -1,       // id of sound to be loaded
  75.     index,               // looping variable
  76.     data_offset,         // offset to data part of file
  77.     playback_rate,       // playback rate as encoded in file
  78.     data_length;         // length of data
  79.  
  80. ULONG  bytesread = 0,    // actual number of bytes read during file read
  81.        filelength;       // length of file
  82.  
  83. int    file_handle;      // general file handle
  84.  
  85. UCHAR *snd_buffer,       // temporary sound buffer to hold voc data
  86.       *audio_ptr_1=NULL, // data ptr to first write buffer 
  87.       *audio_ptr_2=NULL; // data ptr to second write buffer
  88.  
  89. DWORD audio_length_1=0,  // length of first write buffer
  90.       audio_length_2=0;  // length of second write buffer
  91.             
  92. // step one: are there any open id's ?
  93. for (index=0; index < MAX_SOUNDS; index++)
  94.     {    
  95.     // make sure this sound is unused
  96.     if (sound_fx[index].state==SOUND_NULL)
  97.        {
  98.        sound_id = index;
  99.        break;
  100.        } // end if
  101.  
  102.     } // end for index
  103.  
  104. // did we get a free id?
  105. if (sound_id==-1)
  106.     return(-1);
  107.  
  108. // step two: load the voc file off disk
  109. if ((file_handle = _open(filename,_O_BINARY | _O_RDONLY))==-1)
  110.     return(0);
  111.  
  112. // get size of file so we can allocate temporary read buffer
  113. filelength = _filelength(file_handle);
  114.  
  115. // allocate a large enough temporary buffer
  116. snd_buffer = (UCHAR *)malloc(filelength);
  117.  
  118. // now read in the data
  119. bytesread = _read(file_handle, snd_buffer, filelength);
  120.  
  121. // access all values and decode VOC encoding for data fields
  122. data_offset      = snd_buffer[20];
  123. playback_rate = (-1000000/(snd_buffer[data_offset+4]-256));
  124. data_length   = ((*(int *)(snd_buffer+data_offset)) >> 8);
  125.  
  126. // set rate and size in data structure
  127. sound_fx[sound_id].rate  = playback_rate;
  128. sound_fx[sound_id].size  = data_length;
  129. sound_fx[sound_id].state = SOUND_LOADED;
  130.  
  131. // close the file
  132. _close(file_handle);
  133.  
  134. // step three: create the sound buffer and copy voc data into buffer
  135.  
  136. // set up the format data structure
  137. memset(&pcmwf, 0, sizeof(WAVEFORMATEX));
  138.  
  139. pcmwf.wFormatTag      = WAVE_FORMAT_PCM;  // pulse code modulation
  140. pcmwf.nChannels          = 1;                // mono 
  141. pcmwf.nSamplesPerSec  = 11025;            // always this rate
  142. pcmwf.nBlockAlign      = 1;                
  143. pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign;
  144. pcmwf.wBitsPerSample  = 8;
  145. pcmwf.cbSize          = 0;
  146.  
  147. // prepare to create sounds buffer
  148. dsbd.dwSize            = sizeof(DSBUFFERDESC);
  149. dsbd.dwFlags        = DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE;
  150. dsbd.dwBufferBytes    = data_length-NVB_SIZE;
  151. dsbd.lpwfxFormat    = &pcmwf;
  152.  
  153. // create the sound buffer
  154. if (lpds->CreateSoundBuffer(&dsbd,&sound_fx[sound_id].dsbuffer,NULL)!=DS_OK)
  155.    {
  156.    // release memory
  157.    free(snd_buffer);
  158.  
  159.    // return error
  160.    return(-1);
  161.    } // end if
  162.  
  163. // copy data into sound buffer
  164. if (sound_fx[sound_id].dsbuffer->Lock(0,                     
  165.                                       data_length-NVB_SIZE,            
  166.                                       (void **) &audio_ptr_1, 
  167.                                       &audio_length_1,
  168.                                       (void **)&audio_ptr_2, 
  169.                                       &audio_length_2,
  170.                                       DSBLOCK_FROMWRITECURSOR)!=DS_OK)
  171.                                  return(0);
  172.  
  173. // copy first section of circular buffer
  174. memcpy(audio_ptr_1, snd_buffer+data_offset+NVB_SIZE, audio_length_1);
  175.  
  176. // copy last section of circular buffer
  177. memcpy(audio_ptr_2, (snd_buffer+data_offset+NVB_SIZE+audio_length_1),audio_length_2);
  178.  
  179. // unlock the buffer
  180. if (sound_fx[sound_id].dsbuffer->Unlock(audio_ptr_1, 
  181.                                         audio_length_1, 
  182.                                         audio_ptr_2, 
  183.                                         audio_length_2)!=DS_OK)
  184.                                   return(0);
  185.  
  186. // release the temp buffer
  187. free(snd_buffer);
  188.  
  189. // return id
  190. return(sound_id);
  191.  
  192. } // end Load_Voc
  193.  
  194. ///////////////////////////////////////////////////////////
  195.  
  196. int Load_WAV(char *filename, int control_flags)
  197. {
  198. // this function loads a .wav file, sets up the directsound 
  199. // buffer and loads the data into memory, the function returns 
  200. // the id number of the sound
  201.  
  202.  
  203. HMMIO             hwav;    // handle to wave file
  204. MMCKINFO        parent,  // parent chunk
  205.                 child;   // child chunk
  206. WAVEFORMATEX    wfmtx;   // wave format structure
  207.  
  208. int    sound_id = -1,       // id of sound to be loaded
  209.     index;               // looping variable
  210.  
  211. UCHAR *snd_buffer,       // temporary sound buffer to hold voc data
  212.       *audio_ptr_1=NULL, // data ptr to first write buffer 
  213.       *audio_ptr_2=NULL; // data ptr to second write buffer
  214.  
  215. DWORD audio_length_1=0,  // length of first write buffer
  216.       audio_length_2=0;  // length of second write buffer
  217.             
  218. // step one: are there any open id's ?
  219. for (index=0; index < MAX_SOUNDS; index++)
  220.     {    
  221.     // make sure this sound is unused
  222.     if (sound_fx[index].state==SOUND_NULL)
  223.        {
  224.        sound_id = index;
  225.        break;
  226.        } // end if
  227.  
  228.     } // end for index
  229.  
  230. // did we get a free id?
  231. if (sound_id==-1)
  232.     return(-1);
  233.  
  234. // set up chunk info structure
  235. parent.ckid         = (FOURCC)0;
  236. parent.cksize         = 0;
  237. parent.fccType        = (FOURCC)0;
  238. parent.dwDataOffset = 0;
  239. parent.dwFlags        = 0;
  240.  
  241. // copy data
  242. child = parent;
  243.  
  244. // open the WAV file
  245. if ((hwav = mmioOpen(filename, NULL, MMIO_READ | MMIO_ALLOCBUF))==NULL)
  246.     return(-1);
  247.  
  248. // descend into the RIFF 
  249. parent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  250.  
  251. if (mmioDescend(hwav, &parent, NULL, MMIO_FINDRIFF))
  252.     {
  253.     // close the file
  254.     mmioClose(hwav, 0);
  255.  
  256.     // return error, no wave section
  257.     return(-1);     
  258.     } // end if
  259.  
  260. // descend to the WAVEfmt 
  261. child.ckid = mmioFOURCC('f', 'm', 't', ' ');
  262.  
  263. if (mmioDescend(hwav, &child, &parent, 0))
  264.     {
  265.     // close the file
  266.     mmioClose(hwav, 0);
  267.  
  268.     // return error, no format section
  269.     return(-1);     
  270.     } // end if
  271.  
  272. // now read the wave format information from file
  273. if (mmioRead(hwav, (char *)&wfmtx, sizeof(wfmtx)) != sizeof(wfmtx))
  274.     {
  275.     // close file
  276.     mmioClose(hwav, 0);
  277.  
  278.     // return error, no wave format data
  279.     return(-1);
  280.     } // end if
  281.  
  282. // make sure that the data format is PCM
  283. if (wfmtx.wFormatTag != WAVE_FORMAT_PCM)
  284.     {
  285.     // close the file
  286.     mmioClose(hwav, 0);
  287.  
  288.     // return error, not the right data format
  289.     return(-1); 
  290.     } // end if
  291.  
  292. // now ascend up one level, so we can access data chunk
  293. if (mmioAscend(hwav, &child, 0))
  294.    {
  295.    // close file
  296.    mmioClose(hwav, 0);
  297.  
  298.    // return error, couldn't ascend
  299.    return(-1);     
  300.    } // end if
  301.  
  302. // descend to the data chunk 
  303. child.ckid = mmioFOURCC('d', 'a', 't', 'a');
  304.  
  305. if (mmioDescend(hwav, &child, &parent, MMIO_FINDCHUNK))
  306.     {
  307.     // close file
  308.     mmioClose(hwav, 0);
  309.  
  310.     // return error, no data
  311.     return(-1);     
  312.     } // end if
  313.  
  314. // finally!!!! now all we have to do is read the data in and
  315. // set up the directsound buffer
  316.  
  317. // allocate the memory to load sound data
  318. snd_buffer = (UCHAR *)malloc(child.cksize);
  319.  
  320. // read the wave data 
  321. mmioRead(hwav, (char *)snd_buffer, child.cksize);
  322.  
  323. // close the file
  324. mmioClose(hwav, 0);
  325.  
  326. // set rate and size in data structure
  327. sound_fx[sound_id].rate  = wfmtx.nSamplesPerSec;
  328. sound_fx[sound_id].size  = child.cksize;
  329. sound_fx[sound_id].state = SOUND_LOADED;
  330.  
  331. // set up the format data structure
  332. memset(&pcmwf, 0, sizeof(WAVEFORMATEX));
  333.  
  334. pcmwf.wFormatTag      = WAVE_FORMAT_PCM;  // pulse code modulation
  335. pcmwf.nChannels          = 1;                // mono 
  336. pcmwf.nSamplesPerSec  = 11025;            // always this rate
  337. pcmwf.nBlockAlign      = 1;                
  338. pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign;
  339. pcmwf.wBitsPerSample  = 8;
  340. pcmwf.cbSize          = 0;
  341.  
  342. // prepare to create sounds buffer
  343. dsbd.dwSize            = sizeof(DSBUFFERDESC);
  344. dsbd.dwFlags        = control_flags | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE;
  345. dsbd.dwBufferBytes    = child.cksize;
  346. dsbd.lpwfxFormat    = &pcmwf;
  347.  
  348. // create the sound buffer
  349. if (lpds->CreateSoundBuffer(&dsbd,&sound_fx[sound_id].dsbuffer,NULL)!=DS_OK)
  350.    {
  351.    // release memory
  352.    free(snd_buffer);
  353.  
  354.    // return error
  355.    return(-1);
  356.    } // end if
  357.  
  358. // copy data into sound buffer
  359. if (sound_fx[sound_id].dsbuffer->Lock(0,                     
  360.                                       child.cksize,            
  361.                                       (void **) &audio_ptr_1, 
  362.                                       &audio_length_1,
  363.                                       (void **)&audio_ptr_2, 
  364.                                       &audio_length_2,
  365.                                       DSBLOCK_FROMWRITECURSOR)!=DS_OK)
  366.                                  return(0);
  367.  
  368. // copy first section of circular buffer
  369. memcpy(audio_ptr_1, snd_buffer, audio_length_1);
  370.  
  371. // copy last section of circular buffer
  372. memcpy(audio_ptr_2, (snd_buffer+audio_length_1),audio_length_2);
  373.  
  374. // unlock the buffer
  375. if (sound_fx[sound_id].dsbuffer->Unlock(audio_ptr_1, 
  376.                                         audio_length_1, 
  377.                                         audio_ptr_2, 
  378.                                         audio_length_2)!=DS_OK)
  379.                                   return(0);
  380.  
  381. // release the temp buffer
  382. free(snd_buffer);
  383.  
  384. // return id
  385. return(sound_id);
  386.  
  387. } // end Load_WAV
  388.  
  389. ///////////////////////////////////////////////////////////
  390.  
  391. int Replicate_Sound(int source_id)
  392. {
  393. // this function replicates the sent sound and sends back the
  394. // id of the replicated sound, you would use this function
  395. // to make multiple copies of a gunshot or something that
  396. // you want to play multiple times simulataneously, but you
  397. // only want to load once
  398.  
  399. if (source_id!=-1)
  400.     {
  401.     // duplicate the sound buffer
  402.     // first hunt for an open id
  403.  
  404.     for (int id=0; id < MAX_SOUNDS; id++)
  405.         {
  406.         // is this sound open?
  407.         if (sound_fx[id].state==SOUND_NULL)
  408.             {
  409.             // first make an identical copy
  410.             sound_fx[id] = sound_fx[source_id];
  411.  
  412.             // now actually replicate the directsound buffer
  413.             if (lpds->DuplicateSoundBuffer(sound_fx[source_id].dsbuffer,
  414.                                            &sound_fx[id].dsbuffer)!=DS_OK)
  415.                 {
  416.                 // reset sound to NULL
  417.                 sound_fx[id].dsbuffer = NULL;
  418.                 sound_fx[id].state    = SOUND_NULL;
  419.  
  420.                 // return error
  421.                 return(-1);
  422.                 } // end if
  423.  
  424.             // now fix up id
  425.             sound_fx[id].id = id;
  426.             
  427.             // return replicated sound
  428.             return(id);
  429.  
  430.             } // end if found
  431.   
  432.         } // end for id
  433.  
  434.     } // end if
  435. else
  436.    return(-1);
  437.     
  438. // else failure
  439. return(-1);
  440.  
  441. } // end 
  442.  
  443. ///////////////////////////////////////////////////////////
  444.  
  445. int DSound_Init(void)
  446. {
  447. // this function initializes the sound system
  448. static int first_time = 1; // used to track the first time the function
  449.                            // is entered
  450.  
  451. // test for very first time
  452. if (first_time)
  453.     {        
  454.     // clear everything out
  455.     memset(sound_fx,0,sizeof(pcm_sound)*MAX_SOUNDS);
  456.     
  457.     // reset first time
  458.     first_time = 0;
  459.  
  460.     // create a directsound object
  461.     if (DirectSoundCreate(NULL, &lpds, NULL)!=DS_OK )
  462.         return(0);
  463.  
  464.     // set cooperation level
  465.     if (lpds->SetCooperativeLevel((HWND)main_window_handle,DSSCL_NORMAL)!=DS_OK)
  466.         return(0);
  467.  
  468.     } // end if
  469.  
  470. // initialize the sound fx array
  471. for (int index=0; index<MAX_SOUNDS; index++)
  472.     {
  473.     // test if this sound has been loaded
  474.     if (sound_fx[index].dsbuffer)
  475.         {
  476.         // stop the sound
  477.         sound_fx[index].dsbuffer->Stop();
  478.  
  479.         // release the buffer
  480.         sound_fx[index].dsbuffer->Release();
  481.     
  482.         } // end if
  483.  
  484.     // clear the record out
  485.     memset(&sound_fx[index],0,sizeof(pcm_sound));
  486.  
  487.     // now set up the fields
  488.     sound_fx[index].state = SOUND_NULL;
  489.     sound_fx[index].id    = index;
  490.  
  491.     } // end for index
  492.  
  493. // return sucess
  494. return(1);
  495.  
  496. } // end DSound_Init
  497.  
  498. ///////////////////////////////////////////////////////////
  499.  
  500. int DSound_Shutdown(void)
  501. {
  502. // this function releases all the memory allocated and the directsound object
  503. // itself
  504.  
  505. // first turn all sounds off
  506. Stop_All_Sounds();
  507.  
  508. // now release all sound buffers
  509. for (int index=0; index<MAX_SOUNDS; index++)
  510.     if (sound_fx[index].dsbuffer)
  511.         sound_fx[index].dsbuffer->Release();
  512.  
  513. // now release the directsound interface itself
  514. lpds->Release();
  515.  
  516. // return success
  517. return(1);
  518.  
  519. } // end DSound_Shutdown
  520.  
  521. ///////////////////////////////////////////////////////////
  522.  
  523. int Play_Sound(int id, int flags, int volume, int rate, int pan)
  524. {
  525. // this function plays a sound, the only parameter that 
  526. // works is the flags which can be 0 to play once or
  527. // DSBPLAY_LOOPING
  528.  
  529. if (sound_fx[id].dsbuffer)
  530.     {
  531.     // reset position to start
  532.     if (sound_fx[id].dsbuffer->SetCurrentPosition(0)!=DS_OK)
  533.         return(0);
  534.     
  535.     // play sound
  536.     if (sound_fx[id].dsbuffer->Play(0,0,flags)!=DS_OK)
  537.         return(0);
  538.     } // end if
  539.  
  540. // return success
  541. return(1);
  542.  
  543. } // end Play_Sound
  544.  
  545. ///////////////////////////////////////////////////////////
  546.  
  547. int Set_Sound_Volume(int id,int vol)
  548. {
  549. // this function sets the volume on a sound 0-100
  550.  
  551. if (sound_fx[id].dsbuffer->SetVolume(DSVOLUME_TO_DB(vol))!=DS_OK)
  552.     return(0);
  553.  
  554. // return success
  555. return(1);
  556.  
  557. } // end Set_Sound_Volume
  558.  
  559. ///////////////////////////////////////////////////////////
  560.  
  561. int Set_Sound_Freq(int id,int freq)
  562. {
  563. // this function sets the playback rate
  564.  
  565. if (sound_fx[id].dsbuffer->SetFrequency(freq)!=DS_OK)
  566.     return(0);
  567.  
  568. // return success
  569. return(1);
  570.  
  571. } // end Set_Sound_Freq
  572.  
  573. ///////////////////////////////////////////////////////////
  574.  
  575. int Set_Sound_Pan(int id,int pan)
  576. {
  577. // this function sets the pan, -10,000 to 10,0000
  578.  
  579. if (sound_fx[id].dsbuffer->SetPan(pan)!=DS_OK)
  580.     return(0);
  581.  
  582. // return success
  583. return(1);
  584.  
  585. } // end Set_Sound_Pan
  586.  
  587. ////////////////////////////////////////////////////////////
  588.  
  589. int Stop_Sound(int id)
  590. {
  591. // this function stops a sound from playing
  592. if (sound_fx[id].dsbuffer)
  593.    {
  594.    sound_fx[id].dsbuffer->Stop();
  595.    sound_fx[id].dsbuffer->SetCurrentPosition(0);
  596.    } // end if
  597.  
  598. // return success
  599. return(1);
  600.  
  601. } // end Stop_Sound
  602.  
  603. ///////////////////////////////////////////////////////////
  604.  
  605. int Delete_All_Sounds(void)
  606. {
  607. // this function deletes all the sounds
  608.  
  609. for (int index=0; index < MAX_SOUNDS; index++)
  610.     Delete_Sound(index);
  611.  
  612. // return success always
  613. return(1);
  614.  
  615. } // end Delete_All_Sounds
  616.  
  617. ///////////////////////////////////////////////////////////
  618.  
  619. int Delete_Sound(int id)
  620. {
  621. // this function deletes a single sound and puts it back onto the available list
  622.  
  623. // first stop it
  624. if (!Stop_Sound(id))
  625.    return(0);
  626.  
  627. // now delete it
  628. if (sound_fx[id].dsbuffer)
  629.    {
  630.    // release the com object
  631.    sound_fx[id].dsbuffer->Release();
  632.    sound_fx[id].dsbuffer = NULL;
  633.    
  634.    // return success
  635.    return(1);
  636.    } // end if
  637.  
  638. // return success
  639. return(1);
  640.  
  641. } // end Delete_Sound
  642.  
  643. ///////////////////////////////////////////////////////////
  644.  
  645. int Stop_All_Sounds(void)
  646. {
  647. // this function stops all sounds
  648.  
  649. for (int index=0; index<MAX_SOUNDS; index++)
  650.     Stop_Sound(index);    
  651.  
  652. // return success
  653. return(1);
  654.  
  655. } // end Stop_All_Sounds
  656.  
  657. ///////////////////////////////////////////////////////////
  658.  
  659. int Status_Sound(int id)
  660. {
  661. // this function returns the status of a sound
  662. if (sound_fx[id].dsbuffer)
  663.     {
  664.     ULONG status; 
  665.  
  666.     // get the status
  667.     sound_fx[id].dsbuffer->GetStatus(&status);
  668.  
  669.     // return the status
  670.     return(status);
  671.  
  672.     } // end if
  673. else // total failure
  674.     return(-1);
  675.  
  676. } // end Status_Sound
  677.  
  678. ///////////////////////////////////////////////////////////
  679.  
  680. void HLine(int x1,int x2,int y,int color, UCHAR *vbuffer, int lpitch)
  681. {
  682. // draw a horizontal line using the memset function
  683.  
  684. int temp; // used for temporary storage during endpoint swap
  685.  
  686. // perform trivial rejections
  687. if (y > max_clip_y || y < min_clip_y)
  688.    return;
  689.  
  690. // sort x1 and x2, so that x2 > x1
  691. if (x1>x2)
  692.    {
  693.    temp = x1;
  694.    x1   = x2;
  695.    x2   = temp;
  696.    } // end swap
  697.  
  698. // perform trivial rejections
  699. if (x1 > max_clip_x || x2 < min_clip_x)
  700.    return;
  701.  
  702. // now clip
  703. x1 = ((x1 < min_clip_x) ? min_clip_x : x1);
  704. x2 = ((x2 > max_clip_x) ? max_clip_x : x2);
  705.  
  706. // draw the row of pixels
  707. memset((UCHAR *)(vbuffer+(y*lpitch)+x1),
  708.        (UCHAR)color,x2-x1+1);
  709.  
  710. } // end HLine
  711.  
  712. //////////////////////////////////////////////////////////////////////////////
  713.  
  714. void VLine(int y1,int y2,int x,int color,UCHAR *vbuffer, int lpitch)
  715. {
  716. // draw a vertical line, note that a memset function can no longer be
  717. // used since the pixel addresses are no longer contiguous in memory
  718. // note that the end points of the line must be on the screen
  719.  
  720. UCHAR *start_offset; // starting memory offset of line
  721.  
  722. int index, // loop index
  723.     temp;  // used for temporary storage during swap
  724.  
  725.  
  726. // perform trivial rejections
  727. if (x > max_clip_x || x < min_clip_x)
  728.    return;
  729.  
  730. // make sure y2 > y1
  731. if (y1>y2)
  732.    {
  733.    temp = y1;
  734.    y1   = y2;
  735.    y2   = temp;
  736.    } // end swap
  737.  
  738. // perform trivial rejections
  739. if (y1 > max_clip_y || y2 < min_clip_y)
  740.    return;
  741.  
  742. // now clip
  743. y1 = ((y1 < min_clip_y) ? min_clip_y : y1);
  744. y2 = ((y2 > max_clip_y) ? max_clip_y : y2);
  745.  
  746. // compute starting position
  747. start_offset = vbuffer + (y1*lpitch) + x;
  748.  
  749. // draw line one pixel at a time
  750. for (index=0; index<=y2-y1; index++)
  751.     {
  752.     // set the pixel
  753.     *start_offset = (UCHAR)color;
  754.  
  755.     // move downward to next line
  756.     start_offset+=lpitch;
  757.  
  758.     } // end for index
  759.  
  760. } // end VLine
  761.  
  762. ///////////////////////////////////////////////////////////
  763.  
  764. inline void Mem_Set_WORD(void *dest, USHORT data, int count)
  765. {
  766. // this function fills or sets unsigned 16-bit aligned memory
  767. // count is number of words
  768.  
  769. _asm 
  770.     { 
  771.     mov edi, dest   ; edi points to destination memory
  772.     mov ecx, count  ; number of 16-bit words to move
  773.     mov ax,  data   ; 16-bit data
  774.     rep stosw       ; move data
  775.     } // end asm
  776.  
  777. } // end Mem_Set_WORD
  778.  
  779. /////////////////////////////////////////////////////////////
  780.  
  781. void HLine16(int x1,int x2,int y,int color, UCHAR *vbuffer, int lpitch)
  782. {
  783. // draw a horizontal line using the memset function
  784.  
  785. int temp; // used for temporary storage during endpoint swap
  786.  
  787. USHORT *vbuffer2 = (USHORT *)vbuffer; // short pointer to buffer
  788.  
  789. // convert pitch to words
  790. lpitch = lpitch >> 1;
  791.  
  792. // perform trivial rejections
  793. if (y > max_clip_y || y < min_clip_y)
  794.    return;
  795.  
  796. // sort x1 and x2, so that x2 > x1
  797. if (x1>x2)
  798.    {
  799.    temp = x1;
  800.    x1   = x2;
  801.    x2   = temp;
  802.    } // end swap
  803.  
  804. // perform trivial rejections
  805. if (x1 > max_clip_x || x2 < min_clip_x)
  806.    return;
  807.  
  808. // now clip
  809. x1 = ((x1 < min_clip_x) ? min_clip_x : x1);
  810. x2 = ((x2 > max_clip_x) ? max_clip_x : x2);
  811.  
  812. // draw the row of pixels
  813. Mem_Set_WORD((vbuffer2+(y*lpitch)+x1), color,x2-x1+1);
  814.  
  815. } // end HLine16
  816.  
  817. //////////////////////////////////////////////////////////////////////////////
  818.  
  819. void VLine16(int y1,int y2,int x,int color,UCHAR *vbuffer, int lpitch)
  820. {
  821. // draw a vertical line, note that a memset function can no longer be
  822. // used since the pixel addresses are no longer contiguous in memory
  823. // note that the end points of the line must be on the screen
  824.  
  825. USHORT *start_offset; // starting memory offset of line
  826.  
  827. int index, // loop index
  828.     temp;  // used for temporary storage during swap
  829.  
  830. // convert lpitch to number of words
  831. lpitch = lpitch >> 1;
  832.  
  833. // perform trivial rejections
  834. if (x > max_clip_x || x < min_clip_x)
  835.    return;
  836.  
  837. // make sure y2 > y1
  838. if (y1>y2)
  839.    {
  840.    temp = y1;
  841.    y1   = y2;
  842.    y2   = temp;
  843.    } // end swap
  844.  
  845. // perform trivial rejections
  846. if (y1 > max_clip_y || y2 < min_clip_y)
  847.    return;
  848.  
  849. // now clip
  850. y1 = ((y1 < min_clip_y) ? min_clip_y : y1);
  851. y2 = ((y2 > max_clip_y) ? max_clip_y : y2);
  852.  
  853. // compute starting position
  854. start_offset = (USHORT *)vbuffer + (y1*lpitch) + x;
  855.  
  856. // draw line one pixel at a time
  857. for (index=0; index<=y2-y1; index++)
  858.     {
  859.     // set the pixel
  860.     *start_offset = color;
  861.  
  862.     // move downward to next line
  863.     start_offset+=lpitch;
  864.  
  865.     } // end for index
  866.  
  867. } // end VLine16
  868.  
  869. ///////////////////////////////////////////////////////////
  870.  
  871. void Screen_Transitions(int effect, UCHAR *vbuffer, int lpitch)
  872. {
  873. // this function can be called to perform a myraid of screen transitions
  874. // to the destination buffer, make sure to save and restore the palette
  875. // when performing color transitions
  876.  
  877. int pal_reg;         // used as loop counter
  878. int index;           // used as loop counter
  879. int red,green,blue;           // used in fad algorithm
  880.  
  881. PALETTEENTRY color;              // temporary color
  882. PALETTEENTRY work_palette[256];  // used as a working palette
  883. PALETTEENTRY work_color;         // used in color algorithms
  884.  
  885. // test which screen effect is being selected
  886. switch(effect)
  887.       {
  888.       case SCREEN_DARKNESS:
  889.            {
  890.            // fade to black
  891.  
  892.            for (index=0; index<80; index++)
  893.                {
  894.                // get the palette 
  895.                Save_Palette(work_palette);
  896.  
  897.                // process each color
  898.                for (pal_reg=1; pal_reg<256; pal_reg++)
  899.                    {
  900.                    // get the entry data
  901.                    color = work_palette[pal_reg];
  902.  
  903.                    // test if this color register is already black
  904.                    if (color.peRed > 4) color.peRed-=3;
  905.                    else
  906.                       color.peRed = 0;
  907.  
  908.                    if (color.peGreen > 4) color.peGreen-=3;
  909.                    else
  910.                       color.peGreen = 0;
  911.  
  912.                    if (color.peBlue  > 4) color.peBlue-=3;
  913.                    else
  914.                       color.peBlue = 0;
  915.  
  916.                    // set the color to a diminished intensity
  917.                    work_palette[pal_reg] = color;
  918.  
  919.                    } // end for pal_reg
  920.  
  921.                // write the palette back out
  922.                Set_Palette(work_palette);
  923.  
  924.                // wait a bit
  925.                //DD_Wait_For_Vsync();
  926.                Start_Clock(); Wait_Clock(12);
  927.                
  928.                } // end for index
  929.  
  930.            } break;
  931.  
  932.       case SCREEN_WHITENESS:
  933.            {
  934.            // fade to white
  935.            for (index=0; index<64; index++)
  936.                {
  937.                // get the palette 
  938.                Save_Palette(work_palette);
  939.  
  940.                // loop thru all palette registers
  941.                for (pal_reg=0; pal_reg < 256; pal_reg++)
  942.                    {
  943.                    // get the entry data
  944.                    color = work_palette[pal_reg];
  945.  
  946.                    // make 32 bit copy of color
  947.                    red   = color.peRed;
  948.                    green = color.peGreen;
  949.                    blue  = color.peBlue; 
  950.  
  951.                    if ((red+=4) >=255)
  952.                       red=255;
  953.  
  954.                    if ((green+=4) >=255)
  955.                       green=255;
  956.  
  957.                    if ((blue+=4) >=255)
  958.                       blue=255;
  959.                           
  960.                    // store colors back
  961.                    color.peRed   = red;
  962.                    color.peGreen = green;
  963.                    color.peBlue  = blue;
  964.  
  965.                    // set the color to a diminished intensity
  966.                    work_palette[pal_reg] = color;
  967.                    
  968.                    } // end for pal_reg
  969.  
  970.                // write the palette back out
  971.                Set_Palette(work_palette);
  972.  
  973.                // wait a bit
  974.                //DD_Wait_For_Vsync();
  975.                Start_Clock(); Wait_Clock(12);
  976.  
  977.                } // end for index
  978.  
  979.            } break;
  980.  
  981.       case SCREEN_REDNESS:
  982.            {
  983.            // fade to red
  984.  
  985.            for (index=0; index<64; index++)
  986.                {
  987.                // get the palette 
  988.                Save_Palette(work_palette);
  989.                
  990.                // loop thru all palette registers
  991.                for (pal_reg=0; pal_reg < 256; pal_reg++)
  992.                    {
  993.                    // get the entry data
  994.                    color = work_palette[pal_reg];
  995.  
  996.                    // make 32 bit copy of color
  997.                    red   = color.peRed;
  998.                    green = color.peGreen;
  999.                    blue  = color.peBlue; 
  1000.  
  1001.                    if ((red+=6) >=255)
  1002.                       red=255; 
  1003.  
  1004.                    if ((green-=4) < 0)
  1005.                       green=0;
  1006.  
  1007.                    if ((blue-=4) < 0)
  1008.                       blue=0;
  1009.                           
  1010.                    // store colors back
  1011.                    color.peRed   = red;
  1012.                    color.peGreen = green;
  1013.                    color.peBlue  = blue;
  1014.                   
  1015.                    // set the color to a diminished intensity
  1016.                    work_palette[pal_reg] = color;
  1017.  
  1018.                    } // end for pal_reg
  1019.  
  1020.                // write the palette back out
  1021.                Set_Palette(work_palette);
  1022.  
  1023.                // wait a bit
  1024.                //DD_Wait_For_Vsync();
  1025.                Start_Clock(); Wait_Clock(12);
  1026.  
  1027.                } // end for index
  1028.  
  1029.            } break;
  1030.  
  1031.       case SCREEN_BLUENESS:
  1032.            {
  1033.            // fade to blue
  1034.  
  1035.            for (index=0; index<64; index++)
  1036.                {
  1037.                // get the palette 
  1038.                Save_Palette(work_palette);
  1039.                
  1040.                // loop thru all palette registers
  1041.                for (pal_reg=0; pal_reg < 256; pal_reg++)
  1042.                    {
  1043.                    // get the entry data
  1044.                    color = work_palette[pal_reg];
  1045.  
  1046.                    // make 32 bit copy of color
  1047.                    red   = color.peRed;
  1048.                    green = color.peGreen;
  1049.                    blue  = color.peBlue; 
  1050.  
  1051.                    if ((red-=4) < 0)
  1052.                       red=0;
  1053.  
  1054.                    if ((green-=4) < 0)
  1055.                       green=0;
  1056.  
  1057.                    if ((blue+=6) >=255)
  1058.                       blue=255;
  1059.                           
  1060.                    // store colors back
  1061.                    color.peRed   = red;
  1062.                    color.peGreen = green;
  1063.                    color.peBlue  = blue;
  1064.                   
  1065.                    // set the color to a diminished intensity
  1066.                    work_palette[pal_reg] = color;
  1067.  
  1068.                    } // end for pal_reg
  1069.  
  1070.                // write the palette back out
  1071.                Set_Palette(work_palette);
  1072.  
  1073.                // wait a bit
  1074.                //DD_Wait_For_Vsync();
  1075.                Start_Clock(); Wait_Clock(12);
  1076.  
  1077.                } // end for index
  1078.  
  1079.            } break;
  1080.  
  1081.       case SCREEN_GREENNESS:
  1082.            {
  1083.            // fade to green
  1084.            for (index=0; index<64; index++)
  1085.                {
  1086.                // get the palette 
  1087.                Save_Palette(work_palette);
  1088.  
  1089.                // loop thru all palette registers
  1090.                for (pal_reg=0; pal_reg < 256; pal_reg++)
  1091.                    {
  1092.                    // get the entry data
  1093.                    color = work_palette[pal_reg];                  
  1094.  
  1095.                    // make 32 bit copy of color
  1096.                    red   = color.peRed;
  1097.                    green = color.peGreen;
  1098.                    blue  = color.peBlue; 
  1099.  
  1100.                    if ((red-=4) < 0)
  1101.                       red=0;
  1102.  
  1103.                    if ((green+=6) >=255)
  1104.                       green=255;
  1105.  
  1106.                    if ((blue-=4) < 0)
  1107.                       blue=0;
  1108.                           
  1109.                    // store colors back
  1110.                    color.peRed   = red;
  1111.                    color.peGreen = green;
  1112.                    color.peBlue  = blue;
  1113.  
  1114.                    // set the color to a diminished intensity
  1115.                    work_palette[pal_reg] = color; 
  1116.  
  1117.                    } // end for pal_reg
  1118.  
  1119.                // write the palette back out
  1120.                Set_Palette(work_palette);
  1121.  
  1122.                // wait a bit
  1123.                //DD_Wait_For_Vsync();
  1124.                Start_Clock(); Wait_Clock(12);
  1125.  
  1126.  
  1127.                } // end for index
  1128.  
  1129.            } break;
  1130.  
  1131.       case SCREEN_SWIPE_X:
  1132.            {
  1133.            // do a screen wipe from right to left, left to right
  1134.            for (index=0; index < (screen_width/2); index+=2)
  1135.                {
  1136.                // use this as a 1/70th of second time delay
  1137.                //DD_Wait_For_Vsync();
  1138.                Start_Clock(); Wait_Clock(12);
  1139.  
  1140.                // draw two vertical lines at opposite ends of the screen
  1141.                VLine(0,(screen_height-1),(screen_width-1)-index,0,vbuffer,lpitch);
  1142.                VLine(0,(screen_height-1),index,0,vbuffer,lpitch);
  1143.                VLine(0,(screen_height-1),(screen_width-1)-(index+1),0,vbuffer,lpitch);
  1144.                VLine(0,(screen_height-1),index+1,0,vbuffer,lpitch);
  1145.  
  1146.                } // end for index
  1147.  
  1148.            } break;
  1149.  
  1150.       case SCREEN_SWIPE_Y:
  1151.            {
  1152.            // do a screen wipe from top to bottom, bottom to top
  1153.            for (index=0; index < (screen_height/2); index+=2)
  1154.                {
  1155.                // use this as a 1/70th of second time delay
  1156.                //DD_Wait_For_Vsync();
  1157.                Start_Clock(); Wait_Clock(12);
  1158.  
  1159.                // draw two horizontal lines at opposite ends of the screen
  1160.                HLine(0,(screen_width-1),(screen_height-1)-index,0,vbuffer,lpitch);
  1161.                HLine(0,(screen_width-1),index,0,vbuffer,lpitch);
  1162.                HLine(0,(screen_width-1),(screen_height-1)-(index+1),0,vbuffer,lpitch);
  1163.                HLine(0,(screen_width-1),index+1,0,vbuffer,lpitch);
  1164.  
  1165.                } // end for index
  1166.  
  1167.  
  1168.             } break;
  1169.  
  1170.       case SCREEN_SCRUNCH:
  1171.            {
  1172.            // do a screen wipe from top to bottom, bottom to top
  1173.            for (index=0; index < (screen_width/2); index+=2)
  1174.                {
  1175.                // use this as a 1/70th of second time delay
  1176.                //DD_Wait_For_Vsync();
  1177.                Start_Clock(); Wait_Clock(12);
  1178.  
  1179.                // draw two horizontal lines at opposite ends of the screen
  1180.                HLine(0,(screen_width-1),(screen_height-1)-index%(screen_height/2),0,vbuffer,lpitch);
  1181.                HLine(0,(screen_width-1),index%(screen_height/2),0,vbuffer,lpitch);
  1182.                HLine(0,(screen_width-1),(screen_height-1)-(index%(screen_height/2)+1),0,vbuffer,lpitch);
  1183.                HLine(0,(screen_width-1),index%(screen_height/2)+1,0,vbuffer,lpitch);
  1184.  
  1185.                // draw two vertical lines at opposite ends of the screen
  1186.                VLine(0,(screen_height-1),(screen_width-1)-index,0,vbuffer,lpitch);
  1187.                VLine(0,(screen_height-1),index,0,vbuffer,lpitch);
  1188.                VLine(0,(screen_height-1),(screen_width-1)-(index+1),0,vbuffer,lpitch);
  1189.                VLine(0,(screen_height-1),index+1,0,vbuffer,lpitch);
  1190.  
  1191.                } // end for index
  1192.  
  1193.            } break;
  1194.  
  1195.  
  1196.       case SCREEN_DISOLVE:
  1197.            {
  1198.            // disolve the screen by plotting zillions of little black dots
  1199.  
  1200.            for (index=0; index<=screen_width*screen_height*4; index++)
  1201.                Draw_Pixel(rand()%screen_width,rand()%screen_height,0,vbuffer,lpitch);
  1202.        
  1203.            } break;
  1204.  
  1205.        default:break;
  1206.  
  1207.       } // end switch
  1208.  
  1209. } // end Screen_Transitions
  1210.  
  1211. //////////////////////////////////////////////////////////////////////////////
  1212.  
  1213. BOOL CALLBACK DI_Enum_Joysticks(LPCDIDEVICEINSTANCE lpddi,
  1214.                                 LPVOID guid_ptr) 
  1215. {
  1216. // this function enumerates the joysticks, but
  1217. // stops at the first one and returns the
  1218. // instance guid of it, so we can create it
  1219.  
  1220. *(GUID*)guid_ptr = lpddi->guidInstance; 
  1221.  
  1222. // copy name into global
  1223. strcpy(joyname, (char *)lpddi->tszProductName);
  1224.  
  1225. // stop enumeration after one iteration
  1226. return(DIENUM_STOP);
  1227.  
  1228. } // end DI_Enum_Joysticks
  1229.  
  1230. //////////////////////////////////////////////////////////////////////////////
  1231.  
  1232. int DInput_Init(void)
  1233. {
  1234. // this function initializes directinput
  1235.  
  1236. if (DirectInput8Create(main_instance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&lpdi,NULL)!=DI_OK)
  1237.    return(0);
  1238.  
  1239. // return success
  1240. return(1);
  1241.  
  1242. } // end DInput_Init
  1243.  
  1244. ///////////////////////////////////////////////////////////
  1245.  
  1246. void DInput_Shutdown(void)
  1247. {
  1248. // this function shuts down directinput
  1249.  
  1250. if (lpdi)
  1251.    lpdi->Release();
  1252.  
  1253. } // end DInput_Shutdown
  1254.  
  1255. ///////////////////////////////////////////////////////////
  1256.  
  1257. int DI_Init_Joystick(int min_x, int max_x, int min_y, int max_y)
  1258. {
  1259. // this function initializes the joystick, it allows you to set
  1260. // the minimum and maximum x-y ranges 
  1261.  
  1262. // first find the fucking GUID of your particular joystick
  1263. lpdi->EnumDevices(DI8DEVCLASS_GAMECTRL, 
  1264.                   DI_Enum_Joysticks, 
  1265.                   &joystickGUID, 
  1266.                   DIEDFL_ATTACHEDONLY); 
  1267.  
  1268. if (lpdi->CreateDevice(joystickGUID, &lpdijoy, NULL)!=DI_OK)
  1269.    return(0);
  1270.  
  1271. // set cooperation level
  1272. if (lpdijoy->SetCooperativeLevel(main_window_handle, 
  1273.                      DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)!=DI_OK)
  1274.    return(0);
  1275.  
  1276. // set data format
  1277. if (lpdijoy->SetDataFormat(&c_dfDIJoystick)!=DI_OK)
  1278.    return(0);
  1279.  
  1280. // set the range of the joystick
  1281. DIPROPRANGE joy_axis_range;
  1282.  
  1283. // first x axis
  1284. joy_axis_range.lMin = min_x;
  1285. joy_axis_range.lMax = max_x;
  1286.  
  1287. joy_axis_range.diph.dwSize       = sizeof(DIPROPRANGE); 
  1288. joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
  1289. joy_axis_range.diph.dwObj        = DIJOFS_X;
  1290. joy_axis_range.diph.dwHow        = DIPH_BYOFFSET;
  1291.  
  1292. lpdijoy->SetProperty(DIPROP_RANGE,&joy_axis_range.diph);
  1293.  
  1294. // now y-axis
  1295. joy_axis_range.lMin = min_y;
  1296. joy_axis_range.lMax = max_y;
  1297.  
  1298. joy_axis_range.diph.dwSize       = sizeof(DIPROPRANGE); 
  1299. joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
  1300. joy_axis_range.diph.dwObj        = DIJOFS_Y;
  1301. joy_axis_range.diph.dwHow        = DIPH_BYOFFSET;
  1302.  
  1303. lpdijoy->SetProperty(DIPROP_RANGE,&joy_axis_range.diph);
  1304.  
  1305. // acquire the joystick
  1306. if (lpdijoy->Acquire()!=DI_OK)
  1307.    return(0);
  1308.  
  1309. // set found flag
  1310. joystick_found = 1;
  1311.  
  1312. // return success
  1313. return(1);
  1314.  
  1315. } // end DI_Init_Joystick
  1316.  
  1317. ///////////////////////////////////////////////////////////
  1318.  
  1319. int DI_Init_Mouse(void)
  1320. {
  1321. // this function intializes the mouse
  1322.  
  1323. // create a mouse device 
  1324. if (lpdi->CreateDevice(GUID_SysMouse, &lpdimouse, NULL)!=DI_OK)
  1325.    return(0);
  1326.  
  1327. // set cooperation level
  1328. if (lpdimouse->SetCooperativeLevel(main_window_handle, 
  1329.                        DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)!=DI_OK)
  1330.    return(0);
  1331.  
  1332. // set data format
  1333. if (lpdimouse->SetDataFormat(&c_dfDIMouse)!=DI_OK)
  1334.    return(0);
  1335.  
  1336. // acquire the mouse
  1337. if (lpdimouse->Acquire()!=DI_OK)
  1338.    return(0);
  1339.  
  1340. // return success
  1341. return(1);
  1342.  
  1343. } // end DI_Init_Mouse
  1344.  
  1345. ///////////////////////////////////////////////////////////
  1346.  
  1347. int DI_Init_Keyboard(void)
  1348. {
  1349. // this function initializes the keyboard device
  1350.  
  1351. // create the keyboard device  
  1352. if (lpdi->CreateDevice(GUID_SysKeyboard, &lpdikey, NULL)!=DI_OK)
  1353.    return(0);
  1354.  
  1355. // set cooperation level
  1356. if (lpdikey->SetCooperativeLevel(main_window_handle, 
  1357.                  DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)!=DI_OK)
  1358.     return(0);
  1359.  
  1360. // set data format
  1361. if (lpdikey->SetDataFormat(&c_dfDIKeyboard)!=DI_OK)
  1362.    return(0);
  1363.  
  1364. // acquire the keyboard
  1365. if (lpdikey->Acquire()!=DI_OK)
  1366.    return(0);
  1367.  
  1368. // return success
  1369. return(1);
  1370.  
  1371. } // end DI_Init_Keyboard
  1372.  
  1373. ///////////////////////////////////////////////////////////
  1374.  
  1375. int DI_Read_Joystick(void)
  1376. {
  1377. // this function reads the joystick state
  1378.  
  1379. // make sure the joystick was initialized
  1380. if (!joystick_found)
  1381.    return(0);
  1382.  
  1383. if (lpdijoy)
  1384.     {
  1385.     // this is needed for joysticks only    
  1386.     if (lpdijoy->Poll()!=DI_OK)
  1387.         return(0);
  1388.  
  1389.     if (lpdijoy->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joy_state)!=DI_OK)
  1390.         return(0);
  1391.     }
  1392. else
  1393.     {
  1394.     // joystick isn't plugged in, zero out state
  1395.     memset(&joy_state,0,sizeof(joy_state));
  1396.  
  1397.     // return error
  1398.     return(0);
  1399.     } // end else
  1400.  
  1401. // return sucess
  1402. return(1);
  1403.  
  1404. } // end DI_Read_Joystick
  1405.  
  1406. ///////////////////////////////////////////////////////////
  1407.  
  1408. int DI_Read_Mouse(void)
  1409. {
  1410. // this function reads  the mouse state
  1411.  
  1412. if (lpdimouse)    
  1413.     {
  1414.     if (lpdimouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mouse_state)!=DI_OK)
  1415.         return(0);
  1416.     }
  1417. else
  1418.     {
  1419.     // mouse isn't plugged in, zero out state
  1420.     memset(&mouse_state,0,sizeof(mouse_state));
  1421.  
  1422.     // return error
  1423.     return(0);
  1424.     } // end else
  1425.  
  1426. // return sucess
  1427. return(1);
  1428.  
  1429. } // end DI_Read_Mouse
  1430.  
  1431. ///////////////////////////////////////////////////////////
  1432.  
  1433. int DI_Read_Keyboard(void)
  1434. {
  1435. // this function reads the state of the keyboard
  1436.  
  1437. if (lpdikey)
  1438.     {
  1439.     if (lpdikey->GetDeviceState(256, (LPVOID)keyboard_state)!=DI_OK)
  1440.        return(0);
  1441.     }
  1442. else
  1443.     {
  1444.     // keyboard isn't plugged in, zero out state
  1445.     memset(keyboard_state,0,sizeof(keyboard_state));
  1446.  
  1447.     // return error
  1448.     return(0);
  1449.     } // end else
  1450.  
  1451. // return sucess
  1452. return(1);
  1453.  
  1454. } // end DI_Read_Keyboard
  1455.  
  1456. ///////////////////////////////////////////////////////////
  1457.  
  1458. void DI_Release_Joystick(void)
  1459. {
  1460. // this function unacquires and releases the joystick
  1461.  
  1462. if (lpdijoy)
  1463.     {    
  1464.     lpdijoy->Unacquire();
  1465.     lpdijoy->Release();
  1466.     } // end if
  1467.  
  1468. } // end DI_Release_Joystick
  1469.  
  1470. ///////////////////////////////////////////////////////////
  1471.  
  1472. void DI_Release_Mouse(void)
  1473. {
  1474. // this function unacquires and releases the mouse
  1475.  
  1476. if (lpdimouse)
  1477.     {    
  1478.     lpdimouse->Unacquire();
  1479.     lpdimouse->Release();
  1480.     } // end if
  1481.  
  1482. } // end DI_Release_Mouse
  1483.  
  1484. ///////////////////////////////////////////////////////////
  1485.  
  1486. void DI_Release_Keyboard(void)
  1487. {
  1488. // this function unacquires and releases the keyboard
  1489.  
  1490. if (lpdikey)
  1491.     {
  1492.     lpdikey->Unacquire();
  1493.     lpdikey->Release();
  1494.     } // end if
  1495.  
  1496. } // end DI_Release_Keyboard
  1497.  
  1498. ///////////////////////////////////////////////////////////
  1499.  
  1500. int Clone_BOBX(BOB_PTR source, BOB_PTR dest)
  1501. {
  1502. // this function clones a BOB and updates the attr var to reflect that
  1503. // the BOB is a clone and not real, this is used later in the destroy
  1504. // function so a clone doesn't destroy the memory of a real bob
  1505.  
  1506. if (source && dest)
  1507.    {
  1508.    // copy the bob data
  1509.    memcpy(dest,source, sizeof(BOB));
  1510.  
  1511.    // set the clone attribute
  1512.    dest->attr |= BOB_ATTR_CLONE;
  1513.  
  1514.    } // end if
  1515.  
  1516. else
  1517.     return(0);
  1518.  
  1519. // return success
  1520. return(1);
  1521.  
  1522. } // end Clone_BOBX
  1523.  
  1524. ///////////////////////////////////////////////////////////
  1525.  
  1526. int Destroy_BOBX(BOB_PTR bob)
  1527. {
  1528. // destroy the BOB, tests if this is a real bob or a clone
  1529. // if real then release all the memory, otherwise, just resets
  1530. // the pointers to null
  1531.  
  1532. int index; // looping var
  1533.  
  1534. // is this bob valid
  1535. if (!bob)
  1536.     return(0);
  1537.  
  1538. // test if this is a clone
  1539. if (bob->attr && BOB_ATTR_CLONE)
  1540.     {
  1541.     // null link all surfaces
  1542.     for (index=0; index<MAX_BOB_FRAMES; index++)
  1543.         if (bob->images[index])
  1544.             bob->images[index]=NULL;
  1545.  
  1546.     // release memory for animation sequences 
  1547.     for (index=0; index<MAX_BOB_ANIMATIONS; index++)
  1548.         if (bob->animations[index])
  1549.             bob->animations[index]=NULL;
  1550.  
  1551.     } // end if
  1552. else
  1553.     {
  1554.     // destroy each bitmap surface
  1555.     for (index=0; index<MAX_BOB_FRAMES; index++)
  1556.         if (bob->images[index])
  1557.             (bob->images[index])->Release();
  1558.  
  1559.     // release memory for animation sequences 
  1560.     for (index=0; index<MAX_BOB_ANIMATIONS; index++)
  1561.         if (bob->animations[index])
  1562.             free(bob->animations[index]);
  1563.  
  1564.     } // end else not clone
  1565.  
  1566. // return success
  1567. return(1);
  1568.  
  1569. } // end Destroy_BOBX
  1570.  
  1571. ///////////////////////////////////////////////////////////
  1572.  
  1573. int Collision_Test(int x1, int y1, int w1, int h1, 
  1574.                    int x2, int y2, int w2, int h2) 
  1575. {
  1576. // this function tests if the two rects overlap
  1577.  
  1578. // get the radi of each rect
  1579. int width1  = (w1>>1) - (w1>>3);
  1580. int height1 = (h1>>1) - (h1>>3);
  1581.  
  1582. int width2  = (w2>>1) - (w2>>3);
  1583. int height2 = (h2>>1) - (h2>>3);
  1584.  
  1585. // compute center of each rect
  1586. int cx1 = x1 + width1;
  1587. int cy1 = y1 + height1;
  1588.  
  1589. int cx2 = x2 + width2;
  1590. int cy2 = y2 + height2;
  1591.  
  1592. // compute deltas
  1593. int dx = abs(cx2 - cx1);
  1594. int dy = abs(cy2 - cy1);
  1595.  
  1596. // test if rects overlap
  1597. if (dx < (width1+width2) && dy < (height1+height2))
  1598.    return(1);
  1599. else
  1600. // else no collision
  1601. return(0);
  1602.  
  1603. } // end Collision_Test
  1604.  
  1605. ///////////////////////////////////////////////////////////
  1606.  
  1607. int Color_Scan(int x1, int y1, int x2, int y2, 
  1608.                UCHAR scan_start, UCHAR scan_end,
  1609.                UCHAR *scan_buffer, int scan_lpitch)
  1610. {
  1611. // this function implements a crude collision technique
  1612. // based on scanning for a range of colors within a rectangle
  1613.  
  1614. // clip rectangle
  1615.  
  1616. // x coords first    
  1617. if (x1 >= screen_width)
  1618.    x1=screen_width-1;
  1619. else
  1620. if (x1 < 0)
  1621.    x1=0;
  1622.  
  1623. if (x2 >= screen_width)
  1624.    x2=screen_width-1;
  1625. else
  1626. if (x2 < 0)
  1627.    x2=0;
  1628.  
  1629. // now y-coords
  1630. if (y1 >= screen_height)
  1631.    y1=screen_height-1;
  1632. else
  1633. if (y1 < 0)
  1634.    y1=0;
  1635.  
  1636. if (y2 >= screen_height)
  1637.    y2=screen_height-1;
  1638. else
  1639. if (y2 < 0)
  1640.    y2=0;
  1641.  
  1642. // scan the region
  1643. scan_buffer +=y1*scan_lpitch;
  1644.  
  1645. for (int scan_y=y1; scan_y<=y2; scan_y++)
  1646.     {
  1647.     for (int scan_x=x1; scan_x<=x2; scan_x++)
  1648.         {
  1649.         if (scan_buffer[scan_x] >= scan_start && scan_buffer[scan_x] <= scan_end )
  1650.             return(1);
  1651.         } // end for x
  1652.  
  1653.     // move down a line
  1654.     scan_buffer+=scan_lpitch;
  1655.  
  1656.     } // end for y
  1657.  
  1658. // return failure
  1659. return(0);
  1660.  
  1661. } // end Color_Scan
  1662.  
  1663. ////////////////////////////////////////////////////////////////
  1664.  
  1665. int Color_Scan16(int x1, int y1, int x2, int y2, 
  1666.                USHORT scan_start, USHORT scan_end,
  1667.                UCHAR *scan_buffer, int scan_lpitch)
  1668. {
  1669. // this function implements a crude collision technique
  1670. // based on scanning for a range of colors within a rectangle
  1671. // this is the 16-bit version, thus the interpretation of scan_start
  1672. // and end are different, they are they EXACT RGB values you are looking
  1673. // for, thus you can test for 2 values at most, else make them equal to
  1674. // test for one value
  1675. USHORT *scan_buffer2 = (USHORT *)scan_buffer;
  1676.  
  1677. // convert number of bytes per line to number of 16-bit shorts
  1678. scan_lpitch = (scan_lpitch >> 1);
  1679.  
  1680. // clip rectangle
  1681.  
  1682. // x coords first    
  1683. if (x1 >= screen_width)
  1684.    x1=screen_width-1;
  1685. else
  1686. if (x1 < 0)
  1687.    x1=0;
  1688.  
  1689. if (x2 >= screen_width)
  1690.    x2=screen_width-1;
  1691. else
  1692. if (x2 < 0)
  1693.    x2=0;
  1694.  
  1695. // now y-coords
  1696. if (y1 >= screen_height)
  1697.    y1=screen_height-1;
  1698. else
  1699. if (y1 < 0)
  1700.    y1=0;
  1701.  
  1702. if (y2 >= screen_height)
  1703.    y2=screen_height-1;
  1704. else
  1705. if (y2 < 0)
  1706.    y2=0;
  1707.  
  1708. // scan the region
  1709. scan_buffer2 +=y1*scan_lpitch;
  1710.  
  1711. for (int scan_y=y1; scan_y<=y2; scan_y++)
  1712.     {
  1713.     for (int scan_x=x1; scan_x<=x2; scan_x++)
  1714.         {
  1715.         if (scan_buffer2[scan_x] == scan_start || scan_buffer2[scan_x] == scan_end )
  1716.             return(1);
  1717.         } // end for x
  1718.  
  1719.     // move down a line
  1720.     scan_buffer2+=scan_lpitch;
  1721.  
  1722.     } // end for y
  1723.  
  1724. // return failure
  1725. return(0);
  1726.  
  1727. } // end Color_Scan16
  1728.  
  1729. ////////////////////////////////////////////////////////