VOGONS


turboC programming question

Topic actions

Reply 40 of 50, by ncmark

User metadata
Rank Oldbie
Rank
Oldbie

I got it working with kbhit, but still limited to the character repeat rate - the ship just crawls across the screen while the stars are flying by

If a flag is set when the key is pressed that will turn on ship movement, there is no way to turn it off. I store old keypress and compare to mew one, the problem is that that routine is called only when there IS a keypress, so you would have to press again to turn it off.

What I NEED is a function that returns a null value if no key is pressed

Reply 41 of 50, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

you need to do a keyboard isr in that case. i knocked this and tested on my turbo c 2.01

while a key is pressed its value is 1. otherwise its 0. so while user holds RIGHT, it will always = 1, when they let go, its reset to 0.
this does not take into account extended key codes, thats an exercise for the reader 😀

i built it with large model.

tcc -ml kirq.c

#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>

#define KEY_RIGHT 77
#define KEY_LEFT 75
#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_ESC 1

void interrupt (*old_irq9)();

volatile unsigned char keybtable[256];
volatile char ct1;
volatile unsigned int ct2;

void interrupt new_irq9()
{
ct1=inp(0x60);
ct2=ct1;
ct1=inp(0x61);
ct1|=0x82;
outp(0x61, ct1);
outp(0x61, ct1&0x7f);
outp(0x20, 0x20);

if(ct2 >= 0x80)
{
keybtable[ct2&0x7F]=0;
}
else
{
keybtable[ct2]=1;
}
}

int main(void)
{
old_irq9 = getvect(0x9);

memset(keybtable, 0, 256);
setvect(0x9, new_irq9);

while(1)
{
if(keybtable[KEY_DOWN] == 1) printf("down\n");
if(keybtable[KEY_UP] == 1) printf("up\n");
if(keybtable[KEY_LEFT] == 1) printf("left\n");
if(keybtable[KEY_RIGHT] == 1) printf("right\n");

if(keybtable[KEY_ESC] == 1)
break;
}

setvect(0x9, old_irq9);

return 0;
}

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 42 of 50, by ncmark

User metadata
Rank Oldbie
Rank
Oldbie

hey thanks! I will give that a try!

Reply 43 of 50, by ncmark

User metadata
Rank Oldbie
Rank
Oldbie

Well - maybe some people (me) have to learn things the hard way!

I got to fooling around with calling INT16H - that is how "tricks of the game programming gurus" describes doing it.
One call for check keyboard buffer, if key pressed then get the key
So I got it working - return zero if nothing in buffer or keycode if key pressed
Here's the problem - you can sit there and hold down a key, and it gives you five zeros for every one keycode!

So next step, try the above code

Reply 44 of 50, by wbahnassi

User metadata
Rank Oldbie
Rank
Oldbie

Typically, your handler will just check the status of keys that interest you, and update global variables to reflect the current status of each key.
Example, a global variable named keyUP represents the state of the UP arrow key. Your INT handler will detect changes to the UP arrow key. If it's a key pressed, set keyUP=1. If key released, set keyUP=0.
Now in your main game loop you just check on keyUP and move your objects according to it.
This way you're not bound to key repeat rate, and you separated the keyboard input logic from your main code, which is cleaner.

Turbo XT 12MHz, 8-bit VGA, Dual 360K drives
Intel 386 DX-33, TSeng ET3000, SB 1.5, 1x CD
Intel 486 DX2-66, CL5428 VLB, SBPro 2, 2x CD
Intel Pentium 90, Matrox Millenium 2, SB16, 4x CD
HP Z400, Xeon 3.46GHz, YMF-744, Voodoo3, RTX2080Ti

Reply 45 of 50, by ncmark

User metadata
Rank Oldbie
Rank
Oldbie

I took a break on it for a while but is is coming along
Right now I am just using the keys to "toggle" movement to get around the repetition thing - one press starts moving, second stops.
Made patterns for 5x5 numbers to display score
Alien "ships" are 8x8 characters that switch between X and +
Next step is to get the fire button working...will have to worry about collision detection but I have a good idea how to implement this
It rather looks like some old 80s Atari game

I got spoiled on the commodore64 with the sprite graphics...just point to the pattern and supply coordinates as to where it was supposed to be - collisions were also easy to detect...and they could be scrolled off the screen. Here I can make it look like things are scrolling of the screen, but it will take work. Since I am using malloc to make a screen buffer, I can't scroll it outside or program will crash

