void Shape3D :: calc_face_normal(int face_index) { GLfloat* fn = new GLfloat[4]; // calculate face normal GLfloat vector1[4], vector2[4]; vv_sub(verts[faces[face_index][0]], verts[faces[face_index][1]], vector1); vv_sub(verts[faces[face_index][2]], verts[faces[face_index][1]], vector2); vv_cross(vector2, vector1, fn); normalize(fn); // place into face normals array f_norms[face_index] = fn; }
void Cube :: make_face(int face_num, int v1, int v2, int v3) { // allocate new face int* f = new int[3]; // allocate new face normal GLfloat* fn = new GLfloat[4]; init_vector(fn); // set face vertices f[0] = v1; f[1] = v2; f[2] = v3; // place into faces array faces[face_num] = f; // calculate face normal GLfloat vector1[4], vector2[4]; vv_sub(verts[v2], verts[v1], vector1); vv_sub(verts[v2], verts[v3], vector2); vv_cross(vector1, vector2, fn); normalize(fn); // place into face normals array f_norms[face_num] = fn; }
int draw_3d_tri( pVector v1p, Graph3dColor c1p, pVector n1p, pVector v2p, Graph3dColor c2p, pVector n2p, pVector v3p, Graph3dColor c3p, pVector n3p) { int j; int x1, x2, x3; int y1, y2, y3; // First, convert the colors to floats Vector c1 = { (float)c1p.r / 255.0, (float)c1p.g / 255.0, (float)c1p.b / 255.0, 1.0 }; Vector c2 = { (float)c2p.r / 255.0, (float)c2p.g / 255.0, (float)c2p.b / 255.0, 1.0 }; Vector c3 = { (float)c3p.r / 255.0, (float)c3p.g / 255.0, (float)c3p.b / 255.0, 1.0 }; Vector v1, v2, v3; Vector n1, n2, n3; Vector L1, L2, L3; // Next, apply the modelview matrix to the triangle's vertices vv_cpy(v1, v1p); vv_cpy(v2, v2p); vv_cpy(v3, v3p); vm_mul(v1, modelview); vm_mul(v2, modelview); vm_mul(v3, modelview); // And also to the normals vv_cpy(n1, n1p); vv_cpy(n2, n2p); vv_cpy(n3, n3p); vm_mul(n1, modelview); vm_mul(n2, modelview); vm_mul(n3, modelview); // Find the distance for each point from the light vv_cpy(L1, lightpos); vv_sub(L1, v1); v_norm(L1); vv_cpy(L2, lightpos); vv_sub(L2, v2); v_norm(L2); vv_cpy(L3, lightpos); vv_sub(L3, v3); v_norm(L3); // Then, apply our lighting equations // We assume that the triangle's ambient and diffuse values are the same // We also assume that for(j = 0; j < 4; j++) { c1[j] = light_transform(c1[j], n1, L1, j); c2[j] = light_transform(c2[j], n2, L2, j); c2[j] = light_transform(c3[j], n3, L3, j); } // Convert the color values to values the graphics card will accept // c1p et al were passed by value, so we can modify them c1p.r = c1[0] * 255; c1p.g = c1[1] * 255; c1p.b = c1[2] * 255; c2p.r = c2[0] * 255; c2p.g = c2[1] * 255; c2p.b = c2[2] * 255; c3p.r = c3[0] * 255; c3p.g = c3[1] * 255; c3p.b = c3[2] * 255; // Lastly, find the coordinates on the screen for each point, // and draw the triangle x1 = 800 * (depth/height) * (v1[0] / v1[2]); y1 = 600 * (depth/height) * (v1[1] / v1[2]); x2 = 800 * (depth/height) * (v2[0] / v2[2]); y2 = 600 * (depth/height) * (v2[1] / v2[2]); x3 = 800 * (depth/height) * (v3[0] / v3[2]); y3 = 600 * (depth/height) * (v3[1] / v3[2]); draw_2d_tri(x1, y1, c1p, x2, y2, c2p, x3, y3, c3p); printf("v1: %f %f %f\n", v1[0], v1[1], v1[2]); printf("v2: %f %f %f\n", v2[0], v2[1], v2[2]); printf("v2: %f %f %f\n", v3[0], v3[1], v3[2]); printf("%d %d; %d %d; %d %d\n", x1, y1, x2, y2, x3, y3); return GRAPH3D_OK; }
// modify_scene modifies the global variables g_projectiles and g_explosions // during the course of an attack sequence. It takes a parameter dt which // represents the amount of time between frames. // Return: the number of items left to animate. int modify_scene(float dt) { int i, j, num_impacted; float t; struct Projectile *p; struct Explosion *e; struct Tank *tank; Vector v; float d; // Go through all the explosions and update them according to the // amount of time passed. for(j = 0; j < g_num_explosions; j++) { e = &g_explosions[j]; t = update_explosion(e, dt); } // Go through all the projectiles and handle the ones that have not yet // been impacted. for(j = 0, num_impacted = 0; j < g_num_projectiles; j++) { p = &g_projectiles[j]; if(p->o.state != STATE_IMPACTED) { t = update_projectile(p, dt); if(p->o.state == STATE_IMPACTED) { printf("Projectile %d has impacted.\n", j); // If the projectile has impacted, an explosion needs to be // created which is appropriate to the projectile which has // impacted, and which takes on properties of the former // projectile. e = new_explosion(p); // Now, using the remaining time that did not get used on the // projectile, update the new explosion. t = update_explosion(e, dt - t); // And play a sound to match sx3_play_sound(SX3_AUDIO_EXPLOSION); } } if(p->o.state == STATE_IMPACTED) num_impacted++; } // FIX ME!! These two checks don't work properly if we have a low // framerate. for(j = 0; j < g_num_explosions; j++) { e = &g_explosions[j]; for(i = 0; i < g_num_tanks; i++) { tank = &g_tanks[i]; // Don't check this tank if it's already been hit // FIX ME!! This should be on a per-projectile/explosion basis if(tank->s.temp_damage != 0.0) continue; // Find the distance between the tank and the explosion, and test vv_cpy(v, tank->o.props.position); vv_sub(v, e->props.position); d = v_mag(v); if(d < tank->o.props.radius + e->props.radius) { // A tank has been hit! sx3_play_sound(SX3_AUDIO_HIT); printf("Tank %d hit by explosion %d\n", i, j); // FIX ME!! This should not be constant damage. tank->s.temp_damage = 20.0; } } } for(j = 0; j < g_num_projectiles; j++) { p = &g_projectiles[j]; if(p->o.state == STATE_IMPACTED) continue; for(i = 0; i < g_num_tanks; i++) { tank = &g_tanks[i]; // Don't check this tank if it's already been hit // FIX ME!! This should be on a per-projectile/explosion basis if(tank->s.temp_damage != 0.0) continue; // Find the distance between the tank and the projectiles, and test vv_cpy(v, tank->o.props.position); vv_sub(v, p->o.props.position); d = v_mag(v); if(d < tank->o.props.radius + p->o.props.radius) { // A tank has been hit! sx3_play_sound(SX3_AUDIO_HIT); printf("Tank %d hit by projectile %d\n", i, j); // FIX ME!! This should not be constant damage. tank->s.temp_damage = 40.0; } } } return g_num_explosions + g_num_projectiles - num_impacted; }