Cmdgfx - draw 3d and graphic primitives (polygons,circles etc) in cmd window (now with 24-bit RGB support!)

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#46 Post by misol101 » 22 Jul 2016 16:55

Archive updated. This thing has been consuming way too much of my time lately, so it may be the last release.

What's new?

There is a new executable called cmdgfx_gdi.exe. It appears to work just like the regular cmdgfx.exe but is much bigger, ~190k instead of ~75k. This is because the 10 cmd bitmap fonts are embedded inside it, and all "text" drawing is in fact bitmaps. As discussed in the thread before, this increases speed (though not in all cases).

Usage: cmdgfx_gdi [operations] [flags] [fgpalette] [bgpalette]

The main thing about cmdgfx_gdi is you should specify which font you want to use. The program does not care which font you are *actually* using at the moment. You do this with the f flag, as in fn[:x,y,w,h;], where n is the font 0-9, and x,y are where to place the resulting bitmap, and w,h are how big it should be (in characters). Default values are n=6, x=0, y=0, w=current number of columns, h=current number of rows.

There is one more thing that is different: you can optionally specify the colors used for foreground and background, i.e. the RGB values of the index 0-15. They should be specified like "RRGGBB," repeated.

The new gfxtest7.bat shows the use of palette and switching font, and shows a nicely gradiented goraud shaded polygon.

So what about speed?

It's a bit confusing. On the one hand it really improves it in some cases, and in some it's worse. The following bats now use the gdi version by default, because it increases speed, more or less:

3dworld2 (~100%)
bob-flag (~2-300%)
interference (~1-200%)
pixeltest1/2
linetest
gfxtest3
dot-flag
pixel-tunnel (not much)

In these cases, you can press 'r' while running to switch between running cmdgfx.exe and cmdgfx_gdi.exe to see the difference

Generally speaking, the more color changes and the smaller the font, the more speed should increase. However I fail to understand why e.g. interference.bat is so much faster with the gdi version, since it uses just one color?!

(Edit: on second thought it does make sense. The XOR'ing in intereference.bat makes the foreground color switch between 0 and 1 over and over)

The linking of gdi with the exe causes a longer overhead time for simply starting the program, which is one of the reasons it's not always faster. Also, if there are mostly big blocks of the same color, it may also be slower.

Blablabla... :mrgreen:

Image
Last edited by misol101 on 16 Apr 2017 13:04, edited 3 times in total.

penpen
Expert
Posts: 1991
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#47 Post by penpen » 22 Jul 2016 17:59

misol101 wrote:Is there a faster way to create and blit the output to the screen than what I'm doing below?
I'm unsure if how much speed you would gain, but you could minimize the amount of "malloc" and "free" calls (depending on the implementation of malloc/free these functions could be very slow):
Use free and malloc, only malloc on (outdata == null), realloc when the size of the console has changed, and free it on exit.

Same for other variables (hBmp1; maybe you don't need to create the compatible device context on every call - maybe only when the hWnd or hDc changes - maybe never; you have to test this;).


misol101 wrote:Why not use OpenGL instead godammit
To be honest: i don't know how to implement this; i only know that it must be possible, because a fellow student once has implemented it to have a background image in console (but i don't know how fast it was; i saw no differences in speed, but he only executed some batches to compile java, so he never touched the limit).
He read the complete source of glut: Maybe there you could find the solution - but it is probably much work... .


penpen

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#48 Post by misol101 » 22 Jul 2016 18:37

penpen wrote:you could minimize the amount of "malloc" and "free" calls (depending on the implementation of malloc/free these functions could be very slow)
Same for other variables (hBmp1; maybe you don't need to create the compatible device context on every call - maybe only when the hWnd or hDc changes - maybe never; you have to test this;).

Thanks, I did some quick tests of this but it made very little impact.
According to my stats, it's approximately:
for-loop conversion from char to bitmap data: 54% of execution time inside my convertToGdiBitmap function
call to CreateBitmap+BitBlt: 36%
everything else (free/malloc/createDC/releaseDC etc): 9%

penpen wrote:
misol101 wrote:Why not use OpenGL instead godammit
To be honest: i don't know how to implement this; i only know that it must be possible, because a fellow student once has implemented it to have a background image in console (but i don't know how fast it was; i saw no differences in speed, but he only executed some batches to compile java, so he never touched the limit).
He read the complete source of glut: Maybe there you could find the solution - but it is probably much work... .

Ah, I see. That's interesting, although in this context I actually self-sarcastically meant "why am I doing graphics in text mode at all, why don't I spend my time improving my regular rendering chain (such as OpenGL in a regular window or fullscreen) like a normal person?" :)
Last edited by misol101 on 23 Jul 2016 12:35, edited 1 time in total.

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#49 Post by misol101 » 23 Jul 2016 12:25

aGerman wrote:Even default fonts are already problematic. Consolas font was the default setting in my Win 10. Mixing bitmap and text may fail more often as you expect.


As a response to this, I decided to be more dictatorial and force font 6 in all the examples where I didn't set the font automatically before. Not very "nice" behavior, but it's a game/demo engine after all... :)

