PROGRAM floor2;
{
Floor of Doom, second life
- by Bjarke ViksĂe
oct 1994
Use mouse and mousebuttons!
Trying to rotate the damn thing. (Jazz JackRabbit, here I come :)
Anyway, rotating a texturemapped floor is hardly a demo thing -
but a game idea? And very tricky to do.
Ok, it's pretty much the same as "Floor1" except that I do both a x-slope
and a y-slope run.
And all rotated coords are precalc'ed (LINES*2 coords per angle). Only
half of the 512 angles are actually precalc'ed, the other half is
calc'ed using the others (by negating x/y).
Oh, it needs about 320 Kb of free memory! Quit the IDE and start it
from the prompt on machines which are low on memory...
}
{$A+,B-,G+,E+,I+,N-,X+}
{$IFDEF DPMI}
{$C FIXED PRELOAD PERMANENT}
{$ENDIF}
USES
DEMOINIT,MOUSE;
{{$DEFINE DEBUG}
TYPE
pBunk = ^BunkArray;
BunkArray = ARRAY[0..254, 0..255] of byte;
pIntegerArray = ^IntegerArray;
IntegerArray = ARRAY[0..32760] of integer;
CONST
LINES = 70; {how many lines shall we paint}
TILT = 31780; {tilt floor how much?}
VAR
map, tiles : pBunk;
LineTable : array[1..3] of pIntegerArray;
xpos,ypos, angle : word;
CoordPtr : array[0..255] of pointer;
SinusTable : array[0..639] of integer;
(*------------------------------------------------*)
procedure SetupSinus;
var
i : integer;
v, vadd : real;
begin
v:=0.0;
vadd:=(2.0*pi/512.0);
for i:=0 to 639 do begin
SinusTable[i]:=round(sin(v)*32767);
v:=v+vadd;
end;
end;
procedure SetColours;
{Setup ugly, more or less randomly picked, colours}
var
i : integer;
begin
for i:=0 to 7 do setRGB(i, i,i,i);
for i:=8 to 15 do setRGB(i, (i-5)*2,0,0);
for i:=16 to 23 do setRGB(i, 0,(i-10)*2,(i-8)*2);
for i:=24 to 31 do setRGB(i, 0,0,42);
for i:=32 to 39 do setRGB(i, 0,(i-15)*2,0);
for i:=40 to 47 do setRGB(i, i,i,i);
for i:=48 to 55 do setRGB(i, i,0,0);
end;
procedure CreateMap;
{Create map.
Characters in string are indexes to tiles! 'a' is tile #0,
'b' is #1 (red one) and so...}
procedure Strip(ypos,xpos : integer; st : string);
var j : integer;
begin
for j:=1 to length(st) do st[j]:=char(ord(st[j])-ord('a'));
Move(st[1],map^[ypos,xpos],length(st));
end;
var
y : integer;
begin
GetMem(map,65535);
FillChar(map^,65535,#0);
y:=20;
while y<60 do begin
Strip(y,30,'fgfgfgfgfgfgfgfgfgfg');
Strip(y+1,30,'gfgfgfgfgfgfgfgfgfgf');
if (y>35) AND (y<45) then begin Strip(y,39,'aaaaa'); Strip(y+1,39,'aaaaa'); end;
inc(y,2);
end;
Strip(20,70,'bcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbc'); Strip(21,70,'cbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb');
y:=22;
while (y<42) do begin
Strip(y,70,'bcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabc'); Strip(y+1,70,'cbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacb');
Strip(y,60,'dedede'); Strip(y+1,60,'ededed');
inc(y,2)
end;
Strip(42,70,'bcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbc');
Strip(43,70,'cbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb');
end;
procedure CreateTiles;
{Create some ugly tiles. We simple choose some colours and paint
a brick with them}
var
i,j : integer;
begin
GetMem(tiles,65535);
FillChar(tiles^,65535,#0);
for i:=0 to 254 do {254, not 255, to get in running under DPMI!}
for j:=0 to 255 do
tiles^[i,j]:=((j DIV 32)*8) + random(8); {make dithered tile}
end;
procedure PrecalcLines;
const
XPOS = 20; {this will ajust the height of the viewer}
var
q,p,i, x1,y1,x2,y2 : integer;
z,sin1,cos1 : integer;
pos,angle : word;
cx,cy : longint;
begin
for i:=1 to 3 do GetMem(LineTable[i],65535);
p:=1;
pos:=0;
angle:=0;
for q:=0 to 255 do begin
CoordPtr[q]:=@LineTable[p]^[pos];
z:=8000;
sin1:=SinusTable[angle];
cos1:=SinusTable[angle+128];
for i:=1 to LINES do begin
x1:=LongDiv(-XPOS*65536,z); {calc first coord}
y1:=LongDiv((LINES-i)*longint(TILT),z);
cx := (LongMul(x1,cos1) - LongMul(y1,sin1)) DIV 32768; {rotate it}
cy := (LongMul(x1,sin1) + LongMul(y1,cos1)) DIV 32768;
x1:=cx;
y1:=cy;
LineTable[p]^[pos]:=x1;
LineTable[p]^[pos+1]:=y1;
x2:=LongDiv(XPOS*65535,z); {calc second coord}
y2:=LongDiv((LINES-i)*longint(TILT),z);
cx := (LongMul(x2,cos1) - LongMul(y2,sin1)) DIV 32768; {rotate it}
cy := (LongMul(x2,sin1) + LongMul(y2,cos1)) DIV 32768;
x2:=cx;
y2:=cy;
LineTable[p]^[pos+2]:=(longint(x2-x1) SHL 11) DIV 160;
LineTable[p]^[pos+3]:=(longint(y2-y1) SHL 11) DIV 160;
inc(pos,4);
inc(z,310);
end;
{Check if next set of coords should be placed in other buffer, since
they cannot all fit into one 64Kb segment!!!}
if ((pos*2 + (LINES*8)) > 65200) then begin
inc(p);
pos:=0;
end;
inc(angle,1); {calc next angle}
end;
end;
procedure InitDemo;
var
i : integer;
begin
ClearWholeScreen;
SetColours;
SetupSinus;
CreateMap;
CreateTiles;
PrecalcLines;
xpos:=1200; ypos:=800;
angle:=0;
end;
procedure UninitDemo;
var
i : integer;
begin
FreeMem(map,65535);
FreeMem(tiles,65535);
for i:=1 to 3 do FreeMem(LineTable[i],65535);
end;
(*------------------------------------------------*)
procedure MoveHero;
var
x,y, sin1,cos1 : integer;
cx,cy : longint;
begin
{Determine new rotation angle}
ReadMouseMotionCounters(x,y);
angle:=(angle + x) AND 511;
{is hero moving forward?}
if (LeftButton) then begin
sin1:=SinusTable[angle];
cos1:=SinusTable[angle+128];
x:=0; {this is the moving speed}
y:=6;
cx := (longmul(x,cos1) - longmul(y,sin1)) DIV 32768;
cy := (longmul(x,sin1) + longmul(y,cos1)) DIV 32768;
inc(xpos,cx);
inc(ypos,cy);
end;
{hero cannot move outside board}
if (xpos<200) then xpos:=200;
if (xpos>16384) then xpos:=16384;
if (ypos<200) then ypos:=200;
if (ypos>16384) then ypos:=16384;
end;
(*------------------------------------------------*)
procedure DrawFloor(x,y, angle : integer; Coords : pointer); assembler;
var
mappos,tablepos : word;
xadd,yadd,
mapxadd,mapyadd : integer;
height, counts : word;
asm
push ds
mov es,SEGA000
mov di,100*320
mov ax,WORD PTR [map+2]
{mov fs,ax} DB $8E,$E0
mov ax,WORD PTR [Coords+2]
{mov gs,ax} DB $8E,$E8
mov ax,WORD PTR [Coords]
mov [tablepos],ax
mov ds,WORD PTR [tiles+2]
cld
mov [height],LINES
@y_run:
mov si,[tablepos]
DB GS; mov ax,[si+4]
cmp [angle],256
jb @anglelow1
neg ax
@anglelow1:
mov [xadd],ax
mov [mapxadd],1
or ax,ax
jns @mapxup
mov [mapxadd],-1
@mapxup:
DB GS; mov ax,[si+6]
cmp [angle],256
jb @anglelow2
neg ax
@anglelow2:
mov [yadd],ax
mov [mapyadd],256
or ax,ax
jns @mapyup
mov [mapyadd],-256
@mapyup:
DB GS; mov dx,[si]
DB GS; mov cx,[si+2]
cmp [angle],256
jb @anglelow3
neg cx
neg dx
@anglelow3:
add dx,[x]
add cx,[y]
mov bx,dx {Find first tile}
mov ax,cx
shr ax,5
shr bx,5
mov bh,al
mov [mappos],bx
DB FS; mov al,[bx] {get tile-index from map}
mov ah,al {find map position in map-buffer}
and al,7
shr ah,3
shl ax,5
mov si,ax
shl dx,11
shl cx,11
xor dx,$8000
xor cx,$8000
mov [counts],160
@x_run:
mov bh,dh {get x-position of pixel}
mov bl,ch {get y-position of pixel}
shr bx,3
and bx,$1F1F
mov al,[si+bx] {get that pixel}
mov ah,al
stosw {store it... well, we draw it twice to gain speed!}
add dx,[xadd] {add to x-slope}
jno @noxadd
mov bx,[mappos]
add bx,[mapxadd]
mov [mappos],bx
DB FS; mov al,[bx] {get new tile-index from map}
mov ah,al {find tile position in tile-buffer}
and al,7
shr ah,3
shl ax,5
mov si,ax
@noxadd:
add cx,[yadd] {add to y-slope}
jno @noyadd
mov bx,[mappos]
add bx,[mapyadd]
mov [mappos],bx
DB FS; mov al,[bx] {get new tile-index from map}
mov ah,al {find tile position in tile-buffer}
and al,7
shr ah,3
shl ax,5
mov si,ax
@noyadd:
dec [counts]
jnz @x_run
add [tablepos],8
dec [height]
jnz @y_run
pop ds
end;
(*------------------------------------------------*)
procedure RunOnce;
var
i : integer;
begin
VBLANK;
{$IFDEF DEBUG} SetRGB(0,20,0,0); {$ENDIF}
MoveHero;
DrawFloor(xpos,ypos, angle, CoordPtr[angle AND 255]);
{$IFDEF DEBUG} SetRGB(0,0,0,0); {$ENDIF}
end;
begin
if NOT MouseDriverPresent then begin writeln('No mouse...'); halt; end;
SetScreenMode($13);
InitDemo;
repeat RunOnce until KeyPressed;
UninitDemo;
SetScreenMode(TEXTMODE);
end.