Can't beleive I used to write this stuff...

Miscellaneous Forums/General Discussion/Can't beleive I used to write this stuff...

/////////////////////////////////////////////////
// LINEASM.CPP (c) 17/11/1997 Jake Birkett
/////////////////////////////////////////////////
// Assembly implementation of Bresenham's Line Algorithm
//
// External Functions :
///////////////////////
// void LineASM(void);
//
// External Variables :
///////////////////////
// unsigned int lx1 = 0; // line start x coord
// unsigned int ly1 = 0;
// unsigned int lx2 = 0; // line end y coord
// unsigned int ly2 = 0;
//
// unsigned char far *line_dest;
// unsigned char line_colour; // 0-255

/////////////////////////////////////////////////
// I N C L U D E S //////////////////////////////
/////////////////////////////////////////////////

#include "lineasm.h"
/////////////////////////////////////////////////
// D E F I N E S ////////////////////////////////
/////////////////////////////////////////////////

/////////////////////////////////////////////////
// P R O T O T Y P E S //////////////////////////
/////////////////////////////////////////////////
// INTERNAL

// EXTERNAL
void LineASM(void);

/////////////////////////////////////////////////
// G L O B A L S ////////////////////////////////
/////////////////////////////////////////////////
// INTERNAL

// EXTERNAL
unsigned int lx1 = 0; // line start x coord
unsigned int ly1 = 0;
unsigned int lx2 = 0; // line end y coord
unsigned int ly2 = 0;

unsigned char far *line_dest=(unsigned char far *)0xA0000000L; // default destination is video buffer
unsigned char line_colour; // 0-255

