Draw a line?

Is there an easy way to draw a line with the SDL?

Christian Biesinger wrote:

Is there an easy way to draw a line with the SDL?

Try this code. It’s got code for both the regular unantialiased
Bresenham lines and Wu antialiased lines (I rewrote a little code found
in a very old article by Mike Abrash in Dr. Dobb’s Journal for that).
Sam, perhaps part of this could could find its way into the demos when I
polish it up…? Should be easy enough to figure out.–

| Rafael R. Sevilla @Rafael_R_Sevilla |
| Instrumentation, Robotics, and Control Laboratory |

College of Engineering, University of the Philippines, Diliman

-------------- next part --------------
/* libdrawing for SDL. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include “drawing-SDL.h”

/* Modify these parameters if you want the library to try using higher
resolutions or color depths. */
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
#define DEFAULT_DEPTH 16
#define NUM_LEVELS 256

#define SGN(x) ((x)>0 ? 1 : ((x)==0 ? 0:(-1)))
#define ABS(x) ((x)>0 ? (x) : (-x))

static SDL_Surface screen; / initialized by Draw_init */

#define FG_COLOR colors[0]
#define BG_COLOR colors[nlevels-1];

static unsigned char gamma_table[256];

int Draw_antialias_mode = 1; /* use Wu antialiasing /
double Draw_gamma = 2.35; /
looks good enough */

int Draw_init(void)
{
int i;

if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, “Unable to initialize SDL: %s\n”, SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
screen = SDL_SetVideoMode(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_DEPTH,
SDL_HWSURFACE|SDL_ANYFORMAT|SDL_DOUBLEBUF);
if (screen == NULL) {
fprintf(stderr, “Couldn’t set %dx%dx%d bpp video mode: %s\n”,
DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_DEPTH,
SDL_GetError());
exit(1);
}

/* generate gamma correction table */
for (i=0; i<NUM_LEVELS; i++)
gamma_table[i] = (int) (NUM_LEVELS-1)*pow((double)i/((double)(NUM_LEVELS-1)), 1.0/Draw_gamma);
return(screen->format->BitsPerPixel);
}

int Draw_getmaxx(void)
{
return(screen->w-1);
}

int Draw_getmaxy(void)
{
return(screen->h-1);
}

