Newbie in need of help!
-
- New member
- Posts: 5
- Joined: Thu Oct 05, 2017 11:36 am
Newbie in need of help!
Hello everyone,
I'm new to z88dk and wonder if anyone could help me. I'd love to use it for my Spectrum games.
Being a bit confused with the documentation and the several libraries, I?m struggling to do two simple things:
- read the keyboard for games
- print UDGs
I've been reading many posts and code examples but I haven?t managed to make them work. I'd love to get a simple code to achive this two tasks.
Thank you in advance and thanks very much to the developers for the fantastic compiler.
I'm new to z88dk and wonder if anyone could help me. I'd love to use it for my Spectrum games.
Being a bit confused with the documentation and the several libraries, I?m struggling to do two simple things:
- read the keyboard for games
- print UDGs
I've been reading many posts and code examples but I haven?t managed to make them work. I'd love to get a simple code to achive this two tasks.
Thank you in advance and thanks very much to the developers for the fantastic compiler.
Hi symbolshift,
Yes there are two independent libraries for the zx target called classic and newlib. The classic one has some things not in the newlib yet, mainly to do with b&w graphics (line, circle, etc) and the ansi terminal driver. The newlib has a number of things not in classic, mainly the high-colour sprite engines and proportional fonts. Things that both libraries have in common have occasionally been updated in newlib so there are sometimes some small differences in how common functions operate. There are other differences as well.
For newlib there is a short (and incomplete) introduction written by another user learning to use z88dk that might help:
https://github.com/z88dk/z88dk/blob/mas ... Started.md
and there are examples for newlib here:
(generic) https://github.com/z88dk/z88dk/tree/mas ... T/EXAMPLES
(zx) https://github.com/z88dk/z88dk/tree/mas ... XAMPLES/zx
and examples for classic here:
(general, not necessarily generic) https://github.com/z88dk/z88dk/tree/master/examples
(zx) https://github.com/z88dk/z88dk/tree/mas ... s/spectrum
The newlib standardizes around the input library as it is intended to be cross-platform. Some of the functions have had some changes from classic. I'll described newlib here and the tutorial above has one installment that briefly covers some of the input library.
The newlib headers (both included with input.h)
https://github.com/z88dk/z88dk/blob/mas ... cc/input.h
https://github.com/z88dk/z88dk/blob/mas ... input_zx.h
There are two ways to read the keyboard with in_inkey or with scancodes.
in_inkey() is similar to the basic inkey$ function. It scans the entire keyboard and returns 0 (no keypress) if no key is pressed or if more than one key is simultaneously pressed. It understands CAPS, SYMSHIFT and the two together and will return ascii codes according to the instantaneous state of the keyboard.
A scancode is a single 16-bit number that describes which key to check. It can be used even if multiple keys are pressed at the same time. It's a very fast way to look at keys and is meant to be used in games for directions and fire buttons. You can get a scancode in two ways: you can use a predefined one ( https://github.com/z88dk/z88dk/blob/mas ... t_zx.h#L17 ) or you can look one up at runtime using in_key_scancode(int c). The character passed to in_key_scancode() can be anything and the scancode returned with also indicate if CAPS/SYMSHIFT need to be pressed along with the key. A zero return indicates the ascii code cannot be generated on the keyboard. Scan codes can be passed to in_key_pressed() t find out if the corresponding key is currently pressed.
You can also create a keyboard joystick using scancodes. You fill in a structure with scancodes ( https://github.com/z88dk/z88dk/blob/mas ... nput.h#L25 ) and pass it to in_stick_keyboard() ( https://github.com/z88dk/z88dk/blob/mas ... _zx.h#L102 ) to scan the keys and return a joystick value that is equivalent to the values returned by all joystick functions. The joystick functions are intended to be called through a function pointer so that the user can define a joystick to use in a menu and the program can call any of the joystick functions through that to gather input.
Some miscellaneous functions wait for key presses or test for key presses ( https://github.com/z88dk/z88dk/blob/mas ... t_zx.h#L74 ).
in_inkey() and in_key_scancode (which does a table look up to find a scancode corresponding to an ascii char) are relatively big and slow because they use a key translation table and in in_inkey's case must scan the entire keyboard.
Some examples:
In a game setting, the keyboard joystick is most appropriate for most controls.
Yes there are two independent libraries for the zx target called classic and newlib. The classic one has some things not in the newlib yet, mainly to do with b&w graphics (line, circle, etc) and the ansi terminal driver. The newlib has a number of things not in classic, mainly the high-colour sprite engines and proportional fonts. Things that both libraries have in common have occasionally been updated in newlib so there are sometimes some small differences in how common functions operate. There are other differences as well.
For newlib there is a short (and incomplete) introduction written by another user learning to use z88dk that might help:
https://github.com/z88dk/z88dk/blob/mas ... Started.md
and there are examples for newlib here:
(generic) https://github.com/z88dk/z88dk/tree/mas ... T/EXAMPLES
(zx) https://github.com/z88dk/z88dk/tree/mas ... XAMPLES/zx
and examples for classic here:
(general, not necessarily generic) https://github.com/z88dk/z88dk/tree/master/examples
(zx) https://github.com/z88dk/z88dk/tree/mas ... s/spectrum
The classic lib has a version of the input library for direct access to keyboard, joysticks and mice and it has some other joystick functions with similar functionality.symbolshift wrote:- read the keyboard for games
The newlib standardizes around the input library as it is intended to be cross-platform. Some of the functions have had some changes from classic. I'll described newlib here and the tutorial above has one installment that briefly covers some of the input library.
The newlib headers (both included with input.h)
https://github.com/z88dk/z88dk/blob/mas ... cc/input.h
https://github.com/z88dk/z88dk/blob/mas ... input_zx.h
There are two ways to read the keyboard with in_inkey or with scancodes.
in_inkey() is similar to the basic inkey$ function. It scans the entire keyboard and returns 0 (no keypress) if no key is pressed or if more than one key is simultaneously pressed. It understands CAPS, SYMSHIFT and the two together and will return ascii codes according to the instantaneous state of the keyboard.
A scancode is a single 16-bit number that describes which key to check. It can be used even if multiple keys are pressed at the same time. It's a very fast way to look at keys and is meant to be used in games for directions and fire buttons. You can get a scancode in two ways: you can use a predefined one ( https://github.com/z88dk/z88dk/blob/mas ... t_zx.h#L17 ) or you can look one up at runtime using in_key_scancode(int c). The character passed to in_key_scancode() can be anything and the scancode returned with also indicate if CAPS/SYMSHIFT need to be pressed along with the key. A zero return indicates the ascii code cannot be generated on the keyboard. Scan codes can be passed to in_key_pressed() t find out if the corresponding key is currently pressed.
You can also create a keyboard joystick using scancodes. You fill in a structure with scancodes ( https://github.com/z88dk/z88dk/blob/mas ... nput.h#L25 ) and pass it to in_stick_keyboard() ( https://github.com/z88dk/z88dk/blob/mas ... _zx.h#L102 ) to scan the keys and return a joystick value that is equivalent to the values returned by all joystick functions. The joystick functions are intended to be called through a function pointer so that the user can define a joystick to use in a menu and the program can call any of the joystick functions through that to gather input.
Some miscellaneous functions wait for key presses or test for key presses ( https://github.com/z88dk/z88dk/blob/mas ... t_zx.h#L74 ).
in_inkey() and in_key_scancode (which does a table look up to find a scancode corresponding to an ascii char) are relatively big and slow because they use a key translation table and in in_inkey's case must scan the entire keyboard.
Some examples:
Code: Select all
#include <stdio.h>
#include <input.h>
#pragma printf = "%c" // limit the size of printf
while (1)
{
unsigned char c;
while ((c = in_inkey()) == 0) ; // loop while no keys detected
printf("%c", c);
}
Code: Select all
#include <stdio.h>
#include <input.h>
#pragma printf = "" // limit the size of printf
// wait for keypress
in_wait_nokey(); // wait for no keys
in_wait_key(); // wait for key
// wait at most 5 seconds for keypress
in_wait_nokey();
in_pause(5000);
// check if any keys are pressed
if (in_test_key())
printf("quit banging on the keys!\n");
Code: Select all
#include <stdio.h>
#include <input.h>
unsigned int sc;
// check predefined scancodes
if (in_key_pressed(IN_KEY_SCANCODE_z))
printf("You are pressing Z\n");
if (in_key_pressed(IN_KEY_SCANCODE_SPACE | 0x8000)) // space + caps flag 0x8000 ; symshift flag is 0x4000
printf("BREAK pressed\n");
sc = in_key_scancode('$'); // look up the scancode for $
if (in_key_pressed(sc))
printf("Pressed $\n");
If you're familiar with machine code, the asm implementation of functions will give some documentation and insight into how things work.
newlib input:
https://github.com/z88dk/z88dk/tree/mas ... put/zx/z80
classic input (slightly different api than previously described):
https://github.com/z88dk/z88dk/tree/mas ... t/spectrum
However, printing like this is not the fastest way to print graphics to screen. Things have to travel through stdio code before they get printed. Instead, a better way to do things is to have your own print char routine that prints to the screen directly, at least if you need to be as fast as possible (compiled c is quick so maybe printf is good enough depending on what you are doing). You will find that in z88dk the effort is made to try to have speed-critical code written in asm in order to push the c to a higher level - hence the sprite engines are written in asm, just like (ideally) speed critical printchar should be in asm.
There are a bunch of functions in z88dk that will perform various computations on coordinates to find addresses corresponding to characters and pixels in the display file:
(newlib) https://github.com/z88dk/z88dk/blob/mas ... /zx.h#L202
(classic, slightly different) https://github.com/z88dk/z88dk/blob/mas ... rum.h#L325
So a simple example to print a string directly to screen (no bounds checking):
and a machine code version from pietro bros:
https://bitbucket.org/CmGonzalez/pietro ... zx.asm-107
A low level frequently used function like this is ideally written in asm although zsdcc especially does a fairly good job with this code (add "--list" to the compile line to see the asm generated).
newlib input:
https://github.com/z88dk/z88dk/tree/mas ... put/zx/z80
classic input (slightly different api than previously described):
https://github.com/z88dk/z88dk/tree/mas ... t/spectrum
You can print UDGs through printf. The classic library makes an exception for codes 144 and above so that UDGs are looked up like basic does when printing. Newlib is completely independent from the basic rom and makes no such treatment, instead a font comes from anywhere (the rom charset or one in ram) and you can define one with UDGs or change the font address to point at UDG characters. (Although see startup=30 which has newlib using the basic rom to print which means chars 144+ are udgs; startups are described in that tutorial previously linked).- print UDGs
However, printing like this is not the fastest way to print graphics to screen. Things have to travel through stdio code before they get printed. Instead, a better way to do things is to have your own print char routine that prints to the screen directly, at least if you need to be as fast as possible (compiled c is quick so maybe printf is good enough depending on what you are doing). You will find that in z88dk the effort is made to try to have speed-critical code written in asm in order to push the c to a higher level - hence the sprite engines are written in asm, just like (ideally) speed critical printchar should be in asm.
There are a bunch of functions in z88dk that will perform various computations on coordinates to find addresses corresponding to characters and pixels in the display file:
(newlib) https://github.com/z88dk/z88dk/blob/mas ... /zx.h#L202
(classic, slightly different) https://github.com/z88dk/z88dk/blob/mas ... rum.h#L325
So a simple example to print a string directly to screen (no bounds checking):
Code: Select all
// zcc +zx -vn -startup=31 -clib=new test.c -o test -create-app
// zcc +zx -vn -startup=31 -clib=sdcc_iy -SO3 --max-allocs-per-node200000 test.c -o test -create-app
#include <arch/zx.h>
unsigned char x, y;
unsigned char *font = (unsigned char *)(15360); // point font into rom character set (I think that's right)
void zx_print_chr(unsigned char *gr)
{
unsigned char i;
unsigned char *p;
p = zx_cxy2saddr(x,y); // find screen address for character coord x,y
for (i = 0; i != 6; ++i)
{
*p = *gr++;
p += 256;
}
*p = *gr;
}
void zx_print_str(unsigned char *s)
{
unsigned char c;
while (c = *s++)
{
zx_print_chr(font + c*8);
if (++x == 32)
{
x = 0;
y++;
}
}
}
void main(void)
{
zx_print_str("Hello World");
}
https://bitbucket.org/CmGonzalez/pietro ... zx.asm-107
A low level frequently used function like this is ideally written in asm although zsdcc especially does a fairly good job with this code (add "--list" to the compile line to see the asm generated).
Wow, this is a nice link! Where did you got that from?alvin wrote:For newlib there is a short (and incomplete) introduction written by another user learning to use z88dk that might help:
https://github.com/z88dk/z88dk/blob/mas ... Started.md
Maybe I can write something similar, too. I'm a bit busy right now, but it looks cool.
It was written by thricenightly at wos. It's really well written and a good start but of course there is still lots to go and he's taken a bit of a break after the bifrost thing which took him a long time to come to grips with, especially sorting out issues of memory map and so on.Timmy wrote:Wow, this is a nice link! Where did you got that from?alvin wrote:For newlib there is a short (and incomplete) introduction written by another user learning to use z88dk that might help:
https://github.com/z88dk/z88dk/blob/mas ... Started.md
A zx next specific one would also be good as it's going to have quite a lot of differences in terms of tooling and libraries.
-
- New member
- Posts: 5
- Joined: Thu Oct 05, 2017 11:36 am
Hello!
Thank you very much for your thorough and amazingly prompt reply!
I've been reading the suggested links, all very helpful so far.
Thank you also for adding your own examples, this is very kind.
It seems I was having trouble with choosing the right lib and runtimes. Still I have to make more tests and then I'll post again.
Thank you very much for your thorough and amazingly prompt reply!
I've been reading the suggested links, all very helpful so far.
Thank you also for adding your own examples, this is very kind.
It seems I was having trouble with choosing the right lib and runtimes. Still I have to make more tests and then I'll post again.
-
- New member
- Posts: 5
- Joined: Thu Oct 05, 2017 11:36 am
Hello Alvin!
As promised, I'm posting again: My little (and first ever in C) game is almost completed. Having a loading screen would be nice for me, I've tried the instructions in the Wiki section but haven't been able to make it work.
My program is compiled using:
+zx -vn -startup=1 -clib=sdcc_iy -o2 program.c -o program -create-app
Could you please help me adding a loading screen to the final .tap?
Thank you in advance and thank you again to the z88dk team!
As promised, I'm posting again: My little (and first ever in C) game is almost completed. Having a loading screen would be nice for me, I've tried the instructions in the Wiki section but haven't been able to make it work.
My program is compiled using:
+zx -vn -startup=1 -clib=sdcc_iy -o2 program.c -o program -create-app
Could you please help me adding a loading screen to the final .tap?
Thank you in advance and thank you again to the z88dk team!
Nice!My little (and first ever in C) game is almost completed
I added some optimization options to your compile above. You can also add "--opt-code-size" if you want it. This high optimization level will mean a much longer compile time. The defaults are -SO2 and --max-allocs-per-node3000. The -O2 you had is the default, however for zsdcc compiles (as opposed to sccz80), the -O levels are not actually for optimization. Instead they are there to fix certain code generation bugs and to translate the non-standard z80 that zsdcc outputs to more standard form (see https://www.z88dk.org/wiki/doku.php?id=temp:front#sdcc3 )zcc +zx -vn -startup=1 -clib=sdcc_iy -SO3 --max-allocs-per-node200000 program.c -o program -create-app
Sure. The automatic tap generation used when -create-app is present makes a basic loader that loads and runs the compiled code only. But if you want to do something else, like load a screen$, you have to write your own basic loader and construct the tap file manually. This is actually easy to do because tap files can be concatenated together.Could you please help me adding a loading screen to the final .tap?
So first you make a basic loader, for example:
Code: Select all
10 BORDER 0:INK 0:PAPER 0
20 CLEAR 32767
30 LOAD ""SCREEN$
40 POKE 23739,111
50 LOAD ""CODE
60 RANDOMIZE USR 32768
Most emulators will allow you to type in a program and create a tap file this way. But there are also tools that will take a text file containing a BASIC program like the above and generate a tap file for it. For example bas2tap ( https://bitbucket.org/CmGonzalez/gandal ... ?at=master ). There's a windows executable there and the source file to compile on other platforms.
bas2tap -sName -a10 loader.bas loader.tap
will create a basic tap "loader.tap" autostarting at line 10 from the text file "loader.bas". "Name" will be the name of the program seen on screen while loading (remember "Program: Name").
If you look at the basic loader, it expects to load a screen$ followed by the compiled program.
So you make make taps out of those. You can use appmake in z88dk to do that.
Suppose your screen$ is a binary file "screen.bin". Appmake can be used to make a tap out of that (appmake +zx will show options):
appmake +zx -b screen.bin -o screen.tap --org 16384 --noloader --blockname art
A tap file "screen.tap" containing "screen.bin" will be created.
Do the same for your output binary.
zcc +zx -vn -startup=1 -clib=sdcc_iy -SO3 --max-allocs-per-node200000 program.c -o program
(note that -create-app has been dropped - the output binary will be "program_CODE.bin")
appmake +zx -b program_CODE.bin -o program.tap --org 32768 --noloader --blockname game
A tap file "program.tap" containing "program_CODE.bin" will be created.
Then put them all together to form the final tap:
(windows)
copy /b loader.tap + screen.tap + program.tap game.tap
(linux)
cat loader.tap screen.tap program.tap > game.tap
In the above I assumed your program org was 32768. If it isn't, you'll have to change the CLEAR address and RAND USR in the basic loader and the --org in the appmake invoke.
-
- Member
- Posts: 28
- Joined: Thu Jun 01, 2017 5:46 pm
Not so much a "break" as a "recovery"! I got very sick last summer and the recovery period has run into many months. But I'm getting back to normal and have picked up some Spectrum work again. The problem is, like the OP, I'm learning this as I go, and the more I delve into more complex stuff the longer it all takes.alvin wrote:It was written by thricenightly at wos. It's really well written and a good start but of course there is still lots to go and he's taken a bit of a break after the bifrost thing which took him a long time to come to grips with, especially sorting out issues of memory map and so on.Timmy wrote:Wow, this is a nice link! Where did you got that from?alvin wrote:For newlib there is a short (and incomplete) introduction written by another user learning to use z88dk that might help:
https://github.com/z88dk/z88dk/blob/mas ... Started.md
I've had a look at interrupts, and took the chance to fiddle with some z88dk internals. I'll document that next. What I really want to do is investigate the SP1 library, but each time I try to make a start it all looks insurmountable!
-
- New member
- Posts: 5
- Joined: Thu Oct 05, 2017 11:36 am
I honestly don't know how long it's been there, but appmake actually supports inserting a SCREEN$ into the .TAP by itself using the --screen option. So from a zcc command line you just add -Cz--screen=[SCREEN$ file]. This evening I added in the missing poke so the screen isn't corrupted when the program itself is loaded.
There should be also a screen$ option for the turbotape appmake variant.
That 'turbo' mode is quite special, the data is created directly in wav format (at an average pitch giving good stability also in case of crap audio equipment) with an RLE encoding technique enabled by specific audio gaps. The turbo loader recognizes such "special audio periods" and speeds-up by reading the next bits to repeat a whole byte.
The predictive encoding was not possible at those times but the loader will work perfectly on any original Spectrum with a simple tape recorder.
Two more curiosities:
- the existing software copiers won't work on this audio steam
- the wav files created by appmake can be compressed *very* efficiently, please try
That 'turbo' mode is quite special, the data is created directly in wav format (at an average pitch giving good stability also in case of crap audio equipment) with an RLE encoding technique enabled by specific audio gaps. The turbo loader recognizes such "special audio periods" and speeds-up by reading the next bits to repeat a whole byte.
The predictive encoding was not possible at those times but the loader will work perfectly on any original Spectrum with a simple tape recorder.
Two more curiosities:
- the existing software copiers won't work on this audio steam
- the wav files created by appmake can be compressed *very* efficiently, please try
-
- New member
- Posts: 5
- Joined: Thu Oct 05, 2017 11:36 am
Thank you Dom!dom wrote:I honestly don't know how long it's been there, but appmake actually supports inserting a SCREEN$ into the .TAP by itself using the --screen option. So from a zcc command line you just add -Cz--screen=[SCREEN$ file]. This evening I added in the missing poke so the screen isn't corrupted when the program itself is loaded.
I will try your suggestion also.
I will use this existing thread to ask a few very simple beginner's questions.
First: how do I print the ZX81's graphic characters using printf()?
I know that using capital letters in the printf() parameter string will output the respective inverse characters. But what about the rest of the character set?
The solution is probably to use the \x statement (followed by the characters's hex code) within the string parameter.
After some experimenting I found out that this will print the "A" character:
But looking at the ZX81 character set table I have no idea why 0x61 is the hex code of the A character. Can anyone please tell me how to determine the \x hex code of the desired character?
First: how do I print the ZX81's graphic characters using printf()?
I know that using capital letters in the printf() parameter string will output the respective inverse characters. But what about the rest of the character set?
The solution is probably to use the \x statement (followed by the characters's hex code) within the string parameter.
After some experimenting I found out that this will print the "A" character:
Code: Select all
printf("character 97 (hex 61) is \x61.\n");
For the ZX81, ZX80, Lambda there's some translation going on from ASCII to their character sets. The conversion tables (for symbols outside of [A-Za-z0-9] are defined here: https://github.com/z88dk/z88dk/blob/mas ... cnvtab.asm
Looking at them it looks like graphics can't be printed using the standard printf routines at the moment. I'm guessing that code 128-148 would probably be a good space to slot them in.
Looking at them it looks like graphics can't be printed using the standard printf routines at the moment. I'm guessing that code 128-148 would probably be a good space to slot them in.
Thanks, so printf() currently won't help much. I have found out it can print a few characters (but not all), these are:
BTW, is there a platform-independent way to output text to a specific screen location?
For the ZX81 I have so far been using this method taken from the z8048 game source code:
And how could I output graphic characterss by specifying their character codes, either using a modified version of this function or a platform-independent one?
Code: Select all
printf("-------------\n");
printf("\x23 \x27 \x40 \x5b \x5d \x5f \x60");
BTW, is there a platform-independent way to output text to a specific screen location?
For the ZX81 I have so far been using this method taken from the z8048 game source code:
Code: Select all
#include <stdio.h> // required for zxTextOut()
char *display;
extern int d_file @16396;
void zxTextOut(int x, int y, const char* text) // taken from z8048.c written by sirmorris
{
// writes a text to the specified x,y screen position
char* dm = display + x + (33 * y);
while (*text)
{
*dm = ascii_zx(*text);
++text;
++dm;
}
}
Here is the screenshot, the previous upload did not work:RobertK wrote:I have found out it can print a few characters (but not all), these are:
Code: Select all
printf("-------------\n"); printf("\x23 \x27 \x40 \x5b \x5d \x5f \x60");
Short answer is no. But conio.h is fairly close - this uses the ANSI display printer if it's available on a platform (and it is for ZX80, ZX81, Jupiter Ace)BTW, is there a platform-independent way to output text to a specific screen location?
If you're looking to do cross platform then I can recommend taking a look at Fabrizio's cross-chase: https://github.com/Fabrizio-Caruso/CROSS-CHASE
I think if you change *dm = ascii_zx(*text); to *dm = *text; you should be able to print using ZX81 codes. I suspect the characters you've found that work have been mapped through from standard ASCII symbols because "they look like the character they're trying to represent but isn't actually available on the ZX81"And how could I output graphic characterss by specifying their character codes, either using a modified version of this function or a platform-independent one?
When I check like this what system my program is running on (i.e. what system it has been compiled for)...
...the constant's name seems to be identical to the target system name that you specify in the zcc command line (e.g. zcc +zx81 ...).
This works correctly at least for these constants:
__ZX81__
__ZX80__
__ACE__
__GAL__
__AQUARIUS__
__TRS80__
__Z1013__
But for the following systems it does not work:
__VG5K__
__VZ__
__MZ__
Do I have to use other constants for these three systems (Philips VG5000, V-Tech VZ200, Sharp MZ)?
And one more question: how can I identify the sub-type "EG2000"? This is a sub-type of the TRS-80 system, so here __TRS80__ is defined, but I would like to differentiate between TRS-80 and EG2000.
Code: Select all
#if defined(__ZX81__) || defined(__ZX80__) || defined(__ACE__) || defined(__GAL__)
...
#endif
This works correctly at least for these constants:
__ZX81__
__ZX80__
__ACE__
__GAL__
__AQUARIUS__
__TRS80__
__Z1013__
But for the following systems it does not work:
__VG5K__
__VZ__
__MZ__
Do I have to use other constants for these three systems (Philips VG5000, V-Tech VZ200, Sharp MZ)?
And one more question: how can I identify the sub-type "EG2000"? This is a sub-type of the TRS-80 system, so here __TRS80__ is defined, but I would like to differentiate between TRS-80 and EG2000.
Ah, there it is, thanks!dom wrote:The config files in lib/config/ reveal the answers:
Please do so, because the EG2000 has a different lo-res screen resolution than the TRS-80, so we need to know what system our program is running on.dom wrote:There's nothing for the EG2000 at moment, we can add one in pretty easily.
> I have found out it can print a few characters (but not all), these are:
> (...)
My memory is very bad in this period, but I think it is possible to disable the conversion function by calling zx_asciimode():
; Activates /deactivates the ZX81<->ASCII converter
; mode=0 ..disable
; other values ..enable
I also introduced a VT-ANSI character output variant recently, which should give some different collision between printable characters and control codes.
> (...)
My memory is very bad in this period, but I think it is possible to disable the conversion function by calling zx_asciimode():
; Activates /deactivates the ZX81<->ASCII converter
; mode=0 ..disable
; other values ..enable
I also introduced a VT-ANSI character output variant recently, which should give some different collision between printable characters and control codes.
Thanks for the conio.h hint, I tried it for the Jupiter Ace and it works great. I will first concentrate on targets that support low-res plotting *and* VT100 Console I/O.dom wrote:Short answer is no. But conio.h is fairly close - this uses the ANSI display printer if it's available on a platform (and it is for ZX80, ZX81, Jupiter Ace)BTW, is there a platform-independent way to output text to a specific screen location?
If you're looking to do cross platform then I can recommend taking a look at Fabrizio's cross-chase: https://github.com/Fabrizio-Caruso/CROSS-CHASE
How it can be done for other targets can be seen in the Cross Chase source file z88dk_conio_implementation.h. There Fabrizio redefines the gotoxy() command for various platforms:
Code: Select all
#if defined(__SPECTRUM__)
#if defined(SPECTRUM_NATIVE_DIRECTIVES)
#define gotoxy(x,y) printf("\x16%c%c",y+32,x+32);
#else
#define gotoxy(x,y) printf("\x16%c%c",x+1,y+1);
#endif
#elif defined(__ZX81__) || defined(__ZX80__) || defined(__LAMBDA__)
#undef gotoxy
#define gotoxy(x,y) zx_setcursorpos(y,x)
#elif defined(__ENTERPRISE__) || defined(__MTX__)
#define gotoxy(x,y) printf("\x16%c%c",x+1,y+1);
#elif defined(__SVI__) || defined(__MSX__)
#define gotoxy(a,b) printf("\033Y%c%c",b+31+1,a+31)
#define clrscr() printf("\033E")
#define cprintf printf
#define _cprintf printf
#define cputs puts_cons
#define _cputs puts_cons
#define cgets gets
#define _cgets gets
#else
#endif
Exactly, that's the trick! The German-language ZX81 forum team have made a z88dk C tutorial (English translation is here but misses some pictures), and chapter 13 and chapter 17 describe how to disable and enable the character code conversion.stefano wrote:My memory is very bad in this period, but I think it is possible to disable the conversion function by calling zx_asciimode():
Here is a sample program I have written:
Code: Select all
// zcc +zx81 -startup=2 -o printtest4 -create-app printtest4.c
#include <stdio.h> // required for zxTextOut()
void main(void) {
char textP1[25];
char textP2[25];
printf("%c",12); // clear the screen
// Graphic characters test
zx_asciimode(1); // activate the ZX81 <-> ASCII converter (not necessary here as it is on by default)
printf("\nprintf...\n");
zx_asciimode(0); // deactivate the ZX81 <-> ASCII converter
printf("%c%c%c%c%c%c%c%c%c%c\n", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // for some reason characters 8, 9, and 10 do not appear
printf("%c%c%c%c%c%c%c%c%c%c%c\n\n", 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138);
zx_asciimode(1); // activate the ZX81 <-> ASCII converter
printf("\nsprintf and printf...\n");
zx_asciimode(0); // deactivate the ZX81 <-> ASCII converter
sprintf(textP1,"%c%c%c%c%c%c%c%c%c%c\n", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // for some reason characters 8, 9, and 10 do not appear
sprintf(textP2,"%c%c%c%c%c%c%c%c%c%c%c\n\n", 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138);
printf(textP1);
printf("\n");
printf("%s\n",textP2); // this method works as well
zx_asciimode(1); // activate the ZX81 <-> ASCII converter
printf("\nzx-setcursorpos and printf...\n");
zx_asciimode(0); // deactivate the ZX81 <-> ASCII converter
zx_setcursorpos(17,3);
printf(textP1);
zx_setcursorpos(18,3);
printf(textP2);
zx_asciimode(1); // activate the ZX81 <-> ASCII converter
fgetc_cons(); // wait for keypress
return;
}
But is there a reason why the characters number 8, 9 and 10 do not appear on the screen?