Also the commodore 64 sprites were 24 x 21 pixels, but when I tried something that size they seemed WAY too big, hence the 8x8 characters

Long story short - I can do way more here than I could do on the commodore, but it also takes a lot more work to make it happen

Reply 46 of 50, by ncmark

User metadata
Rank Oldbie
Rank
Oldbie

As a side note, just how fast is C really? I am am almost wondering if I could have done the same thing with QuickBasic. I have no speed problem whatsoever here (but it is a p3 650)

Reply 47 of 50, by LoStSOul

User metadata
Rank Newbie
Rank
Newbie

well... long time ago...

When i were playing around "demoscene" world, i have learned that we never use interrupts on dos because they are too slow.

i found this small code lost on hdd that can help you

/*
aPPLiCATiON..: Graphic Library
vERSiON......: 1.2a
uPDATED......: 13-Jan-2k2
rELEASE......: 17-Nov-2k1
aUTHOR(s)....: LoStSOul
lANGUAGE.....: C/C++ (DOS)
nOTES........: Use 80286, 8087/80287 instructions
cOMPiLE......: Borland C++ 3.1
cOMPiLE Flags: -f287 (something like thiz)
*/

#include "dtypes.h"

#ifndef GLIB_H
#define GLIB_H

/* Functions
SetVideoMode(word mode);
ClearScreen(word dest);
PutPixel(int dst, int x, int y, byte color);
FlipScreen(int src, int dst);
PutPixel(int dst, int x, int y, byte color);
WaitVerticalRefresh();
SetRGB(byte color, byte r, byte g, byte b);
GetRGB(byte color, byte r, byte g, byte b);

DrawHLine(int where, int x1,int x2,int y1, byte color);
DrawVLine(int dst, int x1,int y1, int y2, byte color);
DrawLine(int dst, int x1, int y1, int x2,int y2, byte color);
*/

void SetVideoMode(int mode){
asm mov ax, mode
asm int 0x10
}

void ClearScreen(int dst, byte color){
asm mov cx, 32000;
asm mov ax, dst
asm mov es, ax
asm xor di, di
asm mov al, [color]
asm mov ah, al
asm rep stosw
}

void FlipScreen(int src, int dst){
asm mov dx, ds
asm mov ax, [dst]
asm mov es, ax
asm mov ax, [src]
asm mov ds, ax
asm xor si, si
asm xor di, di
// asm mov cx, 16000
asm mov cx, 6000
// asm inc dx
asm rep movsw
asm mov ds, dx
Show last 151 lines
}


void PutPixel(int dst, int x, int y, byte color){
asm mov ax, dst
asm mov es, ax
asm mov ax, y
asm shl ax, 6
asm mov bx, ax
asm shl ax, 2
asm add ax, bx
asm add ax, x
asm mov di, ax
asm mov al, color
asm mov [es:di], al
}

void WaitVerticalRefresh() {
asm mov dx, 0x3DA
lp1:
asm in al, dx
asm and al, 0x08
asm jnz lp1
lp2:
asm in al, dx
asm and al, 0x08
asm jz lp2
}

void SetRGB(byte color, byte r, byte g, byte b){
asm mov dx, 0x3c8
asm mov al, color
asm out dx, al
asm inc dx
asm mov al, r
asm out dx, al
asm mov al, g
asm out dx, al
asm mov al, b
asm out dx, al
}

void GetRGB(byte color, byte r, byte g, byte b){
asm mov dx, 0x3c7
asm mov al, color
asm out dx, al
asm inc dx
asm mov al, r
asm out dx, al
asm mov al, g
asm out dx, al
asm mov al, b
asm out dx, al
}

void DrawHLine(int dst, int x1,int x2,int y1, byte color){
asm mov ax, dst
asm mov es, ax
asm mov ax, y1
asm mov di, ax
asm shl di, 1
asm shl di, 1
asm add di, ax
asm mov cl, 6
asm shl di, cl
asm mov bx, x1
asm mov dx, x2
asm cmp bx, dx
asm jl lp1
asm xchg bx, dx
lp1:
asm inc dx
asm add di, bx
asm mov cx, dx
asm sub cx, bx
asm shr cx, 1
asm mov al, color
asm mov ah, al
asm ror bx, 1
asm jnb lp2
asm stosb
asm ror dx, 1
asm jnb lp3
asm dec cx
lp3:
asm rol dx, 1
lp2:
asm rep
asm stosw
asm ror dx, 1
asm jnb lp4
asm stosb
lp4:
}