/////////////////////////////////////////////////
// F U N C T I O N S ////////////////////////////
/////////////////////////////////////////////////
void LineASM(void)
{ // Draws a line using Bresenham's Line Algorithm onto the
	// video buffer or alternate destination specified by line_dest.
	// Uses 4 octants and pre-specifies up or down

		// AL = Line_Colour
		// BX = DeltaX
		// SI = DeltaY
		// ES:DI = line dest address

		// load registers
		asm push	ds;								// precaution
		asm mov		al, line_colour;	// al = line colour;
		asm mov		bx, lx2;
		asm	sub		bx, lx1;          // DeltaX
		asm mov		si, ly2;
		asm sub		si, ly1;					// DeltaY

		asm les		di, line_dest;  	// memory dest address
		asm mov		dx, ly1;					// calc y offset = y*320 ... y<<8 + y<<6 ... or (y<<2 + y)<<6 quicker
		asm shl		dx, 1;
		asm shl		dx, 1;
		asm add		dx, ly1;
		asm mov		cl, 6;
		asm	shl		dx, cl;
		asm	add		di, dx;
		asm add		di, lx1;					// add x offset
		asm mov		byte ptr es:[di], al; // draw first pixel

		// see if ldy<0 or ldy>0
		asm cmp		si, 0;
		asm jns		Line_Down;   			// if ldy>0 line is moving down
		asm neg		si;					 			// make DeltaY positive
		asm mov		dx, -320;					// set y movement to up
		asm jmp		Continue;
Line_Down:
		asm mov		dx, 320;					// set y movement to down
Continue:
		// see if ldx<0 or ldx>0
		asm cmp		bx, 0;
		asm js		Down_Left;				// if ldx<0 line is moving left

Down_Right: // line is moving Down and Right ... Oct 0 and 1
		asm cmp		bx, si;						// is DeltaX>DeltaY
		asm js		V_Line;						// no, so do a Vertical Line

H_Line:
		asm mov		cx, bx;						// cx = number of pixels in line
		asm jcxz	Line_End;					// jumps if cx=0

		// calc error term values
		asm shl		si, 1;         		// binary shift left ... DeltaY*2
		asm mov		bp, si;						// bp = error term
		asm sub		bp, bx;						// error term starts at DeltaY*2 - DeltaX
		asm shl		bx, 1;						// DeltaX*2
		asm sub		si, bx;						// si = DeltaY*2 - DeltaX*2 ... Error Decrement Value ... used in loop
		asm add   bx, si;						// bx = clever convert bx to DeltaY*2 ... Error Increment Value ... used in loop

H_Line_Loop:
		asm and		bp, bp;						// see if error term is negative
		asm js		Move_X_Coord;			// yes, stay at same Y Coord
		// move the Y Coord
		asm add		di, dx;						// increment Y Coord ...  add 320 to pixel address
		asm add		bp, si;						// decrement Error Term with si
		asm jmp		Next_X_Pixel;
Move_X_Coord:
		asm add		bp, bx;						// increment Error Term with bx
Next_X_Pixel:
		asm inc		di;								// add 1 to X Coord
		asm mov		byte ptr es:[di], al;
		asm loop H_Line_Loop;				// draw next pixel
		asm jmp Line_End;

V_Line:
		asm mov		cx, si;						// cx = number of pixels in line
		asm jcxz	Line_End;					// jumps if cx=0

		// calc error term values
		asm shl		bx, 1;          	// binary shift left ... DeltaY*2
		asm mov		bp, bx;						// bp = error term
		asm sub		bp, si;						// error term starts at DeltaY*2 - DeltaX
		asm shl		si, 1;						// DeltaX*2
		asm sub		bx, si;						// bx = DeltaY*2 - DeltaX*2 ... Error Decrement Value ... used in loop
		asm add   si, bx;						// si = clever convert bx to DeltaY*2 ... Error Increment Value ... used in loop

V_Line_Loop:
		asm and		bp, bp;						// see if error term is negative
		asm jns		Advance_X_Coord;	// no, so advance X Coord
		// don't advance X Coord
		asm add		bp, si;						// increment Error Term with si
		asm jmp		Next_Y_Pixel;
Advance_X_Coord:
		asm inc		di;								// increment X Coord by 1 pixel
		asm add		bp, bx;						// decrement Error Term with bx
Next_Y_Pixel:
		asm add		di, dx;						// add 1 to Y Coord ... address + 320 bytes
		asm mov		byte ptr es:[di], al;
		asm loop V_Line_Loop;				// draw next pixel
		asm jmp Line_End;

Down_Left:
		asm neg bx;									// Make DeltaX positive
		asm cmp bx, si;							// is DeltaX>DeltaY
		asm js V_Line2;							// no, so do a Vertical Line

H_Line2:
		asm mov		cx, bx;						// cx = number of pixels in line
		asm jcxz	Line_End;					// jumps if cx=0

		// calc error term values
		asm shl		si, 1;          	// binary shift left ... DeltaY*2
		asm mov		bp, si;						// bp = error term
		asm sub		bp, bx;						// error term starts at DeltaY*2 - DeltaX
		asm shl		bx, 1;						// DeltaX*2
		asm sub		si, bx;						// si = DeltaY*2 - DeltaX*2 ... Error Decrement Value ... used in loop
		asm add   bx, si;						// bx = clever convert bx to DeltaY*2 ... Error Increment Value ... used in loop

H_Line_Loop2:
		asm and		bp, bp;						// see if error term is negative
		asm js		Move_X_Coord2;		// yes, stay at same Y Coord
		// move the Y Coord
		asm add		di, dx;						// increment Y Coord ...  add 320 to pixel address
		asm add		bp, si;						// decrement Error Term with si
		asm jmp		Next_X_Pixel2;
Move_X_Coord2:
		asm add		bp, bx;						// increment Error Term with bx
Next_X_Pixel2:
		asm dec		di;								// minus 1 to X Coord
		asm mov		byte ptr es:[di], al;
		asm loop H_Line_Loop2;			// draw next pixel
		asm jmp Line_End;

V_Line2:
		asm mov		cx, si;						// cx = number of pixels in line
		asm jcxz	Line_End;					// jumps if cx=0

		// calc error term values
		asm shl		bx, 1;          	// binary shift left ... DeltaY*2
		asm mov		bp, bx;						// bp = error term
		asm sub		bp, si;						// error term starts at DeltaY*2 - DeltaX
		asm shl		si, 1;						// DeltaX*2
		asm sub		bx, si;						// bx = DeltaY*2 - DeltaX*2 ... Error Decrement Value ... used in loop
		asm add   si, bx;						// si = clever convert bx to DeltaY*2 ... Error Increment Value ... used in loop

V_Line_Loop2:
		asm and		bp, bp;						// see if error term is negative
		asm jns		Advance_X_Coord2;	// no, so advance X Coord
		// don't advance X Coord
		asm add		bp, si;						// increment Error Term with si
		asm jmp		Next_Y_Pixel2;
Advance_X_Coord2:
		asm dec		di;								// decrement X Coord by 1 pixel
		asm add		bp, bx;						// decrement Error Term with bx
Next_Y_Pixel2:
		asm add		di, dx;						// add 1 to Y Coord ... address + 320 bytes
		asm mov		byte ptr es:[di], al;
		asm loop V_Line_Loop2;			// draw next pixel
		asm jmp Line_End;

Line_End:
		asm pop ds;									// careful end
} // end LineASM

/////////////////////////////////////////////////


Christ Basic is so much easier, well until you run into slow video buffers and dirty rects problems!

and this ...
/////////////////////////////////////////////////
// LINEC2.CPP (c) 11/11/1997 Jake Birkett
/////////////////////////////////////////////////
// C implementation of Bresenham's Line Algorithm
// using Run Sliced technology
//
// External Functions :
///////////////////////
// void LineC2(void);
//
// External Variables :
///////////////////////
// unsigned int lx1 = 0; // line start x coord
// unsigned int ly1 = 0;
// unsigned int lx2 = 0; // line end y coord
// unsigned int ly2 = 0;
//
// unsigned char far *line_dest;
// unsigned char line_colour; // 0-255

