Page 1 of 2

Drawing pixel resolution graphics in text mode

Posted: 10 Jan 2014 13:38
by Aacini
Some time ago I started to draw color graphics in text mode using the Ascii 219 block character that is displayed as a very low resolution "fat pixel" that have the size of the font (11x18 pixels), so the "graphic" looks rudimentary and grainy as you can see in this image. Later, I used the smallest possible font (Lucida console @ size 5) to generate a smaller "text pixel" of 3x5 pixels that produce more pleasant graphics, like this one. This way, the method to produce better graphics in text mode is via smaller fonts.

I followed the steps described at http://stackoverflow.com/questions/20896597/how-to-create-two-very-simple-bitmap-fonts post to create a "Terminal" raster font of 1x1 pixel size that effectively convert the "text pixel" into a graphics one, so it provides Batch files with the capability to draw graphics at pixel resolution in the same way of standard graphics functions of other programming languages. The result is amazing:

Image

In order to use this resolution you have to install the 1x1 font, create a shortcut to MS-DOS command-line window that use it and modify its buffer and window sizes to large values. It is suggested to use standard graphic screen sizes, like 640x480, 800x600 or 1024x768, and include window and font sizes in the shorcut name as reference; for example: "MS-DOS 800x600 @ 1x1.lnk". Note that when this command-line window is open, you can not distinguish any text in the screen! Most characters different than space will appear as dots, so just type the name of the program you want run and press Enter. The Batch file below create "Terminal 1x1.FNT" font file and display instructions on how to install it if the font file does not exists; the program use :ExtractBinaryFile subroutine described at http://www.dostips.com/forum/viewtopic.php?f=3&t=4842&p=31616#p31616 post to do that.

The 1x1 size font allows to use the 16 standard text colors for the "pixels", but a larger font would allow to define a color gradient via the combination of different foreground and background colors at several percentages ("dithering"); for example, a 2x2 size font would allow 25%, 50% and 75% combinations (I am working on this point). The existent "show color text" methods (like ColorChar.exe auxiliary program or the findstr method) can draw individual "pixels", so they are equivalent to C's "putpixel" graphic function. These routines can be combined with CursorPos.exe cursor positioning auxiliary program in order to develop a "draw line" subroutine. This way, any standard graphic function can be written in Batch, like line, box, circle, etc, and even a floodfill function can be developed with the aid of an auxiliary program that return the color of "pixels" in the screen (equivalent to C's "getpixel"). These operations may be slow because the number of processed pixels is large, so I am planning to also develop additional .exe auxiliary programs to draw lines, boxes, circles, show text, floodfill operations, etc. in a much faster way.

The Batch file below is a modified version of the original Mandelbrot Set program with the code that calculate the points converted to JScript, because the pure Batch code is too slow given the larger number of points in the new screen resolutions. The program create two parallel processes, the first one calculate the points and the other one display them, so it should run faster in a multi-core CPU computer. The image shown above was created by this program running in a 912x684 resolution screen and maxLevel value changed to 1024.

EDIT 2014-01-23: I fixed a small bug in ColorChar.exe program that incorrectly show results when the number of adjacent pixels of same color is larger than 1024.

Code: Select all

@if (@CodeSection == @Batch) @then


@echo off

rem Mandelbrot Set graphic in text mode
rem Batch-JScript hybrid version optimized for high resolution screens
rem Include "Terminal 1x1.FNT" font file and installation instructions
rem Antonio Perez Ayala

setlocal EnableDelayedExpansion
if "%~1" equ "DrawLines" goto DrawLines

rem Create "Terminal 1x1.FNT" file if not exists
if not exist "Terminal 1x1.FNT" (
   call :ExtractBinaryFile "Terminal 1x1.FNT"
   echo/
   echo In order to install a "Terminal" raster font right-click on it and select
   echo "Install", or open Fonts via Control Panel and drag^&drop the font file.
   echo/
   echo To use the installed font in a Command-line window, follow these steps:
   echo/
   echo 1. Right-click on any MS-DOS Command-line icon and select "Create shortcut"
   echo    or "Copy".
   echo 2. Open the folder that contain the programs that will be used in this window
   echo    and type Ctrl-V (paste^); a new MS-DOS shortcut icon is created.
   echo 3. Open the new icon, right-click on the title bar and select "Properties".
   echo 4. Open "Font" tab, select "Bitmap fonts" and "1x1" size.
   echo 5. Open "Layout" tab and enter a large size in Buffer and Window sizes; for
   echo    example: Width: 800, Height: 600 (same values in BOTH Buffer and Window^).
   echo 6. Click OK, type EXIT and press Enter.
   echo/
   echo After that, it is suggested to rename the new icon to include the resolution
   echo and the font size; for example: "MS-DOS 800x600 @ 1x1". To use this icon:
   echo open it, type the name of the program to execute and press Enter.
   echo/
   pause
   goto :EOF
)

rem Working values: maximum screen coordinates
rem The Command-line window MUST have the same values in BOTH Buffer and Window sizes
set /A maxY=0, maxX=0
for /F "skip=2 tokens=2" %%a in ('mode con') do (
   if !maxY! equ 0 ( set /A maxY=%%a-2
   ) else if !maxX! equ 0 ( set /A maxX=%%a-1
   )
)

if not exist ColorChar.exe call :ExtractBinaryFile ColorChar.exe
rem Create the semaphore-signal file and start the asynchronous process
echo X > Flag.out
if exist Flag.in del Flag.in
rem Get output lines from JScript section and show they with ColorChar.exe
cls
CScript //nologo //E:JScript "%~F0" %maxY% %maxX% | "%~F0" DrawLines
del Flag.out
pause
goto :EOF

:DrawLines
   rem Wait for "Data Available" signal
   if not exist Flag.in goto DrawLines
   rem Read the input line sent by JScript code
   set line=
   set /P "line="
   rem Set "Data Read" acknowledgement
   ren Flag.in Flag.out
   rem Check the standard "End Of piped File" mark
   if not defined line goto :EOF
   ColorChar %line%
goto DrawLines


