2006-05-16 14:52:36 +00:00
|
|
|
|
2009-05-08 07:32:33 +00:00
|
|
|
#include "graphics/tinygl/zgl.h"
|
2008-01-26 11:47:23 +00:00
|
|
|
|
2005-01-12 15:26:45 +00:00
|
|
|
#include <string.h>
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
void glopNormal(GLContext *c, TGLParam *p) {
|
|
|
|
V3 v;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
v.X = p[1].f;
|
|
|
|
v.Y = p[2].f;
|
|
|
|
v.Z = p[3].f;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
c->current_normal.X = v.X;
|
|
|
|
c->current_normal.Y = v.Y;
|
|
|
|
c->current_normal.Z = v.Z;
|
|
|
|
c->current_normal.W = 0;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
void glopTexCoord(GLContext *c, TGLParam *p) {
|
|
|
|
c->current_tex_coord.X = p[1].f;
|
|
|
|
c->current_tex_coord.Y = p[2].f;
|
|
|
|
c->current_tex_coord.Z = p[3].f;
|
|
|
|
c->current_tex_coord.W = p[4].f;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
void glopEdgeFlag(GLContext *c, TGLParam *p) {
|
|
|
|
c->current_edge_flag = p[1].i;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
void glopColor(GLContext *c, TGLParam *p){
|
|
|
|
c->current_color.X = p[1].f;
|
|
|
|
c->current_color.Y = p[2].f;
|
|
|
|
c->current_color.Z = p[3].f;
|
|
|
|
c->current_color.W = p[4].f;
|
|
|
|
c->longcurrent_color[0] = p[5].ui;
|
|
|
|
c->longcurrent_color[1] = p[6].ui;
|
|
|
|
c->longcurrent_color[2] = p[7].ui;
|
|
|
|
|
|
|
|
if (c->color_material_enabled) {
|
|
|
|
TGLParam q[7];
|
|
|
|
q[0].op = OP_Material;
|
|
|
|
q[1].i = c->current_color_material_mode;
|
|
|
|
q[2].i = c->current_color_material_type;
|
|
|
|
q[3].f = p[1].f;
|
|
|
|
q[4].f = p[2].f;
|
|
|
|
q[5].f = p[3].f;
|
|
|
|
q[6].f = p[4].f;
|
|
|
|
glopMaterial(c, q);
|
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
void gl_eval_viewport(GLContext *c) {
|
|
|
|
GLViewport *v;
|
|
|
|
float zsize = (1 << (ZB_Z_BITS + ZB_POINT_Z_FRAC_BITS));
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
v = &c->viewport;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
v->trans.X = (float)(((v->xsize - 0.5) / 2.0) + v->xmin);
|
|
|
|
v->trans.Y = (float)(((v->ysize - 0.5) / 2.0) + v->ymin);
|
|
|
|
v->trans.Z = (float)(((zsize - 0.5) / 2.0) + ((1 << ZB_POINT_Z_FRAC_BITS)) / 2);
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
v->scale.X = (float)((v->xsize - 0.5) / 2.0);
|
|
|
|
v->scale.Y = (float)(-(v->ysize - 0.5) / 2.0);
|
|
|
|
v->scale.Z = (float)(-((zsize - 0.5) / 2.0));
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
void glopBegin(GLContext *c, TGLParam *p) {
|
|
|
|
int type;
|
|
|
|
M4 tmp;
|
|
|
|
|
|
|
|
assert(c->in_begin == 0);
|
|
|
|
|
|
|
|
type = p[1].i;
|
|
|
|
c->begin_type = type;
|
|
|
|
c->in_begin = 1;
|
|
|
|
c->vertex_n = 0;
|
|
|
|
c->vertex_cnt = 0;
|
|
|
|
|
|
|
|
if (c->matrix_model_projection_updated) {
|
|
|
|
if (c->lighting_enabled) {
|
|
|
|
// precompute inverse modelview
|
|
|
|
gl_M4_Inv(&tmp, c->matrix_stack_ptr[0]);
|
|
|
|
gl_M4_Transpose(&c->matrix_model_view_inv, &tmp);
|
|
|
|
} else {
|
|
|
|
float *m = &c->matrix_model_projection.m[0][0];
|
|
|
|
// precompute projection matrix
|
|
|
|
gl_M4_Mul(&c->matrix_model_projection,
|
|
|
|
c->matrix_stack_ptr[1],
|
|
|
|
c->matrix_stack_ptr[0]);
|
|
|
|
// test to accelerate computation
|
|
|
|
c->matrix_model_projection_no_w_transform = 0;
|
|
|
|
if (m[12] == 0.0 && m[13] == 0.0 && m[14] == 0.0)
|
|
|
|
c->matrix_model_projection_no_w_transform = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test if the texture matrix is not Identity
|
|
|
|
c->apply_texture_matrix = !gl_M4_IsId(c->matrix_stack_ptr[2]);
|
|
|
|
|
|
|
|
c->matrix_model_projection_updated = 0;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
2006-05-16 14:52:36 +00:00
|
|
|
// viewport
|
|
|
|
if (c->viewport.updated) {
|
|
|
|
gl_eval_viewport(c);
|
|
|
|
c->viewport.updated = 0;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
2006-05-16 14:52:36 +00:00
|
|
|
// triangle drawing functions
|
|
|
|
if (c->render_mode == TGL_SELECT) {
|
|
|
|
c->draw_triangle_front = gl_draw_triangle_select;
|
|
|
|
c->draw_triangle_back = gl_draw_triangle_select;
|
|
|
|
} else {
|
|
|
|
switch (c->polygon_mode_front) {
|
|
|
|
case TGL_POINT:
|
|
|
|
c->draw_triangle_front = gl_draw_triangle_point;
|
|
|
|
break;
|
|
|
|
case TGL_LINE:
|
|
|
|
c->draw_triangle_front = gl_draw_triangle_line;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
c->draw_triangle_front = gl_draw_triangle_fill;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (c->polygon_mode_back) {
|
|
|
|
case TGL_POINT:
|
|
|
|
c->draw_triangle_back = gl_draw_triangle_point;
|
|
|
|
break;
|
|
|
|
case TGL_LINE:
|
|
|
|
c->draw_triangle_back = gl_draw_triangle_line;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
c->draw_triangle_back = gl_draw_triangle_fill;
|
|
|
|
break;
|
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
// coords, tranformation, clip code and projection
|
|
|
|
// TODO : handle all cases
|
|
|
|
static inline void gl_vertex_transform(GLContext *c, GLVertex *v) {
|
|
|
|
float *m;
|
|
|
|
V4 *n;
|
|
|
|
|
|
|
|
if (c->lighting_enabled) {
|
|
|
|
// eye coordinates needed for lighting
|
|
|
|
|
|
|
|
m = &c->matrix_stack_ptr[0]->m[0][0];
|
|
|
|
v->ec.X = (v->coord.X * m[0] + v->coord.Y * m[1] +
|
|
|
|
v->coord.Z * m[2] + m[3]);
|
|
|
|
v->ec.Y = (v->coord.X * m[4] + v->coord.Y * m[5] +
|
|
|
|
v->coord.Z * m[6] + m[7]);
|
|
|
|
v->ec.Z = (v->coord.X * m[8] + v->coord.Y * m[9] +
|
|
|
|
v->coord.Z * m[10] + m[11]);
|
|
|
|
v->ec.W = (v->coord.X * m[12] + v->coord.Y * m[13] +
|
|
|
|
v->coord.Z * m[14] + m[15]);
|
|
|
|
|
|
|
|
// projection coordinates
|
|
|
|
m = &c->matrix_stack_ptr[1]->m[0][0];
|
2008-07-29 19:28:19 +00:00
|
|
|
v->pc.X = (v->ec.X * m[0] + v->ec.Y * m[1] + v->ec.Z * m[2] + v->ec.W * m[3]);
|
|
|
|
v->pc.Y = (v->ec.X * m[4] + v->ec.Y * m[5] + v->ec.Z * m[6] + v->ec.W * m[7]);
|
|
|
|
v->pc.Z = (v->ec.X * m[8] + v->ec.Y * m[9] + v->ec.Z * m[10] + v->ec.W * m[11]);
|
|
|
|
v->pc.W = (v->ec.X * m[12] + v->ec.Y * m[13] + v->ec.Z * m[14] + v->ec.W * m[15]);
|
2006-05-16 14:52:36 +00:00
|
|
|
|
|
|
|
m = &c->matrix_model_view_inv.m[0][0];
|
|
|
|
n = &c->current_normal;
|
|
|
|
|
|
|
|
v->normal.X = (n->X * m[0] + n->Y * m[1] + n->Z * m[2]);
|
|
|
|
v->normal.Y = (n->X * m[4] + n->Y * m[5] + n->Z * m[6]);
|
|
|
|
v->normal.Z = (n->X * m[8] + n->Y * m[9] + n->Z * m[10]);
|
|
|
|
|
|
|
|
if (c->normalize_enabled) {
|
|
|
|
gl_V3_Norm(&v->normal);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// no eye coordinates needed, no normal
|
|
|
|
// NOTE: W = 1 is assumed
|
|
|
|
m = &c->matrix_model_projection.m[0][0];
|
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
v->pc.X = (v->coord.X * m[0] + v->coord.Y * m[1] + v->coord.Z * m[2] + m[3]);
|
|
|
|
v->pc.Y = (v->coord.X * m[4] + v->coord.Y * m[5] + v->coord.Z * m[6] + m[7]);
|
|
|
|
v->pc.Z = (v->coord.X * m[8] + v->coord.Y * m[9] + v->coord.Z * m[10] + m[11]);
|
2006-05-16 14:52:36 +00:00
|
|
|
if (c->matrix_model_projection_no_w_transform) {
|
|
|
|
v->pc.W = m[15];
|
|
|
|
} else {
|
2008-07-29 19:28:19 +00:00
|
|
|
v->pc.W = (v->coord.X * m[12] + v->coord.Y * m[13] + v->coord.Z * m[14] + m[15]);
|
2006-05-16 14:52:36 +00:00
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
v->clip_code = gl_clipcode(v->pc.X, v->pc.Y, v->pc.Z, v->pc.W);
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
void glopVertex(GLContext *c, TGLParam *p) {
|
|
|
|
GLVertex *v;
|
|
|
|
int n, i, cnt;
|
|
|
|
|
|
|
|
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 = (GLVertex *)gl_malloc(sizeof(GLVertex) * c->vertex_max);
|
|
|
|
if (!newarray) {
|
2008-09-28 19:09:23 +00:00
|
|
|
error("unable to allocate GLVertex array.");
|
2006-05-16 14:52:36 +00:00
|
|
|
}
|
|
|
|
memcpy(newarray, c->vertex, n * sizeof(GLVertex));
|
|
|
|
gl_free(c->vertex);
|
|
|
|
c->vertex = newarray;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
2006-05-16 14:52:36 +00:00
|
|
|
// new vertex entry
|
|
|
|
v = &c->vertex[n];
|
|
|
|
n++;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
v->coord.X = p[1].f;
|
|
|
|
v->coord.Y = p[2].f;
|
|
|
|
v->coord.Z = p[3].f;
|
|
|
|
v->coord.W = p[4].f;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
gl_vertex_transform(c, v);
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
// color
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
if (c->lighting_enabled) {
|
|
|
|
gl_shade_vertex(c, v);
|
|
|
|
} else {
|
|
|
|
v->color = c->current_color;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
2006-05-16 14:52:36 +00:00
|
|
|
// 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 TGL_POINTS:
|
|
|
|
gl_draw_point(c, &c->vertex[0]);
|
2005-01-12 15:20:02 +00:00
|
|
|
n = 0;
|
2006-05-16 14:52:36 +00:00
|
|
|
break;
|
|
|
|
case TGL_LINES:
|
|
|
|
if (n == 2) {
|
|
|
|
gl_draw_line(c, &c->vertex[0], &c->vertex[1]);
|
|
|
|
n = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TGL_LINE_STRIP:
|
|
|
|
case TGL_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 TGL_TRIANGLES:
|
|
|
|
if (n == 3) {
|
|
|
|
gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]);
|
|
|
|
n = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TGL_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;
|
2005-01-12 18:00:19 +00:00
|
|
|
case TGL_TRIANGLE_FAN:
|
2006-05-16 14:52:36 +00:00
|
|
|
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;
|
2005-01-12 18:00:19 +00:00
|
|
|
case TGL_QUADS:
|
2006-05-16 14:52:36 +00:00
|
|
|
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 TGL_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 TGL_POLYGON:
|
|
|
|
break;
|
2005-01-12 15:20:02 +00:00
|
|
|
default:
|
2008-09-28 19:09:23 +00:00
|
|
|
error("glBegin: type %x not handled", c->begin_type);
|
2006-05-16 14:52:36 +00:00
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
c->vertex_n = n;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 14:52:36 +00:00
|
|
|
void glopEnd(GLContext *c, TGLParam *) {
|
|
|
|
assert(c->in_begin == 1);
|
|
|
|
|
|
|
|
if (c->begin_type == TGL_LINE_LOOP) {
|
|
|
|
if (c->vertex_cnt >= 3) {
|
|
|
|
gl_draw_line(c, &c->vertex[0], &c->vertex[2]);
|
|
|
|
}
|
|
|
|
} else if (c->begin_type == TGL_POLYGON) {
|
|
|
|
int i = c->vertex_cnt;
|
|
|
|
while (i >= 3) {
|
|
|
|
i--;
|
|
|
|
gl_draw_triangle(c, &c->vertex[i], &c->vertex[0], &c->vertex[i - 1]);
|
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
2006-05-16 14:52:36 +00:00
|
|
|
c->in_begin = 0;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|