delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/03/19/19:43:00

From: alex99 AT death-star DOT com (Alex)
Newsgroups: comp.os.msdos.djgpp
Subject: Re: Memory Models
Date: Wed, 19 Mar 1997 18:50:43 -0000
Message-ID: <MPG.d9a45e1d2b4691998968e@news.demon.co.uk>
References: <01bc33c8$f05661c0$ae80dec2 AT default> <5gnetu$mor AT news DOT epcc DOT edu>
Reply-To: woolly-h AT eftr DOT demon DOT co DOT uk
NNTP-Posting-Host: eftr.demon.co.uk
Lines: 628
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp

In article <5gnetu$mor AT news DOT epcc DOT edu>, av568 AT rgfn DOT epcc DOT edu says...

Some people have been sending reply's to me answering the question(sort 
of!?!) and asking for the source code, well here it is!

/************************************************************************
**
 * mouse.c                                                                
*
 * written by David Brackeen                                              
*
 * brackeen AT silo DOT csci DOT unt DOT edu                                             
*
 *                                                                        
*
 * Tab stops are set to 2.                                                
*
 * Remember to compile in the LARGE memory model!                         
*
 *                                                                        
*
 * This program will only work on DOS- or Windows-based systems with a    
*
 * VGA, SuperVGA or compatible video adapter.                             
*
 *                                                                        
*
 * Please feel to copy this source code.                                  
*
 *                                                                        
*
 * DESCRIPTION: This program demostrates mouse functions.                 
*
 ************************************************************************
**/

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <conio.h>

#define VIDEO_INT           0x10      /* the BIOS video interrupt. */
#define SET_MODE            0x00      /* BIOS func to set the video mode. 
*/
#define VGA_256_COLOR_MODE  0x13      /* use to set 256-color mode. */
#define TEXT_MODE           0x03      /* use to set 80x25 text mode. */

#define PALETTE_INDEX       0x03c8
#define PALETTE_DATA        0x03c9
#define INPUT_STATUS        0x03da
#define VRETRACE            0x08

#define SCREEN_WIDTH        320       /* width in pixels of mode 0x13 */
#define SCREEN_HEIGHT       200       /* height in pixels of mode 0x13 */
#define NUM_COLORS          256       /* number of colors in mode 0x13 */

#define MOUSE_INT           0x33
#define MOUSE_RESET         0x00
#define MOUSE_GETPRESS      0x05
#define MOUSE_GETRELEASE    0x06
#define MOUSE_GETMOTION     0x0B
#define LEFT_BUTTON         0x00
#define RIGHT_BUTTON        0x01
#define MIDDLE_BUTTON       0x02


#define MOUSE_WIDTH         24
#define MOUSE_HEIGHT        24
#define MOUSE_SIZE          (MOUSE_HEIGHT*MOUSE_WIDTH)

#define BUTTON_WIDTH        48
#define BUTTON_HEIGHT       24
#define BUTTON_SIZE         (BUTTON_HEIGHT*BUTTON_WIDTH)
#define BUTTON_BITMAPS      3
#define STATE_NORM          0
#define STATE_ACTIVE        1
#define STATE_PRESSED       2
#define STATE_WAITING       3

#define NUM_BUTTONS         2
#define NUM_MOUSEBITMAPS    9

typedef unsigned char  byte;
typedef unsigned short word;
typedef unsigned long  dword;

byte *VGA=(byte *)0xA0000000L;        /* this points to video memory. */
word *my_clock=(word *)0x0000046C;    /* this points to the 18.2hz system
                                         clock. */

typedef struct tagBITMAP              /* the structure for a bitmap. */
{
  dword width;
  dword height;
  byte palette[256*3];
  byte *data;
} BITMAP;
                                      /* the structure for animated
                                         mouse pointers. */
typedef struct tagMOUSEBITMAP MOUSEBITMAP;
struct tagMOUSEBITMAP
{
  int hot_x;
  int hot_y;
  byte data[MOUSE_SIZE];
  MOUSEBITMAP *next;
};

typedef struct tagMOUSE               /* the structure for a mouse. */
{
  byte on;
  byte button1;
  byte button2;
  byte button3;
  int num_buttons;
  int x;
  int y;
  byte under[MOUSE_SIZE];
  MOUSEBITMAP *bmp;

} MOUSE;

typedef struct tagBUTTON              /* the structure for a button. */
{
  int x;
  int y;
  int state;
  byte bitmap[BUTTON_BITMAPS][BUTTON_SIZE];

} BUTTON;

