• Please review our updated Terms and Rules here

VGA & CGA Graphics Library for DOS Games

I've been trying to figure out how to code a blit routine for the CGA card. From what I understood so far... is that the CGA graphics mode 320x200x4 has the video memory interleaved. Even-numbered scan lines begin at B800:0000, and odd-numbered lines begin at B800:2000. And each byte has 4 pixels inside. I'm guessing that the interleaved is not that difficult to solve, because you could make 2 loops, one for even and another one for odd numbers. But the fact that each byte has 4 pixels makes it difficult to achieve pixel exact location of a bitmap on screen. So, how can I write a function to draw a bitmap on screen with (x,y) location on screen? :confused:
 
From what I understood so far... is that the CGA graphics mode 320x200x4 has the video memory interleaved. Even-numbered scan lines begin at B800:0000, and odd-numbered lines begin at B800:2000. And each byte has 4 pixels inside.

That is correct.

But the fact that each byte has 4 pixels makes it difficult to achieve pixel exact location of a bitmap on screen. So, how can I write a function to draw a bitmap on screen with (x,y) location on screen? :confused:

You have two options:
The slow option: You shift the pixels on-the-fly when you read from your source bitmap, to adjust for the pixel positions inside a byte.
The fast option: You maintain multiple pre-shifted bitmaps in memory, and pick the correct one based on the x-coordinate.

As you can see, my sprite compiler uses the second option (although I use 160x200 mode, so I only have 2 pixels per byte. In 320x200 mode it would generate 4 different sprite routines for X, and two variations for even and odd scanlines).
It takes more memory obviously, but the blit-speed will be as good as with VGA (or well, faster, since you have less bytes to move around). Since an entire CGA-screen is only 16k in size, if you target 640k machines, there's probably no reason to worry about this.

Now wait till you get to EGA :)
Its bitplane-based memory model means you get 8 pixels inside each byte.
On the bright side, it has an onboard ALU which can rotate and mask pixels, so you could use that to shift bitmaps around.
 
The fast option: You maintain multiple pre-shifted bitmaps in memory, and pick the correct one based on the x-coordinate.

To add to what Scali wrote: This is what most games did on 808x if they wanted any semblance of speed, and is what I'd personally recommend. It won't take up any more space than an MCGA bitmap because it's 1/4th the data but you dupe it 4 times.

Now wait till you get to EGA :)
Its bitplane-based memory model means you get 8 pixels inside each byte.
On the bright side, it has an onboard ALU which can rotate and mask pixels, so you could use that to shift bitmaps around.

Too difficult for a beginner! Too difficult even for me right now. But if targeting 16-color mode, Abrash's and Ferraro's work and learning how to use the ALU is required reading. Save 16-color for later.

Bitplanes were too difficult even for some companies; the first 5 or so Silmarils games only supported VGA (really MCGA) and CGA.
 
Is it possible to access members of a structure using inline assembly in C? because I can't make this work. It says "Undefined symbol x".

Code:
typedef struct{
	int x, y;
}t_point;

void sum(t_point *point)
{
	asm mov ax, point->x
	asm mov bx, point->y
	asm add ax, bx
}

int main(void)
{
	t_point point;

	sum(&point);

	return 0;
}

I know I can do this to make it work, but it doesn't look neat...

Code:
typedef struct{
	int x, y;
}t_point;

void sum(t_point *point)
{
        int x = point->x, y = point->y;

	asm mov ax, x
	asm mov bx, y
	asm add ax, bx
}

int main(void)
{
	t_point point;

	sum(&point);

	return 0;
}
 
Code:
	asm mov ax, point->x
	asm mov bx, point->y