/////////////////////////////////////////////////
// I N C L U D E S //////////////////////////////
/////////////////////////////////////////////////

#include "linec2.h"

#include <stdlib.h>
/////////////////////////////////////////////////
// D E F I N E S ////////////////////////////////
/////////////////////////////////////////////////

/////////////////////////////////////////////////
// P R O T O T Y P E S //////////////////////////
/////////////////////////////////////////////////
// INTERNAL
void Line_H_Run(int length); // draws a horizontal run of pixels
void Line_V_Run(int length); // draws a vertival run of pixels

// EXTERNAL
void LineC2(void);

/////////////////////////////////////////////////
// G L O B A L S ////////////////////////////////
/////////////////////////////////////////////////
// INTERNAL
int i = 0; // used in for loops
int index16 = 0; // used in Run Loops
int ldx = 0; // delta x of line
int ldy = 0; // delta y of line
int adj_up = 0; // error term increment
int adj_down = 0; // error term decrement
int error_term = 0; // line error value
int x_inc = 0; // x direction ... -1 = left ; 1 = right
int y_inc = 0;
int whole_step; // minimum number of pixels in a run ... DeltaX/DeltaY
int pc_initial; // pixel count initial ... 1st run
int pc_final; // pixel count final ... last run
int run_length; // length of run to be drawn

unsigned char far *vb_pixel; // pointer to destination pixel

// EXTERNAL
unsigned int lx1 = 0; // line start x coord
unsigned int ly1 = 0;
unsigned int lx2 = 0; // line end y coord
unsigned int ly2 = 0;

unsigned char far *line_dest=(unsigned char far *)0xA0000000L; // default destination if video buffer
unsigned char line_colour; // 0-255

/////////////////////////////////////////////////
// F U N C T I O N S ////////////////////////////
/////////////////////////////////////////////////
void LineC2(void)
{ // Draws a line using Bresenham's Line Algorithm onto the
	// video buffer or alternate destination specified by line_dest.
	// Uses Run Sliced technology

	// calc starting pixel
	vb_pixel = line_dest + (ly1*320) + lx1;
	// compute deltas
	ldx = lx2-lx1;
	ldy = ly2-ly1;

	// calc vertical direction ... up or down
	if (ldy<0)
	{ y_inc = -320;
		ldy = 0-ldy;
	}
	else
		y_inc = 320;

	// calc horizontal direction ... -1 = left ; 1 = right
	if (ldx<0)
	{
		x_inc = -1;
		ldx = 0-ldx; // make DeltaX positive
	}
	else
		x_inc = 1;

	// Special Case : Vertical Line
	if (ldx==0) // no x movement
	{ for (i=0; i<=ldy; i++)
		{ *vb_pixel = line_colour;
			vb_pixel += y_inc;
		}
		return;
	}
	// Special Case : Horizontal Line
	if (ldy==0) // no y movement
	{ for (i=0; i<=ldx; i++)
		{ *vb_pixel = line_colour;
			vb_pixel += x_inc;
		}
		return;
	}
	// Special Case : Diagonal Line
	if (ldx==ldy)
	{ for (i=0; i<=ldx; i++)
		{ *vb_pixel = line_colour;
			vb_pixel += y_inc + x_inc;
		}
		return;
	}

	// find out if line is X Major or Y Major
	if (ldx>=ldy)
	{ // X Major
		whole_step = ldx/ldy; // minimum number of pixels in a run
		adj_up = (ldx%ldy)*2; // % = remainder of division
		adj_down = ldy*2; // DeltaY*2
		error_term = (ldx%ldy) - adj_down; // initial error term at half a pixel

		// Calc lengths of initial and final partial runs
		// because Y advances on 0.5 pixels for these runs.
		// Divide 1 full run + initial pixel between the first_last runs.
		pc_initial = (whole_step/2) + 1;
		pc_final = pc_initial;
		// If the basic run length is even and there is no fractional advance
		// we have 1 pixel too many which will be taken away from pc_initial
		if ((adj_up==0)&&((whole_step&0x01)==0))
			pc_initial --;
		// If there is an odd number of pixels per run, meaning
		// we must adjust the error term by 0.5 .. half a pixel
		if ((whole_step&0x01)!=0)
			error_term += ldy;

		Line_H_Run(pc_initial); // draw initial run
		for (i=0; i<ldy-1; i++)
		{
			run_length = whole_step; // set run length to minimum run length
			if ((error_term += adj_up) > 0) // advance error term and test it
			{ run_length++;
				error_term -= adj_down; // bring error term back down
			}
			Line_H_Run(run_length); // draw this scan lines run
		}
		Line_H_Run(pc_final); // draw final run
		return;
	}
	else
	{ // Y Major
		whole_step = ldy/ldx; // minimum number of pixels in a run
		adj_up = (ldy%ldx)*2; // % = remainder of division
		adj_down = ldx*2; // DeltaY*2
		error_term = (ldy%ldx) - adj_down; // initial error term at half a pixel

		// Calc lengths of initial and final partial runs
		// because X advances on 0.5 pixels for these runs.
		// Divide 1 full run + initial pixel between the first_last runs.
		pc_initial = (whole_step/2) + 1;
		pc_final = pc_initial;
		// If the basic run length is even and there is no fractional advance
		// we have 1 pixel too many which will be taken away from pc_initial
		if ((adj_up==0)&&((whole_step&0x01)==0))
			pc_initial --;
		// If there is an odd number of pixels per run, meaning
		// we must adjust the error term by 0.5 .. half a pixel
		if ((whole_step&0x01)!=0)
			error_term += ldx;

		Line_V_Run(pc_initial); // draw initial run
		for (i=0; i<ldx-1; i++)
		{
			run_length = whole_step; // set run length to minimum run length
			if ((error_term += adj_up) > 0) // advance error term and test it
			{ run_length++;
				error_term -= adj_down; // bring error term back down
			}
			Line_V_Run(run_length); // draw this scan lines run
		}
		Line_V_Run(pc_final); // draw final run
		return;
	}
} // end LineC2
/////////////////////////////
void Line_H_Run(int length)
{	// draws a horizontal run of pixels
	for (index16=0; index16<length; index16++)
	{ *vb_pixel = line_colour;
		vb_pixel += x_inc;
	}
	vb_pixel += y_inc; // point to next scan line down
} // end Line_H_Run