/************************************************************************
**
 *  set_mode                                                              
*
 *     Sets the video mode.                                               
*
 ************************************************************************
**/

void set_mode(byte mode)
{
  union REGS regs;

  regs.h.ah = SET_MODE;
  regs.h.al = mode;
  int86(VIDEO_INT, &regs, &regs);
}

/************************************************************************
**
 *  load_bmp                                                              
*
 *    Loads a bitmap file into memory.                                    
*
 ************************************************************************
**/

void load_bmp(char *file,BITMAP *b)
{
  FILE *fp;
  long index;
  int i,x;

  /* open the file */
  if ((fp = fopen(file,"rb")) == NULL)
  {
    printf("Error opening file %s.\n",file);
    exit(1);
  }

  /* check to see if it is a valid bitmap file */
  if (fgetc(fp)!='B' || fgetc(fp)!='M')
  {
    fclose(fp);
    printf("%s is not a bitmap file.\n",file);
    exit(1);
  }

  /* read in the width and height of the image, ignore the rest */
  for(i=0;i<16;i++) x=fgetc(fp);
  fread(&b->width, sizeof(dword), 1, fp);
  fread(&b->height,sizeof(dword), 1, fp);
  for(i=0;i<28;i++) x=fgetc(fp);

  /* try to allocate memory */
  if ((b->data = (byte *) malloc((word)(b->width*b->height))) == NULL)
  {
    fclose(fp);
    printf("Error allocating memory for file %s.\n",file);
    exit(1);
  }

  /* read the palette information */
  for(index=0;index<256;index++)
  {
    b->palette[index*3+2] = fgetc(fp) >> 2;
    b->palette[index*3+1] = fgetc(fp) >> 2;
    b->palette[index*3+0] = fgetc(fp) >> 2;
    x=fgetc(fp);
  }

  /* read the bitmap */
  for(index=(b->height-1)*b->width;index>=0;index-=b->width)
    for(x=0;x<b->width;x++)
      b->data[index+x]=(byte)fgetc(fp);

  fclose(fp);
}

/************************************************************************
**
 *  set_palette                                                           
*
 *    Sets all 256 colors of the palette.                                 
*
 ************************************************************************
**/

void set_palette(byte *palette)
{
  int i;

  outp(PALETTE_INDEX,0);              /* tell the VGA that palette data
                                         is coming. */
  for(i=0;i<256*3;i++)
    outp(PALETTE_DATA,palette[i]);    /* write the data */
}

/************************************************************************
**
 *  wait_for_retrace                                                      
*
 *    Wait until the *beginning* of a vertical retrace cycle (60hz).      
*
 ************************************************************************
**/

void wait_for_retrace(void)
{
    /* wait until done with vertical retrace */
    while  ((inp(INPUT_STATUS) & VRETRACE));
    /* wait until done refreshing */
    while (!(inp(INPUT_STATUS) & VRETRACE));
}

/************************************************************************
**
 *  get_mouse_motion                                                      
*
 *    Returns the distance the mouse has moved since it was lasted        
*
 *    checked.                                                            
*
 ************************************************************************
**/

void get_mouse_motion(int *dx,int *dy)
{
  union REGS regs;

  regs.x.ax = MOUSE_GETMOTION;
  int86(MOUSE_INT, &regs, &regs);
  *dx=regs.x.cx;
  *dy=regs.x.dx;
}

/************************************************************************
**
 *  init_mouse                                                            
*
 *    Resets the mouse.  Returns 0 if mouse not found.                    
*
 ************************************************************************
**/

int init_mouse(MOUSE *mouse)
{
  int dx,dy;
  union REGS regs;

  regs.x.ax = MOUSE_RESET;
  int86(MOUSE_INT, &regs, &regs);
  mouse->on=regs.x.ax;
  mouse->num_buttons=regs.x.bx;
  mouse->button1=0;
  mouse->button2=0;
  mouse->button3=0;
  mouse->x=SCREEN_WIDTH/2;
  mouse->y=SCREEN_HEIGHT/2;
  get_mouse_motion(&dx,&dy);
  return mouse->on;
}

/************************************************************************
**
 *  get_mouse_press                                                       
*
 *    Returns 1 if a button has been pressed since it was last checked.   
*
 ************************************************************************
**/

int get_mouse_press(int button)
{
  union REGS regs;

  regs.x.ax = MOUSE_GETPRESS;
  regs.x.bx = button;
  int86(MOUSE_INT, &regs, &regs);
  return regs.x.bx;
}

/************************************************************************
**
 *  get_mouse_release                                                     
*
 *    Returns 1 if a button has been released since it was last checked.  
*
 ************************************************************************
**/

