#include "defines.h" fixed sintab[360], costab[360]; Point2D v_cache[MAX_VERTEX]; void mat3_identity(Matrix3 *mat) { memset(mat, 0, sizeof(Matrix3)); mat->m[0][0] = mat->m[1][1] = mat->m[2][2] = int_to_f(1); } void init_engine_math(void) { #ifndef MINIMAL_PLAYER int i; for (i = 0; i < 360; i++) { double r = (double)i * 3.14159265 / 180.0; sintab[i] = (fixed)(sin(r) * 65536.0); costab[i] = (fixed)(cos(r) * 65536.0); } #endif } void mat3_mul(Matrix3 *res, Matrix3 *a, Matrix3 *b) { Matrix3 tmp; int i, j; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) tmp.m[i][j] = f_mul(a->m[i][0], b->m[0][j]) + f_mul(a->m[i][1], b->m[1][j]) + f_mul(a->m[i][2], b->m[2][j]); *res = tmp; } void mat3_rotate_x(Matrix3 *m, int angle) { int a = ((angle % 360) + 360) % 360; fixed c = costab[a], s = sintab[a]; mat3_identity(m); m->m[1][1] = c; m->m[1][2] = -s; m->m[2][1] = s; m->m[2][2] = c; } void mat3_rotate_y(Matrix3 *m, int angle) { int a = ((angle % 360) + 360) % 360; fixed c = costab[a], s = sintab[a]; mat3_identity(m); m->m[0][0] = c; m->m[0][2] = s; m->m[2][0] = -s; m->m[2][2] = c; } void mat3_rotate_z(Matrix3 *m, int angle) { int a = ((angle % 360) + 360) % 360; fixed c = costab[a], s = sintab[a]; mat3_identity(m); m->m[0][0] = c; m->m[0][1] = s; m->m[1][0] = -s; m->m[1][1] = c; } /* Fait pivoter la géométrie locale de l'objet de façon permanente */ /* void bake_object_rotation(Universe *uni, Object3D *obj, int ax, int ay, int az) { Matrix3 rx, ry, rz, tmp, rot; Vector3 *v, *n; int i, vi; fixed vx, vy, vz; if (!obj || !uni) return; /* Composition de la matrice de rotation * / mat3_rotate_x(&rx, ax); mat3_rotate_y(&ry, ay); mat3_rotate_z(&rz, az); mat3_mul(&tmp, &rx, &ry); mat3_mul(&rot, &tmp, &rz); /* Application à tous les sommets et normales de l'objet * / for (i = 0; i < obj->num_verts; i++) { vi = obj->vert_start + i; v = &uni->verts[vi]; n = &uni->v_normals[vi]; /* Sommets * / vx = f_mul(v->x, rot.m[0][0]) + f_mul(v->y, rot.m[1][0]) + f_mul(v->z, rot.m[2][0]); vy = f_mul(v->x, rot.m[0][1]) + f_mul(v->y, rot.m[1][1]) + f_mul(v->z, rot.m[2][1]); vz = f_mul(v->x, rot.m[0][2]) + f_mul(v->y, rot.m[1][2]) + f_mul(v->z, rot.m[2][2]); v->x = vx; v->y = vy; v->z = vz; /* Normales (doivent aussi pivoter pour l'ombrage Gouraud !) * / vx = f_mul(n->x, rot.m[0][0]) + f_mul(n->y, rot.m[1][0]) + f_mul(n->z, rot.m[2][0]); vy = f_mul(n->x, rot.m[0][1]) + f_mul(n->y, rot.m[1][1]) + f_mul(n->z, rot.m[2][1]); vz = f_mul(n->x, rot.m[0][2]) + f_mul(n->y, rot.m[1][2]) + f_mul(n->z, rot.m[2][2]); n->x = vx; n->y = vy; n->z = vz; } } */ void render_universe(Universe *uni, Camera *cam, int mode) { int o, i, vi, front; fixed rx, ry, rz, pz, nz; uint8_t wire_col; Vector3 *v, *n; Object3D *obj; Face *f; Point2D *p1, *p2, *p3; for (o = 0; o < uni->num_objects; o++) { obj = &uni->objects[o]; /* Transformation + projection de tous les sommets de cet objet */ for (i = 0; i < obj->num_verts; i++) { vi = obj->vert_start + i; v = &uni->verts[vi]; n = &uni->v_normals[vi]; rx = f_mul(v->x, obj->rot.m[0][0]) + f_mul(v->y, obj->rot.m[1][0]) + f_mul(v->z, obj->rot.m[2][0]) + obj->pos.x - cam->pos.x; ry = f_mul(v->x, obj->rot.m[0][1]) + f_mul(v->y, obj->rot.m[1][1]) + f_mul(v->z, obj->rot.m[2][1]) + obj->pos.y - cam->pos.y; rz = f_mul(v->x, obj->rot.m[0][2]) + f_mul(v->y, obj->rot.m[1][2]) + f_mul(v->z, obj->rot.m[2][2]) + obj->pos.z - cam->pos.z; pz = (rz < int_to_f(20)) ? int_to_f(20) : rz; v_cache[vi].z = pz; v_cache[vi].x = 160 + f_to_int(f_div(rx << 8, pz)); v_cache[vi].y = 100 - f_to_int(f_div(ry << 8, pz)); nz = f_mul(n->x, obj->rot.m[0][2]) + f_mul(n->y, obj->rot.m[1][2]) + f_mul(n->z, obj->rot.m[2][2]); v_cache[vi].intensity = (nz >= 0) ? int_to_f(1) : f_mul(-nz, int_to_f(14)) + int_to_f(1); } wire_col = (uint8_t)((obj->color << 4) | 15); /* Rendu des faces */ for (i = 0; i < obj->num_faces; i++) { f = &uni->faces[obj->face_start + i]; p1 = &v_cache[f->a]; p2 = &v_cache[f->b]; p3 = &v_cache[f->c]; front = ((p2->x - p1->x) * (p3->y - p1->y) - (p2->y - p1->y) * (p3->x - p1->x)) > 0; switch (mode) { case MODE_WIRE: draw_line_z(p1, p2, wire_col, 0); draw_line_z(p2, p3, wire_col, 0); draw_line_z(p3, p1, wire_col, 0); break; case MODE_HIDDEN: if (front) { draw_line_z(p1, p2, wire_col, 1); draw_line_z(p2, p3, wire_col, 1); draw_line_z(p3, p1, wire_col, 1); } break; case MODE_SOLID: default: if (front) { if (f->force_wire) { draw_line_z(p1, p2, wire_col, 1); draw_line_z(p2, p3, wire_col, 1); draw_line_z(p3, p1, wire_col, 1); } else { fill_triangle_gouraud(p1, p2, p3, obj->color); } } break; } } } }