#include <stdio.h>
#include <graphics.h>
#include <conio.h>
#include <dos.h>
#define ETCH_WIDTH 1000 /* width in steps of etch a sketch */
#define ETCH_HEIGHT 700 /* height in steps of etch a sketch */
#define VIEW_WIDTH 390 /* width in pixels of view portal */
#define VIEW_HEIGHT 198 /* height in pixels of view portal */
#define SCREEN_WIDTH 640 /* width in pixels of screen */
#define SCREEN_HEIGHT 200 /* height in pixels of screen */
#define THRESHOLD 1 /* How many mouse ticks needed for one stepper step */
#define LAG 2 /* How many steps needed to compensate for the lag */
#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 PORT 0x3BC /* choose from: 0x3BC | 0x378 | 0x278 */
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
typedef short sword; /* signed word */
void get_mouse_motion(sword *dx, sword *dy) {
union REGS regs;
regs.x.ax = MOUSE_GETMOTION;
int86(MOUSE_INT, ®s, ®s);
*dx=regs.x.cx;
*dy=regs.x.dx;
}
sword init_mouse() {
sword dx,dy;
union REGS regs;
regs.x.ax = MOUSE_RESET;
int86(MOUSE_INT, ®s, ®s);
get_mouse_motion(&dx,&dy);
return regs.x.ax;
}
sword get_mouse_press(sword button) {
union REGS regs;
regs.x.ax = MOUSE_GETPRESS;
regs.x.bx = button;
int86(MOUSE_INT, ®s, ®s);
return regs.x.bx;
}
sword get_mouse_release(sword button) {
union REGS regs;
regs.x.ax = MOUSE_GETRELEASE;
regs.x.bx = button;
int86(MOUSE_INT, ®s, ®s);
return regs.x.bx;
}
void clearscreen() {
cleardevice();
setcolor(WHITE);
rectangle((SCREEN_WIDTH-VIEW_WIDTH)/2-1, 0, (SCREEN_WIDTH-VIEW_WIDTH)/2+VIEW_WIDTH, VIEW_HEIGHT+1);
}
int main(int argc, char *argv[]) {
sword dx = 0, dy = 0;
sword olddx = 0, olddy = 0;
int bufferx = 0, buffery = 0;
word press, release;
long etchx = ETCH_WIDTH/2, etchy = ETCH_HEIGHT/2;
int lagx = 0, lagy = 0;
int graphdriver = DETECT; /* Expected mode will be 640x200 CGA */
int graphmode;
int statusbyte; /* Latest byte received from the parallel port */
int commandbyte; /* Byte to be sent out the parallel port */
int keypress = 0; /* Latest character from keyboard */
int flipmode = 0; /* Are we tilting down (-1) up (1) or not moving (0) */
int horizontalquad = 0; /* Current step position for motor (0-3) */
int verticalquad = 0; /* Current step position for motor (0-3) */
int now;
int lasttilttime = 0;
int lasthorizontaltime = 0;
int lastverticaltime = 0;
int beep = 0;
int delay = 0;
int d = 0;
if (argc == 2) {
delay = atoi(argv[1]);
printf("Delay = %d.\n", delay);
}
/* Initialize the mouse */
if (!init_mouse()) {
printf("Mouse not found.\n");
exit(1);
}
/* Initialize graphics system */
initgraph(&graphdriver, &graphmode, "");
clearscreen();
while (keypress != 27) { /* start main loop */
now = time();
/* Read the keyboard and mouse buttons */
if (kbhit() != 0)
keypress = getch();
else
keypress = 0;
if (get_mouse_press(LEFT_BUTTON) || keypress == '+') {
flipmode = (flipmode == 0) ? 1 : 0;
lasttilttime = now;
}
if (get_mouse_press(RIGHT_BUTTON) || keypress == '-') {
flipmode = (flipmode == 0) ? -1 : 0;
lasttilttime = now;
}
if (get_mouse_release(LEFT_BUTTON)) {
flipmode = 0;
lasttilttime = now;
}
if (get_mouse_release(RIGHT_BUTTON)) {
flipmode = 0;
lasttilttime = now;
}
if (keypress == ' ') {
clearscreen();
}
commandbyte = 0;
if (flipmode != 0) {
if (now > lasttilttime + 5) {
flipmode = 0; /* Motor stalled? */
beep = 1;
}
statusbyte = inportb (PORT+1);
if ((flipmode == 1) && !(statusbyte & 16) && (statusbyte & 32)) {
flipmode = 0; /* Upper limit */
}
if ((flipmode == -1) && (statusbyte & 16) && (statusbyte & 32)) {
flipmode = 0; /* Lower limit */
clearscreen(); /* Clear CRT */
}
}
if (flipmode == 1) {
commandbyte += 128;
} else if (flipmode == -1) {
commandbyte += 64;
}
/* printf("X = %d \t Y = %d\n", mouse.x, mouse.y); */
get_mouse_motion(&dx,&dy);
/* Add a tiny bit of momentum */
dx = (dx + olddx) / 2; dy = (dy + olddy) / 2;
/* Draw a velocity vector
setcolor(BLACK);
moveto(100,100);
lineto(100+olddx,100+olddy);
setcolor(WHITE);
moveto(100,100);
lineto(100+dx,100+dy);
*/
olddx = dx; olddy = dy;
bufferx += dx; buffery += dy;
if (bufferx>THRESHOLD) {
horizontalquad++;
lasthorizontaltime = now;
if (lagx == LAG) {
etchx++;
if (etchx>ETCH_WIDTH-1) etchx=ETCH_WIDTH-1;
bufferx =- THRESHOLD;
} else {
lagx++;
}
} else if (bufferx<-THRESHOLD) {
horizontalquad--;
lasthorizontaltime = now;
if (lagx == -LAG) {
etchx--;
if (etchx<0) etchx=0;
bufferx =+ THRESHOLD;
} else {
lagx--;
}
}
if (buffery>THRESHOLD) {
verticalquad++;
lastverticaltime = now;
if (lagy == LAG) {
etchy++;
if (etchy>ETCH_HEIGHT-1) etchy=ETCH_HEIGHT-1;
buffery =- THRESHOLD;
} else {
lagy++;
}
} else if (buffery<-THRESHOLD) {
verticalquad--;
lastverticaltime = now;
if (lagy == -LAG) {
etchy--;
if (etchy<0) etchy=0;
buffery =+ THRESHOLD;
} else {
lagy--;
}
}
putpixel((SCREEN_WIDTH-VIEW_WIDTH)/2 + VIEW_WIDTH*etchx/ETCH_WIDTH, 1 + VIEW_HEIGHT*etchy/ETCH_HEIGHT, WHITE);
if (now > lasthorizontaltime + 1) {
/* It's been over a second without movement, idle the motor */
commandbyte += (0+0+4);
} else {
switch (horizontalquad) {
case 4:
horizontalquad = 0;
/* Fall through */
case 0:
commandbyte += 0+0+0;
break;
case 1:
commandbyte += 0+2+0;
break;
case 2:
commandbyte += 1+2+0;
break;
case -1:
horizontalquad = 3;
/* Fall through */
case 3:
commandbyte += 1+0+0;
}
}
if (now > lastverticaltime + 1) {
/* It's been over a second without movement, idle the motor */
commandbyte += (0+0+32);
} else {
switch (verticalquad) {
case 4:
verticalquad = 0;
/* Fall through */
case 0:
commandbyte += 0+0+0;
break;
case 1:
commandbyte += 8+0+0;
break;
case 2:
commandbyte += 8+16+0;
break;
case -1:
verticalquad=3;
/* Fall through */
case 3:
commandbyte += 0+16+0;
}
}
outportb (PORT, commandbyte);
if (beep) {
sound(750); /* Stall warning */
sleep(1);
nosound();
beep = 0;
}
for (d=0; d<delay; d++) {
/* Busy loop */
now = time();
}
} /* end while loop */
cleardevice();
commandbyte = 0x24; /* Switch off the tilt, idle the stepper motors */
outportb (PORT, commandbyte);
return;