• Please review our updated Terms and Rules here

Emulation of rare graphics adapters

yevrowl

Member
Joined
Jun 26, 2022
Messages
20
Location
Kiev
Currently busy writing a chess-like program, with support for all graphics adapters known since the 1980s. But QBasic does not graphically support some, decided to emulate for now:

CGA → CGA (320 × 200 × 4), SCREEN 1 mode
EGA → EGA (320 × 200 × 16), SCREEN 7 mode
VGA → VGA (320 × 200 × 256), SCREEN 13 mode
Tandy → EGA (320 × 200 × 16), SCREEN 7 mode
Olivetti → CGA (640 × 200 × 2), SCREEN 2 mode
Hercules → CGA (640 × 200 × 2), SCREEN 2 mode
Plantronics Colorplus → EGA (320 × 200 × 16), SCREEN 7 mode

Of course, it would be ideal to emulate everything in the 320 × 200 × 16 mode, but would be grateful for any ways. Especially for the Q(uick)Basic library, which adds SCREEN 5 & SCREEN 6 modes.
 

Attachments

  • menu.png
    menu.png
    2.6 KB · Views: 5
  • olivetti.png
    olivetti.png
    1.9 KB · Views: 6
  • cga.png
    cga.png
    1.5 KB · Views: 6
  • ega.png
    ega.png
    1.5 KB · Views: 6

Plasma

Veteran Member
Joined
Nov 7, 2005
Messages
1,375
QB should support Hercules (screen 3) if you load msherc.com first. Olivetti is also supported (screen 4).
 

yevrowl

Member
Joined
Jun 26, 2022
Messages
20
Location
Kiev
For CGA emulation in Hercules there is HGCIBM.
Is there a solution to emulate EGA in Tandy (PCJr)?
Because the video modes are similar (320 × 200 × 16) — https://groups.google.com/g/comp.sys.tandy/c/qQ7XYKSLItA
And also, perhaps, similar solutions for Olivetti and Plantronics Colorplus?
Trying to find Tandy support in Q(uick)Basic.
 
Last edited:

carlos12

Experienced Member
Joined
May 10, 2020
Messages
138
Is there a solution to emulate EGA in Tandy (PCJr)?
Because the video modes are similar (320 × 200 × 16) — https://groups.google.com/g/comp.sys.tandy/c/qQ7XYKSLItA
Although the modes are visually identical (320x200 pixels resolution and the same 16 colors), technically and internally they are not the same at all. For example, you could reuse the same bitmap graphics for all the 320x200x16 modes, but the code to represent those graphics on screen would be radically different.

EGA native modes are planar modes, that is, every of the four basic color components (Blue, Green, Red and Yellow) is stored in one memory plane/bank. They use the same memory address (segment A000h) but a port changes the plane/bank to read from/write to. This "trick" makes possible for the EGA to use more than 64 kb of memory if the card has it, bypassing the original IBM PC memory map and design limitations. So in low resolution mode it can hold up to 8 video pages, 4 on mid resolution (640x200x16). High resolution mode (640x350) is just impossible in full 16 colors if the card doesn't have at least 128 Kb. In brief, each of the 4 colour planes is limited to 64 Kb, but nothing impedes to have 4 planes of 64 kb each on a 256 kb card. If the card only has 64kb of RAM, there still are 4 planes but, logically, with only 16 kb of memory each. This poses and extra difficulty while programming it. Apart of the planar nature, EGA is also a quite more complex piece of hardware, having different extra possibilities than simpler adapters such as CGA or Hercules, such as hardware masking (that is, you can draw a image with transparent pixels by drawing first its bit mask), fast 4 pixels at once hardware memory copying, several different write/read modes, custom charset and smooth 1 pixel horizontal scrolling.

By contrast, both Plantronics and PCjr/Tandy can be seen as extended CGA modes. They are much simplier. In PCjr/Tandy we have two pixels per byte. Each nibble (4 bits) has the 4 color components (this time Red, Green, Blue, Yellow, the order is slightly different than in EGA). The low resolution mode is interchangeable with CGA, there's no need to change the programming. But the 320x200 needs to manage 4 scanlines instead of 2. Plantronics has a similar but slightly different scheme that is very well explained here

