-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Games development on ELKS #871
Comments
The topic of porting graphic libraries and 90's games to ELKS should be preceded by a more substantial discussion regarding the graphics in ELKS in general. I never had occasion to work with nx before meeting ELKS (my past experience with NuttX from which nx originated never went beyond the nsh command line sessions), so I can't really say how good or bad this library is. I just have impression that I already saw things more mature than nx, like Photon on QNX or DirectFB on Linux. Even things like GUILib for multiplatform SDL library seemed more mature despite all of its limitations. And there is also John Elliott's SdSDL library for SDL which emulates GSX and VDI graphics that originates from CP/M and DOS (before MS Windows). And that was the direction I was looking for: John Elliot's fork of GSX/VDI-based GEM (the mighty FreeGEM) works really lovely on both of my XT machines (one 8088, one 8086 based), far better than nx on ELKS on the same machines, though I suspect the secret is in the underlying OS: there's no multitasking in DOS, hence GEM can consume all of the CPU time for handling mouse-driven graphics operations. Yet anyway, it only shows that doing GUI on XT is possible and the user experience does not need to suffer. BTW, Windows 3.0 was the last version of MS Windows that could be installed on 8086 and it offered some kind of multitasking, still being capable of providing good enough user experience. One more thing I remember from the past. My very first Linux back in the 90s (some very early version of RedHat) was installed on some very low end i386 machine equipped with ISA 8-bit VGA graphics card (probably the same I've installed during ELKS times into my Turbo XT to replace Hercules mono graphics card that was installed into it originally). Running X at 640x480x16 offered terrible user experience and 16-color palette looked awful. Yet I managed to force X server to run with 320x200x256 mode and it really started to fly! The user experience was amazing. I guess two factors were playing their role here: lower resolution and a whole byte per pixel which simplified all of the graphic operations. I think it's one of the possible directions nx on ELKS could also explore. In the end, those demos don't really display much of the content on screen. See how GEOS looks like on C64, it's low resolution and it's still really cool (speaking of GEOS, it was ported to 8086 XT's too, yet to my disappointment its final XT-compatible version was working much slower than FreeGEM). |
Hello @toncho11, hello @pawosm-arm, Well, the graphics stuff aside --- I think @ghaerr can comment further on that --- it is obvious that porting Turbo C++ specific code to, well, anything that is not Turbo C++, is going to take some effort. I do not see this as a bug per se: there is no real urgent need for ELKS to be compatible with a non-standard programming interface (even if it will be a "nice thing to have"). |
I remember the times when porting from Turbo C++ was all about getting rid of '#include <conio.h>' :) |
Hello @toncho11 , hello @pawosm-arm,
Well, I guess there are different ways of doing the porting task. :-| In case you missed it: on the MS-DOS front, I have been working on a I am currently keeping this library separate from the underlying C library ( ( If there is real demand, perhaps I can look into extending the scope of Thank you! |
I wonder how far we can go with this... It's like with Fuzix for Z80 machines where ability to run CP/M programs was considered. |
I wonder how far we can go with this... It's like with Fuzix for Z80 machines where ability to run CP/M programs was considered.
Interesting digression @pawosm-arm, I'm curious: anything in particular from cp/m you're interested in?
It may be worthwhile remembering that cp/m and fuzix ran on a different and incompatible architecture (from x86), and most programs were written in assembler. Still, I have 3 operating cp/m machines...
…-Mellvik
|
Nice digression. We need that 👍 By the way is it possible to change the priority of a process in ELKS? There is a nice sys call, but no nice command? Maybe this will make a game run a bit faster. While we wait for @ghaerr I think making a layer that allows for quick porting of turbo C programs and games will be interesting. I mean I want to use ELKS and have software for it. Ok some people are focused only on the kernel and they do not care about userland, but not me. |
@toncho11 I think the 'bug' label here is slightly misleading.
Although interesting, this digression should not grow here as it barely touches the matter of this ticket.
I'm slightly confused here. Both Fuzix and CP/M were originally targeting Z80 machines hence the idea of running CP/M software in Fuzix wasn't that terrible (considering simplicity of CP/M). And this simplicity was a key here: I suspect providing similar compatibility layer in ELKS to enable running 8088/8086 DOS programs would be more difficult. In case of CP/M, attempts to support other architectures (e.g. CP/M-86 or CP/M-68k) never gained popularity due to competition from the natively developed operating systems that were better suited to those machines. Anyway, there is some trace of the feature I've mentioned here in Fuzix's git repo: https://github.com/EtchedPixels/FUZIX/blob/master/Applications/cpm/runcpm.c EOOT. |
Hello everyone, Well, there's a lot that got discussed today, here's a few of my thoughts...
Yes, defining a distinct set of graphics functions, preferably across more than just one game, is a great way to start. Then, the entire function-set can be analyzed a bit and a graphics engine/library used as an API-bridge. Having done a heck of a lot of graphics engine programming, I also highly recommend keeping things simple in the beginning, and adding complexity only after getting the initial game(s) initially drawing. For instance, fill, draw poly and rectangle are pretty basic, but floodfill can get complicated. Text output is a whole 'nother discussion, but if a fixed-size font can be used, things are simplified considerably.
Yes, a lot of the graphics could be mapped to Nano-X, but it will likely be too slow. The biggest reasons for this (to be covered in more detail later) are 1) the lower level routines are written in C, not ASM, and 2) Nano-X has an additional layer of overlapping window management and clipping support. I have a number of graphics translation libraries for various embedded systems like Arduino, but what is really needed here is an (older) 8086 graphics library with direct, fast EGA support.
Actually, Nano-X originated from NanoGUI, which itself was based on some very early code by David I. Bell, the same guy that interestingly enough wrote But I digress. Back to @pawosm-arm's points, SDL, DirectFB, etc - are all too large for ELKS. Since the ELKS applications (not the kernel) will be writing directly to the EGA, what we should seriously consider would be an older, fast EGA library. Those libraries would likely use a different assembler than ia16-gcc-as (which is gcc compatible and AT&T syntax). Another option would be to use the EGA draw routines from Nano-X written in ASM (elkcmd/nano-X/drivers/asmplan4.s), but they would need to be ported from the BCC/AS86 assembler, and the speed would likely improve considerably. Nano-X is written as three layers (driver, engine and API), and the driver and engine could be used without the window-management API overhead, which would help. Its all a bit complicated, but doable.
There's no way to change the priority of a process in ELKS (yet); but when a single program is running, which is usually the case, there's no need for it - the system runs the single process as fast as can be, only taking timer interrupts, which increment a few counters, and then the interrupted process is immediately continued. |
There is another solution: Alfonso Martone found a way to convert DOS Turbo-C programs to enable these to run with ELKS. For this he developed the exe2elks DOS utility program and a small libc without DOS system calls. You compile your C program with this small libc library instead of the standard Turbo-C libc. Then you use the exe2elks utility to convert the generated executable in the DOS EXE format to a 16bit OMAGIC aout file as required by ELKS. So if we accept that the Turbo C graphics.h is not using DOS system calls (I actually do not know) then we could compile a game with Turbo C and:
So again:
What do you think? Are the differences in compiling linking and function parameters handling so different ? |
Argh, this name reuse, so common in Open Source world. Indeed nx graphics in NuttX and nx graphics in ELKS are completely different things of completely different origins. Both had the same purpose in common which is being lightweight, and that confused me. So porting nx from NuttX may be one more path to follow or avoid. Anyway, ability to change resolution (and bytes per pixel) would be a great addition to current graphics layer in ELKS, but only if it doesn't overcomplicate the current codebase. |
Speaking of Turbo C++, it brings me some of my late school days memories, you can have a glimpse here, https://www.youtube.com/watch?v=N8z5kQFhJ9A yet note I'll probably pull it down soon, there's too much cringe in this :) Anyway, looking forward, if you're serious about DOS compatibility in ELKS, IPX would be a nice addition, we had a lot of fun playing those early multiplayer games back in the 90's. |
I have to say, somewhat amazing piece of work by Alfonso. He's definitely provided the basics, that should, possibly without modifications, work today (we upgraded the ELKS a.out format slightly earlier this year, but still support the original a.out format, calling it "v0"). The bigger issue with this approach is that the development is all done on DOS, right? So TurboC is run on DOS to compile and link any TC program, along with the TC graphics library, and Alfonso's DOS-to-ELKS conversion libc which allows the program to run on ELKS without modification. It's a slick way to solve this problem. Perhaps you should try running his sample programs and see if/how they run on ELKS today, for a start. |
I compiled a minimal program that draws a rectangle with Turbo C and then applied exe2elks. It says "invalid argument" on ELKS. |
This is very likely due to the |
Here it is: |
If this is the correct disassembly: then it means that there are 19 int $0x21 DOS calls ... more than I have hoped. |
OK I see now ... probably I need to use the .bat file provided by Alfonso to set the proper options of tcc and tlink ... to generate a better executable ... I was using the IDE with .map file generation enabled. |
Yes, the idea is to compile with TC but link with Alfonso's special library that replaces all the TC libc calls to int 21h with ELKS system calls, and then rewrite the .EXE MZ format to ELKS a.out format. |
Ok it is going to take much more time. |
This is a direct example of Alfonso: It says "invalid argument". We need to fix that first before going deeper into the graphics library. How do you disassemble it? |
I'm not exactly sure what the problem is with ELKS running that (v0 format a.out header) executable, but I have a workaround that works:
It appears we don't have a way to disassemble linked binaries... the |
It is far more complicated ... I can not even compile a normal exe with the integrated bgi driver. @pawosm-arm Do you know how to do that? How to compile from command line with graphics.lib, egavga.obj and registerbgidriver(EGAVGA_driver) ? I can not make it to work. |
Interesting ... I tried to contact Alfonso ... but there is no working email ... nor any other contact information ... |
Can you specify more details? Which 'command line': DOS, Linux, ELKS? (well, ELKS command line doesn't seem to have a linker). What kind of binary do you want to have in effect? |
Compile or link error? You're using TC on DOS so there should be no issues having TC compiling TC programs, including those with graphics.h. Alfonso's trickery is all at the link stage, linking with additional libraries, right? You'll probably need to study TC a bit and understand what options it has for graphics programs, should there be compilation issues with it. |
I'm pretty sure it doesn't. I chose it for porting because it's small and simple. :) It does something like this (for menu handling and scrolling): do
{
move(sy+i,sx);
printw(">%.*s<",maxLen, menuItems[i]);
keyMask = plat_ReadKeys(0);
if(keyMask & INPUT_MOTION)
{
move(sy+i,sx);
printw(" %.*s ",maxLen, menuItems[i]);
switch(keyMask & INPUT_MOTION)
{
case INPUT_UP:
if(!--i)
i = numMenuItems-1;
break;
case INPUT_DOWN:
if(numMenuItems == ++i)
i = 1;
break;
}
}
keyMask &= (INPUT_SELECT | INPUT_BACKUP);
move(sy+height,sx);
printw(" %.*s ",maxLen, pScroller);
if((pEnd - pScroller) < maxLen-1)
{
move(sy+height,sx+(pEnd-pScroller)+1);
printw(" %.*s ",maxLen-(pEnd - pScroller)-1, scroller);
}
if(plat_TimeExpired(SCROLL_SPEED))
{
++pScroller;
if(!*pScroller)
pScroller = scroller;
}
} while(keyMask != INPUT_SELECT && keyMask != INPUT_BACKUP); And thanks for the advice. It gave some ideas where to look into. |
I cleaned up all attron(WA_REVERSE) and color_set functions, so this is a bit simplified version. |
Looks pretty straightforward. If it's scrolling strangely, I would suggest looking at 'if(plat_TimeExpired(SCROLL_SPEED))' as that seems to increment a column (or not). The auto-scroll functionally actually seems kind of cool as written :) [EDIT: Oh I see - you were saying it IS scrolling correctly. Nice!] |
No. It doesn't, unfortunately. At least not in elksemu. I'll test in virtual machine and I might try installing on an older laptop like Rafael. |
In that case, the code in plat_TimeExpired is likely the culprit. This function is either hanging, causing problems with the menu, or always returning 0. If you hack it to always return 1, then the bottom line should scroll (quickly).
I'm on macOS, and elksemu won't even build on macOS. So I can't duplicate any of that. |
I just found out elks will boot on DOSBox-X. I did a test of 1440k floppy and it worked. Later I saw it's used elsewhere in the toolchain for testing. I'm very familiar with DOSBox-X, so I might try that first. Now I'm building a disk image. I might put executable on the fat formatted fd image and run from that. |
Floppy images work well in DOSBox. Hard drive images though have some problems. But in QEMU everything worked out of the box. |
Yes, it's been used for quite some time to run the PC-98 images. Here's the configuration file I use. I'll check this in to the repo, it is used with 'dosbox.sh' which is already checked in.
If you can get that working, please update dosbox.sh and/or dosbox-x.conf, and I'll add that to the repo. |
Deal. :) I gave up for now. But I will try again at some time. |
Great! With the one Rafael ported that's three. |
It is interesting to see battles with 2 chess game computers :) |
I haven't had luck yet. I worked on cc65-chess yesterday but just got entangled with hacking curses code. For some reason anything I tried didn't work. :D So today (sunday) I took a break and will try hacking on it in the next few days again. |
I actually made some progress in the new year. I implemented A_REVERSE and color_set with a little help in debugging from ChatGPT. Haven't got around to fix key bindings and scrolling text. I also took time to test the game in Qemu and elksemu and the result looks and behaves the same. So, I confirm elksemu works right in Linux. Not yet ready for pull request, but we are getting there. :) |
Nice! Does it fit in 640KB memory? |
That looks and sounds great @bocke! When you're ready to contribute, lets have you stick the game in its own directory under elkscmd/, and also use copies of the enhanced curses*.c you've updated. I can then look at them to determine how compatible they'll be with the existing set of elkscmd/tui programs that also use them. It sounds like after your PR will be a good time to convert the curses code into a library and stick it in libc, using your version as a starting point. The only "big" problem coming up is going to be how to determine what the names of each of our different chess programs should be, as they need different names to all live together on a distribution disk! :) |
The binary is 22,8 kb at the moment. That includes curses1.c curses2.c curses3.c and unikey.c from elkscmd/tui. Anyway, There might be some problem with getch from curses2.c. It seems autoscroll doesn't work because the input is blocking. Also, getch() seems to recognize the different arrow keys, but plat_ReadKeys for some reason doesn't. I have to check unikey stuff too. |
I have a very stupid, but also very simple solution to that. 😁 Chess1, chess2, chess3. :) |
This is getch() we have: int getch()
{
int e, n;
int mx, my, modkeys, status;
char buf[32];
fflush(stdout);
if ((n = readansi(0, buf, sizeof(buf))) < 0)
return -1;
if ((e = ansi_to_unikey(buf, n)) != -1) { // FIXME UTF-8 unicode != -1
return e;
}
if ((n = ansi_to_unimouse(buf, n, &mx, &my, &modkeys, &status)) != -1) {
mouse_button = n;
switch (n) {
case kMouseLeftDoubleClick:
waitformouse();
return n;
case kMouseWheelDown:
case kMouseWheelUp:
return n;
}
}
return -1;
} What exactly makes the input blocking, I don't know. :) But I'll try to debug. I took a look at unikey.{c,h} and it doesn't look fun for debugging. |
Heh. Seems ChatGPT caught on possible reason for blocking.
|
It also recommends a potential solution:
I'll check if this solves the blocking problem. The problem is basically: program blocks until a key is pressed. But the program is designed to do autoscrolling in the menu. Also computer player is supposed to play automatically. Same with the game where computer (AI) plays against itself. If the IO is blocked, you have to press a key for game to continue on every move. |
All the TUI programs require an initialization to work with the complicated unikey stuff. This is called
That's different. It's commented out because the system call
I wouldn't recommend calling a delay routine when the problem itself is you don't want blocking. Add the curses
Got it. These differing cases are already handled by the library. What I don't get is why the program didn't come with a call to nodelay in it in the first place... |
The robot solution recommendation is actually the exact opposite of what you need: it is recommending adding a delay, while your whole problem is to remove all blocking or delays, and returning -1 immediately if no character is ready. LOL!!! |
Well, I use AI for code analysis. It's not perfect, but it's much faster than understanding thousands of lines of code someone else wrote on your own. Especially if you have to dive deep into implementation details of multiple inter-connected projects. I am not really a system programmer, so when the things get too low level, I have too use tools I have at my disposal. :) For example, when my brain is out of the solutions, I will pick someone else's brain. In this case AI. If I didn't consult AI, I would probably have to bother you and others in this topic. :) I mean, I don't mind that solution either, but I doubt anyone here has too much time on their disposal. Anyway, no real damage here as I would see it's not working and try something else. |
And I think the author didn't use nodelay() because he used timeout(0). |
No problem - I was just kidding. I personally think that the AI hype is overblown, as was seen here, but |
Nice find. If nodelay works, then go ahead and add the curses timeout function, I wasn't aware of it, |
Nodelay works. :) Such a simple solution. I spent too much time debugging this... 🙄 |
Yes, getch uses the underlying magic of the unikey library code to decode ANSI input streams containing ESC chars, etc. So plat_ReadKeys needs to be recoded or reworked to do the same - possibly by just calling getch itself, unless it's trying to do its own decoding. I haven't looked at the source so I'm just guessing. |
Let's take this example of Snake compiled by Turbo C:
https://github.com/ashmew2/snake-game/blob/master/Final.cpp
delay
,sound
andnosound
are used. We can omit sound for now.kbhit
,clrscr
andgetch
are used in this game! So 3 out 8 functions from conio.h.fillpoly
,drawpoly
,settextstyle
,outtextstyle
,outtextxy
,setfillstyle
,floodfill
,setcolor
,rectangle
@ghaerr Maybe graphics.h can be mapped to Nano-X? But on 8086 computers Naxo-X looks slow for games. For example
The text was updated successfully, but these errors were encountered: