Dos Batch Raycast - Maze3D/Explorer3D Beta

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Dos Batch Raycast - Explorer3D Beta

#16 Post by einstein1969 » 27 Aug 2015 18:42

Thanks Dave!

This is the pre-release of 0.3.5. This turn only to RIGHT.

Code: Select all

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Dos Batch Raycast ver. 0.3.5 PreBETA  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
::
:: Tested on Windows 7
::
:: Changelog
::
:: ver. 0.3.5   xx/yy/2015
::  - Fast rotate. We get about 3-4 FPS
::  - trick by dbenham: Player "direction of view" on map.
::  - Map more readable.
::
:: 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   919
::  - 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
setlocal

setlocal EnableDelayedExpansion
call :Init

set /A y=1, MapsizeX=33, MapsizeY=10, MapsizeX-=1

rem Load the Map grid. 1/2=wall ./0=empty 9=player position

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!0!Map[%%Y]:~%%Z!
      set /A Playerx = %%X, Playery = !y!
    )
  )
  set /A y+=1
)
  set nx=
  set y=

  set /A MulPlayer=10000
  set /A Playerx*=MulPlayer, Playery*=MulPlayer, OldPlayerx=Playerx, OldPlayery=Playery, angle1=0
 
  call :Sin_Cos_Cos "!angle1! * PI / 180" StepY StepX dummy dummy

:loop

  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 (

    if defined Rotate call :Sin_Cos_Cos "!angle1! * PI / 180" StepY StepX dummy dummy

    rem trick by dbenham
    set /a "angle1=(angle1+360)%%360"

    call :raycast %Rotate%
    call :drawMap

    echo Press H for help.

    rem echo Playerx:!Playerx! Playery:!playery! oldplayerx:!oldplayerx! oldplayery=!oldplayery!
    rem echo Angle1:!angle1! gridx:!gridx! gridy:!gridy! StepX=!StepX! StepY=!StepY!

    set /A OldPlayerx = Playerx, OldPlayery = Playery

  )

  set "Rotate="
  set "oldSys=0"

  rem use 'where choice' for localize choice.exe
  C:\Windows\System32\choice.exe /N /C wksladzuh >nul


  rem "w" UP-FORWARD
  if %errorlevel% == 1 set /A "PlayerX+=StepX / 2, PlayerY+=StepY / 2"

  rem "s" DOWN-BACKWARD
  if %errorlevel% == 3 set /A "PlayerX-=StepX / 2, PlayerY-=StepY / 2"

  rem "k" ROTATE LEFT
  rem if %errorlevel% == 2 set /A angle1-=15 & set Rotate=Left
 
  rem "l" ROTATE RIGHT
  if %errorlevel% == 4 set /A angle1+=15 & set Rotate=Right
 
  rem "a" LEFT
  if %errorlevel% == 5 set /A "PlayerX+=StepY / 2, PlayerY-=StepX / 2"

  rem "d" RIGHT
  if %errorlevel% == 6 set /A "PlayerX-=StepY / 2, PlayerY+=StepX / 2"

  if %errorlevel% == 7 set "oldSys=1"

  if %errorlevel% == 9 call :Help

  goto :loop

goto :eof

:raycast

  echo !time: =0!> "%tmp%\raycast.t1.txt"

  set/A Mul1=25, MaxIter1=500, MaxIter2=50, ti=0, from=angle1-32, to=angle1+32

  set /a MM=%MulPlayer%*%Mul1%
  set /A M10=%MulPlayer%*%Mul1%*10

  if /I "%Rotate%" == "Left"  set /A from=angle1-32, to=angle1-18

  if /I "%Rotate%" == "Right" (
    set /A from=angle1+18, to=angle1+32
    (for /f "skip=15 tokens=*" %%f in (%tmp%\raycast.3D.txt) do echo(%%f)>"%tmp%\raycast.3D_.txt"
  )

  setlocal

 (

  for /L %%Z in (%from%,1,%to%) do (

    set /A ti+=1
    for %%t in (!ti!) do set sts=!sti:~0,%%t!

    title !sts!

        rem     call :Sin_Cos_Cos "%%Z * PI / 180" aStepY aStepX "((%%Z-%Angle1%) * PI / 180)" corr
        REM Sin_Cos_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 "aStepY=%%A"
                set "aStepX=%%B"
                set "corr=%%C"
            )
        )


        REM   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 "BREAK=" & set /A DistanceCount=%MaxIter1%

    if "%oldSys%"=="1" (
        for /L %%? in (1,1,%MaxIter1%) do if not defined BREAK (
            set /A ax+=aStepX, ay+=aStepY, 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 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, 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
            )
        )

    rem if !ti! == 63 set "out=!fir! (!ax!,!ay!) (!gridX!,!gridY!) (!aStepX!,!aStepY!)"
    set /A "accumul=DistanceCount*(10000/%Mul1%)"

    rem Last Step
    set /A "ax = (ax-aStepX)*10, ay = (ay-aStepY)*10"

    set "BREAK=" & set /A DistanceCount=%MaxIter2%

    if "%oldSys%"=="1" (
        for /L %%? in (1,1,%MaxIter2%) do if not defined BREAK (
            set /A ax+=aStepX, 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 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"
                )
                set mul=!mulX!
                if !mulX! GEQ !mulY! (
                    set /a mul=mulY
                )
                set /a ax+=aStepX*mul, ay+=aStepY*mul,dis+=mul
                set /a 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"

    rem 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!-
               rem echo -!S_:~0,%%X!²!SC:~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!-
               rem echo -!S_:~0,%%X!²!S2:~0,%%Y!Û!SP:~0,%%X!-
             )
    )

  )

 )> "%tmp%\raycast.3D.txt"

  endlocal

  if /I "%Rotate%" == "Right" copy /Y "%tmp%\raycast.3D_.txt" /B + "%tmp%\raycast.3D.txt" /B "%tmp%\raycast.3D_.txt" >nul

  rem if /I "%Rotate%" == "Left" copy /A "%tmp%\raycast.3D_.txt" + "%tmp%\raycast.3D.txt" "%tmp%\raycast.3D.txt"

  if defined Rotate copy /Y /B "%tmp%\raycast.3D_.txt" "%tmp%\raycast.3D.txt" >nul

  call :transpose
 
  set /P "t1=" < "%tmp%\raycast.t1.txt"
  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