The problem with QBASIC/QuickBASIC is that it's a quite close software ecosystem. Turbo C, Turbo Pascal and, I think, QuickC have a more open and abstract driver model that allows the user to write drivers for different graphic modes/adapters while using the same graphic primitives to draw lines, circles, get/put bitmaps, etc. But AFAIK QuickBASIC doesn't have any of this. The graphics support it has is what you have. The BASIC libraries are very closed. I think Quick BASIC dropped the PCjr/Tandy support. There were some GW-BASIC, ROM BASIC and catridge BASIC versions that supported those modes but not QuickBASIC.

So I think the solution would be to build some custom libraries in assembler with your custom graphic primitives, and call them from your QuickBASIC program. That's something that was done in the game MagiDuck. There's a thread on this very forum with the process. That game used a new pseudo graphic mode tweaking text mode and everything sould be done from scratch and implemented in assembler. That would be definitely something that would give a lot more work that just simply using an already released driver with the BASIC graphic primitives.
 

carlos12

Experienced Member
Joined
May 10, 2020
Messages
138
I think I wrote a surprisingly long post 😳. So here comes the (almost) TLDR version in order, I hope, to be more clear and concise now:

- The machine code procedures to render something to the EGA screen are incompatible with the visually similar, but internally very different Plantronics or Tandy: both are extended CGA cards.
- In order to use the BASIC graphic primitives, such as LINE, CIRCLE, GET, PUT, etc. you must stick with the officially supported modes via SCREEN comand. You just cannot add new modes apart from the official ones, as there's no driver model as there is in Turbo Pascal, Turbo C or QuickC.
- QuikcBASIC dropped the PCjr/Tandy support that was once available on earlier and simplier BASIC versions, and it never supported the Plantronic's modes. But it supports, as Plasma pointed, Hercules and Olivetti.
- The above said doesn't impede you to create external libraries (Quick libraries, or standard libraries/object files to be called with CALL ABSOLUTE) written in assembly language to do whatever you want with your devices. That's a more complex way and it forces you to have a deeper knowledge about the graphic hardware programming, and forces you to have knowledge about implementing algorithms to draw lines, polygons, get/put a bitmap, etc. As a clue, you could use an already done algorithm for CGA for any of these tasks and adapt it to the differences of the 16 color extended CGA modes.
 

Plasma

Veteran Member
Joined
Nov 7, 2005
Messages
1,375
I will note that it is technically possible to alter QB's internal commands, although it's a pain in the butt. I have modified PUT and VIEW in the past to add sprite transparency and clipping for screen 13.

But there's no real advantage to that vs an external library (like GRAFIX) other than your code looks nice (minus the super ugly install functions). We did it back in the day as a loophole for contest rules that called for "pure" QB code with no libraries and no CALL ABSOLUTE.
 

yevrowl

Member
Joined
Jun 26, 2022
Messages
20
Location
Kiev
Thanks everyone for the detailed explanations.
Added support for commands from the library, it was possible to draw a chessboard. However, for some reason, instead of arranging the figures, it hangs...
The program for QuickBasic 4.50 is in the attachment.
 

Attachments

  • chestand.zip
    4.3 KB · Views: 3

Plasma

Veteran Member
Joined
Nov 7, 2005
Messages
1,375
You have a bunch of lines like this which is probably not the logic you actually meant:
Code:
IF dc1 = 1 AND vid <> 4 THEN CALL dice1 ELSE CALL dice1tandy

dice1 is called only if dc1 = 1 and vid <> 4. In all other cases, including dc1 <> 1 and vid <> 4, dice1tandy is called.

You need another THEN to separate the dc1 comparison from the vid comparison:
Code:
IF dc1 = 1 THEN IF vid <> 4 THEN CALL dice1 ELSE CALL dice1tandy

But a cleaner and simpler way is to move the vid check to the sub:
Code:
IF dc1 = 1 THEN CALL dice1

SUB dice1
  IF vid <> 4 THEN
    LINE (4 + x, 4 + y)-(5 + x, 5 + y), c, BF
  ELSE
    CALL FillBox(4 + x, 4 + y, 5 + x, 5 + y, c)
  END IF
