home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-04-19 | 12.2 KB | 477 lines | [TEXT/PJMM] |
- program Map;
-
- uses
- {$IFC UNDEFINED THINK_PASCAL}
- Types, QuickDraw, Menus, ToolUtils, Resources, {}
- SegLoad, Events, Processes, Windows, Dialogs,
- {$ELSEC}
- {$ENDC}
- QDOffScreen, Palettes, TransSkel;
-
- const
- kMaxAngle = 360 * 4; {NOT angle, but number of pixels wide! 360*2 is ok on 68k}
- kFixedDigits = 8;
- kFixedOne = 256; {2 ** kFixedDigits}
- kFixedHalf = kFixedOne div 2;
- kIntMask = $ffffff00;
- kSignMask = $ff000000;
- kAngle30 = kMaxAngle div 12;
- kAngle60 = kMaxAngle div 6;
- kAngle90 = kMaxAngle div 4;
- kAngle120 = kMaxAngle div 3;
- kAngle180 = kMaxAngle div 2;
- kAngle15 = kMaxAngle div 24;
- kAngle10 = kMaxAngle div 60;
- kAngle5 = kMaxAngle div 72;
-
- kViewAngle = kMaxAngle div 8; {8}
- kFullView = Longint(kViewAngle) * 2;
-
- kMaxRows = 200;
- kHalfRows = kMaxRows div 2 * 0;
- kMaxRay1 = 20; {How far with step 1?}
- kMaxRay2 = 40; {How far with step 2?}
- kMaxRay = 80; {How far with step the rest (step 4)?}
-
- kMapSizeH = 256;
- kMapSizeV = 256;
-
- kMapMaskH = kMapSizeH - 1; {For BitAnd with coordinates!}
- kMapMaskV = kMapSizeV - 1;
-
- kMapSizeFixedH = kMapSizeH * kFixedOne;
- kMapSizeFixedV = kMapSizeV * kFixedOne;
- kMapMaskFixedH = kMapSizeFixedH - 1; {For BitAnd with coordinates!}
- kMapMaskFixedV = kMapSizeFixedV - 1;
-
- var
- m: MenuHandle;
- dummy: Boolean;
- r: Rect;
- w: WindowPtr;
- gOffscreen: GrafPtr;
-
- var
- playerX, playerY, playerZ: Longint;
- direction: Longint;
- sinTable, cosTable: array[0..kMaxAngle] of Longint;
-
- type
- ByteArr = packed array[0..99999] of Byte;
- ByteArrPtr = ^ByteArr;
- var
- map, colorScreen: GrafPtr;
- offscreenPixels, mapPixels, colorPixels: ByteArrPtr;
- offscreenRow, mapRow, colorRow: Longint;
- boundsRect, mapBoundsRect: Rect;
-
- c: RGBColor;
- col: Integer;
-
- var
- rowTable, dyTable: array[0..kMaxRows] of Longint;
- mapRowTable: array[0..kMapSizeV] of Longint;
-
- const
- kFokal = 50; {Lower is more flat. 50 is OK.}
- kStartHeight = 80; {Camera height - should be variable}
-
- procedure Render;
- type
- IntPtr = ^Integer;
- var
- x, y, z: Longint; {Ray position}
- dx, dz, dy: Longint; {Ray direction}
- dist, dDist: Integer; {Number of steps so far}
- screenX, screenY, newscreeny: Integer; {Pixel coordinates}
- angle: Integer; {Ray direction}
- height: Integer;
-
- mapBase, mapTableBase, offBase, rowTableBase: Longint;
- tableP: IntPtr;
- mapP, offP: Ptr;
- Pixel: Byte;
- finish: Integer;
- const
- {q = true;}
- kBackPixValue = 205;
-
- procedure RayStep;
- begin
- tableP := IntPtr(mapTableBase + BSL(BSR(z, kFixedDigits), 2));
- mapP := Ptr(mapBase + tableP^ + BSR(x, kFixedDigits));
- height := mapP^;
-
- height := mapPixels^[mapRowTable[BSR(z, kFixedDigits)] + BSR(x, kFixedDigits)]; {Height of ground}
- if y < height then
- begin
- newscreeny := (playerY - height) * kFokal div dist - kHalfRows; {We could make a table for this, but it would be 2D, i.e. big.}
- pixel := colorPixels^[mapRowTable[BSR(z, kFixedDigits)] + BSR(x, kFixedDigits)];
-
- offP := Ptr(offBase + rowTable[screenY] + screenX);
-
- if newscreeny < 0 then
- newscreeny := 0;
- if newscreeny < screenY then
- begin
-
- finish := screenY - newscreeny;
- while finish >= 4 do
- begin
- offP^ := pixel;
- offP := Ptr(Longint(offP) - offscreenRow);
- offP^ := pixel;
- offP := Ptr(Longint(offP) - offscreenRow);
- offP^ := pixel;
- offP := Ptr(Longint(offP) - offscreenRow);
- offP^ := pixel;
- offP := Ptr(Longint(offP) - offscreenRow);
- finish := finish - 4;
- end;
- while finish >= 1 do
- begin
- offP^ := pixel;
- offP := Ptr(Longint(offP) - offscreenRow);
- finish := finish - 1;
- end;
- screenY := newscreeny;
-
- {for screenY := screenY downto newscreeny do}
- {begin}
- {offP^ := pixel;}
- {offP := Ptr(Longint(offP) - offscreenRow);}
- {Not so good:offscreenPixels^[rowTable[screenY] + screenX] := pixel;}
- {end}
- end
- else
- begin {If we get here, something is wrong.}
- end;
- {dy := -screenY * kFixedOne div kFokal; {slope when at screen height screenY!}
- dy := dyTable[screenY];
- y := height;
- end;
-
- dist := dist + dDist;
- x := BAnd(x + dx, kMapMaskFixedH);
- z := BAnd(z + dz, kMapMaskFixedV);
- y := y + dy;
- end; {RayStep}
-
- begin {Render}
- for screenX := 0 to kFullView do
- begin
- angle := (direction - (screenX - kViewAngle) + kMaxAngle) mod kMaxAngle; {always in interval 0..kMaxAngle}
-
- {Double the step to increase speed.}
-
- screenY := kMaxRows - 1;
- dist := 1;
- dDist := 1;
-
- dx := cosTable[angle];
- dz := sinTable[angle];
- dy := dyTable[screenY];
-
- x := playerX;
- z := playerZ;
- y := playerY;
-
- mapBase := Longint(mapPixels);
- mapTableBase := Longint(@mapRowTable);
- offBase := Longint(offscreenPixels);
- rowTableBase := Longint(@rowTable);
- repeat
- RayStep;
- until (screenY <= 0) or (dist > kMaxRay1);
- dx := dx * 2;
- dy := dy * 2;
- dz := dz * 2;
- dDist := dDist * 2;
- repeat
- RayStep;
- until (screenY <= 0) or (dist > kMaxRay2);
- dx := dx * 2;
- dy := dy * 2;
- dz := dz * 2;
- dDist := dDist * 2;
- repeat
- RayStep;
- until (screenY <= 0) or (dist > kMaxRay);
-
- {Paint sky!}
- {This can be replaced by copying in pixels from a background picture.}
- if screenY > 0 then
- begin
- finish := screenY;
- while finish >= 4 do
- begin
- offP^ := kBackPixValue;
- offP := Ptr(Longint(offP) - offscreenRow);
- offP^ := kBackPixValue;
- offP := Ptr(Longint(offP) - offscreenRow);
- offP^ := kBackPixValue;
- offP := Ptr(Longint(offP) - offscreenRow);
- offP^ := kBackPixValue;
- offP := Ptr(Longint(offP) - offscreenRow);
- finish := finish - 4;
- end;
- while finish >= 1 do
- begin
- offP^ := kBackPixValue;
- offP := Ptr(Longint(offP) - offscreenRow);
- finish := finish - 1;
- end;
- screenY := 0;
- end;
- {for screenY := screenY downto 0 do}
- {begin}
- {offscreenPixels^[screenY * offscreenRow + screenX] := kBackPixValue;}
- {end;}
-
- if false then
- begin
- ForeColor(redColor);
- MoveTo(BSR(x, kFixedDigits) + 200, BSR(z, kFixedDigits));
- Line(0, 0);
- ForeColor(blackColor);
- end;
-
- end; {for}
-
- SetGWorld(GWorldPtr(w), GetMainDevice);
- ForeColor(blackColor);
- CopyBits(gOffscreen^.portBits, w^.portBits, gOffscreen^.portRect, gOffscreen^.portRect, srcCopy, nil);
-
- end; {Render}
-
-
- procedure InitTables;
- var
- i: Longint;
- v, scale: Longint;
- const
- Pi = 3.1416;
-
- function Round2 (l: Longint): Longint;
- {Division by 2 with rounding}
- begin
- if l > 0 then
- l := l + 1
- else if l < 0 then
- l := l - 1;
- l := l div 2;
- Round2 := l;
- end;
-
- begin
- for i := 0 to kMaxAngle do
- begin
- sinTable[i] := Round2(Trunc(kFixedOne * 2 * sin(i * 2 * Pi / kMaxAngle)));
- cosTable[i] := Round2(Trunc(kFixedOne * 2 * cos(i * 2 * Pi / kMaxAngle)));
- end;
-
- for i := 0 to kMaxRows do
- rowTable[i] := i * offScreenRow;
-
- for i := 0 to kMapSizeV do
- mapRowTable[i] := i * mapRow;
-
- for i := 0 to kMaxRows do
- dyTable[i] := kHalfRows - i * kFixedOne div kFokal;
-
- end; {InitTables}
-
- procedure About; { Reponse to "About" selection }
- begin
- if 1 = Alert(128, nil) then ;
- end; {About}
-
- procedure DoFileMenu (item: integer); { ignored - there's only quit }
- begin
- case item of
- 1:
- Render;
- 3:
- SkelWhoa; { Tell SkelMain to quit }
- end; {case}
- end;
-
- procedure Mouse (thePt: Point; t: longint; mods: integer);
- begin
- end;
-
- procedure Idle;
- var
- km: KeyMap;
- i: Integer;
- doRender: Boolean;
- begin
- repeat
- doRender := false;
- GetKeys(km);
- {Note: Real programs don't use hard-coded key codes (unless they can display the}
- {correct keys)!}
- if km[37] then {L}
- begin
- direction := (direction + kMaxAngle - 20) mod kMaxAngle;
- doRender := true;
- end;
- if km[38] then {j}
- begin
- direction := (direction + 20) mod kMaxAngle;
- doRender := true;
- end;
- if km[34] then {i}
- begin
- {Move forward}
- for i := 1 to 5 do
- begin
- playerX := BAnd(playerX + cosTable[direction], kMapMaskFixedH);
- playerZ := BAnd(playerZ + sinTable[direction], kMapMaskFixedV);
- end;
- doRender := true;
- end;
- if km[40] then {k}
- begin
- {Reverse}
- playerX := BAnd(playerX - cosTable[direction], kMapMaskFixedH);
- playerZ := BAnd(playerZ - sinTable[direction], kMapMaskFixedV);
- doRender := true;
- end;
-
- if doRender then
- Render;
- until not doRender;
- end; {Idle}
-
- procedure Update (resized: Boolean);
- begin
- Render;
- { ForeColor(cyanColor);
- PaintRect(w^.portRect);}
- end; {Update}
-
- procedure Close;
- begin
- SkelWhoa;
- end; {Close}
-
- procedure Key (ch: char; mods: integer);
- var
- i: Integer;
- begin
- {All keyboard handling is done by GetKeys in Idle!}
- end; {Key}
-
- procedure Setup;
- const
- kColorBaseCLUT = 128;
- kGrayCLUT = 129;
- kScreenCLUT = 130;
- kHeightPict = 128;
- kColorPict = 129;
- var
- h, v: Integer;
- clut: CTabHandle;
- savePort: GrafPtr;
- saveDev: GDHandle;
- derivata: Integer;
- heightPict, colorPict: PicHandle;
- palle: PaletteHandle;
- begin
- GetGWorld(GWorldPtr(savePort), saveDev);
-
- {Create offscreens}
- SetRect(boundsRect, 0, 0, kViewAngle * 2 + 5, kMaxRows + 10);
-
- clut := GetCTable(kScreenCLUT);
- {$IFC UNDEFINED THINK_PASCAL}
- if noErr <> NewGWorld(GWorldPtr(gOffscreen), 8, boundsRect, clut, nil, 0) then
- {$ELSEC}
- if noErr <> NewGWorld(GWorldPtr(gOffscreen), 8, boundsRect, clut, nil, []) then
- {$ENDC}
- ExitToShell;
- if LockPixels(CGrafPtr(gOffscreen)^.portPixMap) then
- ;
-
-
- SetRect(mapBoundsRect, 0, 0, kMapSizeH, kMapSizeV);
-
- {map is the height field}
- clut := GetCTable(kGrayCLUT);
- {$IFC UNDEFINED THINK_PASCAL}
- if noErr <> NewGWorld(GWorldPtr(map), 8, mapBoundsRect, clut, nil, 0) then
- {$ELSEC}
- if noErr <> NewGWorld(GWorldPtr(map), 8, mapBoundsRect, clut, nil, []) then
- {$ENDC}
- ExitToShell;
- if LockPixels(CGrafPtr(map)^.portPixMap) then
- ;
-
- {colorScreen is the pixel values to display}
- clut := GetCTable(kScreenCLUT);
- {$IFC UNDEFINED THINK_PASCAL}
- if noErr <> NewGWorld(GWorldPtr(colorScreen), 8, mapBoundsRect, clut, nil, 0) then
- {$ELSEC}
- if noErr <> NewGWorld(GWorldPtr(colorScreen), 8, mapBoundsRect, clut, nil, []) then
- {$ENDC}
- ExitToShell;
- if LockPixels(CGrafPtr(colorScreen)^.portPixMap) then
- ;
-
- offscreenPixels := ByteArrPtr(CGrafPtr(gOffscreen)^.portPixMap^^.baseAddr);
- mapPixels := ByteArrPtr(CGrafPtr(map)^.portPixMap^^.baseAddr);
- colorPixels := ByteArrPtr(CGrafPtr(colorScreen)^.portPixMap^^.baseAddr);
-
- offscreenRow := BitAnd(CGrafPtr(gOffscreen)^.portPixMap^^.rowBytes, $3fff);
- mapRow := BitAnd(CGrafPtr(map)^.portPixMap^^.rowBytes, $3fff);
- colorRow := BitAnd(CGrafPtr(colorScreen)^.portPixMap^^.rowBytes, $3fff);
-
- SetGWorld(GWorldPtr(map), nil);
- heightPict := GetPicture(kHeightPict);
- DrawPicture(heightPict, mapBoundsRect);
-
- colorPict := GetPicture(kColorPict);
- SetGWorld(GWorldPtr(colorScreen), nil);
- DrawPicture(colorPict, mapBoundsRect);
-
- SetGWorld(GWorldPtr(savePort), saveDev);
- clut := GetCTable(kScreenCLUT); {Not currently used}
- {SetEntries(0, 256, clut^^.ctTable); {applicerar clut på current device}
- {palle := GetNewPalette(128);}
- {SetPalette(w, palle, true);}
- {AnimatePalette(w, clut, 0, 0, 255);}
-
- CopyBits(map^.portBits, w^.portBits, mapBoundsRect, mapBoundsRect, srcCopy, nil);
- CopyBits(colorScreen^.portBits, w^.portBits, mapBoundsRect, mapBoundsRect, srcCopy, nil);
-
- playerX := 0;
- playerZ := kFixedOne * 30;
- playerY := kStartHeight; {50-80 nånstans?}
- direction := kMaxAngle div 8;
- end;
-
- begin
- SkelInit(6, nil); { Initialize }
- SkelApple('About Ingemar''s landscape generator…', @About); { Handle Desk Accessories }
- m := NewMenu(2, 'File'); { Create Menu }
- AppendMenu(m, 'Render/R;(-;Quit/Q');
- dummy := SkelMenu(m, @DoFileMenu, nil, true); { Tell Transkel to handle it }
- SkelSetSleep(0);
-
- r.top := 50;
- r.left := 20;
- r.bottom := 300;
- r.right := 450;
- w := GetNewCWindow(130, nil, WindowPtr(-1));
- SetPort(w);
- dummy := SkelWindow(w, @Mouse, @Key, @Update, nil, @Close, nil, @Idle, true);
-
- Setup;
- InitTables;
- SetPort(w);
-
- SkelMain; { loop til quit selected }
- SkelClobber; { clean up }
- DisposeWindow(w);
- end.