/* 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]; 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]); 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]; 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]); if (c->matrix_model_projection_no_w_transform) { v->pc.W = m[15]; } else { v->pc.W = (v->coord.X * m[12] + v->coord.Y * m[13] + v->coord.Z * m[14] + m[15]); } } v->clip_code = gl_clipcode(v->pc.X, v->pc.Y, v->pc.Z, v->pc.W); }
void glopLight(GLContext *c, GLParam *p) { int light = p[1].i; int type = p[2].i; V4 v; GLLight *l; int i; assert(light >= TGL_LIGHT0 && light < TGL_LIGHT0 + T_MAX_LIGHTS); l = &c->lights[light - TGL_LIGHT0]; for (i = 0; i < 4; i++) v.v[i] = p[3 + i].f; switch(type) { case TGL_AMBIENT: l->ambient = v; break; case TGL_DIFFUSE: l->diffuse = v; break; case TGL_SPECULAR: l->specular = v; break; case TGL_POSITION: { V4 pos; gl_M4_MulV4(&pos, c->matrix_stack_ptr[0], &v); l->position=pos; if (l->position.v[3] == 0) { l->norm_position.X = pos.X; l->norm_position.Y = pos.Y; l->norm_position.Z = pos.Z; gl_V3_Norm(&l->norm_position); } } break; case TGL_SPOT_DIRECTION: for (i = 0; i < 3; i++) { l->spot_direction.v[i] = v.v[i]; l->norm_spot_direction.v[i] = v.v[i]; } gl_V3_Norm(&l->norm_spot_direction); break; case TGL_SPOT_EXPONENT: l->spot_exponent = v.v[0]; break; case TGL_SPOT_CUTOFF: { float a = v.v[0]; assert(a == 180 || (a >= 0 && a <= 90)); l->spot_cutoff=a; if (a != 180) l->cos_spot_cutoff = (float)(cos(a * LOCAL_PI / 180.0)); } break; case TGL_CONSTANT_ATTENUATION: l->attenuation[0] = v.v[0]; break; case TGL_LINEAR_ATTENUATION: l->attenuation[1] = v.v[0]; break; case TGL_QUADRATIC_ATTENUATION: l->attenuation[2] = v.v[0]; break; default: assert(0); } }
// non optimized lightening model void gl_shade_vertex(GLContext *c, GLVertex *v) { float R, G, B, A; GLMaterial *m; GLLight *l; V3 n, s, d; float dist, tmp, att, dot, dot_spot, dot_spec; int twoside = c->light_model_two_side; m = &c->materials[0]; n.X = v->normal.X; n.Y = v->normal.Y; n.Z = v->normal.Z; R = m->emission.v[0] + m->ambient.v[0] * c->ambient_light_model.v[0]; G = m->emission.v[1] + m->ambient.v[1] * c->ambient_light_model.v[1]; B = m->emission.v[2] + m->ambient.v[2] * c->ambient_light_model.v[2]; A = clampf(m->diffuse.v[3], 0, 1); for (l = c->first_light; l != NULL; l = l->next) { float lR, lB, lG; // ambient lR = l->ambient.v[0] * m->ambient.v[0]; lG = l->ambient.v[1] * m->ambient.v[1]; lB = l->ambient.v[2] * m->ambient.v[2]; if (l->position.v[3] == 0) { // light at infinity d.X = l->position.v[0]; d.Y=l->position.v[1]; d.Z=l->position.v[2]; att=1; } else { // distance attenuation d.X = l->position.v[0] - v->ec.v[0]; d.Y = l->position.v[1] - v->ec.v[1]; d.Z = l->position.v[2] - v->ec.v[2]; dist = sqrt(d.X * d.X + d.Y * d.Y + d.Z * d.Z); if (dist > 1E-3) { tmp = 1 / dist; d.X *= tmp; d.Y *= tmp; d.Z *= tmp; } att = 1.0f / (l->attenuation[0] + dist * (l->attenuation[1] + dist * l->attenuation[2])); } dot = d.X * n.X + d.Y * n.Y + d.Z * n.Z; if (twoside && dot < 0) dot = -dot; if (dot > 0) { // diffuse light lR += dot * l->diffuse.v[0] * m->diffuse.v[0]; lG += dot * l->diffuse.v[1] * m->diffuse.v[1]; lB += dot * l->diffuse.v[2] * m->diffuse.v[2]; // spot light if (l->spot_cutoff != 180) { dot_spot = -(d.X * l->norm_spot_direction.v[0] + d.Y * l->norm_spot_direction.v[1] + d.Z * l->norm_spot_direction.v[2]); if (twoside && dot_spot < 0) dot_spot = -dot_spot; if (dot_spot < l->cos_spot_cutoff) { // no contribution continue; } else { // TODO: optimize if (l->spot_exponent > 0) { att = att * pow(dot_spot, l->spot_exponent); } } } // specular light if (c->local_light_model) { V3 vcoord; vcoord.X = v->ec.X; vcoord.Y = v->ec.Y; vcoord.Z = v->ec.Z; gl_V3_Norm(&vcoord); s.X = d.X-vcoord.X; s.Y = d.Y-vcoord.X; s.Z = d.Z-vcoord.X; } else { s.X = d.X; s.Y = d.Y; s.Z = (float)(d.Z + 1.0); } dot_spec = n.X * s.X + n.Y * s.Y + n.Z * s.Z; if (twoside && dot_spec < 0) dot_spec = -dot_spec; if (dot_spec > 0) { GLSpecBuf *specbuf; int idx; tmp = sqrt(s.X * s.X + s.Y * s.Y + s.Z * s.Z); if (tmp > 1E-3) { dot_spec = dot_spec / tmp; } // TODO: optimize // testing specular buffer code // dot_spec= pow(dot_spec,m->shininess) specbuf = specbuf_get_buffer(c, m->shininess_i, m->shininess); idx = (int)(dot_spec * SPECULAR_BUFFER_SIZE); if (idx > SPECULAR_BUFFER_SIZE) idx = SPECULAR_BUFFER_SIZE; dot_spec = specbuf->buf[idx]; lR += dot_spec * l->specular.v[0] * m->specular.v[0]; lG += dot_spec * l->specular.v[1] * m->specular.v[1]; lB += dot_spec * l->specular.v[2] * m->specular.v[2]; } } R += att * lR; G += att * lG; B += att * lB; } v->color.v[0] = clampf(R, 0, 1); v->color.v[1] = clampf(G, 0, 1); v->color.v[2] = clampf(B, 0, 1); v->color.v[3] = A; }