goto :eof

:transpose

setlocal
 
  set /A LineN=0

:: Load and transpose data
  for /f usebackq^ delims^=^ eol^= %%A in ("%tmp%\raycast.3D.txt") 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^!"

  rem to FIX
  set/A MaxN=65

  cls & for %%A in (N) do for /L %%n in (0, 1, !MaxN!) do echo(^|%transposedLine%^| %%n

endlocal

goto :eof


:drawMap


rem  if not defined Rotate (
(
  for /L %%Y in (1,1,!MapsizeY!) do (
    for /L %%X in (0,1,!MapsizeX!) do (

      if "!Map[%%Y]:~%%X,1!" geq "1" (
        set /p "=Û" <nul
      ) else (
       if !gridX! equ %%X (
          rem trick by dbenham
          if !gridY! equ %%Y (set /p "=!P%angle1%!" <nul) else set /p "=." <nul
        ) else set /p "=." <nul
      )
    )
    echo(
  )

) > "%TMP%\Raycast.Map.txt"

 type "%TMP%\Raycast.Map.txt"
 


goto :eof

:Help
  cls
  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(
  pause
goto :eof

:Init

  mode 80,80
  color 0F
  ping 127.0.0.1 -n 2 >nul 

  cls&echo Loading...

  for /f %%i in ('forfiles /m "%~nx0" /c "cmd /c echo 0x07"') do set BEL=%%i

  for /f "delims==" %%v in ('set') do if /I not "%%v" == "TMP" if /I not "%%v" == "BEL" set %%v=

  rem      0123456789012345678901234567890123456789012345678901234567890123456789
  set "sti=||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
  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)"

rem trick by dbenham
:: 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"
  )


goto :eof

::::::::::::::::::::::::::::::::::: TRIGONOMETRIC FUNCTIONS

: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 "%2=%c%" & set "%3=%d%" & set "%5=%b%")
goto :eof


Einstein1969

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Dos Batch Raycast - Explorer3D Beta

#17 Post by dbenham » 27 Aug 2015 20:13

Interesting. I don't understand why you only allow turn to the right. But it is nice to be able to rotate quickly.

Your :drawMap routine is really slow, and it is quite simple to make it almost instantaneous :!:

Instead of redrawing each character, one by one, you can simply create a string with the entire map once, including newlines at the end of each row. Spaces can then be represented by spaces. First prepare the string without the player. Then to draw the map, you simply echo an appropriate leading substring, the player character, and then the trailing substring. :D

Code: Select all

::  Modified definition of map near top : extra MapWidth variable at top plus call to :prepareMap at bottom ---------------
rem Load the Map grid. 1/2=wall ./0=empty 9=player position
set /A y=1, MapsizeX=33, MapsizeY=10, 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!0!Map[%%Y]:~%%Z!
      set /A Playerx = %%X, Playery = !y!
    )
  )
  set /A y+=1
)
call :prepareMap


:: New :prepareMap and modified :drawMap -----------------------
:drawMap
  set /a "pos=(PlayerY/MulPlayer-1)*mapWidth+PlayerX/MulPlayer, pos2=pos+1"
  echo !map:~0,%pos%!!P%angle1%!!map:~%pos2%,-1!
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!"
  )
goto :eof


Dave Benham

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Dos Batch Raycast - Explorer3D Beta

#18 Post by dbenham » 27 Aug 2015 20:36

:idea: I wonder if you could somehow take advantage of today's multi-CPU and/or multi-core machines. You could study my snake.bat game to see how I set up multiple processes and communicate between them.

In theory, you could launch computations for each possible move in separate processes. When the user finally presses a key, the result could be waiting and displayed right away.