rem ExtractBinaryFile from hexadecimal digits placed in a "resource" in this .bat file
:ExtractBinaryFile filename.ext
setlocal EnableDelayedExpansion
set "start="
set "end="
for /F "tokens=1,3 delims=:=>" %%a in ('findstr /N /B "</*resource" "%~F0"') do (
   if not defined start (
      if "%%~b" equ "%~1" set start=%%a
   ) else if not defined end set end=%%a
)
(for /F "skip=%start% tokens=1* delims=:" %%a in ('findstr /N "^" "%~F0"') do (
   if "%%a" == "%end%" goto decodeHexFile
   echo %%b
)) > "%~1.hex"
:decodeHexFile
< "%~1.hex" Cscript //nologo //E:JScript "%~F0" Extract "%~1"
del "%~1.hex"
exit /B


<resource id="Terminal 1x1.FNT">
00034403[2]416e746f6e696f20506572657a204179616c612028616b6120416163696e6929006163696e692900446c6c5c6e74646c6c2e646c6c[24]
9001ff010001[2]01000100207f212061[5]3b03[6]da02[3]01[29]0100da02[2]0100db02[2]0100dc02[2]0100dd02[2]0100de02[2]0100df02
[2]0100e002[2]0100e102[2]0100e202[2]0100e302[2]0100e402[2]0100e502[2]0100e602[2]0100e702[2]0100e802[2]0100e902[2]0100ea
02[2]0100eb02[2]0100ec02[2]0100ed02[2]0100ee02[2]0100ef02[2]0100f002[2]0100f102[2]0100f202[2]0100f302[2]0100f402[2]0100
f502[2]0100f602[2]0100f702[2]0100f802[2]0100f902[2]0100fa02[2]0100fb02[2]0100fc02[2]0100fd02[2]0100fe02[2]0100ff02[2]01
[2]03[2]01000103[2]01000203[2]01000303[2]01000403[2]01000503[2]01000603[2]01000703[2]01000803[2]01000903[2]01000a03[2]01
000b03[2]01000c03[2]01000d03[2]01000e03[2]01000f03[2]01001003[2]01001103[2]01001203[2]01001303[2]01001403[2]01001503[2]
01001603[2]01001703[2]01001803[2]01001903[2]01001a03[2]01001b03[2]01001c03[2]01001d03[2]01001e03[2]01001f03[2]01002003[2]
01002103[2]01002203[2]01002303[2]01002403[2]01002503[2]01002603[2]01002703[2]01002803[2]01002903[2]01002a03[2]01002b03[2]
01002c03[2]01002d03[2]01002e03[2]01002f03[2]01003003[2]01003103[2]01003203[2]01003303[2]01003403[2]01003503[2]01003603[2]
01003703[2]01003803[2]01003903[2]08003a03[3][6x80]0080[7]80[3]808080008080[3]8080[2]8000[6x80][2][9x80]00[5x80]008080[4]
[11x80]00[15x80][3]80005465726d696e616c00
</resource>

<resource id="ColorChar.exe">
4d5a900003[3]04[3]ffff[2]b8[7]40[35]b0[3]0e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f74206265207275
6e20696e20444f53206d6f64652e0d0d0a24[7]55b5b8fd11d4d6ae11d4d6ae11d4d6ae9fcbc5ae18d4d6aeedf4c4ae13d4d6ae5269636811d4d6ae
[8]5045[2]4c010300ff23cd52[8]e0000f010b01050c0004[3]04[7]10[3]10[3]20[4]40[2]10[3]02[2]04[7]04[8]40[3]04[6]03[5]10[2]10
[4]10[2]10[6]10[11]1c20[2]28[84]20[2]1c[27]2e74657874[3]a202[3]10[3]04[3]04[14]20[2]602e7264617461[2]ea[4]20[3]02[3]08[14]
40[2]402e64617461[3]20[4]30[3]02[3]0a[14]40[2]c0[480]e806[3]50e87302[2]558bec81c4f4dffffffc6af5e86e02[2]8945fc6800304000
ff75fce85802[2]8dbdfcdfffff89bdf8dfffffe81302[2]e83202[2]8a064684c00f846001[2]3c2f75672bbdf8dfffff74168d85f4dfffff5057ff
b5f8dfffffff75fce88b01[2]8bbdf8dfffff8a064684c00f842d01[2]2c303c0976082c073c0f76022c208a264684e40f841401[2]80fc20741286
c42c303c0976082c073c0f76022c20d51066a316304000eb853c2275208a064684c00f84e6[3]3c227405880747ebec8a06463c2274f4e961ffffff
3c300f82c9[3]3c390f87c1[3]e8e3[3]8ae080ff2a740a80ff58740580ff7875278adc468a06463c300f829d[3]3c390f8795[3]e8b7[3]0fb7c88a
c3f3aae914ffffff80fc20737780fc09751f8b0d0430400003cf2b8df8dfffff83e10783e908f7d9b020f3aae9ebfeffff2bbdf8dfffff7418508d85
f4dfffff5057ffb5f8dfffffff75fce889[3]588bbdf8dfffff88276a008d85f4dfffff506a01ffb5f8dfffffff75fce8fd[3]6800304000ff75fce8
e4[3]e998feffff882747e990feffff2bbdf8dfffff74168d85f4dfffff5057ffb5f8dfffffff75fce82f[3]33c0c9c3e8[4]6683e00f66b90a008a
3e4680ff30721480ff39770f66f7e180ef30660fb6d76603c2ebe44ec3558bec6a00ff7514ff7510ff750cff7508e880[3]8b4d10578b7d0c66a116
304000f366ab8b0d04304000ff751451ff7510ff750cff7508e85e[3]5f6800304000ff7508e83e[3]c9c21000[6xcc]e847[3]8bf08a06463c2275
098a06463c2275f9eb0c8a06463c20740484c075f54ec38a06463c2074f94ec3ccff2514204000ff2500204000ff2504204000ff2508204000ff250c
204000ff25102040[351]6e20[2]8c20[2]9c20[2]ac20[2]ca20[2]6020[6]4420[10]dc20[3]20[22]6e20[2]8c20[2]9c20[2]ac20[2]ca20[2]
6020[6]9b004578697450726f6365737300f500476574436f6e736f6c6553637265656e427566666572496e666f[2]6a0147657453746448616e646c
65[2]ee025772697465436f6e736f6c654100f2025772697465436f6e736f6c654f757470757441747472696275746500e600476574436f6d6d616e
644c696e6541006b65726e656c33322e646c6c[302]07[489]
</resource>


