Here is a minor release that optionally uses Aacini's CurosorPos.exe to reposition the cursor to the top left corner without clearing the screen. This eliminates screen flicker
The code to generate CursorPos.exe is available at
viewtopic.php?p=32300#p32300.
The ray cast demo continues to work as before (with screen flicker) if CursorPos.exe is not present. But if it does exist in the same folder as the ray cast script, then it will be used to eliminate flicker.
I also tested on my son's gaming PC with 16 cores and a solid state hard drive. ( pretty sweet
). Excessive child processes actually slowed the program down. I crudely determined that 8 is a good maximum number of processes, and modified the code accordingly. I managed to get 6-8 frames per second with 8 total processes
version 0.4.1
Code: Select all
:::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Dos Batch Raycast BETA by Francesco Poscetti aka einstein1969
::
:: This type of Engine 3D is used by Wolfentein 3D,
:: Rise Of The Triad, DOOM, Duke Nukem 3D, etc.
::
:: Ref: http://www.dostips.com/forum/viewtopic.php?f=3&t=5824
::
:: Thanks to Aacini, foxidrive, dbenham, penpen
::
:: Tested on Windows 7
::
:: Changelog
::
:: 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 einstein1969
:: - Not clear the screen until next.
:: - Added moviment on left/right and key "K" "L" for rotate.
:: - Fixed bug on calculate distance
:: - Added partial clipping on Z (Distance)
::
:: ver. 0.1 04/07/2015 einstein1969
:: - 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 einstein1969
:: - Added temporary dir and use swapout mechanism for manage env.
::
:: Ver. 0.01a 09/08/2014 einstein1969
:: - Initial version + some fixes
::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::
@echo off
if "%~1" neq "" goto %1
setlocal EnableDelayedExpansion
mode 80,80
color 0F
cls
echo Loading...
for /f %%i in ('forfiles /m "%~nx0" /c "cmd /c echo 0x07"') do set "BEL=%%i"
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="
set "SS=°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°"
set "SC=/////////////////////////////////////////////////////////////////////////////////////////////"
set "S2=±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±"
set "S_=úúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúú"
set "SP=_____________________________________________________________________________________________"
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 /a y=1, MapsizeX=23, MapsizeY=10, MapWidth=MapSizeX+1, MapsizeX-=1
:: Load the Map grid. 1/2=wall 0=empty 9=player position
for %%D in (
"12121212120002121212121"
"20000000010001000000002"
"10000000021212000012101"
"20000000000000000001002"
"10009000000000000000001"
"20000100012121000000002"
"10000200020002000001001"
"10000100010001000012002"
"20000200020002000000001"
"12122121210001212121212"
) 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!0!Map[%%Y]:~%%Z!
set /A Playerx = %%X, Playery = !y!
)
)
set /a y+=1
)
set nx=
set y=
set /a MulPlayer=10000, Mul1=25, MaxIter1=500, MaxIter2=50, MM=MulPlayer*Mul1, M10=MM*10
set /a Playerx*=MulPlayer, Playery*=MulPlayer, OldPlayerx=Playerx, OldPlayery=Playery, angle1=0, oldSys=0
:: Initialize and launch child 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^!")^"
set /a proc=NUMBER_OF_PROCESSORS, 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
)
:: Initialize main compute engine
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="
:: Prepare the map for display
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!"
)
:: 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"
)
:: 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= "
:: Launch the main loop
"%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 (
call :Sin_Cos_Cos "!angle1! * PI / 180" StepY StepX dummy dummy
set /a "angle1=(angle1+360)%%360"
call :raycast
%= Draw Map =%
set /a "pos=(PlayerY/MulPlayer-1)*mapWidth+PlayerX/MulPlayer, pos2=pos+1"
for /f "tokens=1-3" %%1 in ("!pos! !pos2! !angle1!") do echo !map:~0,%%1!!P%%3!!map:~%%2,-1!
echo Playerx:!Playerx! Playery:!playery! oldplayerx:!oldplayerx! oldplayery=!oldplayery!%space%
echo !method!: Angle1:!angle1! gridx:!gridx! gridy:!gridy! StepX=!StepX! StepY=!StepY! wait=!wait!%space%
set /A OldPlayerx=Playerx, OldPlayery=Playery
)
"%COMSPEC%\..\choice.exe" /N /C wksladzqu >nul
if errorlevel 9 (
%= U - Redraw =%
(call )
) else if errorlevel 8 (
%= 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 7 (
%= Z - Toggle oldSys =%
set /a "oldSys=^!oldSys"
if !oldSys!==0 (set "method=FAST") else set "method=SLOW"
) else if errorlevel 6 (
%= D - Right =%
set /A "PlayerX=PlayerX-StepY/2, PlayerY=PlayerY+StepX/2"
) else if errorlevel 5 (
%= A - Left =%
set /A "PlayerX=PlayerX+StepY/2, PlayerY=PlayerY-StepX/2"
) else if errorlevel 4 (
%= L - Rotate Right =%
set /A angle1+=15
) else if errorlevel 3 (
%= S - Down - Backward =%
set /A "PlayerX=PlayerX-StepX/2, PlayerY=PlayerY-StepY/2"
) else if errorlevel 2 (
%= K - Rotate Left =%
set /A angle1-=15
) else if errorlevel 1 (
%= W - Up - Forward =%
set /A "PlayerX=PlayerX+StepX/2, PlayerY=PlayerY+StepY/2"
)
)
:raycast
:: Save start time
set "t1=!time: =0!"
:: Create jobs
set /a from=angle1-32, to=angle1+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!, angle1=!angle1!, playerX=!playerX!, playerY=!playerY!"
set /a from+=chunk, end+=chunk
ren "%base%%%N_job.bat.tmp" *.
)
setlocal
:computeEngine
%computeEngineBegin%
>"%file%" (
for /L %%Z in (!from!,1,!to!) do (
%= Sin_Cos inline for speed =%
(
setlocal
set "p1=%%Z * PI / 180"
set "p4=((%%Z-Angle1) * PI / 180)"
set /a "a=(!p1!) %% %PIx2%, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*%PIx2%, c=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*%PI%-a, c=%SIN%"
) else set /a "c=%SIN%"
set /a "a=(%PI_div_2%-!p1!) %% %PIx2%, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*%PIx2%, d=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*%PI%-a, d=%SIN%"
) else set /a "d=%SIN%"
set /a "a=(%PI_div_2%-!p4!) %% %PIx2%, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*%PIx2%, b=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*%PI%-a, b=%SIN%"
) else set /a "b=%SIN%"
for /F "tokens=1,2,3" %%A in ("!c! !d! !b!") do (
endlocal
set /a "aStepY=%%A, aStepX=%%B, corr=%%C"
)
)
%= 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 /a ax=PlayerX*%Mul1%, ay=PlayerY*%Mul1%
set "fir=(!ax!,!ay!)"
set "BREAK="
set /A Distancecount=%MaxIter1%
if "%oldSys%"=="1" (
for /L %%? in (1,1,%MaxIter1%) do if not defined BREAK (
set /A ax=ax+aStepX, ay=ay+aStepY, gridX=ax/%MulPlayer%/%Mul1%, gridY=ay/%MulPlayer%/%Mul1%
for /f "tokens=1,2" %%X in ("!gridX! !gridY!") do if "!Map[%%Y]:~%%X,1!" geq "1" set BREAK=true & set /a DistanceCount=%%?
)
) else (
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
set /a 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 "accumul=DistanceCount*(10000/%Mul1%), ax=(ax-aStepX)*10, ay=(ay-aStepY)*10, Distancecount=%MaxIter2%"
if "%oldSys%"=="1" (
for /L %%? in (1,1,%MaxIter2%) do if not defined BREAK (
set /A ax=ax+aStepX, ay=ay+aStepY, 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=%%?
)
) else (
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 /a 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+accumul)*corr/%Mulplayer%+555)/1000)+1), len=distance*2, st=(50-len)/2"
%= 2D-clipping =%
if !st! lss 1 set st=1
if !st! gtr 50 set st=50
for /f "tokens=1,2" %%X in ("!st! !len!") do (
if !C! equ 1 (
if !st! gtr 23 (
echo -!S_:~0,%%X!úúúúúúú!S_:~0,%%Y!_______!SP:~0,%%X!-
) else (
echo -!S_:~0,%%X!°±²Û²±°!SS:~0,%%Y!°±²Û²±°!SP:~0,%%X!-
)
) else if !st! gtr 23 (
echo -!S_:~0,%%X!úúúúúúú!S_:~0,%%Y!_______!SP:~0,%%X!-
) else (
echo -!S_:~0,%%X!°±²Û²±°!S2:~0,%%Y!°±²Û²±°!SP:~0,%%X!-
)
)
)
)
%computeEngineEnd%
endlocal
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 /a "MaxN=LineN-1"
set "transposedLine="
for /l %%m in (1, 1, !LineN!) do set "transposedLine=!transposedLine!^!%%^A%%m:~%%n,1^!"
set /a MaxN=65
%cls%
for %%A in (N) do for /L %%n in (0, 1, !MaxN!) do echo(^|%transposedLine%^| %%n
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"
echo Time Elapsed:!a!0ms%space%
exit /b
:Sin_Cos_Cos rad*10000 return_var*10000 rem RADIANT
setlocal
set /a "a=(%~1) %% PIx2, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*PIx2, c=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*PI-a, c=%SIN%"
) else set /a "c=%SIN%"
set /a "a=(PI_div_2-%~1) %% PIx2, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*PIx2, d=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*PI-a, d=%SIN%"
) else set /a "d=%SIN%"
set /a "a=(PI_div_2-%4) %% PIx2, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*PIx2, b=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*PI-a, b=%SIN%"
) else set /a "b=%SIN%"
endlocal & set /a "%2=%c%, %3=%d%, %5=%b%"
exit /b
I also tried implementing einstein1969's idea for fast rotation in his version 0.3.5. I managed to do both left and right rotation by using SET /P in a FOR /L loop to read the correct number of lines. I successfully integrated the fast rotation with parallel processing. It did nearly double the speed of rotation, but I am disappointed with the result. The raycast result for a given angle is dependent on the angle of the player. So when 3/4 of the rendering from the prior player angle is preserved for the new player angle, it distorts the image. I think this idea would be a dead end anyway if we ever add multiple moving objects on the play field. Even though I think this idea should be dropped, here is the code, in case anyone wants to see how I implemented it.
version 0.4.1.a (this branch should die)
Code: Select all
:::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Dos Batch Raycast BETA by Francesco Poscetti aka einstein1969
::
:: This type of Engine 3D is used by Wolfentein 3D,
:: Rise Of The Triad, DOOM, Duke Nukem 3D, etc.
::
:: Ref: http://www.dostips.com/forum/viewtopic.php?f=3&t=5824
::
:: Thanks to Aacini, foxidrive, dbenham, penpen
::
:: Tested on Windows 7
::
:: Changelog
::
:: ver. 0.4.1.a 2015-08-30 dbenham
:: - Implemented fast rotation similar to what einstein1969 used in version 0.3.5
:: Successfully implemented both left and right rotation. It doubles the speed
:: of rotation, but I don't like it because it distorts the image. The problem
:: is a raycast rendering for a given angle is dependent on the player angle,
:: so preserving a portion of a prior rendering distorts the image. I think this
:: code branch should die. Also, fast rotation will not work if there are other
:: moving objects on the playfield besides the player.
::
:: ver. 0.4.1 2015-08-30 dbenham
:: - Limit number of processes to maximum of 8
:: - Moved 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 einstein1969
:: - Not clear the screen until next.
:: - Added moviment on left/right and key "K" "L" for rotate.
:: - Fixed bug on calculate distance
:: - Added partial clipping on Z (Distance)
::
:: ver. 0.1 04/07/2015 einstein1969
:: - 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 einstein1969
:: - Added temporary dir and use swapout mechanism for manage env.
::
:: Ver. 0.01a 09/08/2014 einstein1969
:: - Initial version + some fixes
::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::
@echo off
if "%~1" neq "" goto %1
setlocal EnableDelayedExpansion
mode 80,80
color 0F
cls
echo Loading...
for /f %%i in ('forfiles /m "%~nx0" /c "cmd /c echo 0x07"') do set "BEL=%%i"
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="
set "SS=°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°"
set "SC=/////////////////////////////////////////////////////////////////////////////////////////////"
set "S2=±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±"
set "S_=úúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúú"
set "SP=_____________________________________________________________________________________________"
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 /a y=1, MapsizeX=23, MapsizeY=10, MapWidth=MapSizeX+1, MapsizeX-=1
:: Load the Map grid. 1/2=wall 0=empty 9=player position
for %%D in (
"12121212120002121212121"
"20000000010001000000002"
"10000000021212000012101"
"20000000000000000001002"
"10009000000000000000001"
"20000100012121000000002"
"10000200020002000001001"
"10000100010001000012002"
"20000200020002000000001"
"12122121210001212121212"
) 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!0!Map[%%Y]:~%%Z!
set /A Playerx = %%X, Playery = !y!
)
)
set /a y+=1
)
set nx=
set y=
set /a MulPlayer=10000, Mul1=25, MaxIter1=500, MaxIter2=50, MM=MulPlayer*Mul1, M10=MM*10
set /a Playerx*=MulPlayer, Playery*=MulPlayer, OldPlayerx=Playerx, OldPlayery=Playery, angle1=0, oldSys=0
:: Initialize and launch child 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^!")^"
set /a proc=NUMBER_OF_PROCESSORS, 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
)
:: Initialize main compute engine
set "file=%base%!proc!.render"
set "right=%base%right.render"
set "left=%base%left.render"
set "tempFile=%base%temp.render"
set files="%left%"
for /l %%N in (1 1 !proc!) do set files=!files! "%base%%%N.render"
set files=!files! "%right%"
set "computeEngineBegin="
set "computeEngineEnd="
:: Prepare the map for display
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!"
)
:: 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"
)
:: 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= "
:: Launch the main loop
"%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 (
call :Sin_Cos_Cos "!angle1! * PI / 180" StepY StepX dummy dummy
set /a "angle1=(angle1+360)%%360"
call :raycast
%= Draw Map =%
set /a "pos=(PlayerY/MulPlayer-1)*mapWidth+PlayerX/MulPlayer, pos2=pos+1"
for /f "tokens=1-3" %%1 in ("!pos! !pos2! !angle1!") do echo !map:~0,%%1!!P%%3!!map:~%%2,-1!
echo Playerx:!Playerx! Playery:!playery! oldplayerx:!oldplayerx! oldplayery=!oldplayery!%space%
echo !method!: Angle1:!angle1! gridx:!gridx! gridy:!gridy! StepX=!StepX! StepY=!StepY! wait=!wait!%space%
set /A OldPlayerx=Playerx, OldPlayery=Playery
)
"%COMSPEC%\..\choice.exe" /N /C wksladzqu >nul
set "rotate="
if errorlevel 9 (
%= U - Redraw =%
(call )
) else if errorlevel 8 (
%= 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 7 (
%= Z - Toggle oldSys =%
set /a "oldSys=^!oldSys"
if !oldSys!==0 (set "method=FAST") else set "method=SLOW"
) else if errorlevel 6 (
%= D - Right =%
set /A "PlayerX=PlayerX-StepY/2, PlayerY=PlayerY+StepX/2"
) else if errorlevel 5 (
%= A - Left =%
set /A "PlayerX=PlayerX+StepY/2, PlayerY=PlayerY-StepX/2"
) else if errorlevel 4 (
%= L - Rotate Right =%
set /A angle1+=15
set "rotate=right"
) else if errorlevel 3 (
%= S - Down - Backward =%
set /A "PlayerX=PlayerX-StepX/2, PlayerY=PlayerY-StepY/2"
) else if errorlevel 2 (
%= K - Rotate Left =%
set /A angle1-=15
set "rotate=left"
) else if errorlevel 1 (
%= W - Up - Forward =%
set /A "PlayerX=PlayerX+StepX/2, PlayerY=PlayerY+StepY/2"
)
)
:raycast
:: Save start time
set "t1=!time: =0!"
:: Create jobs and peserve partial rotation rendering
if defined rotate (
>"%tempFile%" 2>nul type %files%
if !rotate! equ right <"%tempFile%" >"%left%" (
copy nul "%right%" >nul
set /a from=angle1+18, to=angle1+32, chunk=15/proc, end=from+chunk-1
for /l %%N in (1 1 15) do set /p "ln="
for /l %%N in (1 1 50) do set /p "ln="&echo !ln!
) else %= rotate equ left =% <"%tempFile%" >"%right%" (
copy nul "%left%" >nul
set /a from=angle1-32, to=angle1-18, chunk=15/proc, end=from+chunk-1
for /l %%N in (1 1 50) do set /p "ln="&echo !ln!
)
) else (
copy nul "%left%" >nul
copy nul "%right%" >nul
set /a from=angle1-32, to=angle1+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!, angle1=!angle1!, playerX=!playerX!, playerY=!playerY!"
set /a from+=chunk, end+=chunk
ren "%base%%%N_job.bat.tmp" *.
)
setlocal
:computeEngine
%computeEngineBegin%
>"%file%" (
for /L %%Z in (!from!,1,!to!) do (
%= Sin_Cos inline for speed =%
(
setlocal
set "p1=%%Z * PI / 180"
set "p4=((%%Z-Angle1) * PI / 180)"
set /a "a=(!p1!) %% %PIx2%, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*%PIx2%, c=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*%PI%-a, c=%SIN%"
) else set /a "c=%SIN%"
set /a "a=(%PI_div_2%-!p1!) %% %PIx2%, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*%PIx2%, d=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*%PI%-a, d=%SIN%"
) else set /a "d=%SIN%"
set /a "a=(%PI_div_2%-!p4!) %% %PIx2%, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*%PIx2%, b=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*%PI%-a, b=%SIN%"
) else set /a "b=%SIN%"
for /F "tokens=1,2,3" %%A in ("!c! !d! !b!") do (
endlocal
set /a "aStepY=%%A, aStepX=%%B, corr=%%C"
)
)
%= 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 /a ax=PlayerX*%Mul1%, ay=PlayerY*%Mul1%
set "fir=(!ax!,!ay!)"
set "BREAK="
set /A Distancecount=%MaxIter1%
if "%oldSys%"=="1" (
for /L %%? in (1,1,%MaxIter1%) do if not defined BREAK (
set /A ax=ax+aStepX, ay=ay+aStepY, gridX=ax/%MulPlayer%/%Mul1%, gridY=ay/%MulPlayer%/%Mul1%
for /f "tokens=1,2" %%X in ("!gridX! !gridY!") do if "!Map[%%Y]:~%%X,1!" geq "1" set BREAK=true & set /a DistanceCount=%%?
)
) else (
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
set /a 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 "accumul=DistanceCount*(10000/%Mul1%), ax=(ax-aStepX)*10, ay=(ay-aStepY)*10, Distancecount=%MaxIter2%"
if "%oldSys%"=="1" (
for /L %%? in (1,1,%MaxIter2%) do if not defined BREAK (
set /A ax=ax+aStepX, ay=ay+aStepY, 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=%%?
)
) else (
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 /a 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+accumul)*corr/%Mulplayer%+555)/1000)+1), len=distance*2, st=(50-len)/2"
%= 2D-clipping =%
if !st! lss 1 set st=1
if !st! gtr 50 set st=50
for /f "tokens=1,2" %%X in ("!st! !len!") do (
if !C! equ 1 (
if !st! gtr 23 (
echo -!S_:~0,%%X!úúúúúúú!S_:~0,%%Y!_______!SP:~0,%%X!-
) else (
echo -!S_:~0,%%X!°±²Û²±°!SS:~0,%%Y!°±²Û²±°!SP:~0,%%X!-
)
) else if !st! gtr 23 (
echo -!S_:~0,%%X!úúúúúúú!S_:~0,%%Y!_______!SP:~0,%%X!-
) else (
echo -!S_:~0,%%X!°±²Û²±°!S2:~0,%%Y!°±²Û²±°!SP:~0,%%X!-
)
)
)
)
%computeEngineEnd%
endlocal
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 /a "MaxN=LineN-1"
set "transposedLine="
for /l %%m in (1, 1, !LineN!) do set "transposedLine=!transposedLine!^!%%^A%%m:~%%n,1^!"
set /a MaxN=65
%cls%
for %%A in (N) do for /L %%n in (0, 1, !MaxN!) do echo(^|%transposedLine%^| %%n
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"
echo Time Elapsed:!a!0ms%space%
exit /b
:Sin_Cos_Cos rad*10000 return_var*10000 rem RADIANT
setlocal
set /a "a=(%~1) %% PIx2, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*PIx2, c=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*PI-a, c=%SIN%"
) else set /a "c=%SIN%"
set /a "a=(PI_div_2-%~1) %% PIx2, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*PIx2, d=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*PI-a, d=%SIN%"
) else set /a "d=%SIN%"
set /a "a=(PI_div_2-%4) %% PIx2, b=(a>>31|1)*a"
if !b! gtr %PI32% (
set /a "a=a-(a>>31|1)*PIx2, b=%SIN%"
) else if !b! gtr %PI_div_2% (
set /a "a=(a>>31|1)*PI-a, b=%SIN%"
) else set /a "b=%SIN%"
endlocal & set /a "%2=%c%, %3=%d%, %5=%b%"
exit /b
Dave Benham