void DrawVLine(int dst, int x1,int y1, int y2, byte color){
asm mov ax, x1
asm mov bx, y1
asm mov dx, y2
asm cmp bx, dx
asm jl lp1
asm xchg bx, dx
lp1:
asm mov di, bx
asm shl di, 1
asm shl di, 1
asm add di, bx
asm mov cl, 6
asm shl di, cl
asm add di, ax
asm mov cx, dst
asm mov es, cx
asm mov cx, dx
asm sub cx, bx
asm inc cx
asm mov al, color
asm mov bx, 0x13f
lp2:
asm stosb
asm add di, bx
asm loop lp2
}


void DrawLine(int dst, int x1, int y1, int x2,int y2, byte color){
int dx,dy,sx,sy,k;
sx = 1;
sy = 1;
dx = x2-x1;
if (dx<0) {dx=-dx; sx=-1;}
dy= y2-y1;
if (dy<0) {dy=-dy; sy=-1;}
// k= -(dx shr 1);
k = -(dx / 2);
PutPixel(dst, x1,y1, color);
while ((x1 != x2) || (y1 != y2)){
if ((k >= 0) && (y1 != y2)){
y1 =y1+sy;
k = k - dx;
PutPixel(dst, x1,y1, color);
}
else {
x1 = x1 + sx;
k = k+dy;
PutPixel(dst, x1,y1, color);
}
}
}

#endif

GamingPC: R7 5800x3d, x570s Aorus Elite ax,32gb, radeon 7900 xtx, w10
InternetPC/General use: R7 1800x.64gb, Asus prime x370, quadro p620, Debian12

Reply 48 of 50, by ncmark

User metadata
Rank Oldbie
Rank
Oldbie

If anyone is interested...
I have a row of space-invaders type aliens that move across the screen
When you press space bar a "missile" does launch
I can detect collisions and increment/display a score BUT that is all that happens

Next steps:
Detect with which ship the missile has collided so it can be "turned off"
Set it up so more than one missile can be fired at a time

I had to slow the stars WAY down because everything was running on the same clock - stars, aliens, missile all moving at the same speed. Now the stars are like 1/4 and the aliens like 1/2 - only the missile moves at full speed

It is every so slightly jerky - I think that's the screen buffer being copied into video memory. I have a feeling if I were really going to do it right that would have to be an assembly language routine

This is no small programming task (or maybe I am just rusty as heck)

Reply 49 of 50, by wbahnassi

User metadata
Rank Oldbie
Rank
Oldbie
ncmark wrote on 2024-07-13, 19:57:

As a side note, just how fast is C really? I am am almost wondering if I could have done the same thing with QuickBasic. I have no speed problem whatsoever here (but it is a p3 650)

Depends on what you do. Graphics in DOS weren't HW-accelerated (e.g. color-keyed bitblts), so it eats a lot of CPU cycles even for the fastest asm code. You could get away with, say, a turn-based game. But drawing every pixel every frame in interpreted QuickBasic is not going to run smooth on a 650MHz CPU IMO (e.g. an FPS game).

C with a decent compiler isn't supposed to be that different to coding in asm (perf-wise). Maybe even faster than hand-written asm if that asm code was written naively anyways.

This is all assuming your algorithms themselves are fast. Slow algorithms will be slow no matter what language you use.

Turbo XT 12MHz, 8-bit VGA, Dual 360K drives
Intel 386 DX-33, TSeng ET3000, SB 1.5, 1x CD
Intel 486 DX2-66, CL5428 VLB, SBPro 2, 2x CD
Intel Pentium 90, Matrox Millenium 2, SB16, 4x CD
HP Z400, Xeon 3.46GHz, YMF-744, Voodoo3, RTX2080Ti

Reply 50 of 50, by ncmark

User metadata
Rank Oldbie
Rank
Oldbie

I am not sure I could think of a better way to do it
I could have two screen buffers maybe, go through and compare, and only write to video memory those that have changed
BUT that would chew up a lot of cycles doing the checking
I guess it is a question how slow is writing to video memory
it speed up a LOT when a made the video buffer versus reading the entire screen and re-writing