Another possibility is to pre-compute and store all possible renderings for each position and angle. It would take a fair amount of time to initialize, but once complete you could zip around with many frames per second. I suppose this would break down if you start adding multiple moving objects.


Dave Benham

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Dos Batch Raycast - Explorer3D Beta

#19 Post by jeb » 28 Aug 2015 03:23

Good idea Dave,

but I suppose it's easier to use the multiprocessing for splitting the calculation of the rays.
As each calculation is independent of the others this could be a huge improvent of the speed.

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Dos Batch Raycast - Explorer3D Beta

#20 Post by einstein1969 » 28 Aug 2015 08:49

dbenham wrote:Interesting. I don't understand why you only allow turn to the right. But it is nice to be able to rotate quickly.


I have not finished. The algorithm for turn on LEFT plans to skip the lines at the end of a file, and I'm looking for the fastest way.

dbenham wrote:I wonder if you could somehow take advantage of today's multi-CPU and/or multi-core machines. You could study my snake.bat game to see how I set up multiple processes and communicate between them.

Yes I studing your snake.bat(2 ways) and the batch asyncronuos tee(1 way). And the idea of pre-cumpute is nice!

jeb wrote:but I suppose it's easier to use the multiprocessing for splitting the calculation of the rays.
As each calculation is independent of the others this could be a huge improvent of the speed.

Yes jeb! The raycast algorithm is scalable. We can partitioning the data to work. Then merge the results. The problem is the syncronization between processes (I think)

einstein1969

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Dos Batch Raycast - Explorer3D Beta

#21 Post by dbenham » 28 Aug 2015 10:21

einstein1969 wrote:
dbenham wrote:I wonder if you could somehow take advantage of today's multi-CPU and/or multi-core machines. You could study my snake.bat game to see how I set up multiple processes and communicate between them.

jeb wrote:but I suppose it's easier to use the multiprocessing for splitting the calculation of the rays.
As each calculation is independent of the others this could be a huge improvent of the speed.

Yes jeb! The raycast algorithm is scalable. We can partitioning the data to work. Then merge the results. The problem is the syncronization between processes (I think)

I don't think synchronization need be difficult.

We don't want more processes then there are CPU cores. There can be one master process that distributes jobs, and it can also do its own share of computations. Each sub process can run continuously, waiting for instructions in a tight loop.

So suppose there are 4 cores, meaning we have one master process, plus 3 child compute engines. The master script can divide the computations into 4 jobs, storing each set of instructions in job files job1.txt through job4.txt. While writing the job files, they probably should be named something that is not recognized by the compute engines. Once complete, they can be instantly renamed to something that the compute engines recognize. Each compute engine can immediately begin processing its assigned job once it detects the presence of the file. Results can be written to result1.txt through result4.txt. When a job is complete, the compute engine should delete the job file.

The main script can be assigned to process one of the jobs, and as soon as it has completed, it polls to see if there are still job files remaining. Once there are no job files, the master can then proceed with merging the results.

I recommend that the polling used to detect the presence or absence of job files should not contain any sleep or delay mechanism - the polling should run as fast as possible. That should not create a problem as long as we don't have more processes then there are cores.

Currently it takes ~700 msec on my quad core machine per movement. If we have 4 processes, with some reasonable overhead for job coordination, I think we should be able to achieve 4 or 5 frames per second, which would look pretty darn impressive.

Dave Benham

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Dos Batch Raycast - Explorer3D Beta

#22 Post by einstein1969 » 28 Aug 2015 11:57

Ok. This seem good and simply.

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Dos Batch Raycast - Explorer3D Beta

#23 Post by Aacini » 28 Aug 2015 14:30

I tried to pre-compute the sines and cosines table in an array, from 0 to 359 degrees, so the frequent access to these values in :raycast routine be faster. However, the result was slower than the original... It seems that the large number of environment variables was a more important negative factor than the time gained when the operations in :Sin_Cos_Cos routine was avoided... :?

Then, I use the same method to generate 360 disk files, each one with the pre-computed values of sine and cosine for each degree, and then read data from these files each time that a sine/cosine value was needed. Surprisingly, this method was about 12% faster than the original! :D I used Raycast version 0.3 as base for my tests:

Code: Select all

:::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Dos Batch Raycast ver. 0.3 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.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
setlocal

setlocal EnableDelayedExpansion
call :Init
del test.txt 2> nul
set /A y=1, MapsizeX=23, MapsizeY=10, MapsizeX-=1

rem 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
  set /A Playerx*=MulPlayer, Playery*=MulPlayer, OldPlayerx=Playerx, OldPlayery=Playery, angle1=0