@end


if ( WScript.Arguments(0) != "Extract" ) {

// Calculate Mandelbrot Set points and output they to Batch section

fso = new ActiveXObject("Scripting.FileSystemObject");

// Horizontal range: for 4:3 screen use range=3 (-1,2), for 16:9 screen use range=4 (-1.5,2.5)
var           yTop=1.1250,
    xLeft=-1.0000, xRight=2.0000,
           yBottom=-1.1250,       maxLevel=32,  // larger maxLevel values produce finer image details
    maxY=parseInt(WScript.Arguments(0)), maxX=parseInt(WScript.Arguments(1)),
    xStep=(xRight-xLeft)/maxX, yStep=(yBottom-yTop)/maxY, yPos=yTop-yStep,
    color="0123456789ABCDDEEEE";

for ( var y = 0; y <= maxY; y++ ) {
   yPos+=yStep;
   var xPos=xLeft-xStep, line="", prevPixel="", count=0, pixel;
   for ( var x = 0; x <= maxX; x++ ) {
      xPos+=xStep;
      var xIter=xPos, yIter=yPos, xSquare=xIter*xIter, ySquare=yIter*yIter, root=xSquare+ySquare, level=0;
      for ( var i = 1; i <= maxLevel; i++ ) {
         if ( root < 4 ) {
            yIter=2*xIter*yIter-yPos; xIter=xSquare-ySquare-xPos; xSquare=xIter*xIter; ySquare=yIter*yIter; root=xSquare+ySquare;
         } else {
            level=i;
            break;
         }
      }
      pixel = (level<color.length) ? color.charAt(level) : "F";
   // Use next line instead of previous one when maxLevel > 500
   // pixel = (level<color.length) ? color.charAt(level) : ((level<36)?"1":"F");
      if ( pixel != prevPixel ) {
         line+=" /"+prevPixel+" 219*"+count;
         if ( line.length > 1000 ) {
            sendLine(line);
            line = "";
         }
         prevPixel=pixel;
         count=1;
      } else {
         count++;
      }
   }
   line+=" /"+prevPixel+" 219*"+count;
   sendLine(line);
}
// Wait for last "Data Read" acknowledgement
while ( ! fso.FileExists("Flag.out") ) {
      WScript.Sleep(1);
}
// Send the standard "End Of piped File" mark
WScript.Echo();
fso.MoveFile("Flag.out", "Flag.in");

} else {

// Extract a hexadecimal "resource" into a binary file

// Convert Ascii hexadecimal digits from Stdin to a binary string
var count, byte, output = "";
while ( !WScript.Stdin.AtEndOfStream ) {
   var input = WScript.Stdin.ReadLine();
   for ( var index = 0; index < input.length; ) {
      if ( input.charAt(index) == '[' ) {
         for ( count = ++index; input.charAt(index) != 'x' &&
                                input.charAt(index) != ']' ; index++ ) ;
         count = parseInt(input.slice(count,index++));
         if ( input.charAt(index-1) == 'x' ) {
            byte = String.fromCharCode(parseInt(input.substr(index,2),16));
            index += 3;
         } else {
            byte = String.fromCharCode(0);
         }
         for ( var i = 1; i <= count; i++ ) output += byte;
      } else {
         output += String.fromCharCode(parseInt(input.substr(index,2),16));
         index += 2;
      }
   }
}

// Write the binary string to the output file
var ado = WScript.CreateObject("ADODB.Stream");
ado.Type = 2;  // adTypeText = 2
ado.CharSet = "iso-8859-1";  // right code page for output (no adjustments)
ado.Open();
ado.WriteText(output);
ado.SaveToFile(WScript.Arguments(1),2); // adSaveCreateOverWrite = 2
ado.Close();

}

function sendLine ( line ) {
   // Wait for "Data Read" acknowledgement
   while ( ! fso.FileExists("Flag.out") ) {
      WScript.Sleep(1);
   }
   // Send the line to Batch code
   WScript.Echo(line);
   // Set "Data Available" signal
   fso.MoveFile("Flag.out", "Flag.in");
}


Enjoy! :D

Antonio

Re: Drawing pixel resolution graphics in text mode

Posted: 10 Jan 2014 14:33
by dbenham
Very cool 8)

I don't know that I will use it, but cool never-the-less :D


Dave Benham

Re: Drawing pixel resolution graphics in text mode

Posted: 10 Jan 2014 15:46
by Squashman
dbenham wrote:Very cool 8)

I don't know that I will use it, but cool never-the-less :D


Dave Benham

No Snakey.bat upgrade. :(

Re: Drawing pixel resolution graphics in text mode

Posted: 10 Jan 2014 15:50
by penpen
Impressive :!:
I "see" some dos games in "high-res" (320x200: C64 graphic mode resolution), if that's fast enough.

penpen

Re: Drawing pixel resolution graphics in text mode

Posted: 10 Jan 2014 19:04
by berserker
using cscript jscript? how about one only in DOS batch?

Re: Drawing pixel resolution graphics in text mode

Posted: 10 Jan 2014 19:30
by foxidrive
dbenham wrote:Very cool 8)

I don't know that I will use it, but cool never-the-less :D


+1

Re: Drawing pixel resolution graphics in text mode

Posted: 10 Jan 2014 21:45
by dbenham
I like pure batch solutions, which pretty much restricts the screen to monochrome if you want reasonable performance. It also requires a CLS and full screen refresh for each animation frame. The more characters per screen, the longer it takes to clear the screen and refresh, which results in more flicker. For my SNAKE program, I use an entire character to represent one coordinate position. The character represents a sprite, and the positioning of the sprite is restricted to integral character positions. One advantage of restricting the screen to 40 x 25 is to facilitate fast refreshes. (The other reason is so a string of coordinates that fills the screen can fit into a single variable).

Another idea for a batch game is breakout, but limiting ball position to character coordinates severely limits the number of angles and smoothness of the animation. Using 1 pixel (or 4 pixel) characters could produce very smooth animation, but I fear it will be two slow. It would also be tedious and slow to print text (scores) to the screen if you have to build each character pixel by pixel.