Uint32 Draw_mapcolor(Uint8 r, Uint8 g, Uint8 b)
{
double rf, gf, bf, Y;
#if 1
return(SDL_MapRGB(screen->format, gamma_table[r], gamma_table[g], gamma_table[b]));
#else
/* YIQ gray level /
rf = (double)r/255;
gf = (double)g/255;
bf = (double)b/255;
Y = 0.299
rf + 0.587gf + 0.114bf;
Y *= 255;
return(SDL_MapRGB(screen->format, gamma_table[(int)Y], gamma_table[(int)Y],
gamma_table[(int)Y]));
#endif
}

void Draw_pixel(Uint32 x, Uint32 y, Uint32 color)
{
Uint32 bpp, ofs;

bpp = screen->format->BytesPerPixel;
ofs = screen->pitchy + xbpp;

SDL_LockSurface(screen);
memcpy(screen->pixels + ofs, &color, bpp);
SDL_UnlockSurface(screen);
}

/* Basic unantialiased Bresenham line algorithm */
static void bresenham_line(Uint32 x1, Uint32 y1, Uint32 x2, Uint32 y2,
Uint32 color)
{
int lg_delta, sh_delta, cycle, lg_step, sh_step;

lg_delta = x2 - x1;
sh_delta = y2 - y1;
lg_step = SGN(lg_delta);
lg_delta = ABS(lg_delta);
sh_step = SGN(sh_delta);
sh_delta = ABS(sh_delta);
if (sh_delta < lg_delta) {
cycle = lg_delta >> 1;
while (x1 != x2) {
Draw_pixel(x1, y1, color);
cycle += sh_delta;
if (cycle > lg_delta) {
cycle -= lg_delta;
y1 += sh_step;
}
x1 += lg_step;
}
Draw_pixel(x1, y1, color);
}
cycle = sh_delta >> 1;
while (y1 != y2) {
Draw_pixel(x1, y1, color);
cycle += lg_delta;
if (cycle > sh_delta) {
cycle -= sh_delta;
x1 += lg_step;
}
y1 += sh_step;
}
Draw_pixel(x1, y1, color);
}

static void wu_line(Uint32 x0, Uint32 y0, Uint32 x1, Uint32 y1,
Uint32 fgc, Uint32 bgc, int nlevels, int nbits)
{
Uint32 intshift, erracc,erradj;
Uint32 erracctmp, wgt, wgtcompmask;
int dx, dy, tmp, xdir, i;
Uint32 colors[nlevels];
SDL_Rect r;
SDL_Color fg, bg;

SDL_GetRGB(fgc, screen->format, &fg.r, &fg.g, &fg.b);
SDL_GetRGB(bgc, screen->format, &bg.r, &bg.g, &bg.b);

/* generate the colors by linear interpolation, applying gamma correction */
for (i=0; i<nlevels; i++) {
Uint8 r, g, b;

r = gamma_table[fg.r - (i*(fg.r - bg.r))/(nlevels-1)];
g = gamma_table[fg.g - (i*(fg.g - bg.g))/(nlevels-1)];
b = gamma_table[fg.b - (i*(fg.b - bg.b))/(nlevels-1)];
colors[i] = SDL_MapRGB(screen->format, r, g, b);

}
if (y0 > y1) {
tmp = y0; y0 = y1; y1 = tmp;
tmp = x0; x0 = x1; x1 = tmp;
}
/* draw the initial pixel in the foreground color */
Draw_pixel(x0, y0, FG_COLOR);

dx = x1 - x0;
xdir = (dx >= 0) ? 1 : -1;
dx = (dx >= 0) ? dx : -dx;

/* special-case horizontal, vertical, and diagonal lines which need no
weighting because they go right through the center of every pixel. /
if ((dy = y1 - y0) == 0) {
/
horizontal line */
r.x = (x0 < x1) ? x0 : x1;
r.y = y0;
r.w = dx;
r.h = 1;
SDL_FillRect(screen, &r, FG_COLOR);
return;
}

if (dx == 0) {
/* vertical line */
r.x = x0;
r.y = y0;
r.w = 1;
r.h = dy;
SDL_FillRect(screen, &r, FG_COLOR);
return;
}

if (dx == dy) {
for (; dy != 0; dy–) {
x0 += xdir;
y0++;
Draw_pixel(x0, y0, FG_COLOR);
}
return;
}
/* line is not horizontal, vertical, or diagonal /
erracc = 0; /
err. acc. is initially zero /
/
# of bits by which to shift erracc to get intensity level /
intshift = 32 - nbits;
/
mask used to flip all bits in an intensity weighting /
wgtcompmask = nlevels - 1;
/
x-major or y-major? /
if (dy > dx) {
/
y-major. Calculate 16-bit fixed point fractional part of a pixel that
X advances every time Y advances 1 pixel, truncating the result so that
we won’t overrun the endpoint along the X axis /
erradj = ((Uint64)dx << 32) / (Uint64)dy;
/
draw all pixels other than the first and last /
while (–dy) {
erracctmp = erracc;
erracc += erradj;
if (erracc <= erracctmp) {
/
rollover in error accumulator, x coord advances /
x0 += xdir;
}
y0++; /
y-major so always advance Y /
/
the nbits most significant bits of erracc give us the intensity
weighting for this pixel, and the complement of the weighting for
the paired pixel. /
wgt = erracc >> intshift;
Draw_pixel(x0, y0, colors[wgt]);
Draw_pixel(x0+xdir, y0, colors[wgt^wgtcompmask]);
}
/
draw the final pixel, which is always exactly intersected by the line
and so needs no weighting /
Draw_pixel(x1, y1, FG_COLOR);
return;
}
/
x-major line. Calculate 16-bit fixed-point fractional part of a pixel
that Y advances each time X advances 1 pixel, truncating the result so
that we won’t overrun the endpoint along the X axis. /
erradj = ((Uint64)dy << 32) / (Uint64)dx;
/
draw all pixels other than the first and last /
while (–dx) {
erracctmp = erracc;
erracc += erradj;
if (erracc <= erracctmp) {
/
accumulator turned over, advance y /
y0++;
}
x0 += xdir; /
x-major so always advance X /
/
the nbits most significant bits of erracc give us the intensity
weighting for this pixel, and the complement of the weighting for
the paired pixel. /
wgt = erracc >> intshift;
Draw_pixel(x0, y0, colors[wgt]);
Draw_pixel(x0, y0+1, colors[wgt^wgtcompmask]);
}
/
draw final pixel, always exactly intersected by the line and doesn’t
need to be weighted. */
Draw_pixel(x1, y1, FG_COLOR);
}

void Draw_line(Uint32 x1, Uint32 y1, Uint32 x2, Uint32 y2,
Uint32 color)
{
if (Draw_antialias_mode == 0)
bresenham_line(x1, y1, x2, y2, color);
else if (Draw_antialias_mode == 1)
wu_line(x1, y1, x2, y2, color, 0, 256, 8);
}

void Draw_screenupdate(void)
{
SDL_UpdateRect(screen, 0, 0, 0, 0);
}
-------------- next part --------------

#ifndef _DRAWING_H
#define _DRAWING_H

/* Header file for libdrawing-SDL */

#include <SDL/SDL.h>

extern int Draw_init(void);
extern int Draw_getmaxx(void);
extern int Draw_getmaxy(void);
extern Uint32 Draw_mapcolor(Uint8 r, Uint8 g, Uint8 b);
extern void Draw_line(Uint32 x1, Uint32 y1, Uint32 x2, Uint32 y2,
Uint32 color);
extern void Draw_pixel(Uint32 x, Uint32 y, Uint32 color);
extern void Draw_screenupdate(void);