:loop

  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 (

REM APA    call :Sin_Cos_Cos "!angle1! * PI / 180" StepY StepX dummy dummy
    for /F "tokens=1,2" %%s in (t.!angle1!) do set /A StepY = %%s, StepX = %%t

    call :raycast
    call :drawMap

    echo Playerx:!Playerx! Playery:!playery! oldplayerx:!oldplayerx! oldplayery=!oldplayery!
    echo Angle1:!angle1! gridx:!gridx! gridy:!gridy! StepX=!StepX! StepY=!StepY!

    set /A OldPlayerx = Playerx, OldPlayery = Playery

  )


  rem use 'where choice' for localize choice.exe
  C:\Windows\System32\choice.exe /N /C wksladzu >nul


  rem "w" UP-FORWARD
  if %errorlevel% == 1 set /A "PlayerX=PlayerX + StepX / 2, PlayerY=PlayerY + StepY / 2"

  rem "s" DOWN-BACKWARD
  if %errorlevel% == 3 set /A "PlayerX=PlayerX - StepX / 2, PlayerY=PlayerY - StepY / 2"

  rem "k" ROTATE LEFT                                   APA
  if %errorlevel% == 2 set /A "angle1 = (angle1-15+360) %% 360"
 
  rem "l" ROTATE RIGHT                              APA
  if %errorlevel% == 4 set /A "angle1 = (angle1+15) %% 360"
 
  rem "a" LEFT
  if %errorlevel% == 5 set /A "PlayerX=PlayerX + StepY / 2, PlayerY=PlayerY - StepX / 2"

  rem "d" RIGHT
  if %errorlevel% == 6 set /A "PlayerX=PlayerX - StepY / 2, PlayerY=PlayerY + StepX / 2"

  set "oldSys=0"
  if %errorlevel% == 7 set "oldSys=1"

  goto :loop

goto :eof

:raycast

echo !time: =0!> "%tmp%\t1.txt"

set /A from=angle1-32, to=angle1+32, Mul1=25, MaxIter1=500, MaxIter2=50, ti=0
set /a MM=%MulPlayer%*%Mul1%
set /A M10=%MulPlayer%*%Mul1%*10

setlocal
(

    set /A ti=0
    for /L %%Z in (%from%,1,%to%) do (

        set /A ti+=1
        for %%t in (!ti!) do (
            set sts=!sti:~0,%%t!
            REM !si[%%t]!
        )

        title !sts!

        REM APA call :Sin_Cos_Cos "%%Z * PI / 180" aStepY aStepX "((%%Z-%Angle1%) * PI / 180)" corr
        REM APA
        set /A "Z=(%%Z+360) %% 360, corr = (%%Z-%Angle1%+360) %% 360"
        for /F "tokens=1,2" %%s in (t.!Z!) do set /A aStepY = %%s, aStepX = %%t
        for /F "tokens=1,2" %%s in (t.!corr!) do set /A corr = %%t

        REM   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 cnt+=1
                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 DistanceCount=%%?
            )   
        ) ELSE (
            set dis=0
            for /L %%? in (1,1,20) do if not defined BREAK (
                set /a cnt+=1
               
                !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
            )
        )

        rem if !ti! == 63 set "out=!fir! (!ax!,!ay!) (!gridX!,!gridY!) (!aStepX!,!aStepY!)"
        set /A "accumul=DistanceCount*(10000/%Mul1%)"

        rem Last Step
        set /A "ax = (ax-aStepX)*10, ay = (ay-aStepY)*10"

        set "BREAK=" & set /A 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 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"
                )
                set mul=!mulX!
                if !mulX! GEQ !mulY! (
                    set /a mul=mulY
                )
                set /a ax+=aStepX*mul, ay+=aStepY*mul,dis+=mul
                set /a 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"

        rem 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!-
                 )
        )
       
    )

)> "%tmp%\test.txt"

endlocal

call :transpose

set /P "t1=" < "%tmp%\t1.txt"
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

goto :eof

:transpose

setlocal
 
  set /A LineN=0

