void glopEnd(GLContext * c, GLParam * param) { (void) param; gl_assert(c->in_begin == 1); if (c->begin_type == GL_LINE_LOOP) { if (c->vertex_cnt >= 3) { gl_draw_line(c, &c->vertex[0], &c->vertex[2]); } } else if (c->begin_type == GL_POLYGON) { int i = c->vertex_cnt; while (i >= 3) { i--; gl_draw_triangle(c, &c->vertex[i], &c->vertex[0], &c->vertex[i - 1]); } } c->in_begin = 0; }
static void gl_draw_triangle_clip(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2, int clip_bit) { int co, c_and, co1, cc[3], edge_flag_tmp, clip_mask; GLVertex tmp1, tmp2, *q[3]; float tt; cc[0] = p0->clip_code; cc[1] = p1->clip_code; cc[2] = p2->clip_code; co = cc[0] | cc[1] | cc[2]; if (co == 0) { gl_draw_triangle(c, p0, p1, p2); } else { c_and = cc[0] & cc[1] & cc[2]; // the triangle is completely outside if (c_and != 0) return; // find the next direction to clip while (clip_bit < 6 && (co & (1 << clip_bit)) == 0) { clip_bit++; } // this test can be true only in case of rounding errors if (clip_bit == 6) { #if 0 printf("Error:\n"); printf("%f %f %f %f\n", p0->pc.X, p0->pc.Y, p0->pc.Z, p0->pc.W); printf("%f %f %f %f\n", p1->pc.X, p1->pc.Y, p1->pc.Z, p1->pc.W); printf("%f %f %f %f\n", p2->pc.X, p2->pc.Y, p2->pc.Z, p2->pc.W); #endif return; } clip_mask = 1 << clip_bit; co1 = (cc[0] ^ cc[1] ^ cc[2]) & clip_mask; if (co1) { // one point outside if (cc[0] & clip_mask) { q[0] = p0; q[1] = p1; q[2] = p2; } else if (cc[1] & clip_mask) { q[0] = p1; q[1] = p2; q[2] = p0; } else { q[0] = p2; q[1] = p0; q[2] = p1; } tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc); updateTmp(c, &tmp1, q[0], q[1], tt); tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc); updateTmp(c, &tmp2, q[0], q[2], tt); tmp1.edge_flag = q[0]->edge_flag; edge_flag_tmp = q[2]->edge_flag; q[2]->edge_flag = 0; gl_draw_triangle_clip(c, &tmp1, q[1], q[2], clip_bit + 1); tmp2.edge_flag = 1; tmp1.edge_flag = 0; q[2]->edge_flag = edge_flag_tmp; gl_draw_triangle_clip(c, &tmp2, &tmp1, q[2], clip_bit + 1); } else { // two points outside if ((cc[0] & clip_mask) == 0) { q[0] = p0; q[1] = p1; q[2] = p2; } else if ((cc[1] & clip_mask) == 0) { q[0] = p1; q[1] = p2; q[2] = p0; } else { q[0] = p2; q[1] = p0; q[2] = p1; } tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc); updateTmp(c, &tmp1, q[0], q[1], tt); tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc); updateTmp(c, &tmp2, q[0], q[2], tt); tmp1.edge_flag = 1; tmp2.edge_flag = q[2]->edge_flag; gl_draw_triangle_clip(c, q[0], &tmp1, &tmp2, clip_bit + 1); } } }
void glopVertex(GLContext * c, GLParam * p) { GLVertex *v; int n, i, cnt; gl_assert(c->in_begin != 0); n = c->vertex_n; cnt = c->vertex_cnt; cnt++; c->vertex_cnt = cnt; /* quick fix to avoid crashes on large polygons */ if (n >= c->vertex_max) { GLVertex *newarray; c->vertex_max <<= 1; /* just double size */ newarray = gl_malloc(sizeof(GLVertex) * c->vertex_max); if (!newarray) { gl_fatal_error("unable to allocate GLVertex array.\n"); } memcpy(newarray, c->vertex, n * sizeof(GLVertex)); gl_free(c->vertex); c->vertex = newarray; } /* new vertex entry */ v = &c->vertex[n]; n++; v->coord.X = p[1].f; v->coord.Y = p[2].f; v->coord.Z = p[3].f; v->coord.W = p[4].f; gl_vertex_transform(c, v); /* color */ if (c->lighting_enabled) { gl_shade_vertex(c, v); } else { v->color = c->current_color; } /* tex coords */ if (c->texture_2d_enabled) { if (c->apply_texture_matrix) { gl_M4_MulV4(&v->tex_coord, c->matrix_stack_ptr[2], &c->current_tex_coord); } else { v->tex_coord = c->current_tex_coord; } } /* precompute the mapping to the viewport */ if (v->clip_code == 0) gl_transform_to_viewport(c, v); /* edge flag */ v->edge_flag = c->current_edge_flag; switch (c->begin_type) { case GL_POINTS: gl_draw_point(c, &c->vertex[0]); n = 0; break; case GL_LINES: if (n == 2) { gl_draw_line(c, &c->vertex[0], &c->vertex[1]); n = 0; } break; case GL_LINE_STRIP: case GL_LINE_LOOP: if (n == 1) { c->vertex[2] = c->vertex[0]; } else if (n == 2) { gl_draw_line(c, &c->vertex[0], &c->vertex[1]); c->vertex[0] = c->vertex[1]; n = 1; } break; case GL_TRIANGLES: if (n == 3) { gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]); n = 0; } break; case GL_TRIANGLE_STRIP: if (cnt >= 3) { if (n == 3) n = 0; /* needed to respect triangle orientation */ switch(cnt & 1) { case 0: gl_draw_triangle(c,&c->vertex[2],&c->vertex[1],&c->vertex[0]); break; default: case 1: gl_draw_triangle(c,&c->vertex[0],&c->vertex[1],&c->vertex[2]); break; } } break; case GL_TRIANGLE_FAN: if (n == 3) { gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]); c->vertex[1] = c->vertex[2]; n = 2; } break; case GL_QUADS: if (n == 4) { c->vertex[2].edge_flag = 0; gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]); c->vertex[2].edge_flag = 1; c->vertex[0].edge_flag = 0; gl_draw_triangle(c, &c->vertex[0], &c->vertex[2], &c->vertex[3]); n = 0; } break; case GL_QUAD_STRIP: if (n == 4) { gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]); gl_draw_triangle(c, &c->vertex[1], &c->vertex[3], &c->vertex[2]); for (i = 0; i < 2; i++) c->vertex[i] = c->vertex[i + 2]; n = 2; } break; case GL_POLYGON: break; default: gl_fatal_error("glBegin: type %x not handled\n", c->begin_type); } c->vertex_n = n; }