What would you expect this to assemble into? Each of those "asm" statements corresponds to a single instruction, but "point" is not necessarily in a register (in fact, it's probably in [bp+4]. So the compiler would have to make something like:

Code:
	mov ax, [[bp+4]]
	mov bx,[[bp+4]+2]

which are not valid x86 instructions. So (if you know the offsets of x and y within t_point are 0 and 2 respectively) you could write something like:

Code:
	asm mov bx, point
	asm mov ax, [bx]
	asm mov bx, [bx+2]
	asm add ax, bx

I know it would be nicer if the compiler could generate the offsets automatically from the structure definition, but I'm not sure if the old Borland inline assembler is capable of that.
 
Is it possible to access members of a structure using inline assembly in C? because I can't make this work. It says "Undefined symbol x".

Read the Turbo C manual regarding inline assembler syntax. This is definitely possible in Turbo Pascal (offsets are generated by the compiler) and I'd be astonished if it wasn't possible in Turbo C.

In TP, the syntax uses dots:

Code:
mov ax,[bp].xcoord
mov bx,[bp].ycoord

...etc.
 
This is the only way I can make it work:

Code:
typedef struct{
	int x, y;
}t_point;

void sum(t_point *point)
{
	asm mov ax, ss
        asm mov ds, ax
	asm mov bx, word ptr point
	asm mov ax, [bx]
	asm mov bx, [bx+2]
	asm add ax, bx
}

int main(void)
{
	t_point point;
	point.y = 1;
	point.x = 2;

	sum(&point);

	return 0;
}

Or else assigning the values to variables inside the function like this...

Code:
typedef struct{
	int x, y;
}t_point;

void sum(t_point *point)
{
	int x = point-> x, y = point->y;

	asm mov ax, x
	asm mov bx, y
	asm add ax, bx
}

int main(void)
{
	t_point point;
	point.y = 1;
	point.x = 2;

	sum(&point);

	return 0;
}

Check out the code the compiler produces...

Inline asm.jpg
 
Does this not work?

Code:
void sum(t_point * point)
{
	asm mov ax, [point].x
	asm mov bx, [point].y
	asm add ax, bx
}
 
Here's two approaches that work:

Code:
t_point near* pPoint;
t_point point;

	_asm{
		mov si, [pPoint]
		mov ax, [si.x]
		mov dx, [si.y]

		mov ax, [point.x]
		mov dx, [point.y]
	}

You have to be careful with dereferencing pointers.
The .x and .y are just offsets to a base address (+0 and +2 respectively).
I think plasma's example will not work, because it will add the .x and .y to the address of the variable 'point', rather than to the value of point (which is the address of your data). So it doesn't dereference it first.
 
Last edited:
No, it says "Invalid combination of opcode and operands"

That is because you probably use a large memory model, so pointers are far pointers by default?
That's why I added 'near' in my example (a near pointer is just a 16-bit offset, so it can be used directly for addressing. Far pointers also have a segment. You can use 'word ptr' to override the type though, so you can extract just the offset or segment from a far pointer).
 
That is because you probably use a large memory model, so pointers are far pointers by default?
That's why I added 'near' in my example (a near pointer is just a 16-bit offset, so it can be used directly for addressing. Far pointers also have a segment. You can use 'word ptr' to override the type though, so you can extract just the offset or segment from a far pointer).

This one compiles but it doesn't work ok, it moves AX = 0xFFF3 and BX = 0x0001

Code:
typedef struct{
	int x, y;
}t_point;

void sum(t_point near *point)
{
	asm mov ax, word ptr [point].x
	asm mov bx, word ptr [point].y
	asm add ax, bx
}

int main(void)
{
	t_point point;

	point.x = 1;
	point.y = 2;

	sum(&point);

	return 0;
}
 
Here's two approaches that work:

Code:
t_point near* pPoint;
t_point point;

	_asm{
		mov si, [pPoint]
		mov ax, [si.x]
		mov dx, [si.y]

		mov ax, [point.x]
		mov dx, [point.y]
	}

You have to be careful with dereferencing pointers.
The .x and .y are just offsets to a base address (+0 and +2 respectively).
I think plasma's example will not work, because it will add the .x and .y to the address of the variable 'point', rather than to the value of point (which is the address of your data). So it doesn't dereference it first.

I don't understand your example... so this is what I did:

Code:
typedef struct{
	int x, y;
}t_point;

void sum(t_point near *pPoint)
{
	t_point point;

	asm mov si, [pPoint]
	asm mov ax, [si.x]
	asm mov dx, [si.y]

	asm mov ax, [point.x]
	asm mov bx, [point.y]
	asm add ax, bx
}

int main(void)
{
	t_point point;

	point.x = 1;
	point.y = 2;

	sum(&point);

	return 0;
}

It doesn't compile, error "Invalid combination of opcode and operands", warning "Suspiciuos pointer conversion"
 
Depending on what you are ultimately trying to do, you could just pass the structure on the stack as a parameter. For your trivial example, this would simplify the access to the values x and y (much like everyone was trying to do in their examples, and like Pascal does). This approach falls apart if you have a large structure; copying the entire thing to the stack and you are only referencing a few members. The nice thing is it works regardless of memory model.
 
What I'm trying to do is to find a way of accessing structure members using inline asm in C. Because I have 5 functions that have a lot of parameters. So I thought it would be better if I put all those variables inside a structure and just pass a pointer to the structure to the function. Put Turbo C won't let you access the structure members. I have a function defined like this:

Code:
void blit(unsigned char *src, int w, int h, unsigned char far *dest, int x, int y);

so I wanted to create a structure BITMAP like this:

Code:
typedef struct{
	int w;
	int h;
	unsigned char far *data;
}BITMAP;

and then modify blit...

Code:
void blit(BITMAP *image, unsigned char far *dest, int x, int y);

but it seems like Turbo C won't let you access the structure members...
 
Has anyone heard about something called "sequential tables"? I found that this is used in the game Prince of Persia.

https://github.com/jmechner/Prince-of-Persia-Apple-II/blob/master/01 POP Source/Source/SEQTABLE.S

What are they?

I think it's not "sequential tables" but "sequence table", as in a table of sequences. A sequence (in this context) is a temporal sequence of sprites to be drawn on subsequent frames (to animate the various actions the player can do - running, jumping, climbing etc). So it just gives the order in which the sprites need to be drawn to animate them properly.
 
What I'm trying to do is to find a way of accessing structure members using inline asm in C. Because I have 5 functions that have a lot of parameters. So I thought it would be better if I put all those variables inside a structure and just pass a pointer to the structure to the function. Put Turbo C won't let you access the structure members. I have a function defined like this:

I see, and now understand what you are trying to do. It's not a bad idea to create a structure for your bitmaps like that.

However, don't beat yourself up trying to reduce the number of parameters to a routine like blt(), especially if it's only saving a couple of parameters. Yeah, it could be slightly faster to access them directly out of a structure, but the 8088 puts you under such extreme register pressure sometimes it's just easier to have local, stack based copies of working values. I would recommend getting the routine working using all the passed parameters, then worrying if getting some values out of the structure would save you anything. In the long run, it may not make all that much difference.

Just my $.02
 
Back
Top