So the archive was again updated :) Also, I added 3dworld3.bat, which shows how to add moving objects into a static 3d world. Unfortunately this means writing to a file every single frame. Not very efficient... Also, the plane should rotate, Doom-style, to always face the viewer, but it seemed like too much work for a test.

Image
Last edited by misol101 on 16 Apr 2017 13:39, edited 1 time in total.

aGerman
Expert
Posts: 4654
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#50 Post by aGerman » 23 Jul 2016 13:42

Neat :)
misol101 wrote:Not very "nice" behavior

No that's reasonable. Everything has to match in order to get a proper result. I bet you can't adjust the resolution or the font size in any other game, can you? Certainly those are presets. (I'm not a gamer as you may have noticed.)

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#51 Post by misol101 » 01 Aug 2016 21:39

Archive updated.

1. 3d objects can now use gxy textures
This allows for more complex textures (not just color change but also character change).
See gxy-cube.bat for an example (try pressing SPACE, D/d)

2. 3d objects can now set the colors of faces from within the file
This works only for obj files and uses a non-standard extension of the obj file format.
Sure it would be nice to support mtl files with specular/diffuse light etc but it doesn't really work in a 16 color world.
Spaceship.bat provides a (not very exciting) example.

3. Support reading mouse events, support reading key up/down events
This is all done with the M flag, a max wait time can be specified. It returns a 31 bit pattern from which both mouse and key events can be examined.
See mouse_palette-test.bat for explanation/example (hold down left or right button and move, try SPACE and mouse wheel).
Reading keys this way also means you do not have to wait for key repeat.
3world3.bat was changed to show this, as well as some simple "lookaround" with the mouse. Use mouse wheel to turn around.

4. Can now set palette(s) for a color transformation at end of last operation
This way it's sometimes possible to make nicer shades of colors.
Again, see mouse_palette-test.bat (press SPACE to change palette).

Cyberpunky screenshots from mouse_palette-test.bat and gxy-cube.bat:

Image
Last edited by misol101 on 16 Apr 2017 13:05, edited 1 time in total.

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#52 Post by misol101 » 02 Aug 2016 18:36

One more.

Added operation "block" to copy/transform a block. This is a pretty complicated operation, but in the simplest form it just copies or moves a block from one place to another.

The idea is to optionally specify a list of indata and outdata, a form of search/replace for every location in the copied block. For example 1020=a0db would look for all SPACE(20) characters with color 0x01, and replace that with char db,color 0x0a. That is the easy one, but also values can be skipped, like 1???=9??? means match all characters with fgcolor 1 and change to color 9. Also, the output can be increased or decreased, like ?0??=-0?? means for all characters with bgcolor 0, decrease fgcolor by 1. Etc.

There are two examples: mouse-blocktransform.bat, which looks the same as mouse_palette-test.bat, but is much faster due to skipping the two earlier needed extra exe calls. Second example is fire.bat, an attempt to create the classic fire effect with the "block" operation, with so-so results (try SPACE, ENTER, possibly cursor keys).

Image

Edit: it might be interesting to scroll right in fire.bat example, to see what the block operation does behind the scenes(in two steps) :)

Edit2: updated archive with fire2.bat, a slightly better-looking fire
Last edited by misol101 on 16 Apr 2017 13:32, edited 1 time in total.

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#53 Post by misol101 » 09 Aug 2016 18:54

3dworld3.bat in archive updated:

1. a/d can now be used for strafing (and w/s to move, j/k to rotate (in addition to cursor keys))
2. Fixed bug when rotating with mouse
3. Non-repeating keys such as h,m,r,p now work as expected
4. Help text updated

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#54 Post by misol101 » 10 Aug 2016 08:26

Finally put this thing, including all source code, on github:

https://github.com/misol1/cmdgfx

No I certainly don't claim that it's well-written or nicely structured (especially not cmdgfx.c), but there have been a few PM requests for it. It's fairly fast code, but it's quick-n-dirty.

To compile, (with gcc/mingw) write "make cmdgfx.exe" (or "make cmdgfx_gdi.exe"). A simple "make" will instead build "testlib.exe", which uses the rendering in e.g. "gfx.c" in pure C, no batch. You will notice the speed difference (as well as a kind of "antialiasing"), though "testlib.exe" does not use the "bitmap solution" of cmdgfx_gdi, so it may not always be faster. There are lots of keys in "testlib.exe", you'll have to look in the source code for those. Try e.g. in sequence, 'C', 'n', 'o'