#endif

Christian Biesinger wrote:

Is there an easy way to draw a line with the SDL?

Try this code. It’s got code for both the regular unantialiased
Bresenham lines and Wu antialiased lines (I rewrote a little code found
in a very old article by Mike Abrash in Dr. Dobb’s Journal for that).
Sam, perhaps part of this could could find its way into the demos when I
polish it up…? Should be easy enough to figure out.

You might also want to use the put pixel code I posted a while ago
instead of your DrawPixel routine. Should be much faster.

NeilOn Thu, 4 Nov 1999, Rafael R. Sevilla wrote:

Neil McGill mailto:Neil_McGill *8^) . .
Software Developer:ISDN, Cisco Systems Ltd ~~""~""~"~"|~"~
3rd Floor, 96 Commercial Street, Edinburgh, EH6 6LX, UK ||| |||
Tel: 0131 561 3622 Fax: 0131 561 3601 Mob: 07714 226 281 .:|||||:.:|||||:.

Is there an easy way to draw a line with the SDL?

Try this code. It’s got code for both the regular unantialiased
Bresenham lines and Wu antialiased lines (I rewrote a little code found
in a very old article by Mike Abrash in Dr. Dobb’s Journal for that).
Sam, perhaps part of this could could find its way into the demos when I
polish it up…? Should be easy enough to figure out.

IMHO, SDL should use the best method available on the
particular platform,
most modern GFX cards provide 2d acceleration,
why not use these functions.
I don’t know anything if DGA allows this.
But it should devinitively be supported with a fallback method.
(If you have a plain old VGA use Bresenham on the host CPU)

Benno.

This is a multi-part message in MIME format.
--------------856E6D62E93B012EA1E56E0E
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Christian Biesinger wrote:

Is there an easy way to draw a line with the SDL?

Try this code. It’s got code for both the regular unantialiased
Bresenham lines and Wu antialiased lines (I rewrote a little code found
in a very old article by Mike Abrash in Dr. Dobb’s Journal for that).
Sam, perhaps part of this could could find its way into the demos when I
polish it up…? Should be easy enough to figure out.

Hi again,
speaking about Bresenham:
with modern CPUs the floating point addition is almost as fast as
the integer one.
Why not use:
step=max((abs(x2-x1),(y2-y1))
dx=(x2-x1)/step
dy=(y2-y1)/step

x=x1;
y=y1;
for(i=0;i<=step;i++)
{
x=x+dx
y=y+dy
drawpixel(x,y)
}

as you see only 2 additions per pixel,
no conditionals no shifting …

comments about this algorithm ?
I am sure that my algorithm is faster than the
Bresenham one on a Pentium CPU.

You could even optimize my algorithm a bit
using loop unrolling and(plotting 2 pixels
in the loop)
to take advantage of the Pentium pipeline and
parallel execution unit.

regards,
Benno.

Related question: is there a basic primitive toolbox for SDL?
Lines/circles etc…?

Thanks,

Neil

Related question: is there a basic primitive toolbox for SDL?
Lines/circles etc…?

The ones I know of are PowerPak and GNU libxmi:

http://www.angelfire.com/va/powerpakgsdk/

http://www.gnu.org/software/libxmi/libxmi.html

-Roy

Christian Biesinger wrote:

Is there an easy way to draw a line with the SDL?

Try this code. It’s got code for both the regular unantialiased
Bresenham lines and Wu antialiased lines (I rewrote a little code found
in a very old article by Mike Abrash in Dr. Dobb’s Journal for that).
Sam, perhaps part of this could could find its way into the demos when I
polish it up…? Should be easy enough to figure out.

Definitely possible. It’s going to be crazy here for the next few weeks
as the Christmas deadlines approach, but I’ll add it as soon as I can.

-Sam Lantinga				(slouken at devolution.com)

Lead Programmer, Loki Entertainment Software–
“Any sufficiently advanced bug is indistinguishable from a feature”
– Rich Kulawiec

I tried to use the SDL with the Borland Builder 3 but the linker gave me a
strange errormessage like “illegal OMF-recordtype 0x21”. Did I made a mistake
or doesn’t the SDL-Files for Win32 work with an other compiler than Visual
C++?

Thx!

Oxygenic

I tried to use the SDL with the Borland Builder 3 but the linker gave me a
strange errormessage like “illegal OMF-recordtype 0x21”. Did I made a
mistake
or doesn’t the SDL-Files for Win32 work with an other compiler than Visual
C++?

Thx!

Oxygenic

Static library formats (.lib,.a) aren’t (to my knowledge) exchangable
between different
compilers so you’ll have to build your own stub library (only two .c files
from the source
needed). Look up the necessary files in the Makefile, maybe define one or
two macros
(_WIN32 or WIN32) and the resulting library should work. You can of course
also
simply add the .c files to your project. Naturally, you’ll need the source
archive.
BTW, the DLL works with any compiler (should even work with Delphi).

~ Paulus Esterhazy (@Paulus_Esterhazy)