Here is an idea :idea:
Use a custom 8 x 12 pixel charcter set. ASCII values 1-127 can contain the standard ASCII characters. Extended values 128-191 can represent 2x3 logical pixel grids with a square of 4 physical pixels representing each logical pixel. The 64 characters are all that are needed to represent all possible pixel patterns, ranging from all 6 pixels off to all 6 pixels on. That leaves 64 characters (192-255) to represent larger blocks with various shading and/or patterns, or whatever additional sprites as might be needed. The brick wall can be composed of blocks using different shades/patterns to represent different block characteristics.

A playing field of 60 x 40 characters would represent a 120x120 pixel graphic screen, with the ability to easily print text and larger shaded blocks. A string of 60 characters would represent 120x3 pixels. The math required to plot individual pixels by substring minipulation should not be too bad, and I think the performance can still be good.

The moving "ball" can be a block of 2x2 logical pixels, but it can now move as little as 1 logical pixel at a time. This should allow for more angles of motion with smoother animation.

I don't know if I will ever tackle this project, but it sounds interesting to me :)


Dave Benham

Re: Drawing pixel resolution graphics in text mode

Posted: 11 Jan 2014 16:53
by carlos
@Aacini: thanks for the idea about the 1x1 Font size. The only disadvantage is that it need installation. I'm working with the size of the Font. Currently I reduce it to only 290 bytes, but it can be less, sure. I'm Reading the Font specification.

Re: Drawing pixel resolution graphics in text mode

Posted: 11 Jan 2014 20:57
by Aacini
dbenham wrote:Here is an idea :idea:
Use a custom 8 x 12 pixel charcter set. ASCII values 1-127 can contain the standard ASCII characters. Extended values 128-191 can represent 2x3 logical pixel grids with a square of 4 physical pixels representing each logical pixel. The 64 characters are all that are needed to represent all possible pixel patterns, ranging from all 6 pixels off to all 6 pixels on. That leaves 64 characters (192-255) to represent larger blocks with various shading and/or patterns, or whatever additional sprites as might be needed. The brick wall can be composed of blocks using different shades/patterns to represent different block characteristics.

A playing field of 60 x 40 characters would represent a 120x120 pixel graphic screen, with the ability to easily print text and larger shaded blocks. A string of 60 characters would represent 120x3 pixels. The math required to plot individual pixels by substring minipulation should not be too bad, and I think the performance can still be good.

The moving "ball" can be a block of 2x2 logical pixels, but it can now move as little as 1 logical pixel at a time. This should allow for more angles of motion with smoother animation.

I don't know if I will ever tackle this project, but it sounds interesting to me :)


Dave Benham


Although I prefer the traditional "pixel coordinates" method, because it allows to directly convert any graphic application into a Batch file, I can see your viewpoint. Your idea is interesting and it can be implemented in a relatively easy way, at least to draw a single logical pixel in each character cell.

The transformation of logical pixel coordinates into text column and line could be achieved in an easier way if the graphic characters are defined for this purpose. If we take a 8x12 pixels font as base, and we want to use a 2x2 "logical pixel", we need to define the following characters in the font in order to draw just a single "pixel" in one character cell.

Code: Select all

**......  ..**....  ....**..  ......**
**......  ..**....  ....**..  ......**
........  ........  ........  ........
........  ........  ........  ........
........  ........  ........  ........
........  ........  ........  ........
........  ........  ........  ........
........  ........  ........  ........
........  ........  ........  ........
........  ........  ........  ........
........  ........  ........  ........
........  ........  ........  ........

and another 5 similar groups, each one starting with these characters:

Code: Select all

........   ........   ........   ........   ........
........   ........   ........   ........   ........
**......   ........   ........   ........   ........
**......   ........   ........   ........   ........
........   **......   ........   ........   ........
........   **......   ........   ........   ........
........   ........   **......   ........   ........
........   ........   **......   ........   ........
........   ........   ........   **......   ........
........   ........   ........   **......   ........
........   ........   ........   ........   **......
........   ........   ........   ........   **......

so they take 24 characters from the 128 available ones in the 128-255 range.

Lets define a 3x2 text screen as base:

Code: Select all

012
1XX

Previous text screen represent a (3x8) x (2x12) = 24x24 pixels area using the 8x12 font, but our "logical pixel" is 2x2 size, so from this point of view, previous screen have 12x12 "logical pixel" coordinates. For convenience, lets these logical coordinates and the line/column text coordinates start at 0.

If X=horizontal "logical pixel" coordinate from 0 to 11, and Y=vertical "logical pixel" coordinate from 0 to 11, then: set /A column=X*2/8, line=Y*2/12 convert "logical pixel" coordinates into column in 0-2 range and line in 0-1 range ones. In a similar way, set /A colChar=(X*2%%8)/2, lineChar=(Y*2%%12)/2 gives values that select the appropriate "graphic character" this way:

Code: Select all

  colChar = 0         1         2         3

lineChar=0  **......  ..**....  ....**..  ......**
            **......  ..**....  ....**..  ......**
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........

... etc, until:

lineChar=5  ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            ........  ........  ........  ........
            **......  ..**....  ....**..  ......**
            **......  ..**....  ....**..  ......**

If previous characters are defined in the custom font in an adjacent group starting at character number 128, then: set /A char= (Y%%6)*4 + X%%4 + 128 gives the position of the appropriate character. The same value excepting the "+ 128" gives the index in a string comprised of 24 characters starting at Ascii 128.

The Batch file Below is a small example of previous method as a proof of concept:

Oops! After wrote previous text, I developed the program and tried to test it. After many tests, I realized that we can NOT select a "Terminal" face font of the same size of a pre-installed one, although it IS possible to install it: in this case in the list of sizes appear TWO 8x12 sizes and the displayed font changes as you select different ones indeed, but the pre-installed font is always selected when the selection window is closed! For this reason, I had to define a 12x12 size font in order to test previous example, but I opted for not modify the already written text because I think the description is clearer if the two sizes are different. Just note that this modification requires 6x6=36 graphic characters, from 128 to 163, instead of the previous 6x4=24.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

set /A cols=24, lines=24
set /A screenSize=cols*lines-1, logicalCols=cols*6-1, logicalLines=lines*6-1
set "background="
for /F "usebackq delims=" %%a in ("%~F0") do set "background=!background!%%a - "
set "background=!background:~0,%screenSize%!"
set "graphicsChar=€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£"

