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