:: Load and transpose data
  for /f usebackq^ delims^=^ eol^= %%A in ("%tmp%\test.txt") 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^!"

  cls
  rem to FIX
  set/A MaxN=65
  for %%A in (N) do for /L %%n in (0, 1, !MaxN!) do echo(^|%transposedLine%^| %%n

endlocal

goto :eof

:drawMap

  set /A gridX=Playerx/MulPlayer, gridy=Playery/MulPlayer

  for /L %%Y in (1,1,!MapsizeY!) do (
    for /L %%X in (0,1,!MapsizeX!) do (

      if "!Map[%%Y]:~%%X,1!" geq "1" (
        set /p "=Û" <nul
      ) else (
        if !gridX! equ %%X (
          if !gridY! equ %%Y (set /p "=@" <nul) else set /p "=." <nul
        ) else set /p "=." <nul
      )
    )
    echo(
  )
goto :eof


:Init
    mode 80,80
    color 0F
    echo For best view use raster font 8x8 or 16x8.
    echo(
    echo Use WASD for move and KL for turn/rotate.
    echo(
    pause
    cls&echo Loading...

    for /f %%i in ('forfiles /m "%~nx0" /c "cmd /c echo 0x07"') do set BEL=%%i
    set bel=Z
    for /f "delims==" %%v in ('set') do if /I not "%%v" == "TMP" if /I not "%%v" == "BEL" set "%%v="

    set "sti=|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
    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)"

    REM APA - Create Sine and Cosine files for angles from 0 to 359
    for /L %%x in (1,1,89) do (
       call :Sin_Cos_Cos "%%x * PI / 180" S C dummy dummy
       set /A N180Mx=180-%%x, N180Px=180+%%x, N360Mx=360-%%x
       for /F "tokens=1-3" %%i in ("!N180Mx! !N180Px! !N360Mx!") do (
          >t.%%x echo !S! !C!
          >t.%%i echo !S! -!C!
          >t.%%j echo -!S! -!C!
          >t.%%k echo -!S! !C!
       )
    )
    for %%v in (N180Mx N180Px N360Mx S C) do set "%%v="
    >t.0   echo 0       10000
    >t.90  echo 10000   0
    >t.180 echo 0      -10000
    >t.270 echo -10000  0

goto :eof

::::::::::::::::::::::::::::::::::: TRIGONOMETRIC FUNCTIONS

: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%")

REM APA     set /a "a=(%PI_div_2%-%4) %% %PIx2%, b=(a>>31|1)*a"
REM APA     if !b! gtr %PI32% (set /a "a=a-(a>>31|1)*%PIx2%, b=%SIN%")  else (
REM APA       if !b! gtr %PI_div_2% (set /a "a=(a>>31|1)*%PI%-a, b=%SIN%") else set /a "b=%SIN%")

   (endlocal & set "%2=%c%" & set "%3=%d%" & set "%5=%b%")
goto :eof

Antonio

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Dos Batch Raycast - Explorer3D Beta

#24 Post by Aacini » 29 Aug 2015 01:20

I tried to convert this program in a multi-thread application. Initially I planned to use the scheme described at this post, so I must complete a series of small changes in the code in order to use such scheme. The idea was that when the main code is waiting for user input, the concurrent threads calculate the new drawMaps that will result when the user select one of three possible inputs. This way, when the user press a key the result is ready to be displayed or will be very soon.

In order to identify which parts can be isolated in individual threads and have a simpler management of the concurrent code, I eliminated superfluous subdivisions and grouped code into the less possible parts. I eliminated :transpose subroutine division and integrated it into :raycast one. Then, I eliminated :drawMap subroutine division and integrated it into an unique :rayCastANDdrawMap large subroutine, that comprise the core code of the concurrent threads. This grouping also allows to generate an unique output file with all the parts that previously were generated in separate subroutines. This modification alone makes the program run slightly faster and the output was more pleasant because the whole screen was updated with just one TYPE command.

Then, I added the multi-thread management and, when I tested it, the code show a strange run-time error when the concurrent threads were started via a series of pipes. I changed the original pipes method by several START commands synchronized via shared files that emulate "pipes". After that, the program work as expected, although an error message about "The process have not access to the file because it is being used by another process" error message appears now and then...

Code: Select all

@echo off
setlocal EnableDelayedExpansion


REM APA MP - If this file was restarted, goto the thread section
set "myID=%~2"
if "%~1" neq "" goto %1

call :Init
REM APA del test.txt 2> nul
set /A y=1, MapsizeX=23, MapsizeY=10, MapsizeX-=1

rem 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
)

REM APA - Initialize the character map
for /L %%Y in (1,1,!MapsizeY!) do (
   set "mp[%%Y]="
   for /L %%X in (0,1,!MapsizeX!) do (
      if "!Map[%%Y]:~%%X,1!" geq "1" (
         set "mp[%%Y]=!mp[%%Y]!Û"
      ) else (
         set "mp[%%Y]=!mp[%%Y]!."
      )
   )
)

  set nx=
  set y=

  set /A MulPlayer=10000
  set /A Playerx*=MulPlayer, Playery*=MulPlayer, OldPlayerx=Playerx, OldPlayery=Playery, angle1=0


REM APA MP - Start 3 concurrent threads for rayCast and drawMap: Forward and 2 Rotate's

cd . > thread1.txt
start "" /B cmd /C "%~F0" rayCastdrawMap 1 ^< thread1.txt
cd . > thread2.txt
start "" /B cmd /C "%~F0" rayCastdrawMap 2 ^< thread2.txt
cd . > thread3.txt
start "" /B cmd /C "%~F0" rayCastdrawMap 3 ^< thread3.txt


REM APA MP - The following are the commands for the concurrent threads:

:: - Request to perform rayCast with the data provided and create the drawMap:
::   rayCast %PlayerX% %PlayerY% %angle1%
:: - Request to show in the screen the last created drawMap:
::   drawMap
:: - Request to exit:
::   exit


REM APA MP - Request thread #1 to create the initial rayCast and drawMap
echo rayCast %PlayerX% %PlayerY% %angle1% >> thread1.txt
REM APA MP - Initialize "option" as thread #1 in order to draw the initial drawMap
set option=1

:loop

  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 (

   REM APA MP - Request the selected thread to draw the previously created drawMap
   echo drawMap >> thread%option%.txt
   REM APA MP - Wait for such operation be completed
   call :waitForDraw %option%

REM APA    call :Sin_Cos_Cos "!angle1! * PI / 180" StepY StepX dummy dummy
    for /F "tokens=1,2" %%s in (t.!angle1!) do set /A StepY = %%s, StepX = %%t

    echo Playerx:!Playerx! Playery:!playery! oldplayerx:!oldplayerx! oldplayery=!oldplayery!
    echo Angle1:!angle1! gridx:!gridx! gridy:!gridy! StepX=!StepX! StepY=!StepY!

    set /A OldPlayerx = Playerx, OldPlayery = Playery

    REM APA MP - Request all threads to create in advance their corresponding "next" rayCast's and drawMap's
    REM APA MP - Thread #1: Forward
    set /A "PlayX=PlayerX + StepX / 2, PlayY=PlayerY + StepY / 2"
    echo rayCast !PlayX! !PlayY! %angle1% >> thread1.txt
    REM APA MP - Thread #2: Rotate Left
    set /A "angle = (angle1-15+360) %% 360"
    echo rayCast %PlayerX% %PlayerY% !angle! >> thread2.txt
    REM APA MP - Thread #3: Rotate Right
    set /A "angle = (angle1+15) %% 360"
    echo rayCast %PlayerX% %PlayerY% !angle! >> thread3.txt

  )


  rem use 'where choice' for localize choice.exe
  REM APA Just Forward and Rotate's commands are executed in this MP version, plus eXit
  C:\Windows\System32\choice.exe /N /C wklx >nul

  REM APA MP - Store the selected option
  set "option=%errorlevel%"

  set /P "=Please wait..." < NUL

  rem "w" UP-FORWARD
  if %option% == 1 set /A "PlayerX=PlayerX + StepX / 2, PlayerY=PlayerY + StepY / 2"

  rem "k" ROTATE LEFT                                   APA
  if %option% == 2 set /A "angle1 = (angle1-15+360) %% 360"
 
  rem "l" ROTATE RIGHT                              APA
  if %option% == 3 set /A "angle1 = (angle1+15) %% 360"


  REM APA MP - eXit, to close all concurrent threads
  if %option% == 4 (
     echo exit >> thread1.txt
     echo exit >> thread2.txt
     echo exit >> thread3.txt
     exit /B
  )


  rem "s" DOWN-BACKWARD
  if %errorlevel% == 4 set /A "PlayerX=PlayerX - StepX / 2, PlayerY=PlayerY - StepY / 2"

  rem "a" LEFT
  if %errorlevel% == 5 set /A "PlayerX=PlayerX + StepY / 2, PlayerY=PlayerY - StepX / 2"

  rem "d" RIGHT
  if %errorlevel% == 6 set /A "PlayerX=PlayerX - StepY / 2, PlayerY=PlayerY + StepX / 2"

  set "oldSys=0"
  if %errorlevel% == 7 set "oldSys=1"

  goto :loop

goto :eof


REM APA MP - The following are the commands for the concurrent threads:

- Request to perform rayCast with the data provided and create the drawMap:
  rayCast %PlayerX% %PlayerY% %angle1%
- Request to show in the screen the last drawMap created:
  drawMap
- Request to exit:
  exit

REM APA MP - Concurrent thread entry point
:rayCastdrawMap

rem Get command sent from main code
set "command="
:waitForCom
set /P "command="
if not defined command goto waitForCom

for /F "tokens=1-4" %%a in ("%command%") do (
   if %%a equ rayCast (
      set /A "PlayerX=%%b, PlayerY=%%c, angle1=%%d"
      call :rayCastANDdrawMap
   ) else if %%a equ drawMap (
      cls
      type "%tmp%\test%myID%.txt"
      del  "%tmp%\test%myID%.txt"
   ) else if %%a equ exit (
      exit
   )
)

goto rayCastdrawMap


:waitForDraw %thread%
if exist "%tmp%\test%1.txt" goto waitForDraw
exit /B


:rayCastANDdrawMap

echo !time: =0!> "%tmp%\t1.txt"

set /A from=angle1-32, to=angle1+32, Mul1=25, MaxIter1=500, MaxIter2=50, ti=0
set /a MM=%MulPlayer%*%Mul1%
set /A M10=%MulPlayer%*%Mul1%*10

setlocal
(

    REM APA set /A ti=0
    for /L %%Z in (%from%,1,%to%) do (

        REM APA set /A ti+=1
        REM APA for %%t in (!ti!) do (
        REM APA     set sts=!sti:~0,%%t!
        REM APA     REM !si[%%t]!
        REM APA )

        REM APA title !sts!

        REM APA call :Sin_Cos_Cos "%%Z * PI / 180" aStepY aStepX "((%%Z-%Angle1%) * PI / 180)" corr
        REM APA
        set /A "Z=(%%Z+360) %% 360, corr = (%%Z-%Angle1%+360) %% 360"
        for /F "tokens=1,2" %%s in (t.!Z!) do set /A aStepY = %%s, aStepX = %%t
        for /F "tokens=1,2" %%s in (t.!corr!) do set /A corr = %%t

        REM   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 cnt+=1
                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 DistanceCount=%%?
            )   
        ) ELSE (
            set dis=0
            for /L %%? in (1,1,20) do if not defined BREAK (
                set /a cnt+=1
               
                !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
            )
        )

        rem if !ti! == 63 set "out=!fir! (!ax!,!ay!) (!gridX!,!gridY!) (!aStepX!,!aStepY!)"
        set /A "accumul=DistanceCount*(10000/%Mul1%)"

        rem Last Step
        set /A "ax = (ax-aStepX)*10, ay = (ay-aStepY)*10"

        set "BREAK=" & set /A 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 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"
                )
                set mul=!mulX!
                if !mulX! GEQ !mulY! (
                    set /a mul=mulY
                )
                set /a ax+=aStepX*mul, ay+=aStepY*mul,dis+=mul
                set /a 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"

        rem 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!-
                 )
        )
       
    )

)> "%tmp%\test%myID%.txt"

