I was messing around with floor texturing some time ago to figure out the most effective way (besides asm) to handle it with raycasting. Although I'm not into them as much as I use to, I still like to program them from time to time. I tried figuring out a way better than this code I made posted below, but the only conclusion I could come to is that I have to draw the entire floor up to the horizon first, then do the raycasting and draw the walls (for a wolf3d style one) over the floor.
Anyways, I remember that email you sent me some time ago about an equation for texuring on all 3 dimensions and that you could simplify floor texturing to just addition. This is the closest I came to it. Unfortunately I kept my email on the email server and those guys like to delete my emails after 30 days. I don't bother with Sisna anymore, they are full of BS.
This is QBasic code. I believe it's fairly easy to understand. If you want to run it you just need qbasic and a 128X128 8bit bitmap and name is as "test.bmp" and have it in the same directory as this. As for the code, Is this somewhat along the lines of what you were talking about?
'- Floor mapper
'--------------
'- 02/08/04
'- Created by Joe King
'---------------------
DIM ang AS INTEGER
DIM vx AS SINGLE, vy AS SINGLE
DIM tx AS SINGLE, ty AS SINGLE
DIM fx AS SINGLE, fy AS SINGLE
DIM rx AS SINGLE, ry AS SINGLE
DIM sx AS SINGLE, sy AS SINGLE
DIM px AS SINGLE, py AS SINGLE
DIM addx AS SINGLE, addy AS SINGLE
DIM float AS SINGLE
DIM col AS INTEGER, c AS LONG
DIM sp AS LONG, x AS LONG
DIM i AS LONG, y AS LONG
DIM FpsCount AS INTEGER
DIM DistTable(100) AS SINGLE
DIM SinTable(360) AS SINGLE
DIM CosTable(360) AS SINGLE
DIM Texture(127, 127) AS INTEGER
DIM TextureFilename AS STRING
DIM red AS STRING * 1, grn AS STRING * 1
DIM blu AS STRING * 1, null AS STRING * 1
DIM byte AS STRING * 1
CONST PI = 3.141592
TextureFilename = "test.bmp"
SCREEN 13
CLS
'- construct trig tables
FOR i = 0 TO 360
SinTable(i) = SIN(i * PI / 180)
CosTable(i) = COS(i * PI / 180)
NEXT i
'- construct distance table
FOR i = 1 TO 100
DistTable(i) = 32 / i
NEXT i
'- load bitmap
'----------------------
OPEN TextureFilename FOR BINARY AS #1
'- load palette
SEEK #1, 55
FOR i = 0 TO 255
GET #1, , blu
GET #1, , grn
GET #1, , red
GET #1, , null
OUT &H3C8, i
OUT &H3C9, ASC(red) \ 4
OUT &H3C9, ASC(grn) \ 4
OUT &H3C9, ASC(blu) \ 4
NEXT i
'- load image data
FOR y = 127 TO 0 STEP -1
FOR x = 0 TO 127
GET #1, , byte
Texture(x, y) = ASC(byte)
NEXT x
NEXT y
CLOSE #1
'----------------------
ON TIMER(1) GOSUB ShowFPS
TIMER ON
COLOR 255
DEF SEG = &HA000
DO
rx = SinTable(ang)
ry = -CosTable(ang)
fx = CosTable(ang)
fy = SinTable(ang)
sx = fx * -160 + rx * -160
sy = fy * -160 + ry * -160
IF key$ = CHR$(27) THEN EXIT DO
IF key$ = CHR$(0) + "H" THEN px = px - fx * 8: py = py - fy * 8
IF key$ = CHR$(0) + "P" THEN px = px + fx * 8: py = py + fy * 8
IF key$ = CHR$(0) + "M" THEN ang = ang + 8
IF key$ = CHR$(0) + "K" THEN ang = ang - 8
IF ang < 0 THEN ang = ang + 360
IF ang > 360 THEN ang = ang - 360
Your code works fine - the projection is correct : ) There are a few things you could do to speed it up without resorting to assembler. Rather than explain it tutorial style, I'll just post my results after optimization:
'02/08/2004: Floor mapper Created by Joe King
'01/30/2005: Code optimized by Ken Silverman
DIM f AS SINGLE, fx AS SINGLE, fy AS SINGLE
DIM px AS SINGLE, py AS SINGLE, sx AS SINGLE, sy AS SINGLE
DIM i AS INTEGER, x AS INTEGER, y AS INTEGER, ang AS INTEGER
DIM vx AS LONG, vy AS LONG, addx AS LONG, addy AS LONG
DIM FpsCount AS INTEGER
DIM DistTable(100) AS SINGLE, Texture(16383) AS INTEGER
DIM SinTable(512 + 512 \ 4) AS SINGLE
SCREEN 13: CONST PI = 3.141592653589793#
FOR i = 0 TO 512 + 512 \ 4 - 1: SinTable(i) = SIN(i * PI / 256): NEXT i
FOR i = 1 TO 100: DistTable(i) = 131072 / i: NEXT i
OUT &H3C8, 0: FOR i = 0 TO 767: OUT &H3C9, i \ 12: NEXT i
FOR y = 0 TO 127
FOR x = 0 TO 127
Texture(y * 128 + x) = (x + y) \ 2 + (x XOR y)
NEXT x
NEXT y
COLOR 255: ON TIMER(1) GOSUB ShowFPS: TIMER ON
DO
fx = SinTable((ang AND 511) + 128): fy = SinTable(ang AND 511)
sx = (fx + fy) * -160
sy = (fx - fy) * 160
FOR y = 100 TO 199
f = DistTable(y - 99): DEF SEG = y * 20 + &HA000
vx = ((sx * f + px) AND &H7FFFF): addx = ((fy * f) AND &H7FFFF)
vy = ((sy * f + py) AND &H7FFFF): addy = ((-fx * f) AND &H7FFFF)
FOR x = 0 TO 319
POKE x, Texture(((vy \ 32) AND &H3F80) + ((vx \ 4096) AND &H7F))
vx = vx + addx: vy = vy + addy
NEXT
NEXT
DO
key$ = INKEY$: IF key$ = "" THEN EXIT DO
IF key$ = CHR$(27) THEN END
IF key$ = CHR$(0) + "H" THEN px = px - fx * 32768: py = py - fy * 32768
IF key$ = CHR$(0) + "P" THEN px = px + fx * 32768: py = py + fy * 32768
IF key$ = CHR$(0) + "M" THEN ang = (ang + 12) AND 511
IF key$ = CHR$(0) + "K" THEN ang = (ang - 12) AND 511
LOOP
FpsCount = FpsCount + 1
LOOP
Your code works fine - the projection is correct : ) There are a few things you could do to speed it up without resorting to assembler. Rather than explain it tutorial style, I'll just post my results after optimization:
Good assumption! The code explains it all :)
sx = fx * -160 + rx * -160
sy = fy * -160 + ry * -160
Hmm...yeah, all the algebra I've taken and I forgot about that rule lol!
The most interesting hack to me is the "AND &H3F80" hack. It wasn't hard to see how it worked, pretty clever. I'm going to note that somewhere for future reference. This is some good stuff.
Awesoken at
If you don't mind a loss of precision, this version should be nearly twice as fast as my previous one. Most of the speedup (and precision loss) is due to squeezing the texture U/V variables into 16-bit integers. 16-bit integers are much faster in QB than 32-bit integers. The tricky part was getting the masks right to avoid any "Overflow" errors.
'02/08/2004: Floor mapper Created by Joe King
'01/30/2005,02/01/2005: Code optimized by Ken Silverman
DIM f AS SINGLE, fx AS SINGLE, fy AS SINGLE
DIM px AS SINGLE, py AS SINGLE, sx AS SINGLE, sy AS SINGLE
DIM SinTable(2048 + 2048 \ 4) AS SINGLE, DistTable(100) AS SINGLE
DIM x AS INTEGER, y AS INTEGER, ang AS INTEGER
DIM vx AS INTEGER, vy AS INTEGER, ax AS INTEGER, ay AS INTEGER
DIM Texture(127, 127) AS INTEGER, FpsCount AS INTEGER
SCREEN 13: CONST PI = 3.141592653589793#
FOR x = 0 TO 2048 + 2048 \ 4 - 1: SinTable(x) = SIN(x * PI / 1024): NEXT
FOR x = 1 TO 100: DistTable(x) = 8192 / x: NEXT
OUT &H3C8, 0: FOR x = 0 TO 767: OUT &H3C9, x \ 12: NEXT x
FOR y = 0 TO 127
FOR x = 0 TO 127
Texture(x, y) = (x + y) \ 2 + (x XOR y)
NEXT
NEXT
COLOR 255: ON TIMER(1) GOSUB ShowFPS: TIMER ON
DO
fx = SinTable((ang AND 2047) + 512): fy = SinTable(ang AND 2047)
sx = (fy + fx) * -160
sy = (fy - fx) * -160
FOR y = 100 TO 199
f = DistTable(y - 99): DEF SEG = y * 20 + &HA000
vx = ((sx * f - px) AND &H7FFF): ax = ((-fy * f) AND &H7FFF)
vy = ((sy * f - py) AND &H7FFF): ay = ((fx * f) AND &H7FFF)
FOR x = 0 TO 319
POKE x, Texture(vx \ 256, vy \ 256)
vx = (vx - ax) AND &H7FFF
vy = (vy - ay) AND &H7FFF
NEXT
NEXT
px = px + fx * 128: py = py + fy * 128: ang = (ang + 1) AND 2047
FpsCount = FpsCount + 1
LOOP WHILE INKEY$ = ""
END
For better precision with 16-bit U/V, replace the inner loop of the above program with this one:
DIM x AS INTEGER, y AS INTEGER, z AS INTEGER, ang AS INTEGER
...
FOR y = 100 TO 199
f = DistTable(y - 99): DEF SEG = y * 20 + &HA000
ax = ((-fy * f) AND &H7FFF)
ay = ((fx * f) AND &H7FFF)
FOR z = 0 TO 319 STEP 64
vx = (((sx + fy * z) * f - px) AND &H7FFF)
vy = (((sy - fx * z) * f - py) AND &H7FFF)
FOR x = z TO z + 63
POKE x, Texture(vx \ 256, vy \ 256)
vx = (vx - ax) AND &H7FFF
vy = (vy - ay) AND &H7FFF
NEXT
NEXT
NEXT
I gain additional precision by re-calculating the starting U/V coordinates every 64 pixels. This sacrifices a little speed, yet it's still much faster than anything with 32-bit U/V in QB.
Enjoy!
Anonymous at
Or just code it in 32-bit C, and get a 500% increase in speed , LOL 8)
Silhouette of a Can at
Anonymous said
Or just code it in 32-bit C, and get a 500% increase in speed , LOL 8)
Definately! But I usually will code something in basic first to understand the concept more easily. Being as with Qbasic/FreeBasic you can just pull it up and code away, no fiddling with typing hundreds of lines of code to initialize the graphics and input. ;)
Anonymous at
Silhouette of a Can said
Anonymous said
Or just code it in 32-bit C, and get a 500% increase in speed , LOL 8)
Definately! But I usually will code something in basic first to understand the concept more easily. Being as with Qbasic/FreeBasic you can just pull it up and code away, no fiddling with typing hundreds of lines of code to initialize the graphics and input. ;)
The same in C:
asm {
mov ax,0x13
int 10h
}
...do stuff here...
asm {
mov ax, (forgot)
int 10h
}
There, a couple of lines and you can do all ur grafx on the VGA memory, just like what QBASIC does, and u got input with C's input library.
Silhouette of a Can at
No no no. First of all, that looks like 16-bit code, and second I don't use dos (C/C++) compilers.
Anonymous at
Silhouette of a Can said
No no no. First of all, that looks like 16-bit code, and second I don't use dos (C/C++) compilers.
yes, yes its 16-bit code... but you can still make that above code into a 32-bit Win exe (wont work on WinXP with SP).
I was just trying to show that C is easier than QBASIC. QBASIC is 16-bit just in case u didnt know :D
Frobozz at
Take a shot at using FreeBASIC. It's a 32-bit compiler that has the goal of being as compatible with QB as possible. I think you'll find it much faster.
http://fbc.sourceforge.net/
GothOtaku at
I was just trying to show that C is easier than QBASIC.
:shock:
C's easier than QB!? Umm...
It might be simpler but in QB there's no libraries that you need to include to do even the simplest stuff, it's more readable, has better string handling, and is easier to debug. I used to do all my coding in QB so I could read it better and debug it and then port it to C if I needed to and Ken says he does the same thing.
EDIT: I also tried FreeBASIC recently too and found it to be an acceptable replacement for QB doing most thiings. I'd probably use it if the ON ERROR command was supported. I switched during the summer from using QB for algorithms to Euphoria since it's supported on more platforms (and easier to use).
Frobozz at
It's funny but now that I've begun to use C/C++, I do find it easier. With QB you didn't have syntax highlighting and you had a lot of words you had to search through. Good thing about C/C++ is it uses a lot of symbols so you don't have to sort through as much.
And libraries aren't that big of a deal. QB could use libraries as well and a few were made. FutureLibrary and the Ultimate Gaming Library come to mind. :wink:
maniac1701 at
I use a compiler called djgpp (dos version of gcc) and you can also get an IDE called rhide for it that gives it the SAME debugging capabilities of qbasic. as for libraries, i have been working on a 2d rts engine for a long time in my spare time (which isn't much) but since it has a lot of features like bmp loading and translucentcy as well as other things i find it easier to test things by adding it on to my engine then writing a program in basic from scratch.
masterlee at
C++ seems also easier for programs with more than 500 Lines of Code. but for small code QBasic is a god alternative. But currently i use SAS for experiments is the only software on work and has better error finding solutions.