Note: At the top of cmdgfx.c is a "to-do" list. Yes, yes, go ahead... :mrgreen:

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#55 Post by misol101 » 14 Aug 2016 11:17

I was supposed to stop playing with this...

Anyway, I saw a program by carlos called pixelfont.exe and that made me a bit curious how that would look with the 3d world. So I added pixelfonts 1x1, 2x2 and 3x3 to cmdgfx_gdi (to use them, specify a,b, or c as font to the f flag). In these fonts, all characters except 0,32 and 255 show the fgcolor only.

Result, 3dworld3_pxlfont.bat (720x500 resolution, pixelfont 1x1):

Image

The downside to this is that the normal 3dworld3.bat looks like crap in comparison :) So, again I ask myself what I have been doing with this text stuff for so long...haha

Also added a new bat with rotating balls sorted acording to z value, called balls-sorted.bat.
Last edited by misol101 on 16 Apr 2017 13:06, edited 1 time in total.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#56 Post by foxidrive » 17 Aug 2016 09:57

Bro and I used to be heavily into Doom and similar games of the time.

If anyone said there would be such things as you are doing here back then they would have been laughed out of the building. :)

So many graphic batch files and tools have been shown in DosTips in the last year that just astound me with the thought that it was so limited back then and has come to the point that all these batch scripts are now possible.

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

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#57 Post by Aacini » 17 Aug 2016 11:20

You may review the original source of the 1x1 pixel size font at this thread.

Antonio

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#58 Post by misol101 » 18 Aug 2016 16:50

foxidrive wrote:Bro and I used to be heavily into Doom and similar games of the time.

If anyone said there would be such things as you are doing here back then they would have been laughed out of the building. :)

So many graphic batch files and tools have been shown in DosTips in the last year that just astound me with the thought that it was so limited back then and has come to the point that all these batch scripts are now possible.

Yeah, though I guess there is no limit to what a "batch script" can do if it consist of one line only: @runprogram.exe :mrgreen:

But I think cmdgfx strikes a fair balance between doing the logic with scripting and leaving the rendering to the external program.

Aacini wrote:You may review the original source of the 1x1 pixel size font at this thread.

Cool, so it was a joint effort :) I cannot actually use pixelfnt.exe for my purposes though, because of the previously discussed slowness of the WriteConsoleOutput API. The FPS for 3dworld3_pxlfont.bat drops from ~30 to ~3 on my computer using pixelfnt instead of directly writing a bitmap to the window.

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#59 Post by misol101 » 04 Sep 2016 15:34

Archive and repo update. Cmdwiz (the cmdgfx companion) had a bunch of new operations added:

1. getwindowbounds to get the console window's x/y position or its width and height. Note that the border is also included in these values.

2. setwindowpos to set the position of the console window

3. getdisplaydim to get the resolution of the current display (useful to e.g center the window with setwindowpos)

4. getmousecursorpos returns the screen coordinates of the mouse pointer

5. setmousecursorpos to set the mouse pointer position. In addition, it is possible to specify that a click happens after the move, either a left click, a right click, a left button down, or left button up. The last two can be used to e.g. simulate dragging windows around. This makes cmdwiz useful as a simple mouse task automation tool.

6. insertbmp is used to paste a bmp file in the console window, either as-is or stretched-out either as a percentage or as width/height settings. Full credits to aGerman for this function, which is also noted in the source code.

7. setwindowtransparency is used to set the transparency of the console window between 0 and 100. Again, full credit to aGerman for the source code.

8. setfont was lifted from carlos BG tool, full credit to him for this functionality (also noted in the source code). I then extended this operation by adding support for saved fonts, so in addition to the 10 terminal bitmap fonts it is also possible to load any font added to the console which has been saved with the corresponding savefont operation. This also makes it possible to restore your original font after a change to another font.

9. quickedit operation changed name to setquickedit and a corresponding getquickedit operation was added


See the thread here (viewtopic.php?f=3&t=7129) for an example batch showing how to use these operations. Also, 3dworld_pixelfont.bat uses some of them to center its window on the screen.

misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Cmdgfx - draw graphic primitives (polygons,circles etc) in cmd line window

#60 Post by misol101 » 15 Sep 2016 15:46

I decided to try cmdgfx with some other scripting languages to investigate the difference in speed.

Conclusion: it doesn't look too good for batch :) (kind of expected)

I made the test script in batch, then Python, and then (since I heard it was supposed to be quite fast) Lua.
The script(s) moves 200 stars individually per frame, running 400 frames before printing the FPS.

Results:
Batch: 9 FPS
Python: 72 FPS
Lua: 25 FPS

So at least in my naive scripts, Python is clearly the fastest, about 8 times as fast as Batch. Python also has the advantage that it's very easy to run the external program (cmdgfx) asynchronously. However, when I ran it synchronously, the FPS was still 66, so that part doesn't make a real big difference (I thought it would).