endlocal

:::::::::::::::::::
REM APA call :transpose
:transpose

setlocal
 
  set /A LineN=0

:: Load and transpose data
  for /f usebackq^ delims^=^ eol^= %%A in ("%tmp%\test%myID%.txt") do (
    set /A LineN+=1
    set "N!LineN!=%%A"
  )

  REM APA set /A "MaxN=LineN-1"
  set "transposedLine="
  for /L %%m in (1, 1, !LineN!) do set "transposedLine=!transposedLine!^!N%%m:~%%n,1^!"

  rem to FIX
  REM APA set/A MaxN=65


REM APA Start of long redirected code block
(

  REM APA               LineN
  for /L %%n in (0, 1, !LineN!) do echo ^|%transposedLine%^| %%n

  set /P "t1=" < "%tmp%\t1.txt"
  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

endlocal

REM APA goto :eof
REM :::::::::::::


REM APA goto :eof
REM :::::::::::::


REM :drawMap

   set /A gridX=Playerx/MulPlayer, gridy=Playery/MulPlayer

   REM APA - Modified drawMap
   for /L %%Y in (1,1,!MapsizeY!) do (
      if %%Y neq !gridY! (
         echo !mp[%%Y]!
      ) else (
         set /A I=gridX-1
         for /F "tokens=1,2" %%I in ("!I! !gridX!") do (
            echo !mp[%%Y]:~0,%%I!!P%angle1%!!mp[%%Y]:~%%J!
         )
      )
   )


REM APA End of long redirected code block
) > "%tmp%\test%myID%.txt"

