[SDL] 3d coding question

John R. Hall overcode at lokigames.com
Wed Jun 28 00:08:56 PDT 2000


Luke Bond wrote:
> 
> hi all,
> 
> i'm in the process of developing a simple 3d game engine and at the moment
> i'm using SDL to do the drawing. my question is: is SDL a good choice for
> doing the drawing (not just straight blits)? for example, i'm sure there's a
> better way to implement a putpixel function than to draw a rectangle 1x1
> pixel in size? what do you guys do for low-level drawing functions?

You can lock a surface and gain direct access to its pixels with the
'pixels' field. Look at the SDL docs; there is an example.
It's generally a good idea to pick one or two common pixel formats to
support (16-bit 565, for instance) and let SDL sort the rest out with
its format emulation.

Here's a simple linear texturemapper I wrote a while back. It's
completely unoptimized (there's no excuse for that multiplication in the
inner loop), but it's an example of direct surface access. It only
supports 16-bit pixels, which is fairly reasonable these days.
You'd want to call SDL_LockSurface on target and texture before using
this function, and SDL_UnlockSurface on them afterwards.

void drawTexturedPoly16(SDL_Surface *target, SDL_Surface *texture, int
num_vertices, point2d_p tgt_vertices[], point2d_p tex_vertices[])
{
	int i;
	int top_index = 0, bottom_index = 0;
	int left_index, right_index;
	int next_left_index, next_right_index;
	int tgt_row, tgt_final_row;
	Sint32 tgt_left_x, tgt_right_x;
	Sint32 tgt_left_xstep, tgt_right_xstep;
	Sint32 tgt_left_xspan, tgt_right_xspan;
	Sint32 tgt_left_yspan, tgt_right_yspan;
	
	Sint32 tex_left_x, tex_left_y;
	Sint32 tex_right_x, tex_right_y;
	Sint32 tex_left_xstep, tex_right_xstep;
	Sint32 tex_left_ystep, tex_right_ystep;
		
	int strip_width;
	
	Sint32 u, v, ustep, vstep;
	
	Uint16 *tgt_memory, *tex_memory;
	
	for (i = 0; i < num_vertices; i++) {
		if (tgt_vertices[i]->y < tgt_vertices[top_index]->y)
			top_index = i;
		if (tgt_vertices[i]->y > tgt_vertices[bottom_index]->y)
			bottom_index = i;
	};
	
	left_index = top_index;
	right_index = top_index;
	next_left_index = (top_index - 1);if (next_left_index < 0)
next_left_index += num_vertices;
	next_right_index = (top_index + 1); if (next_right_index >=
num_vertices) next_right_index -= num_vertices;

	tgt_row = tgt_vertices[top_index]->y;
	tgt_final_row = tgt_vertices[bottom_index]->y;

	tgt_left_x = tgt_vertices[top_index]->x << 16;
	tgt_right_x = (tgt_vertices[top_index]->x << 16) + 65535;

	tgt_left_xspan = tgt_vertices[next_left_index]->x -
tgt_vertices[left_index]->x;
	tgt_right_xspan = tgt_vertices[next_right_index]->x -
tgt_vertices[right_index]->x;
	tgt_left_yspan = tgt_vertices[next_left_index]->y -
tgt_vertices[left_index]->y;
	if (tgt_left_yspan == 0) tgt_left_yspan = 1;
	tgt_right_yspan = tgt_vertices[next_right_index]->y -
tgt_vertices[right_index]->y;
	if (tgt_right_yspan == 0) tgt_right_yspan = 1;
	tgt_left_xstep = (tgt_left_xspan << 16) / tgt_left_yspan;
	tgt_right_xstep = (tgt_right_xspan << 16) / tgt_right_yspan;

	tex_left_x = tex_vertices[left_index]->x << 16;
	tex_right_x = tex_vertices[right_index]->x << 16;
	tex_left_y = tex_vertices[left_index]->y << 16;
	tex_right_y = tex_vertices[right_index]->y << 16;
	tex_left_xstep = ((tex_vertices[next_left_index]->x -
tex_vertices[left_index]->x) << 16) / tgt_left_yspan;
	tex_left_ystep = ((tex_vertices[next_left_index]->y -
tex_vertices[left_index]->y) << 16) / tgt_left_yspan;
	tex_right_xstep = ((tex_vertices[next_right_index]->x -
tex_vertices[right_index]->x) << 16) / tgt_right_yspan;
	tex_right_ystep = ((tex_vertices[next_right_index]->y -
tex_vertices[right_index]->y) << 16) / tgt_right_yspan;

	while (tgt_row <= tgt_final_row) {
		
		/* Progress to the next left edge if necessary. */
		while (tgt_row >= tgt_vertices[next_left_index]->y) {

			left_index--; if (left_index < 0) left_index += num_vertices;
			next_left_index--; if (next_left_index < 0) next_left_index +=
num_vertices;
			
			tgt_left_xspan = tgt_vertices[next_left_index]->x -
tgt_vertices[left_index]->x;
			tgt_left_yspan = tgt_vertices[next_left_index]->y -
tgt_vertices[left_index]->y;
			if (tgt_left_yspan == 0) tgt_left_yspan = 1;
			tgt_left_xstep = (tgt_left_xspan << 16) / tgt_left_yspan;
			
			tex_left_xstep = ((tex_vertices[next_left_index]->x -
tex_vertices[left_index]->x) << 16) / tgt_left_yspan;
			tex_left_ystep = ((tex_vertices[next_left_index]->y -
tex_vertices[left_index]->y) << 16) / tgt_left_yspan;

			tgt_left_x = tgt_vertices[left_index]->x << 16;
			tex_left_x = tex_vertices[left_index]->x << 16;
			tex_left_y = tex_vertices[left_index]->y << 16;
			
			if (tgt_row >= tgt_final_row) break;
		};
		
		/* Progress to the next right edge if necessary. */
		while (tgt_row >= tgt_vertices[next_right_index]->y) {

			right_index++; if (right_index >= num_vertices) right_index -=
num_vertices;
			next_right_index++; if (next_right_index >= num_vertices)
next_right_index -= num_vertices;

			tgt_right_xspan = tgt_vertices[next_right_index]->x -
tgt_vertices[right_index]->x;
			tgt_right_yspan = tgt_vertices[next_right_index]->y -
tgt_vertices[right_index]->y;
			if (tgt_right_yspan == 0) tgt_right_yspan = 1;
			tgt_right_xstep = (tgt_right_xspan << 16) / tgt_right_yspan;

			tex_right_xstep = ((tex_vertices[next_right_index]->x -
tex_vertices[right_index]->x) << 16) / tgt_right_yspan;
			tex_right_ystep = ((tex_vertices[next_right_index]->y -
tex_vertices[right_index]->y) << 16) / tgt_right_yspan;

			tgt_right_x = tgt_vertices[right_index]->x << 16;
			tex_right_x = tex_vertices[right_index]->x << 16;
			tex_right_y = tex_vertices[right_index]->y << 16;

			if (tgt_row >= tgt_final_row) break;
		};

		/* Draw the current scanline. */
		if (tgt_row >= 0 && tgt_row < target->h) {
			u = tex_left_x + 65536/2;		/* these are shifted by 16 */
			v = tex_left_y + 65536/2;
		
			strip_width = (tgt_right_x - tgt_left_x) >> 16;
			if (strip_width > 0) {
		
				ustep = (tex_right_x - tex_left_x) / strip_width;
				vstep = (tex_right_y - tex_left_y) / strip_width;
				
				tgt_memory = (Uint16 *)target->pixels + target->w * tgt_row +
(tgt_left_x >> 16);
				tex_memory = (Uint16 *)texture->pixels;

				for (i = 0; i + (tgt_left_x >> 16) < 0 && i < strip_width; i++) {
					tgt_memory++;
					u += ustep;
					v += vstep;
				};
				
				if ((tgt_right_x >> 16) >= target->w)
					strip_width -= ((tgt_right_x >> 16) - target->w + 1);

				tex_memory = (Uint16 *)texture->pixels;

				/* FIXME: get that multiplication out of the loop */
				for (; i < strip_width; i++) {
					*tgt_memory = tex_memory[(texture->w * (v >> 16)) + (u >> 16)];
					tgt_memory++;
					u += ustep;
					v += vstep;
				};

			};
		};

		/* Advance to the next row. */
		tgt_row++;

		/* Calculate the next edge coordinates. */
		tgt_left_x += tgt_left_xstep;
		tgt_right_x += tgt_right_xstep;
		tex_left_x += tex_left_xstep;
		tex_left_y += tex_left_ystep;
		tex_right_x += tex_right_xstep;
		tex_right_y += tex_right_ystep;

	};
	
}


-John



More information about the SDL mailing list