void lightsource_fake_phong (float *vertex, float *norm, const float *light_pos, const float *light_up, const float *eye_pos, matrix_t *invcamera, vertex_attrs *vertex_info, unsigned int idx) { float norm_light[3]; float eye_to_vertex[3], tmp[3], reflection[3]; float light_to_vertex[3]; float eye_dot_norm; vec_sub (light_to_vertex, light_pos, vertex); vec_normalize (norm_light, light_to_vertex); vec_sub (eye_to_vertex, eye_pos, vertex); vec_normalize (eye_to_vertex, eye_to_vertex); eye_dot_norm = vec_dot (eye_to_vertex, norm); vec_scale (tmp, norm, 2.0 * eye_dot_norm); vec_sub (reflection, tmp, eye_to_vertex); if (eye_dot_norm < 0) vertex_info[idx].fakephong.transformed_z = -0.01; else fakephong_texcoords (&vertex_info[idx].fakephong.texc[0], &vertex_info[idx].fakephong.texc[1], reflection, norm_light, light_up, &vertex_info[idx].fakephong.transformed_z); }
void eff_expl_flash_2() { set(me, BRIGHT | TRANSLUCENT | ZNEAR | PASSABLE); my.blue = 150; my.green = 235; my.red = 255; my.alpha = 0; my.roll = random(360); vec_fill(my.scale_x, 3); vec_for_angle(vecEffectsTemp, vector( my.roll, 0, 0)); vec_rotate(vecEffectsTemp, vector(camera.pan, camera.tilt+90, 0)); vec_normalize(vecEffectsTemp, 40); vec_add(vecEffectsTemp, my.x); vec_set(my.x, vecEffectsTemp); while(my.alpha < 100) { if (my.lightrange < 1000 ) my.lightrange += 2000 * time_step; my.alpha += time_step * (random(20)+20); my.roll += time_step * sign(ang(my.roll)); vec_normalize ( my.blue, 150 + random(105) ); wait(1); } ent_create("explSmoke02.tga", my.x, eff_expl_smoke); while(my.alpha > 0) { if (my.lightrange > 0) my.lightrange -= 500 * time_step; my.alpha -= time_step * 20; my.roll += time_step * sign(ang(my.roll))*5; wait(1); } while (my.lightrange > 0) { my.lightrange -= 500 * time_step; wait(1); } ent_remove(me); }
void mat_make_look_at(struct matrix *m, const struct vector *o, const struct vector *p) { struct vector n, u, v, t; struct matrix a; vec_sub(&n, p, o); vec_normalize(&n); /* v' = (0, 1, 0) */ vec_set(&v, 0.f, 1.f, 0.f); /* v = v' - (v'*n)*n */ vec_scalar_mul_copy(&t, &n, vec_dot_product(&v, &n)); vec_sub_from(&v, &t); vec_normalize(&v); vec_cross_product(&u, &v, &n); vec_normalize(&u); m->m11 = u.x; m->m12 = u.y; m->m13 = u.z; m->m14 = 0.f; m->m21 = v.x; m->m22 = v.y; m->m23 = v.z; m->m24 = 0.f; m->m31 = n.x; m->m32 = n.y; m->m33 = n.z; m->m34 = 0.f; mat_make_translation(&a, -o->x, -o->y, -o->z); mat_mul(m, &a); }
int MoleculeGraphics::add_tricolor(const float *x1, const float *x2, const float *x3, const float *n1, const float *n2, const float *n3, int c1, int c2, int c3) { ShapeClass s(TRICOLOR, 21, next_id); float *data = s.data; vec_copy(data+ 0, x1); vec_copy(data+ 3, x2); vec_copy(data+ 6, x3); vec_copy(data+ 9, n1); vec_normalize(data+ 9); // normalize this normal to prevent problems later vec_copy(data+12, n2); vec_normalize(data+12); // normalize this normal to prevent problems later vec_copy(data+15, n3); vec_normalize(data+15); // normalize this normal to prevent problems later data[18] = (float)c1; data[19] = (float)c2; data[20] = (float)c3; // new one goes at next_id if (next_index < num_elements()) shapes[next_index] = s; else shapes.append(s); return added(); }
// Calculates cartesian axes based on coords of nuclei in ring // using cremer-pople algorithm. It is assumed that the // centre of geometry is the centre of the ring. void ring_axes(const float * X, const float * Y, const float * Z, int N, float x[3], float y[3], float z[3]) { float Rp[3] = {0.0, 0.0, 0.0}; float Rpp[3] = {0.0, 0.0, 0.0}; int j; for (j=0; j<N; j++) { float ze_angle = 2.0f * float(VMD_PI) * float(j-1) / float(N); float ze_sin = sinf(ze_angle); float ze_cos = cosf(ze_angle); vec_incr(Rp, X[j]*ze_sin, Y[j]*ze_sin, Z[j]*ze_sin); vec_incr(Rpp, X[j]*ze_cos, Y[j]*ze_cos, Z[j]*ze_cos); } cross_prod(z, Rp, Rpp); vec_normalize(z); /* * OK, now we have z, the norm to the central plane, we need * to calculate y as the projection of Rp onto the plane * and x as y x z */ float lambda = dot_prod(z, Rp); y[0] = Rp[0] - z[0]*lambda; y[1] = Rp[1] - z[1]*lambda; y[2] = Rp[2] - z[2]*lambda; vec_normalize(y); cross_prod(x, y, z); // voila ! }
void eff_expl_smoke2 () { set(me, TRANSLUCENT | ZNEAR | PASSABLE | LIGHT); my.roll = random(360); my.alpha = 100; my.scale_x = 0.2; my.scale_y = 0.7; my.skill1 = random(3)+2; vec_fill(my.blue, 30); while(my.alpha > 0) { if(my.alpha > 93 ) { vec_for_angle(vecEffectsTemp, vector( my.roll,0,0)); vec_rotate(vecEffectsTemp, vector(camera.pan, camera.tilt+90, 0)); vec_normalize(vecEffectsTemp, time_step * (my.alpha/my.skill1) * 0.4); vec_add(my.x, vecEffectsTemp); my.scale_y += vec_length(vecEffectsTemp)/46; my.alpha -= time_step * 3; } else { vec_for_angle(vecEffectsTemp, vector(my.roll, 0, 0)); vec_rotate(vecEffectsTemp, vector(camera.pan, camera.tilt+90, 0)); vec_normalize(vecEffectsTemp, time_step * (my.alpha/(my.skill1*2))); vec_add(my.x, vecEffectsTemp); my.scale_y += vec_length(vecEffectsTemp) / 5000; my.alpha -= time_step * 9; } wait(1); } ent_remove(me); return; }
// draw a cylinder void X3DDisplayDevice::cylinder_noxfrm(float *ta, float *tb, float radius, int filled) { if (ta[0] == tb[0] && ta[1] == tb[1] && ta[2] == tb[2]) { return; // we don't serve your kind here } float height = distance(ta, tb); fprintf(outfile, "<Transform translation='%g %g %g' ", ta[0], ta[1] + (height / 2.0), ta[2]); float rotaxis[3]; float cylaxdir[3]; float yaxis[3] = {0.0, 1.0, 0.0}; vec_sub(cylaxdir, tb, ta); vec_normalize(cylaxdir); float dp = dot_prod(yaxis, cylaxdir); cross_prod(rotaxis, cylaxdir, yaxis); vec_normalize(rotaxis); // if we have decent rotation vector, use it if ((rotaxis[0]*rotaxis[0] + rotaxis[1]*rotaxis[1] + rotaxis[2]*rotaxis[2]) > 0.5) { fprintf(outfile, "center='0.0 %g 0.0' ", -(height / 2.0)); fprintf(outfile, "rotation='%g %g %g %g'", rotaxis[0], rotaxis[1], rotaxis[2], -acos(dp)); } else if (dp < -0.98) { // if we have denormalized rotation vector, we can assume it is // caused by a cylinder axis that is nearly coaxial with the Y axis. // If this is the case, we either perform no rotation in the case of a // angle cosine near 1.0, or a 180 degree rotation for a cosine near -1. fprintf(outfile, "center='0.0 %g 0.0' ", -(height / 2.0)); fprintf(outfile, "rotation='0 0 -1 -3.14159'"); } fprintf(outfile, ">\n"); fprintf(outfile, " <Shape>\n"); fprintf(outfile, " "); write_cindexmaterial(colorIndex, materialIndex); // draw the cylinder fprintf(outfile, " <Cylinder " "bottom='%s' height='%g' radius='%g' side='%s' top='%s' />\n", filled ? "true" : "false", height, radius, "true", filled ? "true" : "false"); fprintf(outfile, " </Shape>\n"); fprintf(outfile, "</Transform>\n"); }
void orthonormal_basis(const float b[9], float e[9]) { float ob[3*3]; vec_copy(ob+0, b+0); vec_copy(e+0, ob+0); vec_normalize(e+0); vec_triad(ob+3, b+3, -dot_prod(e+0, b+3), e+0); vec_copy(e+3, ob+3); vec_normalize(e+3); vec_triad(ob+6, b+6, -dot_prod(e+0, b+6), e+0); vec_triad(ob+6, ob+6, -dot_prod(e+3, b+6), e+3); vec_copy(e+6, ob+6); vec_normalize(e+6); }
COLOR_T illuminate (SCENE_T scene, RAY_T ray, VP_T int_pt, VP_T normal, int object) { COLOR_T color; COLOR_T input_color = scene.objs[object].color; if(scene.objs[object].checkerboard) { if(((int)floor(int_pt.x) + (int)floor(int_pt.y) + (int)floor(int_pt.z)) & 1) { input_color = scene.objs[object].color2; } } //ambient color.R = 0.1 * scene.objs[object].color.R; color.G = 0.1 * scene.objs[object].color.G; color.B = 0.1 * scene.objs[object].color.B; if(!test_shadow(scene, int_pt, normal, object)) { //diffuse VP_T L = vec_subtract(scene.light.location, int_pt); double dL = vec_len(L); L = vec_normalize(L); double dot_L = vec_dot(normal, L); double c1 = 0.002, c2 = 0.02, c3 = 0.2; double light_atten = 1.0 / (c1 * dL * dL + c2 * dL + c3); if (dot_L > 0) { color.R += dot_L * input_color.R * light_atten; color.G += dot_L * input_color.G * light_atten; color.B += dot_L * input_color.B * light_atten; //specular VP_T R; R.x = L.x - 2 * dot_L * normal.x; R.y = L.y - 2 * dot_L * normal.y; R.z = L.z - 2 * dot_L * normal.z; R = vec_normalize(R); double dot_R = vec_dot(R, ray.direction); if (dot_R > 0) { color.R += pow(dot_R, 100); color.G += pow(dot_R, 100); color.B += pow(dot_R, 100); } } } return color; }
void mesh_init_vertex_normals(struct mesh *mesh) { struct polygon *p, *poly_end; struct vertex *v, *vtx_end; struct vector *poly_normal; int *idx; int nvtx; vtx_end = &mesh->vtx[mesh->nvtx]; for (v = mesh->vtx; v != vtx_end; v++) vec_zero(&v->normal); poly_end = &mesh->poly[mesh->npoly]; for (p = mesh->poly; p != poly_end; p++) { poly_normal = &p->normal; idx = p->vtx_index; nvtx = p->nvtx; while (nvtx--) vec_add_to(&mesh->vtx[*idx++].normal, poly_normal); } for (v = mesh->vtx; v != vtx_end; v++) vec_normalize(&v->normal); }
quat quat_load_axis_angle(avec axis, float angle) { vec q = vec_mul(vec_normalize(axis), sinf(0.5f*angle)); vec w = vec_load4(0.0f, 0.0f, 0.0f, cosf(0.5f*angle)); // Shift q into v0, v1, v2 and put w into v3. return vec_add(q, w); }
float PSDisplayDevice::compute_light(float *a, float *b, float *c) { float norm[3]; float light_scale; // compute a normal vector to the surface of the polygon norm[0] = a[1] * (b[2] - c[2]) + b[1] * (c[2] - a[2]) + c[1] * (a[2] - b[2]); norm[1] = a[2] * (b[0] - c[0]) + b[2] * (c[0] - a[0]) + c[2] * (a[0] - b[0]); norm[2] = a[0] * (b[1] - c[1]) + b[0] * (c[1] - a[1]) + c[0] * (a[1] - b[1]); // if the normal vector is zero, something is wrong with the // object so we'll just display it with a light_scale of zero if (!norm[0] && !norm[1] && !norm[2]) { light_scale = 0; } else { // otherwise we use the dot product of the surface normal // and the light normal to determine a light_scale vec_normalize(norm); light_scale = dot_prod(norm, norm_light); if (light_scale < 0) light_scale = -light_scale; } return light_scale; }
color_t getAntialiasedPixel(float x, float y, intersect_t *intersect, float antialiasLevel) { float antialiasLevelSquared = antialiasLevel * antialiasLevel; float precalculatedOffsetPart = 1.0 / (2.0 * antialiasLevel); point_t pos; vec_t rayDirection; ray_t ray; color_t color; float avgR = 0, avgG = 0, avgB = 0; for (int j = 0; j < antialiasLevel; j++) { for (int i = 0; i < antialiasLevel; i++) { float xOff = i / antialiasLevel + precalculatedOffsetPart; float yOff = j / antialiasLevel + precalculatedOffsetPart; float xPos = (x + xOff) * 2 / width - 1; float yPos = -((y + yOff) * 2 / height - 1); pos = point_new(xPos, yPos, -2); rayDirection = vec_normalize(point_direction(cameraPos, pos)); ray = ray_new(cameraPos, rayDirection); color = shootRay(ray, intersect, 0); avgR += (float)color.r / (float)antialiasLevelSquared; avgG += (float)color.g / (float)antialiasLevelSquared; avgB += (float)color.b / (float)antialiasLevelSquared; } } return rgb((char)avgR, (char)avgG, (char)avgB); }
//this function tests to see if a pixel is shadowed by another object static int test_shadow(SCENE_T scene, VP_T int_pt, VP_T normal, int object) { RAY_T shadow_ray; VP_T dummy_int_pt = int_pt; VP_T dummy_normal = normal; double dummy_t = 1; int i; shadow_ray.origin.x = int_pt.x; shadow_ray.origin.y = int_pt.y; shadow_ray.origin.z = int_pt.z; shadow_ray.direction.x = scene.light.location.x - int_pt.x; shadow_ray.direction.y = scene.light.location.y - int_pt.y; shadow_ray.direction.z = scene.light.location.z - int_pt.z; shadow_ray.direction = vec_normalize(shadow_ray.direction); for(i = 0; i < scene.num_objs; i++) { if(i != object) { if(scene.objs[i].intersect(scene.objs[i], shadow_ray, &dummy_int_pt, &dummy_normal, &dummy_t)) { return 1; } } } return 0; }
void auto_orient (void) { int face; for (face = 0; face < 6; face++) { float u[3], a_minus_b[3], a_minus_c[3]; vec_sub (a_minus_b, points[tristrips[face][0]], points[tristrips[face][1]]); vec_scale (a_minus_b, a_minus_b, texcoords[0][1] - texcoords[2][1]); vec_sub (a_minus_c, points[tristrips[face][0]], points[tristrips[face][2]]); vec_scale (a_minus_c, a_minus_c, texcoords[0][1] - texcoords[1][1]); vec_sub (u, a_minus_b, a_minus_c); /* Not really sure if this is right. */ if (((texcoords[0][0] - texcoords[1][0]) * (texcoords[0][1] - texcoords[2][1]) - (texcoords[0][0] - texcoords[2][0]) * (texcoords[0][1] - texcoords[1][1])) < 0.0f) vec_scale (u, u, -1.0f); vec_normalize (u, u); printf ("face %d: calculated [ %f %f %f ]\n", face, u[0], u[1], u[2]); printf (" previously [ %f %f %f ]\n", face_orient[face][0], face_orient[face][1], face_orient[face][2]); } }
/** genRay **/ vector_t genRay(scene_t *scene, int column, int row) { //initialize the vector for the world vector_t vector; //obtain the window window_t *window = (window_t*)scene->window->entDerived; //obtain the viewpoint point_t viewpoint = ((window_t*)scene->window->entDerived)->viewPoint; // calculations for world coordinates double x = ((double)(column) / (double)(scene->picture->columns - 1)) * window->windowWidth; x -= window->windowWidth/2.0; double y = ((double)(row) / (double)(scene->picture->rows - 1)) * window->windowHeight; y -= window->windowHeight/2.0; //assign values to vector vector.x = x; vector.y = y; vector.z = 0; //compute distance between the points vector_t result; result = vec_subtract(vector, viewpoint); //return the normalized vector return vec_normalize(result); } /* End genRay */
triangle_t triangle_new3(point_t a, point_t b, point_t c, material_t material) { triangle_t triangle; triangle.points[0] = a; triangle.points[1] = b; triangle.points[2] = c; triangle.material = material; triangle.normal = vec_normalize(vec_cross(point_direction(a, b), point_direction(a, c))); return triangle; }
void X3DDisplayDevice::cone(float *a, float *b, float r) { float ta[3], tb[3], radius; if (a[0] == b[0] && a[1] == b[1] && a[2] == b[2]) { return; // we don't serve your kind here } // transform the coordinates (transMat.top()).multpoint3d(a, ta); (transMat.top()).multpoint3d(b, tb); radius = scale_radius(r); float height = distance(a, b); fprintf(outfile, "<Transform translation='%g %g %g' ", ta[0], ta[1] + (height / 2.0), ta[2]); float rotaxis[3]; float cylaxdir[3]; float yaxis[3] = {0.0, 1.0, 0.0}; vec_sub(cylaxdir, tb, ta); vec_normalize(cylaxdir); float dp = dot_prod(yaxis, cylaxdir); cross_prod(rotaxis, cylaxdir, yaxis); vec_normalize(rotaxis); if ((rotaxis[0]*rotaxis[0] + rotaxis[1]*rotaxis[1] + rotaxis[2]*rotaxis[2]) > 0.5) { fprintf(outfile, "center='0.0 %g 0.0' ", -(height / 2.0)); fprintf(outfile, "rotation='%g %g %g %g'", rotaxis[0], rotaxis[1], rotaxis[2], -acos(dp)); } fprintf(outfile, ">\n"); fprintf(outfile, " <Shape>\n"); fprintf(outfile, " "); write_cindexmaterial(colorIndex, materialIndex); // draw the cone fprintf(outfile, " <Cone bottomRadius='%g' height='%g'/>\n", radius, height); fprintf(outfile, " </Shape>\n"); fprintf(outfile, "</Transform>\n"); }
void Window::setUpCamera() { //camera setup GLfloat eyeMinusLook[3] = { look[0], look[1], look[2] }; GLfloat eyePlusOffset[3] = { eye[0]+eyeoffset[0], eye[1]+eyeoffset[1], eye[2] }; vec_normalize( eyeMinusLook ); float u[3], v[3]; vec_cross(u, up, eyeMinusLook); vec_normalize(u); vec_cross(v, eyeMinusLook, u); float cam_mat[] = { u[0], v[0], eyeMinusLook[0], 0, u[1], v[1], eyeMinusLook[1], 0, u[2], v[2], eyeMinusLook[2], 0, -dot(u, eyePlusOffset), -dot(v, eyePlusOffset), -dot(eyeMinusLook, eyePlusOffset), 1 }; for(int i = 0; i < 16; i++) { v_matrix[i] = cam_mat[i]; } }
static void midpoint (float *out, float *a, float *b) { out[0] = (a[0] + b[0]) / 2.0; out[1] = (a[1] + b[1]) / 2.0; out[2] = (a[2] + b[2]) / 2.0; vec_normalize (&out[0], &out[0]); }
color_t getPixel(float x, float y, intersect_t *intersect) { intersect->t = -1; x = (x + 0.5) * 2 / width - 1; y = -((y + 0.5) * 2 / height - 1); point_t pixelPos = point_new(x, y, -2); vec_t rayDirection = vec_normalize(point_direction(cameraPos, pixelPos)); ray_t ray = ray_new(cameraPos, rayDirection); return shootRay(ray, intersect, 0); }
void Window::moveRight() { float right[3]; vec_cross(right, up, look); vec_normalize(right); eye[0] += (right[0] * STEPSIZE); eye[1] += (right[1] * STEPSIZE); eye[2] += (right[2] * STEPSIZE); setUpCamera(); }
void Window::moveDown() { float temp[3] = { look[0], look[1], look[2] }; vec_normalize(temp); eye[0] += (temp[0] * STEPSIZE); eye[1] += (temp[1] * STEPSIZE); eye[2] += (temp[2] * STEPSIZE); setUpCamera(); }
void Window::moveLeft() { float left[3]; vec_cross(left, look, up); vec_normalize(left); eye[0] += (left[0] * STEPSIZE); eye[1] += (left[1] * STEPSIZE); eye[2] += (left[2] * STEPSIZE); setUpCamera(); }
// draw a line from a to b void POV3DisplayDevice::line(float *a, float*b) { int i, j, test; float dirvec[3], unitdirvec[3]; float from[3], to[3], tmp1[3], tmp2[3]; if (lineStyle == ::SOLIDLINE) { // transform the world coordinates (transMat.top()).multpoint3d(a, from); (transMat.top()).multpoint3d(b, to); // write_materials(); // Draw the line fprintf(outfile, "VMD_line(<%.4f,%.4f,%.4f>,<%.4f,%.4f,%.4f>,", from[0], from[1], -from[2], to[0], to[1], -to[2]); fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n", matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2], 1 - mat_opacity); } else if (lineStyle == ::DASHEDLINE) { // transform the world coordinates (transMat.top()).multpoint3d(a, tmp1); (transMat.top()).multpoint3d(b, tmp2); // how to create a dashed line vec_sub(dirvec, tmp2, tmp1); // vector from a to b vec_copy(unitdirvec, dirvec); vec_normalize(unitdirvec); // unit vector from a to b test = 1; i = 0; while (test == 1) { for (j=0; j<3; j++) { from[j] = (float) (tmp1[j] + (2*i)*DASH_LENGTH*unitdirvec[j]); to[j] = (float) (tmp1[j] + (2*i + 1)*DASH_LENGTH*unitdirvec[j]); } if (fabsf(tmp1[0] - to[0]) >= fabsf(dirvec[0])) { vec_copy(to, tmp2); test = 0; } // write_materials(); // Draw the line fprintf(outfile, "VMD_line(<%.4f,%.4f,%.4f>,<%.4f,%.4f,%.4f>,", from[0], from[1], -from[2], to[0], to[1], -to[2]); fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n", matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2], 1 - mat_opacity); i++; } } else { msgErr << "POV3DisplayDevice: Unknown line style " << lineStyle << sendmsg; } }
/* Return the discrete pdf law associated with the Generalized Gaussian of parameters gamma, beta and C */ vec source_pdf_GG (vec symbols, double alpha, double beta) { idx_t i; vec pdf = vec_new_zeros (vec_length (symbols)); for (i = 0; i < vec_length (symbols); i++) pdf[i] = GenGaussian (alpha, beta, symbols[i]); vec_normalize (pdf, 1); return pdf; }
void p_eff_expl_particle(PARTICLE *p) { p.bmap = bmapExplParticle; p.angle = random(360); vec_for_angle(vecEffectsTemp, vector(p.angle, 0, 0 )); vec_rotate(vecEffectsTemp, vector(camera.pan, camera.tilt-90, 0)); vec_normalize(vecEffectsTemp, 10+random(50)); vec_add(p.x, vecEffectsTemp); if (random(2) > 1) { vec_set(vecEffectsTemp, vector( 1, 0, 0 )); vec_rotate(vecEffectsTemp, vector(camera.pan, camera.tilt+90, 0)); vec_normalize(vecEffectsTemp, 10+random(5)); vec_set(p.vel_x, vecEffectsTemp); } p.vel_z *= random(1); p.size = 5 ; p.alpha = 50 ; p.flags |= TRANSLUCENT | MOVE; p.event = p_eff_expl_particle_fade; }
void effEbBlood (VECTOR* pos, VECTOR* vecVel, var pSpeed, BOOL bInverse, int num, double scale) { vec_normalize(vecVel, pSpeed); if (bInverse) vec_scale(vecVel, -1); g_effEbBloodScale = scale; effect(effEbBlood_p, num, pos, vecVel); }
static vec3 randomVector(void) { vec3 v; v.x = rand()/(float)RAND_MAX - 0.5f; v.y = rand()/(float)RAND_MAX - 0.5f; v.z = rand()/(float)RAND_MAX - 0.5f; vec_normalize(&v, &v); return (v); }
// put in new data, and put the command void DispCmdTriangle::putdata(const float *p1, const float *p2, const float *p3, VMDDisplayList *dobj) { int i; float tmp1[3], tmp2[3], tmp3[3]; // precompute the normal for for (i=0; i<3; i++) { // faster drawings later tmp1[i] = p2[i] - p1[i]; tmp2[i] = p3[i] - p2[i]; } cross_prod( tmp3, tmp1, tmp2); vec_normalize(tmp3); set_array(p1, p2, p3, tmp3, tmp3, tmp3, dobj); }