goto :eof


:Init
    mode 80,80
    color 0F
    echo For best view use raster font 8x8 or 16x8.
    echo/
    echo Use W for move forward and KL for turn/rotate.
    echo Use X to exit.
    echo/
    pause
    cls&echo Loading...

    for /f %%i in ('forfiles /m "%~nx0" /c "cmd /c echo 0x07"') do set BEL=%%i
    REM APA set bel=Z
    for /f "delims==" %%v in ('set') do if /I not "%%v" == "TMP" if /I not "%%v" == "BEL" set "%%v="

    set "sti=|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
    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)"

    REM APA - Create Sine and Cosine files for angles from 0 to 359, if not exists
    if exist t.0 goto :initChar
    for /L %%x in (1,1,89) do (
       call :Sin_Cos_Cos "%%x * PI / 180" S C dummy dummy
       set /A N180Mx=180-%%x, N180Px=180+%%x, N360Mx=360-%%x
       for /F "tokens=1-3" %%i in ("!N180Mx! !N180Px! !N360Mx!") do (
          >t.%%x echo !S! !C!
          >t.%%i echo !S! -!C!
          >t.%%j echo -!S! -!C!
          >t.%%k echo -!S! !C!
       )
    )
    >t.0   echo 0       10000
    >t.90  echo 10000   0
    >t.180 echo 0      -10000
    >t.270 echo -10000  0

    REM APA - Initialize the player characters
    :initChar
    set "s=>\v/<\^/>"
    set "c=0"
    for /L %%i in (0,15,345) do (
       set /A "c+=^!((%%i+15) %% 45)"
       for %%c in (!c!) do set "P%%i=!s:~%%c,1!"
    )
    for %%v in (N180Mx N180Px N360Mx S C) do set "%%v="

goto :eof

::::::::::::::::::::::::::::::::::: TRIGONOMETRIC FUNCTIONS

: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%")

REM APA     set /a "a=(%PI_div_2%-%4) %% %PIx2%, b=(a>>31|1)*a"
REM APA     if !b! gtr %PI32% (set /a "a=a-(a>>31|1)*%PIx2%, b=%SIN%")  else (
REM APA       if !b! gtr %PI_div_2% (set /a "a=(a>>31|1)*%PI%-a, b=%SIN%") else set /a "b=%SIN%")

   (endlocal & set "%2=%c%" & set "%3=%d%" & set "%5=%b%")
goto :eof

Antonio

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Dos Batch Raycast - Explorer3D Beta