mode con cols=%cols% lines=%lines%
for /L %%y in (0,1,%logicalLines%) do (
   set /A line=%%y/6
   for /L %%x in (0,1,%logicalCols%) do (
      set /A "column=%%x/6, char= (%%y%%6)*6 + %%x%%6"
      set /A head=line*cols+column, tail=head+1
      for /F "tokens=1-3" %%a in ("!head! !char! !tail!") do (
         cls
         set /P "=!background:~0,%%a!!graphicsChar:~%%b,1!!background:~%%c!" < NUL
      )
      ping -n 1 localhost >nul
   )
)

You may create the 12x12 custom font that include the 36 graphic characters required for previous test from this "resource":

Code: Select all

<resource id="Terminal 12x12 with 2x2 pixels.FNT">
0003911e[2]416e746f6e696f20506572657a204179616c612028616b6120416163696e6929[2]433a5c4e745c446c6c5c6e74646c6c2e646c6c[9]
5a000c0012000a[8]9001ff0c000c[2]0c000c0001ff1f1fff01[4]881e[6]9406[3]01[29]0c009406[2]0c00ac06[2]0c00c406[2]0c00dc06[2]
0c00f406[2]0c000c07[2]0c002407[2]0c003c07[2]0c005407[2]0c006c07[2]0c008407[2]0c009c07[2]0c00b407[2]0c00cc07[2]0c00e407[2]
0c00fc07[2]0c001408[2]0c002c08[2]0c004408[2]0c005c08[2]0c007408[2]0c008c08[2]0c00a408[2]0c00bc08[2]0c00d408[2]0c00ec08[2]
0c000409[2]0c001c09[2]0c003409[2]0c004c09[2]0c006409[2]0c007c09[2]0c009409[2]0c00ac09[2]0c00c409[2]0c00dc09[2]0c00f409[2]
0c000c0a[2]0c00240a[2]0c003c0a[2]0c00540a[2]0c006c0a[2]0c00840a[2]0c009c0a[2]0c00b40a[2]0c00cc0a[2]0c00e40a[2]0c00fc0a[2]
0c00140b[2]0c002c0b[2]0c00440b[2]0c005c0b[2]0c00740b[2]0c008c0b[2]0c00a40b[2]0c00bc0b[2]0c00d40b[2]0c00ec0b[2]0c00040c[2]
0c001c0c[2]0c00340c[2]0c004c0c[2]0c00640c[2]0c007c0c[2]0c00940c[2]0c00ac0c[2]0c00c40c[2]0c00dc0c[2]0c00f40c[2]0c000c0d[2]
0c00240d[2]0c003c0d[2]0c00540d[2]0c006c0d[2]0c00840d[2]0c009c0d[2]0c00b40d[2]0c00cc0d[2]0c00e40d[2]0c00fc0d[2]0c00140e[2]
0c002c0e[2]0c00440e[2]0c005c0e[2]0c00740e[2]0c008c0e[2]0c00a40e[2]0c00bc0e[2]0c00d40e[2]0c00ec0e[2]0c00040f[2]0c001c0f[2]
0c00340f[2]0c004c0f[2]0c00640f[2]0c007c0f[2]0c00940f[2]0c00ac0f[2]0c00c40f[2]0c00dc0f[2]0c00f40f[2]0c000c10[2]0c002410[2]
0c003c10[2]0c005410[2]0c006c10[2]0c008410[2]0c009c10[2]0c00b410[2]0c00cc10[2]0c00e410[2]0c00fc10[2]0c001411[2]0c002c11[2]
0c004411[2]0c005c11[2]0c007411[2]0c008c11[2]0c00a411[2]0c00bc11[2]0c00d411[2]0c00ec11[2]0c000412[2]0c001c12[2]0c003412[2]
0c004c12[2]0c006412[2]0c007c12[2]0c009412[2]0c00ac12[2]0c00c412[2]0c00dc12[2]0c00f412[2]0c000c13[2]0c002413[2]0c003c13[2]
0c005413[2]0c006c13[2]0c008413[2]0c009c13[2]0c00b413[2]0c00cc13[2]0c00e413[2]0c00fc13[2]0c001414[2]0c002c14[2]0c004414[2]
0c005c14[2]0c007414[2]0c008c14[2]0c00a414[2]0c00bc14[2]0c00d414[2]0c00ec14[2]0c000415[2]0c001c15[2]0c003415[2]0c004c15[2]
0c006415[2]0c007c15[2]0c009415[2]0c00ac15[2]0c00c415[2]0c00dc15[2]0c00f415[2]0c000c16[2]0c002416[2]0c003c16[2]0c005416[2]
0c006c16[2]0c008416[2]0c009c16[2]0c00b416[2]0c00cc16[2]0c00e416[2]0c00fc16[2]0c001417[2]0c002c17[2]0c004417[2]0c005c17[2]
0c007417[2]0c008c17[2]0c00a417[2]0c00bc17[2]0c00d417[2]0c00ec17[2]0c000418[2]0c001c18[2]0c003418[2]0c004c18[2]0c006418[2]
0c007c18[2]0c009418[2]0c00ac18[2]0c00c418[2]0c00dc18[2]0c00f418[2]0c000c19[2]0c002419[2]0c003c19[2]0c005419[2]0c006c19[2]
0c008419[2]0c009c19[2]0c00b419[2]0c00cc19[2]0c00e419[2]0c00fc19[2]0c00141a[2]0c002c1a[2]0c00441a[2]0c005c1a[2]0c00741a[2]
0c008c1a[2]0c00a41a[2]0c00bc1a[2]0c00d41a[2]0c00ec1a[2]0c00041b[2]0c001c1b[2]0c00341b[2]0c004c1b[2]0c00641b[2]0c007c1b[2]
0c00941b[2]0c00ac1b[2]0c00c41b[2]0c00dc1b[2]0c00f41b[2]0c000c1c[2]0c00241c[2]0c003c1c[2]0c00541c[2]0c006c1c[2]0c00841c[2]
0c009c1c[2]0c00b41c[2]0c00cc1c[2]0c00e41c[2]0c00fc1c[2]0c00141d[2]0c002c1d[2]0c00441d[2]0c005c1d[2]0c00741d[2]0c008c1d[2]
0c00a41d[2]0c00bc1d[2]0c00d41d[2]0c00ec1d[2]0c00041e[2]0c001c1e[2]0c00341e[2]0c004c1e[2]0c00641e[2]08007c1e[4]1e619280e1
9e611e[5]804040c04080[5]1e7fedff9ee17f1e[5]80c0c040c080[5]73ffffff7f1e0c0c[4]80c0c0c080[7]0c1e7fffff7f1e0c[6]80c0c080[5]
020f0f1f7f7f1d021f[4]8080c0f0f0c000c0[3]020f1f7f7f7f1d021f[4]80c0f0f0f0c000c0[5]0c1e7f1e0c[9]80[7]fffff3e180e1f3ffff[3]
[4xc0]40[4xc0][5]1e6161611e[8]808080[6]ffffe19e9e9ee1ffff[3]c0c0c0404040c0c0c0[3]0301027c8282827c[4]c0c040[9]0f1010100f
021f0202[3]804040408000c0[5]0e0e0d0d0c0c7d70[6]80c0404080[5]031e[4x10]e3e3[4]c0[5x40]8080[4]0c6d1e61e1611e6d0c[4]800080
c0800080[6]101c1e1f1e1c10[8]80[8]01030f1f0f0301[5][7x80][3]0c1e6d0c0c0c6d1e0c[5]80[3]80[4][6x71][2]7171[2][6xc0][2]c0c0
[2]1f7f7f7f1f[5x01][2]f0[9xc0][2]1f71701e731d0f01717f[2]c0c0[2]80c080c0c080[7][5xff][7][5xc0][2]0c1e6d0c0c6d1e0c007f[4]
80[2]80[3]80[3]0c1e6d[6x0c][5]80[9][6x0c]6d1e0c[9]80[8]0201ff0102[8]80c080[8]1060ff6010[9]c0[10][4x70]7f[11]c0[6]1261ff
6112[8]80c080[8]020f1f7f[9]80c0f0[7]7f1f0f02[8]f0c080[30][5x1e]0c0c001e1e[14]1d1d1d[9]c0c0c0[9]1111117f11117f111111[2]808080
c08080c0808080[2]0e0e1f70701f01017f0e0e[3]c0[2]80c0c080[3]1c72721d030e1d736301[3]3070c08000c0b0b0c0[2]1e7373731e73717171
1e[3]80808000f0c0c0c070[2]0e0e0e[21]030e0e[4x1c]0e0e03[2]80[8]80[2]1c0e0e[4x03]0e0e1c[5][4x80][7]1d0f7f0f1d[7]c080f080c0
[8]0e0e7f0e0e[9]c0[14]0f03030e[8]808080[6]7f[11]c0[14]0f0f[10]8080[2]010103030e0e1c1c7070[2]c0c08080[8]1f717373737d7d7d
711f[2]80[8xc0]80[2]030f7f[7x03][2][10x80][2]1f71710101030e1c707f[2]80[4xc0]80[3]c0[2]1f7101010f010101711f[2]80c0c0c080
[4xc0]80[2]1c1c1c1d1d71717f0101[5][4xc0]f0c0c0[2]7f7070707f010101711f[2]c0[3]80[4xc0]80[2]030e1c1c7f[4x71]1f[2]80[3]80[4xc0]
80[2]7f0103030e0e0e1c1c1c[2]c0c08080[8]1f71717d1f737171711f[2]80c0c0c080[4xc0]80[2]1f[4x71]1f030e1c70[2]80[4xc0]8080[8]
0f0f[3]0f0f[5]8080[3]8080[5]0f0f[3]0f03030e[3]8080[3]808080[2]01030e1c701c0e0301[3]8080[5]8080[5]7f[2]7f[8]c0[2]c0[6]60
701c0e030e1c7060[7]80[6]1f710101030e0e000e0e[2]80c0c0c080[7]7f808f[4x9d]8f807f[2]8040[5xc0]8000c0[2]0e1f[4x71]7f717171[3]
80[8xc0][2]7f7171717f[4x71]7f[2]80c0c0c080[4xc0]80[2]1f7171[4x70]71711f[2]80c0c0[4]c0c080[2]7e73[6x71]737e[3]80[6xc0]80
[3]7f7070707f[4x70]7f[2]c0[3]80[4]c0[2]7f7070707f[5x70][2]c0[3]80[7]1f71717070737171711f[2]80c0c0[2][5xc0][2][4x71]7f[5x71]
[2][10xc0][2]1f[8x0e]1f[2]80[8]80[2][5x01][4x71]1f[2][9xc0]80[2]717173737e7e73737171[2]c0c08080[2]8080c0c0[2][9x70]7f[11]
c0[2]70707d[5x72]7070[2]7070f0[7x70][2]70707c7e7371[4x70][2][4x70]f0f0[4x70][2]1f[8x71]1f[2]80[8xc0]80[2]7f7171717f[5x70]
[2]80c0c0c080[7]1f[8x71]1f030180[8xc0]8080c07f7171717f73[4x71][2]80[4xc0]80[4xc0][2]1f71717c1e0f0371711f[2]80c0c0[2]80c0c0c0
80[2]7f[9x0e][2]c0[11][9x71]1f[2][9xc0]80[2][8x71]1f0e[2][8xc0]80[3][4x70]7272721d1d1d[2][7x70]c0c0c0[2]7171711f0e1f[4x71]
[2]c0c0c0800080[4xc0][2][4x71]1f[5x0e][2][4xc0]80[7]7f0103030e0e1c1c707f[2]c0c08080[5]c0[2]1f[8x1c]1f[2]80[8]80[2]70701c1c
0e0e03030101[8]8080c0c0[2]1f[8x03]1f[2][10x80][2]0e1f71[10]80c0[19]ff[11]f0001e03[11]80[13]1f011f7171711f[5]80[6xc0][2]
7070707f[5x71]7f[5]80[5xc0]80[5]1f71707070711f[5]80c0[3]c080[2]0101011f[5x71]1f[2][10xc0][5]1f71717f70701f[5]80c0c0c0[2]
c0[2]030e0e1f[6x0e][2]c0[2]c0[11]1f[4x71]1f01017f[3][8xc0]807070707f[6x71][5]80[6xc0][2]0e[2]7e[5x0e]7f[11]c0[2]03[2]1f
[7x03]1e80[2][8x80]0070707071737e7e737171[5]c080[2]80c0c0[2]7e[8x0e]7f[11]c0[5]7f[5x72]70[5]c0[6x70][5]7f[6x71][5]80[6xc0]
[5]1f[5x71]1f[5]80[5xc0]80[5]7f[5x71]7f7070[3]80[5xc0]80[5]1f[5x71]1f0101[3][9xc0][3]1d1f1e[4x1c][5]c0c0[10]1f70701f0101
7f[5]c0[2]80c0c080[3]0e0e1f[5x0e]03[5]80[5]c0[5][6x71]1f[5][7xc0][5][5x71]1f0e[5][5xc0]80[6]70707272721d1d[5][5x70]c0c0
[5]71711f0e1f7171[5]c0c0800080c0c0[5][5x71]1f030e7c[3][5xc0]8080[5]7f01030e1c707f[5]c0c080[3]c0[2]030e0e1c70701c0e0e03[2]
c0[8]c0[2][12x0e][12]7c0e0e030101030e0e7c[5]80c0c080[5]1c7f63[9]40c080[11]0e1f71[4x60]7f[5]80c0[4x40]c0[2]c0c0[22]3030[22]
0c0c[22]0303[34]c0c0[22]3030[12]c0c0[22]3030[22]0c0c[22]0303[34]c0c0[22]3030[12]c0c0[22]3030[22]0c0c[22]0303[34]c0c0[22]
3030[12]c0c0[22]3030[22]0c0c[22]0303[34]c0c0[22]3030[12]c0c0[22]3030[22]0c0c[22]0303[34]c0c0[22]3030[12]c0c0[22]3030[22]
0c0c[22]0303[34]c0c0[22]30301d73007f[6x71][2]c0800080[6xc0][2]1d7300717d7f73717171[2]c08000[7xc0][2]1f011f71711f007f[4]
80[5xc0]00c0[4]1f[4x71]1f007f[4]80[4xc0]8000c0[4]0e0e000e0e1c7070711f[10]c080[2]7fe19e929e9c9292e17f[2]80c0[6x40]c080[7]
7f[4x01][7][5xc0][2]1c7c1c1c1f1c0001030f[6]c07070c080f0[2]1c7c1c1c1c1d010203[7]70f0f070f070[2]1e1e[2]0c0c[4x1e][17]1d73
eeee731d[6]c080[2]80c0[6]731d0e0e1d73[6]80c07070c080[3]10008200100082001000820040[3]40[3]40[3]10821082108210821082108240
00400040004000400040006d926d926d926d926d926d92b040b040b040b040b040b040[12x02][12][5x02]fe[6x02][12]030e0e1f71717f717171
[2]c0[2]80[6xc0][2]1f710e1f71717f717171[2]80c00080[6xc0][2]7c0e0e1f71717f717171[5]80[6xc0][2]7fe18e[4x9c]8ee17f[2]80c0[6x40]
c080[2][4x0d]fd01fd[5x0d][12x80][12x0d][12x80][4]ff01fd[5x0d][4][8x80][4x0d]fd01ff[5][7x80][5]0e0e1f717070711f0e0e[4]80
c0[2]c080[4][4x71]1f7f0e7f0e0e[2][4xc0]80c000c0[9]fe[6x02][12][5x02]03[11]f0[6][5x02]ff[11]f0[11]ff[6x02][5]f0[6][5x02]
03[6x02][5]f0[11]ff[11]f0[6][5x02]ff[6x02][5]f0[6]1d73001f011f7171711f[2]c0800080[6xc0][2]1d730e1f71717f717171[2]c08000
80[6xc0][2][5x0d]0c0f[5][4x80]f000f0[9]0f0c[6x0d][4]f000f0[5x80][4x0d]fd00ff[5][4x80]f000f0[9]ff00fd[5x0d][4]f000f0[5x80]
[5x0d]0c[6x0d][4x80]f000f0[5x80][4]ff00ff[9]f000f0[5][4x0d]fd00fd[5x0d][4x80]f000f0[5x80]00e1731e73731e73e1[4]c080008080
0080c0[3]721c6e031f[4x71]1f[5]8080[4xc0]80[2]7f717171fd[4x71]7f[2]80[8xc0]80[2]1f71007f70707e70707f[2]80c000c0[5]c0[2]71
007f70707e7070707f[2]c000c0[6]c0[2]7c0e007f70707e70707f[5]c0[5]c0[5]7e[5x0e]7f[11]c0[2]030e001f[5x0e]1f[2]c0[2]80[5]80[2]
1f71001f[5x0e]1f[2]80c00080[5]80[2]71001f[6x0e]1f[2]c00080[6]80[2][5x02]fe[23]03[6x02][5]f0[6][12xff][12xf0][6][6xff][6]
[6xf0][4x0e][2][4x0e][14]7c0e001f[5x0e]1f[5]80[5]80[2][6xff][6][6xf0][6]030e1f[6x71]1f[2]c00080[6xc0]80[2]1f7171717f[4x71]
73[2]80c0c0c080[4xc0]80[2]1f601f[6x71]1f[2]804080[6xc0]80[2]7c0e1f[6x71]1f[4]80[6xc0]80[2]1d73001f[5x71]1f[2]c0800080[5xc0]
80[2]1d731f[6x71]1f[2]c08080[6xc0]80[5][6x71]7e7070[3][6xc0]70[2]7070707f[5x71]7f7070[3]80[5xc0]80[2]7070707f[4x71]7f707070
[3]80[4xc0]80[3]030e[7x71]1f[2]c000[7xc0]80[2]1f7100[6x71]1f[2]80c000[6xc0]80[2]7c0e[7x71]1f[4][7xc0]80[2]030e00[5x71]1f
030e7cc0[2][5xc0]8080[2]030e007171711f0e0e0e[2]80[2]c0c0c080[5]ff[11]f0[11]0f1c[10]80[16]1f[11]80[8]0e0e7f0e0e007f[7]c0
[3]c0[13]ffff[10]f0f07c0e1c0e7c01010203[7]70f0f070f070[2]1f7f7f7f1f[5x01][2]f0[9xc0][2]1f71701e731d0f01717f[2]c0c0[2]80
c080c0c080[4]0e0e007f000e0e[8]c0[15]0e030e[10]80001f7171711f[7]80c0c0c080[7]7171[10]c0c0[15]0e0e[17]0e7e[4x0e][18]7f0e1e
03037e[6]80[2]8080[7]7e03030e1c7f[7]8080[2]80[9][7xff][5][7xc0][38]5465726d696e616c00
</resource>

