// Full Screen Rotation // ==================== // Written using Borland C++ v3.1 and TASM 3.1. // // This code demonstrates a number of things. // - Full screen image rotation/scaling using a reverse transformation // algorithm. // - Simple fixed point math. // - Loading 320X200X256 PCX files. // - Palette manipulation. // - How to get into a square aspect ratio, in 320X200X256 CHAINED mode. // // I did this as an experiment to see how fast I could make it fly. It's a // shame that I couldn't get it to go any faster. // // How I can be reached: // // Internet: sad@umcc.umich.edu // CIS: 73053,3347 // Snail: 14985 Brookview Dr., Apt. #201 // Riverview, MI 48192 // // ============================================================================= // This source code is Copyright 1994, by Scott A. Deming. All Rights Reserved! // Permission is granted to anyone who wishes to use it as a learning tool, for // profit, or not-for profit. I don't care how you use it, but I would like to // know about anyone it helps. Please drop me a line one way or another. It's // always nice to hear from people who have actually gotten something out of // what I've written. // ============================================================================= // // Scott A. Deming // sad@umcc.umich.edu #include #include #include #include #include #include #include "gfxpal.h" #include "gfxpcx.h" #include "gfxmath.h" char palette[768]; char *vgaScreen = MK_FP(0xA000, 0x0000); void gfxSetMode(int mode) { // Set screen mode by calling interrupt 0x10 asm { mov ax, mode int 0x10 } } void gfxExtendMode(void) { // Square aspect ratio. outportb(0x3C2, 0xE3); } void gfxRotateFullScreenImage(char *image, char *screen, int angle, int scale) { long c, s; int ys, yc; int x, y; int xT, yT; // Since we're using a "reverse" transformation, we should adjust the angle // accordingly. So the angle is actually 255-angle. c = cosTab[255-angle]; s = sinTab[255-angle]; // The main loop will loop from -100(y) to 100(y) and -160(x) to 160(x) so // we rotate around the center of the screen. This, in effect, places 0,0 // at the center of the screen. for (y=-100; y<100; y++) { // We want to calculate sin(y) and cos(y) outside of the X loop. There // isn't any reason to do it more than once per screen row. ys = (y*s>>10); yc = (y*c>>10); for (x=-160; x<160; x++) { // x' = cos(x)-sin(y) * scaleRatio; xT = ((((x*c)>>10)-ys)*scaleTab[scale])>>10; // y' = sin(x)+cos(y) * scaleRatio; yT = ((((x*s)>>10)+yc)*scaleTab[scale])>>10; // Simple clipping goes here. We don't want a bunch of garbage on // the screen do we? if (xT>-160 && xT < 160 && yT > -100 && yT < 100) { screen[(x+160)+yTab[(y+100)]] = image[(xT+160)+yTab[yT+100]]; } } } } int main() { int angle = 0; int aDir = 1; int scale = 0; int sDir = 1; char *scrImage; char *screen; // Allocate/Initialize screen buffer memory. screen = malloc(64000U); if (screen == NULL) { printf("Error allocating screen memory.\n"); return (0); } memset(screen, 0, 64000U); // Initialize fixed point sin/cos/scale/Y tables. -- See gfxmath.c gfxInitTables(); // Set video mode to graphics mode 320X200X256 gfxSetMode(0x13); // Set square aspect ratio. gfxExtendMode(); // Load in our test.pcx image. -- See gfxpcx.c scrImage = gfxLoadPCX("test.pcx", scrImage, palette); // Set the palette to that in our test.pcx file. -- See gfxpal.c gfxSetPalette(0, 256, palette); // Display the image and wait for a keypress before beginning, clear screen. memcpy(vgaScreen, scrImage, 64000U); getch(); memset(vgaScreen, 0, 64000U); // Loop. Rotate/Scale the image over and over again until a key is pressed. while (!kbhit()) { // Rotate/Scale the image into a buffer. Makes for smoother animation. gfxRotateFullScreenImage(scrImage, screen, angle, scale); asm { push ds // Save ds. cld // Clear direction flag. // Move the image to the screen quickly using a 32 bit blit. les di, vgaScreen // Load vgaScreen into [es:di]. lds si, screen // Load screen into [ds:si]. mov ecx, 16000 // 64000/4 bytes [4 byte (32 bit) movs]. rep movsd // 32 bit movs. // Clear the screen buffer les di, screen // Load screen into [es:di]. mov ecx, 16000 // 64000/4 bytes [4 byte (32 bit) stos]. xor eax, eax // Set clear color to 0. rep stosd // 32 bit stos. pop ds // restore ds. } // Adjust rotation. angle+=aDir; if (angle>=255) { aDir = -1; } else if (angle<1) { aDir = 1; } // Adjust scaling. scale+=sDir; if (scale>=127) { sDir = -1; } else if (scale<1) { sDir = 1; } } // Pull the keystroke from the keyboard buffer. getch(); // Return to text mode. gfxSetMode(0x03); // Clean up free(scrImage); free(screen); // And finally return to dos. return (0); }