/////////////////////////////
void Line_V_Run(int length)
{
	for (index16=0; index16<length; index16++)
	{ *vb_pixel = line_colour;
		vb_pixel += y_inc;
	}
	vb_pixel += x_inc; // point to next scan line down

} // end Line_V_Run

/////////////////////////////////////////////////


The assembly one was around twice as fast btw.

You need to get out more.

PS. I was doing ASM on the C64 (with Zeus Assembler) when I was about 13 so I can't talk.

Never tries doing ASM and by the looks of it I never will.

Tim. Yeah I learnt ASM on Spectrum, BBC and C64 and of course Amiga 68000 (was the best) as a teenager.

Here are some exes first one is assembly, second is C. Hold R to see a raster. The red is Video time and the green is CPU time. You can see the ASM version used less CPU time.

http://www.jbcomputersolutions.com/misc/oldexes.zip

You really didnt have much a choice in the 90's....before the time of DirectX and OGL, graphics were usually done in assembly....interesting thing is......most people who used it didnt really know why it did it what it did....but just knew that it did it.....yep...the days of Mode13h...

HESMON baby... the only way to breeze through 6502....

wait a minute... that looks like 8088 assembler...

it's been soooooooo loooooong...

:)

--Mike

that was inline assembly in Borland Turbo C++ for DOS. I used to love inlining 68000 in the BBasic 2 on the Amiga. Best of both worlds, nice easy basic and roasting assembler for the graphics.

check out this for smooth scrolling. It was v. fast even on a P200! Of course it was DOS based. Arrow keys move and ENTER exits (weird, what was I thinking!)

http://www.jbcomputersolutions.com/misc/game5.zip (31kb)

P.S. maybe it's best not to scroll around the memory too much in case windows doesn't like it.

Anyone else remember PCX files?

The only assembly I did was on the Amiga.

and how nice it was too.

I tried to learn ASM when I had C64 - it was way too hard!

Assembly is very simple, that's why it's so hard to program in. :)

thing was, in the old days you had to know binary and hex just to make graphics (redefining characters and using them for example). And you Peeked and Poked stuff to get it to work and you used DATA statements. You knew how variables and loops worked so it was just doing the same with funny little commands (that you had to remember or look up) instead. Also there were only 3 variables on the C64 and 16 on the Amiga, you could make more in the memory of course but those variables were the fastest.

variables? you mean registers surely? and from my dark and distant past with the C64... I am sure there were more than 3 :)

"registers" of course I do, I was just trying to simplify it. Wasn't it IX, IY and A? I'll google ...

Inside every Commodore 64 is a MOS 6510 processor, the big brother to the 6502 that is used in the VIC-20 and most disk drives. This processor has three registers that can be used for many purposes. They are, the accumulator, denoted here as ".A", the X Index Register, denoted as ".X", and the Y Index Register, denoted as ".Y".

source: http://www.go64.de/english/online_e/04_99_1e.htm

Cool, directly accessing CPU registers is so leet. But I'm glad I have Basic and C++ to do that for me.