Remember that you must install this font and prepare a MS-DOS command-line icon as described in the first post of this thread in order to run previous Batch file. Note that just one "Terminal" face font can be installed at any given time, so this new font will replace the previous 1x1 size one if you had installed it to draw the Mandelbrot Set.

Antonio

Re: Drawing pixel resolution graphics in text mode

Posted: 12 Jan 2014 00:44
by dbenham
Aacini wrote:Although I prefer the traditional "pixel coordinates" method, because it allows to directly convert any graphic application into a Batch file, I can see your viewpoint. Your idea is interesting and it can be implemented in a relatively easy way, at least to draw a single logical pixel in each character cell.

You almost got my concept. Except my idea is to have each character represent 6 pixels in a 2x3 grid. Each pixel represents one bit, so it only takes 64 characters to represent all possible configurations of on/off pixels. I would have the low bit (value 1) in the upper left corner, and the high bit (value 32) in the lower right. SET /A can be used to OR bits together to get the correct character numeric code value for any possible 6 pixel block, and a simple map used to convert the numeric code into the appropriate character. The graphic "characters" would start at code 128, so no pixels on would be decimal 128, the upper left on 129, etc.

The first 128 characters are normal ASCII, and the next 64 are the the graphic characters representing 6 logical pixels. That leaves an additional 64 characters for either larger scale sprites, or else 6 additional pixels half lit (50%) . The 50% lit option would give every pixel 3 "colors": Off, Gray, White. Smooth grays would require each logical pixel to be multiples of 2 physical pixels (2x2, 4x4, 6x6, etc.)