int get_mouse_release(int button)
{
  union REGS regs;

  regs.x.ax = MOUSE_GETRELEASE;
  regs.x.bx = button;
  int86(MOUSE_INT, &regs, &regs);
  return regs.x.bx;
}

/************************************************************************
**
 *  show_mouse                                                            
*
 *    Displays the mouse.  This code is not optimized.                    
*
 ************************************************************************
**/

void show_mouse(MOUSE *mouse)
{
  int x, y;
  int mx = mouse->x - mouse->bmp->hot_x;
  int my = mouse->y - mouse->bmp->hot_y;
  long screen_offset = (my<<8)+(my<<6);
  word bitmap_offset = 0;
  byte data;

  for(y=0;y<MOUSE_HEIGHT;y++)
  {
    for(x=0;x<MOUSE_WIDTH;x++,bitmap_offset++)
    {
      mouse->under[bitmap_offset] = VGA[screen_offset+mx+x];
      /* check for screen boundries */
      if (mx+x < SCREEN_WIDTH  && mx+x >= 0 &&
          my+y < SCREEN_HEIGHT && my+y >= 0)
      {
        data = mouse->bmp->data[bitmap_offset];
        if (data) VGA[screen_offset+mx+x] = data;
      }
    }
    screen_offset+=SCREEN_WIDTH;
  }
}

/************************************************************************
**
 *  hide_mouse                                                            
*
 *    hides the mouse.  This code is not optimized.                       
*
 ************************************************************************
**/

void hide_mouse(MOUSE *mouse)
{
  int x, y;
  int mx = mouse->x - mouse->bmp->hot_x;
  int my = mouse->y - mouse->bmp->hot_y;
  long screen_offset = (my<<8)+(my<<6);
  word bitmap_offset = 0;

  for(y=0;y<MOUSE_HEIGHT;y++)
  {
    for(x=0;x<MOUSE_WIDTH;x++,bitmap_offset++)
    {
      /* check for screen boundries */
      if (mx+x < SCREEN_WIDTH  && mx+x >= 0 &&
          my+y < SCREEN_HEIGHT && my+y >= 0)
      {

        VGA[screen_offset+mx+x] = mouse->under[bitmap_offset];
      }
    }

    screen_offset+=SCREEN_WIDTH;
  }
}

/************************************************************************
**
 *  draw_button                                                           
*
 *    Draws a button.                                                     
*
 ************************************************************************
**/

void draw_button(BUTTON *button)
{
  int x, y;
  word screen_offset = (button->y<<8)+(button->y<<6);
  word bitmap_offset = 0;
  byte data;

  for(y=0;y<BUTTON_HEIGHT;y++)
  {
    for(x=0;x<BUTTON_WIDTH;x++,bitmap_offset++)
    {
      data = button->bitmap[button->state%BUTTON_BITMAPS][bitmap_offset];
      if (data) VGA[screen_offset+button->x+x] = data;
    }
    screen_offset+=SCREEN_WIDTH;
  }
}

/************************************************************************
**
 *  Main                                                                  
*
 ************************************************************************
**/