END SUB

You can also omit LET/CALL and replace REM with ' (unless you prefer the old school style :poop:)
 

yevrowl

Member
Joined
Jun 26, 2022
Messages
20
Location
Kiev
You have a bunch of lines like this which is probably not the logic you actually meant:

Thanks for the help!
Please advise further. How can I use this library to print a string variable in graphics mode?

Code:
CALL SetCursor(x, y): Print fen$
 

yevrowl

Member
Joined
Jun 26, 2022
Messages
20
Location
Kiev
Throws out of the program and displays a screen with such an error. At the same time, QuickBasic hangs.
 

Attachments

  • chess.zip
    4.2 KB · Views: 5
  • ssc.png
    ssc.png
    4.7 KB · Views: 11

Plasma

Veteran Member
Joined
Nov 7, 2005
Messages
1,375
Thanks for the help!
Please advise further. How can I use this library to print a string variable in graphics mode?

Code:
CALL SetCursor(x, y): Print fen$
PRINT won't work in Tandy graphics modes because QB isn't aware of those modes. You need to use PrintString or PrintStringX from the library.
 

Krille

Veteran Member
Joined
Aug 14, 2010
Messages
1,011
Location
Sweden
String space corrupt is what usually happens when QB programs become sufficiently large. It's one of the many reasons we love and cherish QB. ;) Think of it as QB:s subtle way of letting you know it's time to optimize the code. :giggle:
 

yevrowl

Member
Joined
Jun 26, 2022
Messages
20
Location
Kiev
PRINT won't work in Tandy graphics modes because QB isn't aware of those modes. You need to use PrintString or PrintStringX from the library.
Yes, already aware of this. The problem is that...
Code:
CALL SetCursor(2, 8): CALL PrintString(fen$)
and
Code:
CALL SetCursor(2, 8): CALL PrintStringX(fen$)
...do not work either.

String space corrupt is what usually happens when QB programs become sufficiently large. It's one of the many reasons we love and cherish QB. ;) Think of it as QB:s subtle way of letting you know it's time to optimize the code. :giggle:
In the compiled form, such problems have not yet been observed. =)
 

Plasma

Veteran Member
Joined
Nov 7, 2005
Messages
1,375
Yes, already aware of this. The problem is that...
Code:
CALL SetCursor(2, 8): CALL PrintString(fen$)
and
Code:
CALL SetCursor(2, 8): CALL PrintStringX(fen$)
...do not work either.
PrintStringX is used in the city.bas demo. Does that work?
 

Plasma

Veteran Member
Joined
Nov 7, 2005
Messages
1,375
I guess I don't understand. You can pass whatever string you want.

Code:
fen$ = "blah blah"
CALL PrintStringX(fen$)

Does it not output? Crash?
 

yevrowl

Member
Joined
Jun 26, 2022
Messages
20
Location
Kiev
I guess I don't understand. You can pass whatever string you want.

Code:
fen$ = "blah blah"
CALL PrintStringX(fen$)

Does it not output? Crash?
For some reason, it displays in the lower right corner, after which it hangs.

Code:
CLS
LET fen$ = "Chess-notation"
CALL MediumGraphics
CALL SetCursor(4, 4)
CALL PrintString(fen$)

DOSBox 0.74, QuickBasic 4.50.
 

Attachments

  • run.png
    run.png
    1.1 KB · Views: 6
  • after.png
    after.png
    2.8 KB · Views: 6
  • compiled.png
    compiled.png
    1.1 KB · Views: 6

carlos12

Experienced Member
Joined
May 10, 2020
Messages
138
Sorry if it's a stupid question, just trying to find an explanation: according to GRAFIX documentation:

GRAFIX is a memory resident graphics and sound program for your Tandy 1000
series personal computer. It provides you with a complete set of graphics and
sound functions that can be executed from your favorite programming language
such as compiled BASIC and PASCAL. To use GRAFIX just install it when you start
up your computer by including the following lines in your AUTOEXEC.BAT file:

TANDY11
GRAFIX

Did you load those TSRs before running your BASIC application?
 
Top