[SDCC] - New library to allow ANSI 16 Color text rendering on Screen 7

Страница 2/3
1 | | 3

By rolandve

Master (254)

Аватар пользователя rolandve

27-04-2020, 23:29

ducasp wrote:
rolandve wrote:

Is someone able to translate these assembly routines to turbo pascal inline functions? Automated, would to keep the amount of work low please.

Hope that helps you:

https://github.com/ducasp/MSX-Development/tree/master/TURBOP...

P.s.: I don't have the binary for V9990 but it should be quite easy for you to compile, there is a batch file and tniasm there

Yes it helps. Thanks for your efforts. Your comments in the assembly tell me how and where ANSI support is implemented. Support in 99xx serie is pretty limited. It will show you colours but a lot of standard sequences like 2j or 0m are missing. In the v99xx series, the bright colours (starting at [90m) are not implemented. So in total, you get somewhere around 16 colours, with some doubles (cyan/bright version) magenta (bright version). Ofcourse ANSI (this standard to be precise) is a very wide standard and as a developer you may choose what you implement or not, so implementing a wide set, would require much more code.

Furthermore: turbo pascal's string routines are not useful with the ansi CSI, the compiler either ignores them or terminates the string manipulation so you will have to create your own string handling tools.

Some code to show how to use the library below

Program TestA;

type
	OpenStringb = String[255];
	aColStr	= String[7];

Var
aString :OpenStringb;
dummy:char;

Procedure LOAD_ansi;
Var
	driver: file of byte; 
	by,by2 : byte;
	BytePtr : ^Byte;
	inta:integer; 
	doll: char;
Begin;
	Inta:=$b000;
	Assign (driver,'ANSI-DRV.BIN');   { Assign file name    }
    Reset  (driver);   { Open for read       }

	repeat
		read(driver,by); 
		mem[inta]:=by;
		inta:=inta+1;
    until eof(driver);
    
    close(driver);  
  End;

Procedure Ansi_INIT; 
Begin; 
	Inline ($CD/$00/$b0 ); 
End;

Procedure Ansi_STOP; 
Begin;
 Inline ($CD/$03/$b0 ); 
End;

Procedure Ansi_PRINT(STR:OpenStringb ); 
Begin;
 Inline ($21/STR/ $CD/$09/$b0 ); 
End;

Procedure Ansi_PRINTchar(STR:char); 
begin;
Inline ($3A/STR/$CD/$06/$b0); 
end;

procedure black;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[30m');
	end;

procedure gray;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[1m');
		black;
	end;
			
procedure red;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[31m');
	end;


Procedure orange;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[1m');
		red;
	end;

procedure green;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[32m');
	end;

procedure brightgreen;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[1m');
		green;
	end;

procedure yellow;
 	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[33m');
	end;

procedure yellow2;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[1m');
		orange;
	end;

procedure blue;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[34m');
	end;

Procedure purple;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[1m');
		blue;
	end;

procedure magenta;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[35m');
	end;

Procedure brightmagenta;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[1m');
		magenta;
	end;

procedure cyan;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[36m');
	end;

Procedure brightcyan;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[1m');
		cyan;
	end;

procedure white;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[37m');
	end;

Procedure brightwhite;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[1m');
		white;
	end;

Procedure resetColor;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[0m');
	end;

Procedure Reverse; { not supported }
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[7m');
	end;

procedure aClrScr;
	begin;
		Ansi_PRINTchar(#27);
		Ansi_PRINT('[2j');
	end;	

Begin;
	read(kbd,dummy);
	LOAD_ansi;
	Ansi_INIT; 
	Reverse;
	blue;
	Ansi_PRINTchar('A');
	green;
	Ansi_PRINTchar('N');
	red;
	Ansi_PRINTchar('S');
	yellow;
	Ansi_PRINTchar('I');
	aClrScr;
	brightwhite;
	Ansi_PRINT(' colors');
	magenta;
	Ansi_PRINT(' version 0.1');
	repeat until keypressed;
	Ansi_STOP;
end.

By ducasp

Champion (461)

Аватар пользователя ducasp

28-04-2020, 05:24

Not much choice other than supporting only 16 colors, G6 is the only mode with enough resolution that allows 80 columns and that mode only allows 16 colors.

Regarding the missing sequences, the original author meant to have the fastest possible ANSI driver for a Telnet client written in Turbo Pascal, so it was focused on what most ANSI art and menus had at that point in time. Since the author sent me the source code so I could make a C library out of it, I got quite a few more codes supported (0m and J are two examples) as well as Pitter Punk who has fixed a few wrong behaviors and added more escape codes, but in this case, this has been implemented only on the C library, I don't feel comfortable changing the original pascal bin file as I have no means to test it (as I'm not a Pascal developer).

P.s.: in ANSI 16 colors, you get access to the bright colors using any of the regular 8 colors with bold turned on ( CSI1;31m for bright red as an example), colors part of ANSI 16 color are only 30-37 and background colors 40-47. Bright colors using 90-97 and 100-107 are a specific IBM aix implementation, might add support for it in the future with the sdcc library, should not be too difficult. Smile

By rolandve

Master (254)

Аватар пользователя rolandve

28-04-2020, 09:04

Hi Ducasp,

I am grateful for your contribution, not critical. I just observed somethings. It's very ANSI color implementation like to have only a few control sequences supported. I once wrote an ANSI driver for the PC that allowed music. When the ANSI driver got the right sequence, it send the following characters to the PC's speaker. A full ANSI terminal driver is a big piece of code, very complex while 99% of the time people just requires color and character positioning. So I completely understand, the choices.

I used this site as reference.
ANSI 16 colours go from. 30 - 37 and the bright colors go from 90 - 97. Bright is supported, that's how I got to 16 colours on MSX :) There is even ANSI support for true color.

By ducasp

Champion (461)

Аватар пользователя ducasp

28-04-2020, 13:44

I know you are being constructive and be sure that I'm not in a defensive position Wink

I like discussing the details and decisions and reviewing them as more people get interested in it. I might be tempted to say I will never implement scroll margins as this would possibly be something that would have bad performance (this library and the driver that precedes it is fast due to scrolling using the adjust register, but if you set scrolling margins then the adjust can't be used and scrolling a l one would take a considerable amount of time in a full screen), but if someone has a good idea on how to implement it or show that it is really important for an application most people can use, I will revisit my opinion. Wink

By Dolphin101546015

Champion (326)

Аватар пользователя Dolphin101546015

28-04-2020, 15:46

Just look

Methink, for speedup, you need keep technical patterns in shadow VRAM, with 2 degree of width (for fast blit purposes).
Then every scroll line, you will place 10 new chars below screen. Such on 8th scroll line, you get full new string below screen, witch start show on next scroll line (where you will put 10 next chars on next string).
Such you got 80 chars per line on scrolling screen.
Something kinda.
For decoding 10 chars per frame, you have plenty of time using this way.

So you need made your self mechanics for output chars, without using BIOS subroutines.
Then have smooth scroll with VRT loop, with nice speed (7.5 ANSI strings per second for NTSC (60 lines of screen), or 6.25 ANSI strings for PAL (50 lines of screen)).

UPD: Also for fast decoding, you need internal representation of decoded ANSI flow.
May be something like: 05 20 06 20 07 etc, where codes folow as COLORS CHAR COLORS CHAR etc.
And where colors, mean TEXT COLOR (high nibble) with BG COLOR (low nibble).
So you need 4kb per screen (in internal representation), where you might using also fast RLE coding, for compress codes by groups.

By rolandve

Master (254)

Аватар пользователя rolandve

28-04-2020, 15:33

I love to discuss this subject Smile

I am not sure how many people will actually use it. I jumped on it because I like 80x25 with 16 colors for each character. The regular functions like color can be translated to a new procedure aColor that send the apropriate CSI sequence. Then you would have most normal character for use on the screen (its not the complete MSX character table, I noticed). Using a simple color statement would be much faster because the driver wouldn't need to decode CSI1;32m

From a technical perspective (and performance perspective) we can see two distinct functionalities in the ANSI driver:
- ANSI protocol support
- Individual characters can have individual colours on a 80x5 screen and the screen can be addressed;

The protocol requires a significant amount of parsing to reach the point where you tell the V99xx that it should do the second bullet. So a lot of CPU cycles are spend on deciphering, what actually should be done. The hard work (VRAM manipulations) are done by the V99xx.I suppose that's where the scrolling would be done best.

So it more or less depends on what the user needs. Does he/she need support for the ANSI protocol or does he/she need multi coloured characters on the screen? These factors decide whether someone would want to use this.

By ducasp

Champion (461)

Аватар пользователя ducasp

28-04-2020, 23:19

Dolphin101546015 wrote:

Just look

Methink, for speedup, you need keep technical patterns in shadow VRAM, with 2 degree of width (for fast blit purposes).
Then every scroll line, you will place 10 new chars below screen. Such on 8th scroll line, you get full new string below screen, witch start show on next scroll line (where you will put 10 next chars on next string).
Such you got 80 chars per line on scrolling screen.
Something kinda.
For decoding 10 chars per frame, you have plenty of time using this way.

So you need made your self mechanics for output chars, without using BIOS subroutines.
Then have smooth scroll with VRT loop, with nice speed (7.5 ANSI strings per second for NTSC (60 lines of screen), or 6.25 ANSI strings for PAL (50 lines of screen)).

UPD: Also for fast decoding, you need internal representation of decoded ANSI flow.
May be something like: 05 20 06 20 07 etc, where codes folow as COLORS CHAR COLORS CHAR etc.
And where colors, mean TEXT COLOR (high nibble) with BG COLOR (low nibble).
So you need 4kb per screen (in internal representation), where you might using also fast RLE coding, for compress codes by groups.

This lib do not hook bios neither replace bios text rendering, so, it is not like jANSI, calls are straight to the functions and pretty fast,but application must have it built in and of course no msx dos output redirection is possible.

I'm not looking to improve speed further right now, the scroll region example was just me telling an example of something that I don't remotely think doing but that some arguing could make me rethink it (that would require scrolling only certain regions of the screen, while others would be fixed, and that would most likely kill scrolling because you need to split screen twice during rendering and not sure this is doable through horizontal sync irq) but sure there is room for it, tokenization and patterns stored in vram is a way to speed up for sure as well changing the current way where character table is stored in MSX memory not in vdp memory.

The compromise to have an Acid Viewer like (if something that smooth is even possible on MSX, probably will require a specific design) experience probably would be too much for most uses of this lib now, it is for live content that keep refreshing (I.e.: telnet terminal or application building its menus and text), buffering, pre-parsing and then showing is quite nice for a viewer like Acid Viewer, but for general usage not quite as we have limited ram and dynamic content. On the other hand I would love to see something like that, so who knows about the future or if someone else pick this up to build that concept, for sure it would be damn amazing seeing ansi art scrolling this smooth on a MSX.

Focus right now has been on getting it more and more reliable and rendering in good shape with good performance. With the latest contribution from Piter Punk and some fixes from me as well, this lib is rendering ncurses applications really well when accessing a Linux box through telnet, HTOP looks quite amazing. Once that is done, probably will pick up the work to modify the behavior to use fonts from vram, not sure how much gain will be had, but I guess it will speed up the print on screen process quite a bit :)

By Dolphin101546015

Champion (326)

Аватар пользователя Dolphin101546015

01-05-2020, 16:31

Here my own ANSI driver in Basic, with first good test Smile
Sample preview

By ducasp

Champion (461)

Аватар пользователя ducasp

01-05-2020, 17:01

rolandve wrote:

I love to discuss this subject Smile

I am not sure how many people will actually use it. I jumped on it because I like 80x25 with 16 colors for each character. The regular functions like color can be translated to a new procedure aColor that send the apropriate CSI sequence. Then you would have most normal character for use on the screen (its not the complete MSX character table, I noticed). Using a simple color statement would be much faster because the driver wouldn't need to decode CSI1;32m

From a technical perspective (and performance perspective) we can see two distinct functionalities in the ANSI driver:
- ANSI protocol support
- Individual characters can have individual colours on a 80x5 screen and the screen can be addressed;

The protocol requires a significant amount of parsing to reach the point where you tell the V99xx that it should do the second bullet. So a lot of CPU cycles are spend on deciphering, what actually should be done. The hard work (VRAM manipulations) are done by the V99xx.I suppose that's where the scrolling would be done best.

So it more or less depends on what the user needs. Does he/she need support for the ANSI protocol or does he/she need multi coloured characters on the screen? These factors decide whether someone would want to use this.

Hi rolandve,

I agree fully with you that thinking of a lib for general applications in 8 bits, ANSI could be a little bit too much and a more tokenized approach to commands would be desirable, but I do not like the idea of functions to set colors and position, as functions usually require stacking and un-stacking registers (not sure about pascal, but SDCC does unless you used z88dk fastcall, but that limits functions to one parameter only) which could be quite counter-productive. But having less bytes for command in strings and thinking on a way that is fast for a z80 to identify and switch, that could end with very good results. Who knows in the future either I pick up this idea or anyone else does that? Would be quite nice for sure.

But talking about why lib is as is, it was not my intention at all to make a general color text rendering library, I've created a Telnet Client for MSX and have been working on it for a while, and accessing BBS's through telnet and being able to download files from the BBS was the major goal. At first I've used jANSI as an ANSI rendering engine, it does hook to DOS calls and if you enable it you can use it with any DOS application. But, hooking to DOS calls, that are already not fast, made it really slow. Afterwards found the documentation for jANSI and Memman, and after a few hours having headaches trying to understand google translation of dutch, could implement direct access to jANSI, which was a lot faster. Then I've found Toby, I already knew his great/amazing work for a previous telnet client by Carlos de Santana (that was made in Turbo Pascal), it was even faster than jANSI directly, integrated it. Then, I thought, if I'm getting this, improving it, and using in C, why not make a relocatable library that anyone can use? Work for that was pretty much minimal, in a single day I've converted the code from TNIASM to SDASZ80 and making it a lib was just a simple SDARZ80 command once I had it in SDASZ80 syntax. So, did this to share whoever needs it, so it absolutely needs to be ANSI because it was born this way and used for a Telnet client that needs ANSI.

But, thinking about it, parsing the ANSI codes is not so heavy on z80 the way that Toby did (and the Pascal lib is his end result, the SDCC lib is an evolution of his end result adding more capabilities, 25 lines, cursor, new commands, etc but the rendering engine and the ANSI parsing code is mostly intact and original) and it is a lot faster than using DOS to print or SDCC printf implementations that rely on DOS or BIOS printing, so it is already a win situation for anyone targetting MSX2, thus why I had the idea to share it as is. I.e.: HUBG is menu oriented, color version of MSX HUB, I've made it using this library and it renders text on screen faster than the command line version of MSX HUB (which is not to say anything bad of it, it is really good and the base for HUBG, and has the advantage of not needing v9938 and some people like command line better than menus).

I know for sure that both Toby and I will be really happy if someone pick up this code and make a different library that is more efficient for other use cases, that is why he shared the source code and why I share the source code of my modifications as well, he is no longer investing time on MSX, I'm investing the little time I have for MSX on other stuff, so any work on top of it is more than welcome. Wink

By ducasp

Champion (461)

Аватар пользователя ducasp

01-05-2020, 17:04

Dolphin101546015 wrote:

Here my own ANSI driver in Basic, with first good test Smile
Sample preview

You got quite smooth results! It reminds me of jANSI smooth scrolling (that is quite weird while rendering BBSs but it is absolutely wonderful when rendering animations), they did it through VDP interrupts and adjust register, instead of doing the whole line scrolling at once, do it one line at a time every couple of vdp interrupts.

Страница 2/3
1 | | 3