#25 Post by dbenham » 29 Aug 2015 23:21

Success :!:

I reverted back to jeb's code, and then successfully implemented parallel processing of ray cast partitions using the algorithm I outlined earlier. I made a number of other changes as well, all briefly documented in the change log.

I get 4-5 frames per second on my quad core machine. :D

I even get 1-2 frames per second using the old slow rendering algorithm :!:

The code automatically optimizes itself for the number of processors (cores) available.

The main process and the compute engine child processes share the same ray cast code. The compute engine processes have their own entry point, along with begin and end macros that put the engine in an endless FOR /L loop that looks for and executes jobs. The main process does not have the macros defined, so it falls through without looping.

The FOR /F transpose loop is able to process a list of ray cast files, so it can efficiently merge the results without having to physically merge the files.

Code: Select all

:::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Dos Batch Raycast ver. 0.3 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     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/right 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
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 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
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="

:: 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"
)

"%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!
    echo Angle1:!angle1! gridx:!gridx! gridy:!gridy! StepX=!StepX! StepY=!StepY! oldSys=!oldSys! waitCnt=!waitCnt!
    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"
  ) 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
  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" *.
  )
  :computeEngine
  %computeEngineBegin%
  setlocal
  >"%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!-
        )
      )
    )
  )
  endlocal
  %computeEngineEnd%
  set /a waitCnt=0
  :waitForJobCompletion
  if exist "%base%*_job.bat" (
    set /a waitCnt+=1
    goto :waitForJobCompletion
  )
  call :transpose
  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
exit /b


:transpose
  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^!"
  cls
  set /a MaxN=65
  for %%A in (N) do for /L %%n in (0, 1, !MaxN!) do echo(^|%transposedLine%^| %%n
  endlocal
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

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Dos Batch Raycast - Explorer3D Beta

#26 Post by dbenham » 30 Aug 2015 19:05

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 :D ). 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 8)

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

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Dos Batch Raycast - Explorer3D Beta

#27 Post by einstein1969 » 31 Aug 2015 09:54

@jeb
I saw that the results were slightly different from your code, I tried to understand the code, but I got lost. Could you explain how you came to that code?

@Antonio
I could try the first part of your code and it seems to be faster.

@Antonio & dbenham
I could not try the multi-threaded versions but I'm looking forward to it. 8)
Although I have a multiprocessor machine I hope to do the same tests. Thanks thanks thanks, very good job!

@dbenham
For the fast rotate you are right! The raycast result for a given angle is dependent on the angle of the player. But...
This is true if we take the final result with the "correction" (look the code for the variable "corr"). If we take
the partial result (witch it's lot of computation), we can reuse the partial computation.
dbenham wrote:Excessive child processes actually slowed the program down.

It would be nice to understand because it 's so. I think that maybe there is a solution.

@all
Why the set/p has problem in the process inter-communications?

Einstein1969

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Dos Batch Raycast - Explorer3D Beta

#28 Post by Aacini » 31 Aug 2015 22:45

einstein1969 wrote:@all
Why the set/p has problem in the process inter-communications?

Einstein1969

The SET /P problem have been solved and can be used for inter-process communications via a pipe. I used it in my new method to achieve a multi-thread application in Batch. My new version of the Raycast program will use it (that was my original goal, indeed).

Antonio

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Dos Batch Raycast - Explorer3D Beta

#29 Post by jeb » 04 Sep 2015 09:55

einstein1969 wrote:@jeb
I saw that the results were slightly different from your code, I tried to understand the code, but I got lost. Could you explain how you came to that code?


Your code adds aStepX and aStepY to the ax/ay variables.
Then gridX/gridY is calculating, but in the most cases neither gridX nor gridY changes it's value as aStepX/Y is very small.
So you need many loops to add and check always the same map points before you find a wall.

My version simply calculates how many loops you whould need to reach the next change for gridX and/or gridY and I take the smaller value.
Additionally, I have to take care about the case when aStep? is zero and when it's negative.

But that's all.

I also recognized that the results are slightly different. Perhaps the cause is that I first go to the next step of gridX/Y before testing the map.
That seems wrong to me.

But next time I will check it with using both algorithms and stop when there is a different result.

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: Dos Batch Raycast - Explorer3D Beta

#30 Post by einstein1969 » 04 Sep 2015 16:07

@jeb
Thanks jeb.

@Aacini
I have probe your multitasking version and run good, but there is too much cpu time wasted. :(

@dbenham
I have tested the version 0.4.0 - 0.4.1 and 0.41a and all is ok.
Than I only modify a line of code for probe multitasking on my monocore.
from:

Code: Select all

  set /a proc=NUMBER_OF_PROCESSORS, childCnt=proc-1

to:

Code: Select all

  set /a proc=NUMBER_OF_PROCESSORS+1, childCnt=proc-1

In this case the result are not always the same. The output is only half some time. Some time is full and sometime is half good and half not. :(

EDIT: it would seem that the job variable is not set for the main thread and/or use the child/parallel definition.

Einstein1969

Post Reply