Topic : DOS Game Programming
Author : Alexander Russell
Page : << Previous 8  Next >>
Go to page :


                                *

;*                                                             *

;*****************************************************

; real code for real men

; adjust for proper memory model

.MODEL SMALL,C



.CODE

      PUBLIC mouse_event_func,mouse_int



mouse_event_func DD ?





mouse_int PROC FAR

          PUSHF

          CALL CS:[mouse_event_func]

          RET

mouse_int ENDP



END



This ASM function is called by the int33h driver. Mouse_int() in turn calls what ever function mouse_event_func points to. Mouse_event_func is a pointer to a function - it is not itself a function.
This is the c code to use the mouse.


#define ESC 27

short mouse_x, mouse_y;

short mouse_present;

short mouse_hidden=0;

short button_stat=0;

unsigned short flags;



extern void far *far mouse_event_func;

void mouse_int(void);



typedef struct

   {

   unsigned int flags, x, y, button_flag;

   }

mouse_info_t;



#define MAX_MOUSE_EVENTS 10





#define MOUSE_MOVE   1

#define MOUSE_L_DN   2

#define MOUSE_L_UP   4

#define MOUSE_R_DN   8

#define MOUSE_R_UP   16



#define EVENT_MASK   31   /* the logical OR of the 5 above vars */



mouse_info_t mouse_info[MAX_MOUSE_EVENTS];

int head=0;

int tail=0;





/* the low level interrupt handler calls this */

/* ---------------------- mouse_handler() ----------------- April 1,1993 */

void far interrupt mouse_handler(void)

{



   /* save info returned by mouse device driver */

   asm   {

         mov   flags,   ax

         mov   mouse_x, cx

         mov   mouse_y, dx

         mov   button_stat, bx

         }





   // place the mouse information in a circular queue

   mouse_info[tail].x=mouse_x;

   mouse_info[tail].y=mouse_y;

   mouse_info[tail].button_flag=button_stat;

   mouse_info[tail].flags=flags;



   tail++;

   if ( tail == MAX_MOUSE_EVENTS )

      tail=0;

   if ( tail == head )

      {

      head++;

      if ( head == MAX_MOUSE_EVENTS )

         head=0;

      }

}


/*



   the assembler function mouse_int() calls

   mouse_event_func whenever the mouse moves, or a button

   is pressed, or released. mouse_event_func points to mouse_handler

   which ques up the mouse events, get_event can be used to read these

   events.



/* is there a mouse, install int handlers */

/* ---------------------- init_mouse() -------------- April 1,1993 */

short init_mouse(void)

{

   unsigned short c_seg, c_off;



   asm   {

         xor   ax, ax

         int   033h



         /* note BX holds number of buttons, but we don't care */

         mov   mouse_present, ax

         }



   if ( mouse_present )

      {

      /* install our own handler */

      mouse_event_func=mouse_handler; /* global func pointer */



      /* install mouse_int as mouse handler, which will call

         mouse_handler */



      c_seg=FP_SEG(mouse_int);

      c_off=FP_OFF(mouse_int);

      asm   {

            mov   ax, c_seg

            mov   es, ax

            mov   dx, c_off

            mov   ax, 0ch

            mov   cx, EVENT_MASK



            int 033h

            }



      /* set mouse x, y limits */

      asm   {

            mov   ax, 7

            mov   cx, 0

            mov   dx, 359



            int 033h



            mov   ax, 8

            mov   cx, 0

            mov   dx, 239



            int 033h





            /* set initial mouse_x, mouse_y */

            mov   ax, 3

            int 033h



            mov   mouse_x, cx

            mov   mouse_y, dx

            }  

      }



   return(mouse_present);

}



* ---------------------- deinit_mouse() ------------------ April 1,1993 */

void deinit_mouse(void)

{



   if ( mouse_present )

      {

      /* deinstall our mouse handler by making int 33 never call it */

      asm   {

            mov   ax, 0ch

            xor   cx, cx     /* mask == 0, handler never called */



            int 033h



            /* reset mouse driver */

            xor   ax, ax

            int   033h

            }

      }

}



