#include #include #include #include #include #include "fixed.h" #include "vga.h" #include "pcx.h" #include "kb.h" void __crt0_load_environment_file(char *_app_name) { } char **__crt0_glob_function(char *_arg) { return 0; } void __crt0_setup_arguments(void) { } typedef struct { char *texture[4]; int texturewidth[4]; int textureheight[4]; } rcMapBkInfo; typedef struct { char *map; int width; int height; fixed playerx, playery; fixed playerstartx, playerstarty; fixed playerangle, playerstartangle; fixed playerheight, wallheight; rcMapBkInfo mapbkinfo[256]; } rcMapType; int rcScreenWidth, rcScreenHeight, rcLineWidth; char myMap[20][20] = { { 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20 }, { 20, 0, 0, 0, 0,20, 0, 0, 0, 0, 0, 0, 0,20,30, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,20, 0, 0, 0, 0, 0, 0, 0,20,30, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,20,20, 0,20, 0, 0, 0,10,20,20,20,20,20, 0,20 }, { 20, 0, 0, 0, 0,20, 0, 0,20, 0,30, 0,10,20, 0, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,20, 0, 0,20, 0, 0, 0,10,20, 0, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,20, 0, 0,20, 0, 0, 0, 0,20, 0, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,20, 0, 0,20,20,20,20,20,20, 0, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,20, 0, 0, 0, 0, 0,10, 0, 0, 0,30,30,20,20,20 }, { 20, 0, 0, 0, 0,20, 0, 0, 0,10, 0, 0, 0,10, 0,30,30, 0, 0,20 }, { 20, 0, 0, 0, 0,20, 0, 0,20,20,20,20,20,20, 0, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,10, 0, 0, 0, 0, 0, 0, 0,20, 0, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,10, 0, 0, 0, 0, 0, 0, 0,20, 0, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,10, 0, 0, 0, 0, 0, 0, 0,10,20, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0,10,20,20,20,20,20,20, 0,20,20, 0, 0, 0, 0,20 }, { 20, 0, 0,30, 0,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,20 }, { 20, 0, 0,30, 0,10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,20 }, { 20, 0, 0,30,30,30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,20 }, { 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,20 }, { 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20 } }; typedef struct { fixed xinfo; char mapID; char whichface; fixed distance; fixed yintersect, xintersect; } rcVScanlineinfo; void rcCastRay(rcMapType *map, fixed angle, rcVScanlineinfo *v) { fixed x, y, z, dx, dy, dz; unsigned long dst; char mapID; dst = 0xFFFFFFFF; dx = fixedCos(angle + map->playerangle); if (dx) { dy = fixedDiv(fixedSin(angle + map->playerangle),dx); dz = fixedDiv(IntToFixed(1),dx); } if (dx > 0) { x = (map->playerx | 0x0000FFFF) + 1; z = fixedMul(dz,x - map->playerx); y = map->playery + fixedMul(dy,x - map->playerx); x >>= 16; while (x < map->width) { if ((mapID = map->map[x + ((y>>16)*map->width)]) != 0) { v->xintersect = x<<16; v->yintersect = y; v->whichface = 0; v->mapID = mapID; v->xinfo = y & 0x0000FFFF; dst = z; x = map->width; continue; } z += dz; y += dy; x ++; if (y < 0 || (y>>16) > map->height) x = map->width; } } if (dx < 0) { x = (map->playerx & 0xFFFF0000); z = fixedMul(dz,x - map->playerx); y = map->playery + fixedMul(dy,x - map->playerx); x >>= 16; while (x > 0) { if ((mapID = map->map[x - 1 + ((y>>16)*map->width)]) != 0) { if (z < dst) { v->xintersect = x<<16; v->yintersect = y; v->whichface = 1; v->mapID = mapID; v->xinfo = y & 0x0000FFFF; dst = z; } x = 0; continue; } z -= dz; y -= dy; x --; if (y < 0 || (y>>16) > map->height) x = 0; } } dy = fixedSin(angle + map->playerangle); if (dy) { dx = fixedDiv(fixedCos(angle + map->playerangle),dy); dz = fixedDiv(IntToFixed(1),dy); } if (dy > 0) { y = (map->playery | 0x0000FFFF) + 1; x = map->playerx + fixedMul(dx,y - map->playery); z = fixedMul(dz,y - map->playery); y >>= 16; while (y < map->height) { if ((mapID = map->map[(x>>16) + (y*map->width)]) != 0) { if (z < dst) { v->xintersect = x; v->yintersect = y<<16; v->mapID = mapID; v->whichface = 2; v->xinfo = x & 0x0000FFFF; dst = z; } y = map->height; continue; } z += dz; x += dx; y ++; if (x < 0 || (x>>16) > map->width) y = map->height; } } if (dy < 0) { y = map->playery & 0xFFFF0000; x = map->playerx + fixedMul(dx,y - map->playery); z = fixedMul(dz,y - map->playery); y >>= 16; while (y > 0) { if ((mapID = map->map[(x>>16) + ((y-1)*map->width)]) != 0) { if (z < dst) { v->xintersect = x; v->yintersect = y<<16; v->mapID = mapID; v->whichface = 3; v->xinfo = x & 0x0000FFFF; dst = z; } y = 0; continue; } z -= dz; x -= dx; y --; if (x < 0 || (x>>16) > map->width) y = 0; } } if (dst == 0xFFFFFFFF) { v->distance = 4<<16; v->mapID = 0; v->whichface = 4; } else v->distance = fixedMul(dst, fixedCos(angle)); } void rcScalevline(char *out, int outend, int outstart, char *in, int inx, int inwidth, int inheight) { fixed Y = 0; fixed dY = fixedDiv(inheight, outend-outstart); int outlen; in += (inx * inwidth); if (outend > rcScreenHeight) outend = rcScreenHeight; if (outstart < 0) { Y -= dY * outstart; outstart = 0; } outlen = outend-outstart; if (outlen <= 0) return; asm(" pushl %%ebp movl %%eax, %%ebp subl %%ecx, %%edi 0: movl %%ebx, %%eax addl %%ecx, %%edi shrl $16, %%eax addl %%edx, %%ebx decl %%ebp movb (%%esi, %%eax), %%al movb %%al, (%%edi) jnz 0b popl %%ebp " ::"a" (outlen), "D" (out), "S" (in), "b" (Y), "d" (dY), "c" (rcLineWidth) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp"); } void rcRenderVScanline(rcMapType *map, char *mem, rcVScanlineinfo *v) { int starty, endy, y; if (!v->distance) return; starty = (rcScreenHeight>>1) - ((rcScreenHeight * (map->wallheight - map->playerheight)) / v->distance); endy = (rcScreenHeight>>1) + ((rcScreenHeight * (map->playerheight)) / v->distance); if (endy < 1) return; if (starty > rcScreenHeight) return; if (starty > 0) { asm(" movb %0, %%al 0: movb %%al, (%%edi) addl %%ebx, %%edi decl %%ecx jnz 0b ": :"g" (251), "b" (rcLineWidth), "D" (mem), "c" (starty) :"%eax", "%ebx", "%ecx", "%edi"); mem += rcLineWidth * starty; } rcScalevline(mem, endy, starty, map->mapbkinfo[(int) v->mapID].texture[(int)v->whichface], fixedMul(v->xinfo, map->mapbkinfo[(int)v->mapID].textureheight[(int)v->whichface] -1), map->mapbkinfo[(int) v->mapID].textureheight[(int) v->whichface], map->mapbkinfo[(int) v->mapID].texturewidth[(int)v->whichface]); mem += (endy-starty) * rcLineWidth; y = rcScreenHeight - endy; if (y > 0) { asm(" movb %0, %%al 0: movb %%al, (%%edi) addl %%ebx, %%edi decl %%ecx jnz 0b ": :"g" (250), "b" (rcLineWidth), "D" (mem), "c" (y) :"%eax", "%ebx", "%ecx", "%edi"); } } void rcRenderMap(rcMapType *map, char *mem) { fixed angle = IntToFixed(-45); fixed dangle = fixedDiv(90, rcScreenWidth); rcVScanlineinfo v; int x; for (x = 0; x < rcScreenWidth; x++) { vgaSetXModeWriteMask(1<<(x&3)); rcCastRay(map,(fixedSin(angle) * 45),&v); rcRenderVScanline(map, mem,&v); if ((x & 3) == 3) mem++; angle += dangle; } } char *LoadTxr(char *filename, char *pal, rcMapType *map, int num, int add) { int texturewidth, textureheight; char *texture, *pal2; if (pcxLoad(filename,&texturewidth, &textureheight, &pal2, &texture) < 0) return NULL; vgaMemcpy(pal,pal2,768); free(pal2); vgaMemadd(texture,add,texturewidth*textureheight); map->mapbkinfo[num].texture[0] = texture; map->mapbkinfo[num].texture[1] = texture; map->mapbkinfo[num].texture[2] = texture; map->mapbkinfo[num].texture[3] = texture; map->mapbkinfo[num].texturewidth[0] = texturewidth; map->mapbkinfo[num].texturewidth[1] = texturewidth; map->mapbkinfo[num].texturewidth[2] = texturewidth; map->mapbkinfo[num].texturewidth[3] = texturewidth; map->mapbkinfo[num].textureheight[0] = textureheight; map->mapbkinfo[num].textureheight[1] = textureheight; map->mapbkinfo[num].textureheight[2] = textureheight; map->mapbkinfo[num].textureheight[3] = textureheight; return texture; } void main() { kbKeyType escKey = { 1,0,0 }; kbKeyType upArrowKey = { 72,1,0 }; kbKeyType downArrowKey = { 80,1,0 }; kbKeyType leftArrowKey = { 75,1,0 }; kbKeyType rightArrowKey = { 77,1,0 }; rcMapType Map; char pal1[768]; char pal[768]; char *texture1, *texture2, *texture3; int frames = 0; int ticks; vgaMemset(pal,0,768); if ((texture1 = LoadTxr("texture1.pcx",pal1,&Map,20, 0)) == NULL) exit(1); vgaMemcpy(pal,pal1,16*3); if ((texture2 = LoadTxr("texture2.pcx",pal1,&Map,30,16)) == NULL) exit(1); vgaMemcpy(pal + 16*3,pal1,16*3); if ((texture3 = LoadTxr("texture3.pcx",pal1,&Map,10,32)) == NULL) exit(1); vgaMemcpy(pal + 32*3,pal1,16*3); pal[250*3] = 13; pal[250*3+1] = 13; pal[250*3+2] = 13; pal[251*3] = 0; pal[251*3+1] = 0; pal[251*3+2] = 30; Map.map = (char *) myMap; Map.width = 20; Map.height = 20; Map.wallheight = 1 << 16; Map.playerheight = Map.wallheight>>1; Map.playerstartx = IntToFixed(2); Map.playerstarty = IntToFixed(2); Map.playerstartangle = IntToFixed(90); Map.playerx = Map.playerstartx; Map.playery = Map.playerstarty; Map.playerangle = Map.playerstartangle; fixedInit(); if (vgaSetMode(VGA_MODEX_320x200,1) < 0) exit(1); vgaSetPalette(pal); rcScreenWidth = vgaScreen.Width; rcScreenHeight = vgaScreen.Height; rcLineWidth = vgaScreen.LineWidth; kbSet(1,10); kbClearKeys(); kbMonitorKey(&escKey); kbMonitorKey(&leftArrowKey); kbMonitorKey(&rightArrowKey); kbMonitorKey(&upArrowKey); kbMonitorKey(&downArrowKey); ticks = _farpeekl(_dos_ds,0x46C); while (!escKey.pressed) { int qw; qw = 0; //((frames & 1) * // (vgaScreen.LineWidth * (vgaScreen.Height))); rcRenderMap(&Map,vgaScreen.GraphMem + qw); // vgaSetXModeVisibleStart(qw); if (leftArrowKey.pressed) Map.playerangle -= IntToFixed(2); if (rightArrowKey.pressed) Map.playerangle += IntToFixed(2); if (upArrowKey.pressed) { int r = 3; Map.playerx += fixedCos(Map.playerangle)>>r; Map.playery += fixedSin(Map.playerangle)>>r; Map.playerx += fixedCos(Map.playerangle)>>(r+1); Map.playery += fixedSin(Map.playerangle)>>(r+1); if (Map.map[(Map.playerx>>16) + (Map.playery>>16)*Map.width]) { Map.playerx -= fixedCos(Map.playerangle)>>r; Map.playery -= fixedSin(Map.playerangle)>>r; } Map.playerx -= fixedCos(Map.playerangle)>>(r+1); Map.playery -= fixedSin(Map.playerangle)>>(r+1); } if (downArrowKey.pressed) { int r = 4; Map.playerx -= fixedCos(Map.playerangle)>>r; Map.playery -= fixedSin(Map.playerangle)>>r; Map.playerx -= fixedCos(Map.playerangle)>>(r+1); Map.playery -= fixedSin(Map.playerangle)>>(r+1); if (Map.map[(Map.playerx>>16) + (Map.playery>>16)*Map.width]) { Map.playerx += fixedCos(Map.playerangle)>>r; Map.playery += fixedSin(Map.playerangle)>>r; } Map.playerx += fixedCos(Map.playerangle)>>(r+1); Map.playery += fixedSin(Map.playerangle)>>(r+1); } frames++; } ticks = _farpeekl(_dos_ds,0x46C) - ticks; free(texture3); free(texture2); free(texture1); kbSet(0,0); vgaSetMode(VGA_MODETEXT,1); printf("%.2f fps\n",((float) frames) / (((float) ticks) / 18.2)); }