Aacini wrote:After many tests, I realized that we can NOT select a "Terminal" face font of the same size of a pre-installed one, although it IS possible to install it: in this case in the list of sizes appear TWO 8x12 sizes and the displayed font changes as you select different ones indeed, but the pre-installed font is always selected when the selection window is closed!

That's a shame, because I think 8x12 would be an ideal layout for my scheme (each logical pixel represented as 4x4 physical pixels. I even went so far as to use fontedit.exe to build an 8x12 font with all 64 combinations (white only, no gray) before I read your discovery that I couldn't use it. (BTW - I still don't understand the process to convert a fontedit font into something I can use as a console font.)

The following character sizes are available, and I think they all would work well with my scheme:

6x9 (3x3 per logical pixel) No smooth gray
10x15 (5x5 per logical pixel) No smooth gray

12x18 (6x6 per logical pixel) This could support a smooth gray, but the pixel sizes are quite large - far from ideal.


Dave Benham

Re: Drawing pixel resolution graphics in text mode

Posted: 13 Jan 2014 22:15
by Aacini
@dbenham:

Yes, I correctly got your idea, but I wanted to do first a very simple test to prove the smoothness of a 2x2 pixel animation because this is the size I will use in order to increase the number of available colors via dithering. I created both the program and the font very quickly, but I spent too much time in the duplicated 8x12 size font problem...

You need to do these changes in a copy of SAMPLE.FNT file in order to use it in the command-line window:
In Edit > Header... change Face Name from "Tester" to "Terminal", and in Character Set change SYMBOL (2) to EOM (255).

The complete requirements for the font are explained in this SO post.

Antonio

Re: Drawing pixel resolution graphics in text mode

Posted: 18 Jan 2014 12:48
by einstein1969
berserker wrote:using cscript jscript? how about one only in DOS batch?


the initial version is in batch only and using "findstr" trick.

If you want do faster you can use "mode" trick and use multiprocessor/core with multithreading batch, or use colorshow.exe with is faster but has the disadvantage that is ISA(Instruction Set Architecture) dependent.

einstein1969

Re: Drawing pixel resolution graphics in text mode

Posted: 18 Jan 2014 13:09
by Ed Dyreen
einstein1969 wrote:the initial version is in batch only and using "findstr" trick.

If you want do faster you can use "mode" trick and use multiprocessor/core with multithreading batch,
tell me about this mode trick, do you have a reference ?
einstein1969 wrote:or use colorshow.exe with is faster but has the disadvantage that is ISA(Istruction Set Architecture) dependent.
Not sure what you mean depends on x86 instruction set ?? Istruction is misspelled, you can enable check spelling within your browser and download languages.. Quite handy :roll:

Re: Drawing pixel resolution graphics in text mode

Posted: 18 Jan 2014 13:24
by einstein1969
Ed Dyreen wrote:
einstein1969 wrote:the initial version is in batch only and using "findstr" trick.

If you want do faster you can use "mode" trick and use multiprocessor/core with multithreading batch,
tell me about this mode trick, do you have a reference ?
einstein1969 wrote:or use colorshow.exe with is faster but has the disadvantage that is ISA(Istruction Set Architecture) dependent.
Not sure what you mean depends on x86 instruction set ?? Istruction is misspelled, you can enable check spelling within your browser and download languages.. Quite handy :roll:


Yes, there is a spelling mistake. I meant to write "Instruction" . Yes depends on x86.

You can see a mode trick in this post.

einstein1969

Re: Drawing pixel resolution graphics in text mode

Posted: 18 Jan 2014 16:27
by einstein1969
dbenham wrote:I like pure batch solutions, which pretty much restricts the screen to monochrome if you want reasonable performance. It also requires a CLS and full screen refresh for each animation frame. The more characters per screen, the longer it takes to clear the screen and refresh, which results in more flicker.


I have done a test on my windows 7 for flickering.
I have seen that the condition for low flicker seem to be fast redraw a screen near a timer coalescing.. I get more flicker even with few characters if i far from timer coalescing.

I get a indicator for timer coalescing in the change of %TIME% variable.

I not have done testing in windows 8 (that has a tikless kernel). The windows 8.1 has another change for tick interval respect at 8.0

einstein1969