See the source files joy.c, mouse.c, mousetub.asm, and key.c for mini programs that demonstrate using all this i/o code.
Event QueueThe next step is to combine all these different input streams into a single combined stream of input. Doing this makes the game program's code much simpler. This combined input stream is demonstrated in chap4.c Below is an excerpt from chap4.c.


// add an event to out generic input queue

/* ---------------------- add_input() ------------------- October 8,1998 */

void add_input(event_t *event)

{



   in[i_tail].type=event->type;

   in[i_tail].sub_type=event->sub_type;

   in[i_tail].x=event->x;

   in[i_tail].y=event->y;

   in[i_tail].data1=event->data1;

   in[i_tail].data2=event->data2;



   i_tail++;

   if ( i_tail == MAX_INPUT )

      i_tail=0;

   if ( i_tail == i_head )

      {

      i_head++;

      if ( i_head == MAX_INPUT )

         i_head=0;

      }



}



// see if there  any user generated input waiting for processing

int check_input(event_t *event)

{

   int is_event=0;

   static unsigned long next_joy_check=0;

   event_t new_event;

   int dx, dy;



   if ( get_tick() > next_joy_check )

      {

      // read the joy stick only at regular intervals

      read_joy();



      // this dx/dy thing is to prevent extra joy events caused

      // by normal joystick instability

      dx=abs(last_joy_x - joy_x);

      dy=abs(last_joy_y - joy_y);

      if ( dx > 10 || dy > 10 )

         {

         // add a joy event

         new_event.type=JOY;

         new_event.sub_type=J_MOVE;

         new_event.x=joy_x;

         new_event.y=joy_y;



         add_input(&new_event);

         last_joy_x=joy_x;

         last_joy_y=joy_y;

         }



      next_joy_check=get_tick();

      }



   read_joy_buttons();

   if ( last_b0 != b0 )

      {

      new_event.type=JOY;

      new_event.sub_type=J_BUTTON0;

      new_event.data1=!b0;



      add_input(&new_event);

      last_b0=b0;

      }

   if ( last_b1 != b1 )

      {

      new_event.type=JOY;

      new_event.sub_type=J_BUTTON1;

      new_event.data1=!b1;



      add_input(&new_event);

      last_b1=b1;

      }



   // place any pending mouse events in generic queue

   // could easily make mouse code place its events directly in

   // generic input queue

   while ( head != tail )

      {

      new_event.type=MOUSE;

      new_event.x=mouse_info[head].x;

      new_event.y=mouse_info[head].y;

      if ( mouse_info[head].flags & MOUSE_MOVE )

         new_event.sub_type=M_MOVE;

      else

         {

         if ( mouse_info[head].flags & MOUSE_L_DN )

            new_event.sub_type=M_L_BUT_DOWN;

         else

            {

            if ( mouse_info[head].flags & MOUSE_L_UP )

               new_event.sub_type=M_L_BUT_UP;

            else

               {

               if ( mouse_info[head].flags & MOUSE_R_DN )

                  new_event.sub_type=M_R_BUT_DOWN;

               else

                  {

                  if ( mouse_info[head].flags & MOUSE_R_UP )

                     new_event.sub_type=M_R_BUT_UP;

                  }

               }

            }

         }



      add_input(&new_event);



      head++;

      if ( head == MAX_MOUSE_EVENTS )

         head=0;



      }



   // place any pending keyboard events in queue

   // in a real game you might want to do some processing to

   // the raw scan codes to convert them to ASCI or an other

   // more convenient format

   while ( gb_scan_head != gb_scan_tail )

      {

      new_event.type=KEY;

      new_event.data1=gb_scan_q[gb_scan_head];



      // 0xe0 indicates a key from the SECOND keypad, real code will

      // follow

      if ( new_event.data1 == 0xe0 )

         {

         gb_scan_head++;

         continue;

         }



      gb_scan_head++;



      if ( new_event.data1 & KEY_UP_MASK )

         new_event.sub_type=KEY_UP;

      else

         new_event.sub_type=KEY_DOWN;



      new_event.data1&=KEY_ALL_MASK;  // clear high bit



      // this is where you would convert the raw scan code to ascii

      // and do other high level processing if required

      // eg  new_event.data2=get_ascii(new_event.data1);



      add_input(&new_event);

      }



   // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

   // check if there are any pending events, and


Page : << Previous 8  Next >>