Still I'm pretty sure if there is no heavy processing going on, then batch is faster or equally fast as python, since the overhead time for executing the external seems slightly bigger in Python.

Can anybody remake this in Jscript (I don't know it, but heard it's fast)?
Also, are there other scripting languages known for high speed?

Batch script:

Code: Select all

@echo off
setlocal ENABLEDELAYEDEXPANSION

for /F "Tokens=1 delims==" %%v in ('set') do if /I not "%%v" == "PATH" set "%%v="
set /a XSIZE=140, YSIZE=50, NOF=200, XDELAY=2, TIMES=400
mode %XSIZE%,%YSIZE% & cls
set /a XMAX=%XSIZE%*%XDELAY%, YMAX=%YSIZE%*%XDELAY%
for /L %%b in (0,1,%NOF%) do call :MAKESTAR %%b
cmdwiz gettime&set STARTT=!errorlevel!

for /L %%a in (1,1,%TIMES%) do (
   set FIELD=""
   for /L %%b in (0,1,%NOF%) do set /a XTMP=!SX%%b!/%XDELAY%, SX%%b+=!SS%%b!&set FIELD="!FIELD:~1,-1! & pixel !SC%%b! 0 . !XTMP!,!SY%%b!"&if !SX%%b! geq %XMAX% set /a SX%%b=0
   cmdgfx !FIELD!
)

mode 80,50&cls
cmdwiz gettime&set /a FPS=(!errorlevel!-%STARTT%)/1000&set /a FPS=%TIMES%/!FPS!&echo !FPS!
endlocal
goto :eof

:MAKESTAR
set /a SY%1=%RANDOM% %% %YSIZE%, SX%1=%RANDOM% %% %XMAX%
set /a SS%1=%RANDOM% %% 3 + 1
if !SS%1! == 1 set SC%1=8
if !SS%1! == 2 set SC%1=7
if !SS%1! == 3 set SC%1=F


Python (hybrid Batch) script:

Code: Select all

0<0# : ^
'''
@echo off
setlocal ENABLEDELAYEDEXPANSION
cmdwiz setfont 6 & cls & mode 140,50
cmdwiz gettime&set STARTT=!errorlevel!
python %~f0 %*
mode 80,50 & cls
cmdwiz gettime&set /a FPS=(!errorlevel!-%STARTT%)/1000&set /a FPS=400/!FPS!&echo !FPS!
endlocal
exit /b 0
'''

from subprocess import Popen
from random import randint, uniform

out, process, nofStars = 0, 0, 200
starsX,starsY,starsS,starsC=[],[],[],[]

for x in range(0, nofStars):
  starsX+=[randint(0,140)]
  starsY+=[randint(0,50)]
  starsS+=[uniform(0.1,1.3)]
  if starsS[x] < 0.5:
    starsC += [8]
  elif starsS[x] < 1.1:
    starsC += [7]
  else:
    starsC += [15]
 
#while (out != 27):
for x in range(0, 400):
  outString=""
  for i in range(0, nofStars):
     starsX[i] += starsS[i]
     if starsX[i] > 140:
        starsX[i] = 0
     outString = outString + "& pixel " + str(starsC[i]) + " 0 . " + str(int(starsX[i])) + "," + str(starsY[i])

  if process != 0:
     out = process.wait()
  process = Popen(["cmdgfx.exe", outString, "k"])


Lua (hybrid Batch) script:

Code: Select all

--[=====[ >nul 2>nul
@echo off
setlocal ENABLEDELAYEDEXPANSION
cls & cmdwiz setfont 6 & mode 140,50
cmdwiz gettime&set STARTT=!errorlevel!
lua %~f0 %*
mode 80,50 & cls
cmdwiz gettime&set /a FPS=(!errorlevel!-%STARTT%)/1000&set /a FPS=400/!FPS!&echo !FPS!
endlocal
exit /b 0
--]=====]

nofStars = 200
starsX = {}
starsY = {}
starsS = {}
starsC = {}

for i=0,nofStars,1 do
  starsX[i]=math.random() + math.random(1, 139)
  starsY[i]=math.random(1, 49)
  starsS[i]=math.random()*1.3
  if starsS[i] < 0.5 then
   starsC[i] = 8
  elseif starsS[i] < 1.1 then
    starsC[i] = 7
  else
    starsC[i] = 15
  end
end

for j=0,400,1 do
  outString=""
  for i=0,nofStars,1 do
     starsX[i] = starsX[i] + starsS[i]
     if starsX[i] > 140 then
        starsX[i] = 0
     end
     outString = outString .. "& pixel " .. starsC[i] .. " 0 . " .. math.floor(starsX[i]) .. "," .. starsY[i]
  end

  key = os.execute('cmdgfx "' .. outString .. '" k')
end

Post Reply