void main()
{
  BITMAP bmp;
  MOUSE  mouse;
  MOUSEBITMAP mb[NUM_MOUSEBITMAPS],
    *mouse_norm, *mouse_wait, *mouse_new=NULL;

  BUTTON button[NUM_BUTTONS];
  word redraw;
  int dx = 0, dy = 0, new_x, new_y;
  int press, release;
  int i,j, done = 0, x,y;
  word last_time,offset;

  mouse_norm = &mb[0];
  mouse_wait = &mb[1];

  mouse.bmp = mouse_norm;

  button[0].x     = 48;               /* set button states */
  button[0].y     = 152;
  button[0].state = STATE_NORM;

  button[1].x     = 224;
  button[1].y     = 152;
  button[1].state = STATE_NORM;

  if (!init_mouse(&mouse))            /* init mouse */
  {
    printf("Mouse not found.\n");
    exit(1);
  }

  set_mode(VGA_256_COLOR_MODE);       /* set the video mode. */
  load_bmp("images.bmp",&bmp);        /* load icons */


  for(i=0;i<NUM_MOUSEBITMAPS;i++)     /* copy mouse pointers */
    for(y=0;y<MOUSE_HEIGHT;y++)
      for(x=0;x<MOUSE_WIDTH;x++)
      {
        mb[i].data[x+y*MOUSE_WIDTH] = 
bmp.data[i*MOUSE_WIDTH+x+y*bmp.width];
        mb[i].next=&mb[i+1];
        mb[i].hot_x=12;
        mb[i].hot_y=12;
      }

  mb[0].next=&mb[0];
  mb[8].next=&mb[1];
  mb[0].hot_x  = 7;
  mb[0].hot_y  = 2;
                                      /* copy button bitmaps */
  for(i=0;i<NUM_BUTTONS;i++)
    for(j=0;j<BUTTON_BITMAPS;j++)
      for(y=0;y<BUTTON_HEIGHT;y++)
        for(x=0;x<BUTTON_WIDTH;x++)
        {
          button[i].bitmap[j][x+y*BUTTON_WIDTH] =
            bmp.data[i*(bmp.width>>1) + j*BUTTON_WIDTH + x +
            (BUTTON_HEIGHT+y)*bmp.width];
        }

  free(bmp.data);                     /* free up memory used */

  set_palette(bmp.palette);

  for(y=0;y<SCREEN_HEIGHT;y++)        /* display a background */
    for(x=0;x<SCREEN_WIDTH;x++)
      VGA[(y<<8)+(y<<6)+x]=y;

  new_x=mouse.x;
  new_y=mouse.y;
  redraw=0xFFFF;
  show_mouse(&mouse);
  last_time=*my_clock;
  while (!done)                       /* start main loop */
  {
    if (redraw)                       /* draw the mouse only as needed */
    {
      wait_for_retrace();
      hide_mouse(&mouse);
      if (redraw>1)
      {
        for(i=0;i<NUM_BUTTONS;i++)
          if (redraw&(2<<i)) draw_button(&button[i]);
      }
      if (mouse_new!=NULL) mouse.bmp=mouse_new;
      mouse.x=new_x;
      mouse.y=new_y;
      show_mouse(&mouse);
      last_time=*my_clock;
      redraw=0;
      mouse_new=NULL;
    }

    do {                              /* check mouse status */
      get_mouse_motion(&dx,&dy);
      press   = get_mouse_press(LEFT_BUTTON);
      release = get_mouse_release(LEFT_BUTTON);
    } while (dx==0 && dy==0 && press==0 && release==0 &&
      *my_clock==last_time);

    if (*my_clock!=last_time)         /* check animation clock */
    {
      if (mouse.bmp!=mouse.bmp->next)
      {
        redraw=1;
        mouse.bmp = mouse.bmp->next;
      }
      else
        last_time = *my_clock;
    }

    if (press) mouse.button1=1;
    if (release) mouse.button1=0;

    if (dx || dy)                     /* calculate movement */
    {
      new_x = mouse.x+dx;
      new_y = mouse.y+dy;
      if (new_x<0)   new_x=0;
      if (new_y<0)   new_y=0;
      if (new_x>319) new_x=319;
      if (new_y>199) new_y=199;
      redraw=1;
    }

    for(i=0;i<NUM_BUTTONS;i++)        /* check button status */
    {
      if (new_x >= button[i].x && new_x < button[i].x+48 &&
          new_y >= button[i].y && new_y < button[i].y+24)
      {
        if (release && button[i].state==STATE_PRESSED)
        {
          button[i].state=STATE_ACTIVE;
          redraw|=(2<<i);
          if (i==0)
          {
            if (mouse.bmp==mouse_norm)
              mouse_new=mouse_wait;
            else
              mouse_new=mouse_norm;
          }
          else if (i==1) done=1;
        }
        else if (press)
        {
          button[i].state=STATE_PRESSED;
          redraw|=(2<<i);
        }
        else if (button[i].state==STATE_NORM && mouse.button1==0)
        {
          button[i].state=STATE_ACTIVE;
          redraw|=(2<<i);
        }
        else if (button[i].state==STATE_WAITING)
        {
          if (mouse.button1)
          {
            button[i].state=STATE_PRESSED;
          }
          else
          {
            button[i].state=STATE_ACTIVE;
          }
          redraw|=(2<<i);
        }
      }
      else if (button[i].state==STATE_ACTIVE)
      {
        button[i].state=STATE_NORM;
        redraw|=(2<<i);
      }
      else if (button[i].state==STATE_PRESSED && mouse.button1)
      {
        button[i].state=STATE_WAITING;
        redraw|=(2<<i);
      }
      else if (button[i].state==STATE_WAITING && release)
      {
        button[i].state=STATE_NORM;
        redraw|=(2<<i);
      }

    }
  }                                   /* end while loop */

  set_mode(TEXT_MODE);                /* set the video mode back to
                                         text mode. */

  return;
}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019