EDIT 16/10/2015 :Below the code of the latest version.
EDIT 31/08/2015 :For dbenham multithreading version look at viewtopic.php?p=42705#p42705
Improvements:
Code: Select all
vers. frame time FPS Columns
0.01a 14890ms 0.06 40
0.01b 5870ms 0.17 40 swap out environment
0.1.0 3610ms 0.27 64 new algorithm (ray marching like, fixed step)
0.2.0 3840ms 0.26 64 Added moviment on left/ritgh and key "K" "L" for rotate.
0.3.0 750ms 1.33 64 jeb trick fast ray traversal
0.4.1 720ms 1.38* 64 dbenham multithread on monocore @2.00Ghz , 2-3 times faster on quad-core machine (4-5 frames per second)
0.5.1 400ms 2.50** 64 dda algorithm on monocore @2.00Ghz
0.5.2 300ms 3.33* 64 Using Aacini method for SIN(x). 6.25 FPS on quad-core @3.4Ghz
*: on monocore. In multicore the FPS are more
**: multicore performance data not avaible N/D
Get the code at pastebin:http://pastebin.com/16YHns0h
Code: Select all
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Dos Batch Raycast ver. 0.5.3 BETA by Francesco Poscetti aka einstein1969
::
::--------------------------------------------------------------------------
::
:: Ref: http://www.dostips.com/forum/viewtopic.php?f=3&t=5824
::
:: Thanks to Aacini, foxidrive, dbenham, penpen, jeb, neorobin, Liviu, aGerman
::
:: Tested on Windows 7
::
:: Changelog
::
:: ver. 0.5.3 2016-04-03 einstein1969
:: - Disabled parallel processing for a cuncurrent access problem see:
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=7053
::
:: ver. 0.5.2 2016-03-22 einstein1969
:: - Add new SIN(x) calculus using Aacini method. Improved speed (~20%)
::
:: ver. 0.5.1 2015-10-17 einstein1969
:: - Add choice emulation. Now it should run on XP platform. Not tested.
::
:: ver. 0.5.0 2015-10-16 einstein1969
:: - Implemented DDA algorithm. Improved speed (~40%)
:: - Moved output of execution time on title + Add FPS counter.
:: - "H" now display Help.
:: - "M" now toggle the view of the Map
:: - Improved speed by clear the environment + other optimization (~10-15% on reference system)
:: - Map more readable.
:: - revert "reduce CALLs and rearrange code to minimize CALL distance" for easy code develop. TODO later. See ver. 0.4.x
:: - revert fast 3D clipping
::
:: ver. 0.4.1 2015-08-30 dbenham
:: - Limit number of processes to maximum of 8
:: - Move Transpose inside of :raycast
:: - Optionally use Aacini's CursorPos.exe to eliminate screen flicker
:: Implementation is the same as for SNAKE.BAT
:: Code is available at http://goo.gl/hr6Kkn
::
:: ver. 0.4 2015-08-30 dbenham
:: - Many minor optimizations:
:: - consolidate and minimize SET /A statements
:: - main loop is now an endless FOR /L loop running in a child process
:: - reduce CALLs and rearrange code to minimize CALL distance
:: - remove dynamic title
:: - Nearly instantaneous drawing of 2D map
:: - Player character now indicates orientation
:: - Implemented parallel processing of ray cast partitions based on NUMBER_OF_PROCESSORS
:: - "Z" now toggles between Old and New rendering algorithm
:: - "Q" quits the program
:: - New (fast) rendering now 2-3 times faster on quad-core machine (4-5 frames per second)
:: - Old (slow) rendering now 4+ times faster on quad-core machine (1-2 frames per second)
::
:: ver. 0.3 jeb 2015-08-25
:: - Improved speed by inlining the Sinus calculation (~15% on reference system)
:: - Improved speed by direct calculating the next gridX/Y coordinates (~60%)
::
:: ver. 0.2 20/08/2015
:: - Not clear the screen until next.
:: - Added moviment on left/ritgh and key "K" "L" for rotate.
:: - Fixed bug on calculate distance
:: - Added partial clipping on Z (Distance)
::
:: ver. 0.1 04/07/2015
:: - New faster algorithm. Not optimizated for now.
:: - Use transpose trick of penpen
:: - Use new set of character for better visualize and fast antialiasing.
:: - Detect when a player slamming against the wall.
:: - You can use WASD for move!
:: - You can view the player in the MAP.
:: - You can modify the MAP more easily.
::
:: Ver. 0.01b 10/08/2014
:: - Added temporary dir and use swapout mechanism for manage env.
::
:: Ver. 0.01a 09/08/2014
:: - Initial version + some fixes
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@echo off
:: Multithread dispatcher
if "%~1" neq "" goto %1
setlocal EnableDelayedExpansion
:: Initialize some stuff...
call :Init
:: Load the Map grid. 1/2=wall ./0=empty 9=player position
Set /A MapsizeX=33, MapsizeY=10, y=1, MapWidth=MapsizeX+1, MapsizeX-=1
for %%D in (
"1212121212...2121212121.........."
"2........1...1........2..121....."
"1........21212....121.1.2...2...."
"2..................1..21.....1..."
"1...9.........................2.."
"2....1...12121................2.."
"1....2...2...2.....1..11.....1..."
"1....1...1...1....12..2.2...2...."
"2....2...2...2........1..121....."
"1212212121...1212121212.........."
) do (
set Map[!y!]=%%~D
for %%Y in (!y!) do for /L %%X in (0,1,!MapSizeX!) do (
if "!Map[%%Y]:~%%X,1!" equ "9" (
set /A nx=%%X+1
for %%Z in (!nx!) do set Map[!y!]=!Map[%%Y]:~0,%%X!.!Map[%%Y]:~%%Z!
set /A Playerx = %%X, Playery = !y!
set nx=
)
)
set /A y+=1
)
set y=
:: setting player position
set /A Playerx*=MulPlayer, Playery*=MulPlayer, OldPlayerx=Playerx, OldPlayery=Playery
:: prepare map for draw
call :prepareMap
:: Prepare for multithread engines
call :InitEngines
"%COMSPEC%" /d /v:on /c "%~f0" :mainLoop
exit /b
:mainLoop
for /l %%. in () do (
set /a gridX=Playerx/MulPlayer, gridy=Playery/MulPlayer
for %%X in (!gridx!) do for %%Y in (!gridy!) do if "!Map[%%Y]:~%%X,1!" geq "1" (
set /A Playerx = OldPlayerx, Playery = OldPlayery
set /P ".=%BEL%"<nul
) else (
set /A "StepY=%SIN(x):x=!Angle! * PI / 180%, StepX=%SIN(x):x=PI_div_2-!Angle! * PI / 180%"
call :raycast
%= Draw Map =%
if "!SeeMap!" equ "1" (
set /a "pos=(PlayerY/MulPlayer-1)*mapWidth+PlayerX/MulPlayer, pos2=pos+1"
for /f "tokens=1-3" %%1 in ("!pos! !pos2! !Angle!") do echo !map:~0,%%1!!P%%3!!map:~%%2,-1!
set pos=&set pos2=
)
echo PlayerX/Y:!Playerx!/!Playery! OldplayerX/Y:!oldplayerX!/!oldplayerY!%space%& rem FastRotate=!Fastrotate!
echo !method!: Angle:!Angle! GridX/Y:!gridx!/!gridy! StepX/Y=!StepX!/!StepY! wait=!wait!%space%
set /A OldPlayerx = Playerx, OldPlayery = Playery
)
call :choice wksladhmfzqu >nul
rem "%COMSPEC%\..\choice.exe" /N /C wksladhmfzqu >nul
if errorlevel 12 (
%= U - Redraw =%
(call )
) else if errorlevel 11 (
%= Q - Quit =%
for /l %%N in (1 1 !childCnt!) do >"%base%%%N_job.bat.tmp" echo del "%%~f0"^&exit
ren "%base%*_job.bat.tmp" *.
for /l %%. in () do if not exist "%base%*_job.bat" del "%base%*.render"&exit
) else if errorlevel 10 (
%= Z - Toggle oldSys =%
set /a "oldSys=^!oldSys"
if !oldSys!==0 (set "method=FAST") else set "method=SLOW"
) else if errorlevel 9 (
%= F - Toggle Fastrotate =%
set /a "fastRotate=^!fastrotate"
) else if errorlevel 8 (
%= M - Toggle Map =%
set /a "SeeMap=^!SeeMap"
if "!SeeMap!" equ "0" cls
) else if errorlevel 7 (
%= H - Help =%
call :Help
) else if errorlevel 6 (
%= D - Right =%
set /A "PlayerX-=StepY/2, PlayerY+=StepX/2"
) else if errorlevel 5 (
%= A - Left =%
set /A "PlayerX+=StepY/2, PlayerY-=StepX/2"
) else if errorlevel 4 (
%= L - Rotate Right =%
set /A "Angle=(Angle+15+360) %% 360" & set Rotate=Right
) else if errorlevel 3 (
%= S - Down - Backward =%
set /A "PlayerX-=StepX/2, PlayerY-=StepY/2"
) else if errorlevel 2 (
%= K - Rotate Left =%
set /A "Angle=(Angle-15+360) %% 360" & set Rotate=Left
) else if errorlevel 1 (
%= W - Up - Forward =%
set /A "PlayerX+=StepX/1, PlayerY+=StepY/1"
)
)
:raycast
:: Save start time
set "t1=!time: =0!"
:: Create Jobs
set/A from=Angle-32, to=Angle+32, chunk=65/proc, end=from+chunk-1
for /l %%N in (1 1 %childCnt%) do (
>"%base%%%N_job.bat.tmp" echo set /a "from=!from!, to=!end!, Angle=!Angle!, playerX=!playerX!, playerY=!playerY!"
set /a from+=chunk, end+=chunk
ren "%base%%%N_job.bat.tmp" *.
)
:computeEngine
setlocal & ( %= For Empty Environment =%
%= Empty Environment =%
for %%v in (MaxIter1 MaxIter2 Mul1 MulPlayer base file files childCnt comspec
Angle MapSizeX MapSizeY MapWidth BEL OldPlayerX OldPlayerY TMP MM M10
cls Number_of_Processors pathext proc seemap space t1 turbo wait pathext end
formx formy grix gridy mul mulx muly chunk fastrotate dis files
P345 P0 P15 P30 P45 P60 P75 P90 P105 P120 P135 P150 P165 P180 P195 method
P210 P225 P240 P255 P270 P285 P300 P315 P330 PI PI32 PIx2 PI_div_2 SIN(x^) prompt
GridX GridY LF MAP StepX StepY oldSys
) do set "%%v="
rem (set&pause)>con
%computeEngineBegin%
>"%file%" (
for /L %%Z in (!from!,1,!to!) do (
set /A "Z=%%Z, aStepY=%SIN(x):x=Z * 31416 / 180%"
set /A "aStepX=%SIN(x):x=15708-(Z * 31416 / 180)%"
set/A "A=%Angle%, corr=%SIN(x):x=15708-(Z-A) * 31416 / 180%"
if "%oldSys%"=="1" (
set "BREAK="
set /A DistanceCount=%MaxIter1%, ax =PlayerX*%Mul1%, ay = PlayerY*%Mul1%
%= Precompute how mulX/Y has to be computed =%
if !aStepX! equ 0 (
set "formX=set mul=%MaxIter1%"
set mulX=%MaxIter1%
) else if !aStepX! GTR 0 (
set "formX=set /a mulX=(aStepX+%MM%-(ax %% %MM%))/aStepX, mul=mulX"
) else if !aStepX! LSS 0 (
set "formX=set /a mulX=-(ax %% %MM%)/aStepX+1, mul=mulX"
)
if !aStepY! equ 0 (
set "formY="
set mulY=%MaxIter1%
) else if !aStepY! GTR 0 (
set "formY=set /a mulY=(aStepY+%MM%-(ay %% %MM%))/aStepY"
) else if !aStepY! LSS 0 (
set "formY=set /a mulY=-(ay %% %MM%)/aStepY+1"
)
set dis=0
for /L %%? in (1,1,20) do if not defined BREAK (
!formX!
!formY!
if !mulX! GEQ !mulY! set /a mul=mulY
set /a ax+=aStepX*mul, ay+=aStepY*mul,dis+=mul, gridX=ax/%MM%, gridY=ay/%MM%
for /f "tokens=1,2" %%X in ("!gridX! !gridY!") do if "!Map[%%Y]:~%%X,1!" geq "1" set BREAK=true & set /a DistanceCount=dis
)
%= Last Step =%
set "BREAK="
set /A "Zaccumul=DistanceCount*(10000/%Mul1%), ax=(ax-aStepX)*10, ay=(ay-aStepY)*10, DistanceCount=%MaxIter2%"
set dis=0
for /L %%? in (1,1,20) do if not defined BREAK (
if !aStepX! equ 0 (set mulX=90) ELSE if !aStepX! GTR 0 (
set /a "mulX=(aStepX+%M10%-(ax %% %MM%))/aStepX"
) else (
set /a "mulX=((ax %% %M10%))/-aStepX+1"
)
if !aStepY! equ 0 (set mulY=90) ELSE if !aStepY! GTR 0 (
set /a "mulY=(aStepY+%M10%-(ay %% %M10%))/aStepY"
) else (
set /a "mulY=((ay %% %M10%))/-aStepY+1"
)
if !mulX! GEQ !mulY! (set /a mul=mulY) else set mul=!mulX!
set /a ax+=aStepX*mul, ay+=aStepY*mul, dis+=mul, gridX=ax/%M10%, gridY=ay/%M10%
for /f "tokens=1,2" %%X in ("!gridX! !gridY!") do if "!Map[%%Y]:~%%X,1!" geq "1" set BREAK=true & set /a DistanceCount=dis
)
for /f "tokens=1,2" %%X in ("!gridX! !gridY!") do set "C=!Map[%%Y]:~%%X,1!"
set /A "distance=350/((((DistanceCount+Zaccumul)*corr/%Mulplayer%+555)/1000)+1), len=distance*2, st=(50-len)/2"
) else (
set /A $X=%PlayerX%/10000, $Y=%PlayerY%/10000
if !aStepX! equ 0 (
set /A $tx=Dtx=100000000, $SX=0
) else if !aStepX! lss 0 (
set /A "$tx=($X*10000-PlayerX)*10000/aStepX, Dtx=-10000*10000/aStepX, $SX=-1"
) else set /A "$tx=(($X+1)*10000-PlayerX)*10000/aStepX, Dtx=10000*10000/aStepX, $SX=1"
if !aStepY! equ 0 (
set /A $ty=Dty=100000000, $SY=0
) else if !aStepY! lss 0 (
set /A "$ty=($Y*10000-PlayerY)*10000/aStepY, Dty=-10000*10000/aStepY, $SY=-1"
) else set /A "$ty=(($Y+1)*10000-PlayerY)*10000/aStepY, Dty=10000*10000/aStepY, $SY=1"
set "$B=" & set /A "Distance=21*10000"
for /L %%£ in (1,1,3) do if not defined $B for /L %%? in (1,1,7) do if not defined $B (
if !$tx! lss !$ty! (
set /A $tx+=Dtx, $X+=$SX
for /f "tokens=1,2" %%X in ("!$X! !$Y!") do if "!Map[%%Y]:~%%X,1!" geq "1" (
set /A Distance=$tx-Dtx, Side=0, $B=!Map[%%Y]:~%%X,1!
)
) else (
set /A $ty+=Dty, $Y+=$SY
for /f "tokens=1,2" %%X in ("!$X! !$Y!") do if "!Map[%%Y]:~%%X,1!" geq "1" (
set /A Distance=$ty-Dty, Side=1, $B=!Map[%%Y]:~%%X,1!
)
)
)
if not defined $B set "$B=1"
set /A "distance=350/((((k=(Distance*corr))/%Mulplayer%+555)/1000)+1), len=distance*2, st=(50-len)/2"
set /A C=$B
)
%= 2D-clipping =%
if !st! lss 1 (set st=1) else if !st! gtr 50 set st=50
for /f "tokens=1,2" %%X in ("!st! !len!") do (
if !C! equ 1 (
echo -!S_:~0,%%X!°±²Û²±°!SS:~0,%%Y!°±²Û²±°!SP:~0,%%X!-
) else (
echo -!S_:~0,%%X!°±²Û²±°!S2:~0,%%Y!°±²Û²±°!SP:~0,%%X!-
)
)
set C=&set Distance=&set len=&set st=&set ZAccumul=
)
)
%computeEngineEnd%
) & endlocal %= For Empty Environment =%
set /a wait=0
:waitForJobCompletion
if exist "%base%*_job.bat" (
set /a wait+=1
goto :waitForJobCompletion
)
:: Transpose and display results
setlocal
set /A LineN=0
for /f usebackq^ delims^=^ eol^= %%A in (%files%) do (
set /A LineN+=1
set "N!LineN!=%%A"
)
set "transposedLine="
for /L %%m in (1, 1, !LineN!) do set "transposedLine=!transposedLine!^!N%%m:~%%n,1^!"
set/A MaxN=65
%cls%
echo(
for /L %%n in (0, 1, !LineN!) do echo( ^|%transposedLine%^|
endlocal
:: Compute and display rendering time
for /F "tokens=1-8 delims=:.," %%a in ("!t1!:!time: =0!") do set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31)&8640000, FPS=10000/a"
Title Raycast Dos Batch - Press H for help - Time Elapsed:!a!0ms - FPS: !FPS:~0,-2!.!FPS:~-2!
set a=&set t1=
exit /b
:choice
setlocal EnableDelayedExpansion
set "c=" &set "e=" &set "map=%~1"
if not defined map endlocal &exit /b 0
for /f "delims=" %%i in ('2^>nul %COMSPEC%\..\xcopy /lw "%~f0" "%~f0"') do if not defined c set "c=%%i"
set "c=%c:~-1%"
if defined c (
For /L %%i in (0,1,127) do (
set "e=!map:~%%i,1!"
if not defined e endlocal &<nul set /p "=%BEL%" >CON&exit /b 0
if /i "!e!"=="!c!" (
echo(!c!
set /A n=%%i+1
for /f %%j in ("!n!") do endlocal &exit /b %%j
)
)
)
endlocal &<nul set /p "=%BEL%" >CON &goto choice
exit /b
:prepareMap
set ^"LF=^
^" The above empty line is critical - DO NOT REMOVE
set "map="
for /L %%Y in (1,1,!MapsizeY!) do (
for /L %%X in (0,1,!MapsizeX!) do (
if "!Map[%%Y]:~%%X,1!" geq "1" (
set "map=!map!Û"
) else (
set "map=!map! "
)
)
set "map=!map!!LF!"
)
exit /b
:Help
cls
echo(
echo For best view use raster font 8x8 or 16x8.
echo(
echo Use keyboard:
echo(
echo WASD for move
echo KL for turn/rotate.
echo Z for old rendering system.
echo U for redraw
echo M for view map ON/OFF
echo F for Fastrotate ON/OFF (Not implemented)
echo Q for quit
echo H for Help
echo(
pause
exit /b
:InitEngines
:: Initialize and launch compute engines
set "base=%tmp%\%~nx0"
2>nul del "%base%*_job.bat"
set ^"computeEngineBegin=for /l %%. in () do if exist "^!job^!" ( call "^!job^!"^"
set ^"computeEngineEnd=del "^!job^!")^"
rem disabling parallel processing :
rem see http://www.dostips.com/forum/viewtopic.php?f=3&t=7053
rem set /a proc=NUMBER_OF_PROCESSORS, childCnt=proc-1
set /a proc=1, childCnt=proc-1
if %proc% gtr 8 set /a proc=8
for /l %%N in (1 1 !childCnt!) do (
set "file=%base%%%N.render"
set "job=%base%%%N_job.bat"
>nul 2>nul <nul start "" /b "%comspec%" /d /v:on /c "%~f0" :computeEngine
)
set "file=%base%!proc!.render"
set "files="
for /l %%N in (1 1 !proc!) do set files=!files! "%base%%%N.render"
set "computeEngineBegin="
set "computeEngineEnd="
exit/b
:Init
Title Raycast Dos Batch - Loading...
mode 69,80
color 0F
cls
:: capture del BEL char
for /f %%i in ('forfiles /m "%~nx0" /c "cmd /c echo 0x07"') do set "BEL=%%i"
:: empty environment
set "preserve= TMP BEL COMSPEC NUMBER_OF_PROCESSORS preserve "
for /f "delims==" %%v in ('set') do if "!preserve: %%v =!" equ "!preserve!" set "%%v="
set "preserve="
:: Setting output char
set "SS=°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°"
set "S_=úúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúú"
set "S2=±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±"
set "SP=__________________________"
set "SC=///////////////////////////////////////////////////"
:: Trigonometric variables
set /a "PI=(35500000/113+5)/10, PI_div_2=(35500000/113/2+5)/10, PIx2=2*PI, PI32=PI+PI_div_2"
set "SIN=(a - a*a/1920*a/312500 + a*a/1920*a/15625*a/15625*a/2560000 - a*a/1875*a/15360*a/15625*a/15625*a/16000*a/44800000)"
set "SIN(x)=(a=(x)%%62832, c=(a>>31|1)*a, a-=(((c-47125)>>31)+1)*((a>>31|1)*62832) + (-((c-47125)>>31))*( (((c-15709)>>31)+1)*(-(a>>31|1)*31416+2*a) ), %SIN%)"
set SIN=
:: Define player characters:
for %%# in (
"345 0 15 >"
" 30 45 60 \"
" 75 90 105 v"
"120 135 150 /"
"165 180 195 <"
"210 225 240 \"
"255 270 285 ^"
"300 315 330 /"
) do for /f "tokens=1-4" %%A in (%%#) do (
set "P%%A=%%D"
set "P%%B=%%D"
set "P%%C=%%D"
)
set /A MulPlayer=10000, Mul1=25, MaxIter1=500, MaxIter2=50, MM=MulPlayer*Mul1, M10=MM*10
set /A Angle=0, oldSys=0, FastRotate=0, SeeMap=1
:: Define some screen management variables and macros
if exist "%~dp0CursorPos.exe" (
set "cls=CursorPos 0 0"
) else (
set "cls=cls"
)
set "method=FAST"
set "space= "
exit /b
5/7/2015 - Edit: For older version (ver 0.1) look viewtopic.php?p=41919#p41919
-------------------------------------------------------------
Original post
Hi to all,
It was a long time that I wanted to make something interactive 3D. This is my initial attempt. It's a porting from an c++ application. The beta is not interactive for now...
IT's a 3d graphics engine that allows you to perform various types of applications. Not just games.
The goal is to be able to make it fast enough, and possibly that work on multiple cores.
I hope in the help of everyone.
Soon I will comment the code, and if there are any questions I am available!
Use font raster 16x8
version 0.01b:
Code: Select all
::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Explorer3D by Francesco Poscetti aka einstein1969
::
:: Version 0.01b BETA
::
:: 10/8/2014 Added temporary dir and use swapout mechanism for manage env.
::
:: Version 0.01a BETA
::
:: 9/8/2014 initial version + some fixes
::
:: Developed on monocore seven 32bit system.
::
:: This type of Engine 3D is used by Wolfentein 3D,
:: Rise Of The Triad, DOOM, Duke Nukem 3D, etc.
::
:: Thanks to Antonio Acini, penpen, foxidrive
::
::::::::::::::::::::::::::::::::::::::::::::::::::::
:: integer variables = UPPERCASE , fixed point variables = lowercase/Mixed
:: Use fonts raster 16x8
@echo off
setlocal EnableDelayedExpansion
for /f "delims==" %%v in ('set') do if /I not "%%v" == "ComSpec" if /I not "%%v" == "USERPROFILE" if /I not "%%v" == "PATH" if /I not "%%v" == "TMP" set %%v=
rem resolution
set /a SCREEN_W=40, SCREEN_H=30+4
(
for /f "delims==" %%v in ('set') do echo Set %%v=
mode %SCREEN_W%,%SCREEN_H%
set /a SCREEN_H=%SCREEN_H%-4
)
rem use a temporary directory
md Explorer3d 2>nul
pushd Explorer3d
del *.$$$.tmp 2>nuls
call :LoadWorld
rem fov=0.66 = 66/100 , real to integer
set /a fov=66*10000/100
rem pi=3.1416
set /a pi=31416
rem stepD=MovSpeed=0.5, RotationSpeed=0.05
set /a MovSpeed=5*10000/10, RotSpeed=5*10000/100
rem init frame/canvas
set /a FRAME.WIDTH=SCREEN_W, FRAME.HEIGHT=SCREEN_H
rem initial state
set /a state.posx=3 * 10000
set /a state.posy=3 * 10000
set /a state.dirx=1 * 10000
set /a state.diry=0 * 10000
set /a state.camx=0 * 10000
set /a "state.camy=fov" & rem already fixed point format!
For /L %%r in (1,1,15) do (
call :RenderScene
set /a state.posx+=state.dirx*movSpeed/10000, state.posy+=state.diry*movSpeed/10000
)
del *.$$$.tmp
popd
exit /b
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:RenderScene
set /a LASTCOL=FRAME.WIDTH-1
rem for each column
For /L %%c in (0,1,!LASTCOL!) do (
title %%c
set /a cameraX=2 * %%c * 10000 / FRAME.WIDTH - 1 * 10000
set /a rayPosX=state.posx, rayPosY=state.posy
rem CHECK cameraX on second line!
set /a rayDirX=state.dirx + state.camx * cameraX / 10000
set /a rayDirY=state.diry + state.camy * cameraX / 10000
rem integer part
set /a MAPX=rayPosX/10000, MAPY=rayPosY/10000
rem ray length
rem set /a "_deltaDistX= 1 * 10000 + (rayDirY*rayDiry)/(rayDirX*rayDirX) * 10000"
rem set /a "_deltaDistY= 1 * 10000 + (rayDirX*rayDirX)/(rayDirY*rayDirY) * 10000"
rem check raydirx ZERO!
set /a "_deltaDistX= 1 * 10000 + (rayDirY*rayDiry)/rayDirX*10000/rayDirX"
rem check raydiry ZERO!
set /a "_deltaDistY= 1 * 10000 + (rayDirX*rayDirX)/rayDirY*10000/rayDirY"
rem CALCOLARE la radice quadrata dei due precedenti. by Antonio Acini
call :sqrt _deltaDistX deltaDistX %%c
call :sqrt _deltaDistY deltaDistY %%c
if !rayDirX! lss 0 (
set /a STEPX=-1
set /a "sideDistX=(rayPosX - MAPX * 10000) * deltaDistX /10000"
) else (
set /a STEPX=1
set /a "sideDistX=(MAPX * 10000 + 1 * 10000 - rayPosX) * deltaDistX /10000"
)
if !rayDirY! lss 0 (
set /a STEPY=-1
set /a "sideDistY=(rayPosY-MAPY * 10000) * deltaDistY /10000"
) else (
set /a STEPY=1
set /a "sideDistY=(MAPY * 10000 + 1 * 10000 - rayPosY) * deltaDistY /10000"
)
rem ray casting
rem implementazione while con massimo "dm" cicli. Trick by Antonio Aacini
set dm=64*2
set break=
for /L %%w in (0,1,!dm!) do if not defined break (
set /a CC=MAPX + MAPY * WORLD.WIDTH
for %%C in ("!CC!") do if not defined WORLD.DATA[%%C] (
set /p "WORLD.DATA[%%C]=" < WORLD.DATA[%%C].$$$.tmp
set /a WD=!WORLD.DATA[%%C]!
) else set /a WD=!WORLD.DATA[%%C]!
if !sideDistX! lss !sideDistY! (
set /a sideDistX += deltaDistX, MAPX += STEPX, SIDE = 0
) else set /a sideDistY += deltaDistY, MAPY += STEPY, SIDE = 1
if !wd! neq 0 set break=TRUE
)
rem ray len.
if !SIDE! == 0 (
rem perpWallDist = fabs((mapX - rayPosX + (1 - stepX) / 2) / rayDirX);
set /a "perpWallDist = (MAPX * 10000 - rayPosX + (1 * 10000 - STEPX * 10000 ) / 2) * 10000 / rayDirX"
) else (
set /a "perpWallDist = (MAPY *10000 - rayPosY + (1 * 10000 - STEPY * 10000 ) / 2) * 10000 / rayDirY"
)
if !perpWallDist! lss 0 set /A perpWallDist=-perpWallDist
set /a "what.distance = perpWallDist"
set /a what.MAPX = MAPX
set /a what.MAPY = MAPY
set /a what.SIDE = SIDE
set /a what.rayDirX = rayDirX
set /a what.rayDirY = rayDirY
rem draw column:
rem per ora un solo tipo di muro
rem type = world.data[what.mapX + what.mapY * world.width];
rem if type =1 then r,g,b=1 ....
rem colh = abs(int(FRAME.HEIGHT / what.distance));
if !what.distance! equ 0 (set /a COLH=FRAME.HEIGHT) else (
set /a "COLH=FRAME.HEIGHT * 10000 / what.distance , COLH=(COLH>>31|1)*COLH"
)
set /a CROPUP=0, CROPDOWN=0, INDEX=0
if !COLH! gtr !FRAME.HEIGHT! (
set /a "index=%%c, cropup = (COLH - FRAME.HEIGHT) / 2, DROPDOWN = CROPUP + 1"
) else set /a "index=%%c + ((FRAME.HEIGHT - COLH) / 2) * FRAME.WIDTH, CROPUP = 0, CROPDOWN = 0"
rem disegna colonna
set /A "LASTC=(COLH - CROPDOWN)-1"
call :color
rem empty column. Si puo' ottimizzare ancora con 0-cropup, lastc-tot e mettere su file come singola stringa.
set I=%%c
set /a TOT=FRAME.HEIGHT-1, TOTM=FRAME.HEIGHT/2-1, TOTM2=TOTM+1
For /L %%i in (0,1,!TOTM!) do (
set FRAME.data[!I!]=ú
set /a I+=FRAME.WIDTH
)
For /L %%i in (!TOTM2!,1,!TOT!) do (
set FRAME.data[!I!]=_
set /a I+=FRAME.WIDTH
)
for /L %%N in (!CROPUP!,1,!LASTC!) do (
For %%C in (!dd!) do set frame.data[!INDEX!]=!g:~%%C,1!
set /a INDEX+=FRAME.WIDTH
)
if 1==0 call :Debug %%c
set /a n=%%c %% 8
if !n! equ 0 call :swapout frame.data[ 0
)
call :swapout frame.data[ 0
::DrawScene
set /a TOT=FRAME.WIDTH*FRAME.HEIGHT
set canvas=
for /L %%C in (0,1,!TOT!) do (
if not defined frame.data[%%C] set /p "frame.data[%%C]=" < frame.data[%%C].$$$.tmp
set canvas=!canvas!!frame.data[%%C]!
set frame.data[%%C]=
)
cls & set/p ".=!canvas!" <nul
rem pause
exit /b
:color
set g=Û²±°/:.....................................................
set /a dd=what.distance /20000
exit /b
:sqrt
set /a number=%1 * 100
set /A iter1=number/2
rem The maximum number of iterations to calculate sqrt of a 32 bits integer number is 20
set "sqrt="
for /L %%i in (1,1,20) do if not defined sqrt (
set /A "iter2=number/iter1, iter1=(iter1+iter2)/2"
if !iter2! geq !iter1! set /A "sqrt=(iter1+iter2)/2"
)
set /a %2= sqrt *10
exit /b
example of world/map
64
64
111111111111111111111111111
1 4 1
1 4 4 4 4 4 4 4 4 4 4 4 4 1
1 1
1 3 22222 4 1
1 2 4 1
1 3 2 44444 4441
1 3 2222222 4 1
1 2 1
1444444444 2 222222221
14 4 2 2 21
14 222 2 44 21
14 4 2 21
1444444444 222222221
111111111111111111111111111
:LoadWorld
echo Creating random map/world.
set /a WORLD.WIDTH=64, WORLD.HEIGHT=64, ww=WORLD.WIDTH-1, wh=WORLD.HEIGHT-1
For /L %%h in (0,1, !wh!) do (
set /p ".=." <nul
For /L %%w in (0,1, !ww!) do (
if !random! gtr 3276 (set F=0) else set F=1
if %%h equ 0 set F=1
if %%h equ !wh! set F=1
if %%w equ 0 set F=1
if %%w equ !wh! set F=1
set /a cc=%%w + %%h * WORLD.WIDTH
rem for %%C in ("!cc!") do if !F! equ 0 (set "WORLD.data[%%C]=0" & set /p ".=_" <nul) else (set "WORLD.data[%%C]=1" & set /p ".=*" <nul)
for %%C in ("!cc!") do if !F! equ 0 (set "WORLD.data[%%C]=0") else set "WORLD.data[%%C]=1"
rem empty env
if !cc! gtr !_! call :swapout WORLD.data[ 400
)
rem echo(
)
call :swapout WORLD.data[ 0
set F=
exit /b
:swapout
( for /f "delims==" %%A in ('2^>nul set %1') do (
>%%A.$$$.tmp echo !%%A!
set "%%A="
)
set /A _+=%2
exit /b )
:debug
echo(
echo DEBUG BreakPpoin Col=%1
set cameraX
set CC
set COLH
set CROPUP
set CROPDOWN
set deltaDistX
set deltaDistY
set fov
set FRAME.HEIGHT
set FRAME.WIDTH
set index
set LASTC
set MAPX
set MAPY
set perpWallDist
set rayDirX
set rayDirY
set rayPosX
set rayPosY
set state.camx
set state.camY
set state.dirx
set state.diry
set state.posx
set state.posy
set sideDistX
set sideDistY
set SIDE
set STEPX
set STEPY
set what.distance
set WD
set _deltaDistX
set _deltaDistY
pause
exit /b
version 0.01a:
Code: Select all
::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Explorer3D by Francesco Poscetti aka einstein1969
::
:: Version 0.01a BETA 9/8/2014
::
:: Developed on monocore seven 32bit system.
::
:: This type of Engine 3D is used by Wolfentein 3D,
:: Rise Of The Triad, DOOM, Duke Nukem 3D, etc.
::
:: Thanks to Antonio Acini, penpen, foxidrive
::
::::::::::::::::::::::::::::::::::::::::::::::::::::
:: integer variables = UPPERCASE , fixed point variables LOWERCASE/Mixed
:: Use font 16x8
@echo off
setlocal EnableDelayedExpansion
for /f "delims==" %%v in ('set') do if /I not "%%v" == "ComSpec" if /I not "%%v" == "USERPROFILE" if /I not "%%v" == "PATH" if /I not "%%v" == "TMP" set %%v=
rem for /f "delims==" %%v in ('set') do echo Set %%v=
rem resolution
set /a SCREEN_W=64, SCREEN_H=84+4
set /a SCREEN_W=40, SCREEN_H=40+4
mode !SCREEN_W!,!SCREEN_H!
set /a SCREEN_H-=4
rem fov=0.66 = 66/100 , real to integer
set /a fov=66*10000/100
rem pi=3.1416
set /a pi=31416
rem stepD=MovSpeed=0.1, RotationSpeed=0.05
set /a MovSpeed=5*10000/10, RotSpeed=5*10000/100
rem init frame/canvas
set /a FRAME.WIDTH=SCREEN_W, FRAME.HEIGHT=SCREEN_H
rem initial state
set /a state.posx=3 * 10000
set /a state.posy=3 * 10000
set /a state.dirx=1 * 10000
set /a state.diry=0
set /a state.camx=0
set /a state.camy=fov
call :LoadWorld
For /L %%r in (1,1,50) do (
call :RenderScene
set /a state.posx+=state.dirx*movSpeed/10000, state.posy+=state.diry*movSpeed/10000
)
exit /b
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:RenderScene
rem empty
title Empty frame buffer ...
set /a TOT=FRAME.WIDTH*FRAME.HEIGHT-1, TOTM=FRAME.WIDTH*FRAME.HEIGHT/2-1, TOTM2=TOTM+1
For /L %%i in (0,1,!TOTM!) do set FRAME.data[%%i]=ú
For /L %%i in (!TOTM2!,1,!TOT!) do set FRAME.data[%%i]=_
set /a LASTCOL=FRAME.WIDTH-1
rem for each column
For /L %%c in (0,1,!LASTCOL!) do (
title %%c
set /a cameraX=2 * %%c * 10000 / FRAME.WIDTH - 1 * 10000
set /a rayPosX=state.posx, rayPosY=state.posy
rem CHECK cameraX on second line!
set /a rayDirX=state.dirx + state.camx * cameraX / 10000
set /a rayDirY=state.diry + state.camy * cameraX / 10000
rem integer part
set /a MAPX=rayPosX/10000, MAPY=rayPosY/10000
rem ray length
rem set /a "_deltaDistX= 1 * 10000 + (rayDirY*rayDiry)/(rayDirX*rayDirX) * 10000"
rem set /a "_deltaDistY= 1 * 10000 + (rayDirX*rayDirX)/(rayDirY*rayDirY) * 10000"
set /a "_deltaDistX= 1 * 10000 + (rayDirY*rayDiry)/rayDirX*10000/rayDirX"
set /a "_deltaDistY= 1 * 10000 + (rayDirX*rayDirX)/rayDirY*10000/rayDirY"
rem CALCOLARE la radice quadrata dei due precedenti.
set /a number=_deltaDistX * 100
set /A iter1=number/2
rem The maximum number of iterations to calculate sqrt of a 32 bits integer number is 20
set "sqrt="
for /L %%i in (1,1,20) do if not defined sqrt (
set /A "iter2=number/iter1, iter1=(iter1+iter2)/2"
if !iter2! geq !iter1! set /A "sqrt=(iter1+iter2)/2"
)
set /a deltaDistX= sqrt * 10
call :sqrt _deltaDistY deltaDistY %%c
rem echo .
if !rayDirX! lss 0 (
set /a STEPX=-1
set /a "sideDistX=(rayPosX - MAPX * 10000) * deltaDistX /10000"
) else (
set /a STEPX=1
set /a "sideDistX=(MAPX * 10000 + 1 * 10000 - rayPosX) * deltaDistX /10000"
)
rem echo ..
if !rayDirY! lss 0 (
set /a STEPY=-1
set /a "sideDistY=(rayPosY-MAPY * 10000) * deltaDistY /10000"
) else (
set /a STEPY=1
set /a "sideDistY=(MAPY * 10000 + 1 * 10000 - rayPosY) * deltaDistY /10000"
)
rem echo .._
rem ray casting
set /a CC=MAPX + MAPY * WORLD.WIDTH
for %%C in ("!CC!") do set /a WD=!world.data[%%C]!
rem echo ...
rem implementazione while con massimo "dm" cicli
set dm=64*2
set break=
for /L %%w in (0,1,!dm!) do if not defined break (
rem echo inner: !wd! %%w
if !sideDistX! lss !sideDistY! (
set /a sideDistX += deltaDistX, MAPX += STEPX, SIDE = 0
) else set /a sideDistY += deltaDistY, MAPY += STEPY, SIDE = 1
set /a cc=MAPX + MAPY * WORLD.WIDTH
for %%C in ("!cc!") do set /a wd=!world.data[%%C]!
if !wd! neq 0 set break=TRUE
)
rem ray len. CALCOLARE FABS=float abs
if !SIDE! == 0 (
rem perpWallDist = fabs((mapX - rayPosX + (1 - stepX) / 2) / rayDirX);
set /a "perpWallDist = (MAPX * 10000 - rayPosX + (1 * 10000 - STEPX * 10000 ) / 2) * 10000 / rayDirX"
) else (
set /a "perpWallDist = (MAPY *10000 - rayPosY + (1 * 10000 - STEPY * 10000 ) / 2) * 10000 / rayDirY"
)
if !perpWallDist! lss 0 set /A perpWallDist=-perpWallDist
set /a "what.distance = perpWallDist"
set /a what.MAPX = MAPX
set /a what.MAPY = MAPY
set /a what.SIDE = SIDE
set /a what.rayDirX = rayDirX
set /a what.rayDirY = rayDirY
rem echo ....
rem disegna la colonna:
rem per ora un solo tipo di muro
rem type = world.data[what.mapX + what.mapY * world.width];
rem if type =1 then r,g,b=1 ....
rem colh = abs(int(FRAME.HEIGHT / what.distance));
if !what.distance! equ 0 (set /a COLH=FRAME.HEIGHT) else (
set /a "COLH=FRAME.HEIGHT * 10000 / what.distance , COLH=(COLH>>31|1)*COLH"
)
set /a CROPUP=0, CROPDOWN=0, INDEX=0
if !COLH! gtr !FRAME.HEIGHT! (
set /a "index=%%c, cropup = (COLH - FRAME.HEIGHT) / 2, DROPDOWN = CROPUP + 1"
) else set /a "index=%%c + ((FRAME.HEIGHT - COLH) / 2) * FRAME.WIDTH, CROPUP = 0, CROPDOWN = 0"
rem disegna colonna
set /A "LASTC=(COLH - CROPDOWN)-1"
rem echo .....
call :color
for /L %%N in (!CROPUP!,1,!LASTC!) do (
For %%C in (!dd!) do set frame.data[!INDEX!]=!g:~%%C,1!
set /a INDEX+=FRAME.WIDTH
)
if 1==0 (
echo(
echo DEBUG BP Col=%%c
set cameraX
set CC
set COLH
set CROPUP
set CROPDOWN
set deltaDistX
set deltaDistY
set fov
set FRAME.HEIGHT
set FRAME.WIDTH
set index
set LASTC
set MAPX
set MAPY
set perpWallDist
set rayDirX
set rayDirY
set rayPosX
set rayPosY
set state.camx
set state.camY
set state.dirx
set state.diry
set state.posx
set state.posy
set sideDistX
set sideDistY
set SIDE
set STEPX
set STEPY
set what.distance
set WD
set _deltaDistX
set _deltaDistY
pause
)
)
::DrawScene
set /a TOT=FRAME.WIDTH*FRAME.HEIGHT
set canvas=
for /L %%C in (0,1,!TOT!) do set canvas=!canvas!!frame.data[%%C]!
cls & set/p ".=!canvas!" <nul
rem pause
exit /b
:color
set g=Û²±°/:.....................................................
set /a dd=what.distance /20000
exit /b
:sqrt
set /a number=%1 * 100
set /A iter1=number/2
if %3 equ 999 (
echo set /a number=%1 * 10000
echo set /A iter1=number/2
echo %1=!%1! number=!number! iter1=!iter1!
pause
)
rem The maximum number of iterations to calculate sqrt of a 32 bits integer number is 20
set "sqrt="
for /L %%i in (1,1,20) do if not defined sqrt (
set /A "iter2=number/iter1, iter1=(iter1+iter2)/2"
if !iter2! geq !iter1! set /A "sqrt=(iter1+iter2)/2"
if %3 equ 999 (
echo set /A "iter2=number/iter1, iter1=(iter1+iter2)/2"
echo if !iter2! geq !iter1! set /A "sqrt=(iter1+iter2)/2"
echo iter1=!iter1! iter2=!iter2! number=!number! sqrt=!sqrt!
pause
)
)
set /a %2= sqrt *10
exit /b
64
64
111111111111111111111111111
1 4 1
1 4 4 4 4 4 4 4 4 4 4 4 4 1
1 1
1 3 22222 4 1
1 2 4 1
1 3 2 44444 4441
1 3 2222222 4 1
1 2 1
1444444444 2 222222221
14 4 2 2 21
14 222 2 44 21
14 4 2 21
1444444444 222222221
111111111111111111111111111
:LoadWorld
echo Creating random map/world...
set /a WORLD.WIDTH=64, WORLD.HEIGHT=64, ww=WORLD.WIDTH-1, wh=WORLD.HEIGHT-1
For /L %%h in (0,1, !wh!) do (
For /L %%w in (0,1, !ww!) do (
if !random! gtr 3276 (set F=0) else set F=1
if %%h equ 0 set F=1
if %%h equ !wh! set F=1
if %%w equ 0 set F=1
if %%w equ !wh! set F=1
set /a cc=%%w + %%h * WORLD.WIDTH
rem for %%C in ("!cc!") do if !F! equ 0 (set "WORLD.data[%%C]=0" & set /p ".=_" <nul) else (set "WORLD.data[%%C]=1" & set /p ".=*" <nul)
for %%C in ("!cc!") do if !F! equ 0 (set "WORLD.data[%%C]=0") else set "WORLD.data[%%C]=1"
)
rem echo(
)
set F=
exit /b
EDIT 20/08/2015 changed Subject.
einstein1969