/* * f15demo.c — F-15C Eagle body viewer (OpenGL 1.1 + GLUT) * * Not a flight sim. Orbit a 3D F-15 built from F-15C planform * proportions (length/span/height ~ 63.8 / 42.8 / 18.5 ft). * * GNU/Linux (Hawthorne): * gcc -O2 -o f15demo f15demo.c -lglut -lGLU -lGL -lm * ./f15demo * * That binary will NOT run on the Ultra 5. Different CPU and ABI. * Copy this .c file to the Sun and compile there: * * gcc -O2 -o f15demo f15demo.c \ * -I/usr/openwin/include -L/usr/openwin/lib -Wl,-R,/usr/openwin/lib \ * -lglut -lGLU -lGL -lX11 -lXext -lm * * Optional real mesh: * ./f15demo F-15.obj * * Keys: w wire s solid h hidden-line a auto r reset +/- zoom q quit * Mouse: left orbit, right zoom */ #include #include #include #include #include #ifdef __APPLE__ #include #else #include #endif #ifndef M_PI #define M_PI 3.14159265358979323846 #endif enum { MODE_WIRE = 0, MODE_SOLID = 1, MODE_HIDDEN = 2 }; static int g_mode = MODE_WIRE; static int g_auto = 1; static float g_yaw = 40.0f; static float g_pitch = 16.0f; static float g_dist = 7.4f; static int g_last_x, g_last_y, g_btn = -1; static int g_width = 960, g_height = 700; static float *g_obj_v = NULL; static int *g_obj_i = NULL; static int g_obj_nv = 0, g_obj_ni = 0; static int g_have_obj = 0; static float g_obj_cx, g_obj_cy, g_obj_cz, g_obj_scale = 1.0f; static void v3(float x, float y, float z) { glVertex3f(x, y, z); } #define SEGS 16 static void ring_point(float x, float y, float z, float w, float h, int i, int n, float *ox, float *oy, float *oz) { float a = (float)i / (float)n * 2.0f * (float)M_PI; float c = (float)cos(a); float s = (float)sin(a); float k = 0.82f + 0.18f * (float)fabs(c); *ox = x; *oy = y + s * h * 0.5f * k; *oz = z + c * w * 0.5f; } static void loft(float x0, float y0, float z0, float w0, float h0, float x1, float y1, float z1, float w1, float h1) { int i; glBegin(GL_QUADS); for (i = 0; i < SEGS; i++) { float ax, ay, az, bx, by, bz, cx, cy, cz, dx, dy, dz; ring_point(x0, y0, z0, w0, h0, i, SEGS, &ax, &ay, &az); ring_point(x0, y0, z0, w0, h0, i + 1, SEGS, &bx, &by, &bz); ring_point(x1, y1, z1, w1, h1, i + 1, SEGS, &cx, &cy, &cz); ring_point(x1, y1, z1, w1, h1, i, SEGS, &dx, &dy, &dz); v3(ax, ay, az); v3(bx, by, bz); v3(cx, cy, cz); v3(dx, dy, dz); } glEnd(); } static void disc(float x, float y, float z, float w, float h, int flip) { int i; float cx, cy, cz; glBegin(GL_TRIANGLE_FAN); v3(x, y, z); if (!flip) { for (i = 0; i <= SEGS; i++) { ring_point(x, y, z, w, h, i, SEGS, &cx, &cy, &cz); v3(cx, cy, cz); } } else { for (i = SEGS; i >= 0; i--) { ring_point(x, y, z, w, h, i, SEGS, &cx, &cy, &cz); v3(cx, cy, cz); } } glEnd(); } static void quad4(float ax, float ay, float az, float bx, float by, float bz, float cx, float cy, float cz, float dx, float dy, float dz) { glBegin(GL_QUADS); v3(ax, ay, az); v3(bx, by, bz); v3(cx, cy, cz); v3(dx, dy, dz); glEnd(); } static void panel(float xle_root, float xte_root, float z_root, float xle_tip, float xte_tip, float z_tip, float y, float thick) { float yt = y + thick * 0.5f, yb = y - thick * 0.5f; quad4(xle_root, yt, z_root, xle_tip, yt, z_tip, xte_tip, yt, z_tip, xte_root, yt, z_root); quad4(xle_root, yb, z_root, xte_root, yb, z_root, xte_tip, yb, z_tip, xle_tip, yb, z_tip); quad4(xle_root, yb, z_root, xle_tip, yb, z_tip, xle_tip, yt, z_tip, xle_root, yt, z_root); quad4(xte_root, yb, z_root, xte_root, yt, z_root, xte_tip, yt, z_tip, xte_tip, yb, z_tip); quad4(xle_tip, yb, z_tip, xte_tip, yb, z_tip, xte_tip, yt, z_tip, xle_tip, yt, z_tip); } static void vtail(float xr_le, float xr_te, float yr, float xt_le, float xt_te, float yt, float z, float thick, float cant) { float z0 = z - thick * 0.5f; float z1 = z + thick * 0.5f + cant; quad4(xr_le, yr, z1, xr_te, yr, z1, xt_te, yt, z1, xt_le, yt, z1); quad4(xr_te, yr, z0, xr_le, yr, z0, xt_le, yt, z0, xt_te, yt, z0); quad4(xr_le, yr, z0, xr_le, yr, z1, xt_le, yt, z1, xt_le, yt, z0); quad4(xr_te, yr, z1, xr_te, yr, z0, xt_te, yt, z0, xt_te, yt, z1); quad4(xt_le, yt, z0, xt_le, yt, z1, xt_te, yt, z1, xt_te, yt, z0); } static void draw_f15(void) { loft(-2.28f, 0.06f, 0.f, 0.010f, 0.010f, -2.18f, 0.06f, 0.f, 0.028f, 0.028f); loft(-2.18f, 0.06f, 0.f, 0.028f, 0.028f, -1.72f, 0.05f, 0.f, 0.22f, 0.20f); loft(-1.72f, 0.05f, 0.f, 0.22f, 0.20f, -1.35f, 0.05f, 0.f, 0.32f, 0.28f); loft(-1.35f, 0.04f, 0.f, 0.32f, 0.28f, -0.85f, 0.03f, 0.f, 0.42f, 0.34f); loft(-1.22f, 0.22f, 0.f, 0.16f, 0.10f, -0.92f, 0.30f, 0.f, 0.22f, 0.16f); loft(-0.92f, 0.30f, 0.f, 0.22f, 0.16f, -0.55f, 0.32f, 0.f, 0.24f, 0.18f); loft(-0.55f, 0.32f, 0.f, 0.24f, 0.18f, -0.18f, 0.20f, 0.f, 0.20f, 0.08f); loft(-0.85f, 0.03f, 0.f, 0.42f, 0.34f, -0.15f, 0.02f, 0.f, 0.70f, 0.36f); loft(-0.15f, 0.02f, 0.f, 0.70f, 0.36f, 0.70f, 0.00f, 0.f, 0.86f, 0.38f); loft(0.70f, 0.00f, 0.f, 0.86f, 0.38f, 1.45f, 0.00f, 0.f, 0.90f, 0.36f); loft(-0.78f, -0.10f, 0.24f, 0.26f, 0.18f, 0.20f, -0.08f, 0.30f, 0.30f, 0.20f); loft(-0.78f, -0.10f, -0.24f, 0.26f, 0.18f, 0.20f, -0.08f, -0.30f, 0.30f, 0.20f); disc(-0.78f, -0.10f, 0.24f, 0.26f, 0.18f, 1); disc(-0.78f, -0.10f, -0.24f, 0.26f, 0.18f, 1); loft(1.20f, -0.02f, 0.23f, 0.34f, 0.32f, 1.95f, -0.02f, 0.23f, 0.32f, 0.30f); loft(1.20f, -0.02f, -0.23f, 0.34f, 0.32f, 1.95f, -0.02f, -0.23f, 0.32f, 0.30f); loft(1.95f, -0.02f, 0.23f, 0.32f, 0.30f, 2.16f, -0.02f, 0.23f, 0.28f, 0.26f); loft(1.95f, -0.02f, -0.23f, 0.32f, 0.30f, 2.16f, -0.02f, -0.23f, 0.28f, 0.26f); disc(2.16f, -0.02f, 0.23f, 0.22f, 0.20f, 0); disc(2.16f, -0.02f, -0.23f, 0.22f, 0.20f, 0); disc(2.16f, -0.02f, 0.23f, 0.28f, 0.26f, 0); disc(2.16f, -0.02f, -0.23f, 0.28f, 0.26f, 0); panel(-0.20f, 1.38f, 0.40f, 0.58f, 1.08f, 1.52f, 0.07f, 0.050f); panel(-0.20f, 1.38f, -0.40f, 0.58f, 1.08f, -1.52f, 0.07f, 0.050f); panel(-0.70f, 0.15f, 0.18f, -0.20f, 0.40f, 0.42f, 0.06f, 0.040f); panel(-0.70f, 0.15f, -0.18f, -0.20f, 0.40f, -0.42f, 0.06f, 0.040f); loft(0.55f, 0.07f, 1.50f, 0.06f, 0.05f, 1.05f, 0.07f, 1.52f, 0.05f, 0.04f); loft(0.55f, 0.07f, -1.50f, 0.06f, 0.05f, 1.05f, 0.07f, -1.52f, 0.05f, 0.04f); vtail(1.05f, 1.62f, 0.16f, 1.38f, 1.68f, 1.02f, 0.38f, 0.040f, 0.06f); vtail(1.05f, 1.62f, 0.16f, 1.38f, 1.68f, 1.02f, -0.38f, 0.040f, -0.06f); panel(1.18f, 1.92f, 0.38f, 1.48f, 1.88f, 1.18f, 0.04f, 0.032f); panel(1.18f, 1.92f, -0.38f, 1.48f, 1.88f, -1.18f, 0.04f, 0.032f); vtail(1.18f, 1.48f, -0.14f, 1.38f, 1.52f, -0.46f, 0.30f, 0.028f, 0.f); vtail(1.18f, 1.48f, -0.14f, 1.38f, 1.52f, -0.46f, -0.30f, 0.028f, 0.f); loft(0.25f, 0.20f, 0.f, 0.18f, 0.03f, 0.85f, 0.20f, 0.f, 0.16f, 0.03f); } static int load_obj(const char *path) { FILE *fp; char line[1024]; float *v = NULL; int *idx = NULL; int nv = 0, ni = 0, vcap = 0, icap = 0; float minx=1e9f,miny=1e9f,minz=1e9f, maxx=-1e9f,maxy=-1e9f,maxz=-1e9f; float dx, dy, dz, m; fp = fopen(path, "r"); if (!fp) return 0; while (fgets(line, sizeof(line), fp)) { if (line[0] == 'v' && isspace((unsigned char)line[1])) { float x, y, z; if (sscanf(line + 1, "%f %f %f", &x, &y, &z) == 3) { if (nv + 3 > vcap) { vcap = vcap ? vcap * 2 : 1024; v = (float *)realloc(v, (size_t)vcap * sizeof(float)); if (!v) { fclose(fp); return 0; } } v[nv++] = x; v[nv++] = y; v[nv++] = z; if (x < minx) minx = x; if (x > maxx) maxx = x; if (y < miny) miny = y; if (y > maxy) maxy = y; if (z < minz) minz = z; if (z > maxz) maxz = z; } } else if (line[0] == 'f' && isspace((unsigned char)line[1])) { int verts[64], n = 0; char *p = line + 1; while (*p && n < 64) { int vi; while (*p && isspace((unsigned char)*p)) p++; if (!*p || *p == '\n') break; if (sscanf(p, "%d", &vi) == 1) { if (vi < 0) vi = (nv / 3) + vi + 1; verts[n++] = vi - 1; } while (*p && !isspace((unsigned char)*p)) p++; } if (n >= 3) { int t; for (t = 1; t < n - 1; t++) { if (ni + 3 > icap) { icap = icap ? icap * 2 : 2048; idx = (int *)realloc(idx, (size_t)icap * sizeof(int)); if (!idx) { fclose(fp); return 0; } } idx[ni++] = verts[0]; idx[ni++] = verts[t]; idx[ni++] = verts[t + 1]; } } } } fclose(fp); if (nv < 9 || ni < 3) { free(v); free(idx); return 0; } dx = maxx - minx; dy = maxy - miny; dz = maxz - minz; m = dx; if (dy > m) m = dy; if (dz > m) m = dz; if (m < 1e-6f) m = 1.0f; g_obj_v = v; g_obj_i = idx; g_obj_nv = nv / 3; g_obj_ni = ni; g_obj_cx = (minx + maxx) * 0.5f; g_obj_cy = (miny + maxy) * 0.5f; g_obj_cz = (minz + maxz) * 0.5f; g_obj_scale = 4.4f / m; g_have_obj = 1; fprintf(stderr, "loaded %s (%d verts, %d tris)\n", path, g_obj_nv, g_obj_ni / 3); return 1; } static void draw_obj(void) { int t; glPushMatrix(); glScalef(g_obj_scale, g_obj_scale, g_obj_scale); glTranslatef(-g_obj_cx, -g_obj_cy, -g_obj_cz); glBegin(GL_TRIANGLES); for (t = 0; t < g_obj_ni; t++) { float *p = g_obj_v + g_obj_i[t] * 3; v3(p[0], p[1], p[2]); } glEnd(); glPopMatrix(); } static void draw_model(void) { if (g_have_obj) draw_obj(); else draw_f15(); } static void draw_scene(void) { if (g_mode == MODE_WIRE) { glDisable(GL_LIGHTING); glDisable(GL_POLYGON_OFFSET_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3f(0.25f, 0.95f, 0.45f); glLineWidth(1.0f); draw_model(); } else if (g_mode == MODE_SOLID) { GLfloat amb[4] = { 0.16f, 0.18f, 0.20f, 1 }; GLfloat diff[4] = { 0.55f, 0.60f, 0.64f, 1 }; GLfloat spec[4] = { 0.30f, 0.32f, 0.34f, 1 }; glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_LIGHTING); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diff); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 24.0f); glColor3f(0.70f, 0.74f, 0.78f); draw_model(); } else { glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.0f, 1.0f); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_LIGHTING); glColor3f(0.03f, 0.04f, 0.06f); draw_model(); glDisable(GL_POLYGON_OFFSET_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3f(0.30f, 0.95f, 0.50f); glLineWidth(1.0f); draw_model(); } glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } static void display(void) { int i; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.f, -0.15f, -g_dist); glRotatef(g_pitch, 1, 0, 0); glRotatef(g_yaw, 0, 1, 0); glDisable(GL_LIGHTING); glColor3f(0.10f, 0.16f, 0.14f); glBegin(GL_LINES); for (i = -8; i <= 8; i++) { v3(i * 0.5f, -0.70f, -4.f); v3(i * 0.5f, -0.70f, 4.f); v3(-4.f, -0.70f, i * 0.5f); v3( 4.f, -0.70f, i * 0.5f); } glEnd(); draw_scene(); glutSwapBuffers(); } static void reshape(int w, int h) { g_width = w; g_height = h < 1 ? 1 : h; glViewport(0, 0, g_width, g_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(40.0, (double)g_width / (double)g_height, 0.2, 50.0); glMatrixMode(GL_MODELVIEW); } static void idle(void) { if (g_auto) { g_yaw += 0.32f; if (g_yaw > 360.f) g_yaw -= 360.f; glutPostRedisplay(); } } static void keyboard(unsigned char key, int x, int y) { (void)x; (void)y; switch (key) { case 'w': case 'W': g_mode = MODE_WIRE; break; case 's': case 'S': g_mode = MODE_SOLID; break; case 'h': case 'H': g_mode = MODE_HIDDEN; break; case 'a': case 'A': g_auto = !g_auto; break; case 'r': case 'R': g_yaw = 40.f; g_pitch = 16.f; g_dist = 7.4f; break; case '+': case '=': g_dist -= 0.25f; if (g_dist < 2.4f) g_dist = 2.4f; break; case '-': case '_': g_dist += 0.25f; if (g_dist > 18.f) g_dist = 18.f; break; case 27: case 'q': case 'Q': exit(0); default: return; } glutPostRedisplay(); } static void mouse(int button, int state, int x, int y) { if (state == GLUT_DOWN) { g_btn = button; g_last_x = x; g_last_y = y; g_auto = 0; } else g_btn = -1; } static void motion(int x, int y) { int dx = x - g_last_x, dy = y - g_last_y; g_last_x = x; g_last_y = y; if (g_btn == GLUT_LEFT_BUTTON) { g_yaw += dx * 0.4f; g_pitch += dy * 0.4f; if (g_pitch > 89.f) g_pitch = 89.f; if (g_pitch < -89.f) g_pitch = -89.f; glutPostRedisplay(); } else if (g_btn == GLUT_RIGHT_BUTTON) { g_dist += dy * 0.02f; if (g_dist < 2.4f) g_dist = 2.4f; if (g_dist > 18.f) g_dist = 18.f; glutPostRedisplay(); } } static void init_gl(void) { GLfloat pos[4] = { 5.f, 8.f, 6.f, 0.f }; GLfloat amb[4] = { 0.22f, 0.22f, 0.25f, 1 }; GLfloat diff[4] = { 0.85f, 0.85f, 0.80f, 1 }; glClearColor(0.015f, 0.02f, 0.04f, 1); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glShadeModel(GL_SMOOTH); glEnable(GL_NORMALIZE); glLightfv(GL_LIGHT0, GL_POSITION, pos); glLightfv(GL_LIGHT0, GL_AMBIENT, amb); glLightfv(GL_LIGHT0, GL_DIFFUSE, diff); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(g_width, g_height); glutCreateWindow("F-15C Eagle — w wire s solid h hidden a rotate"); init_gl(); if (argc > 1) { if (!load_obj(argv[1])) fprintf(stderr, "could not load %s, using built-in F-15\n", argv[1]); } glutDisplayFunc(display); glutReshapeFunc(reshape); glutIdleFunc(idle); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(motion); fprintf(stderr, "F-15C body viewer\n" " w wire s solid h hidden-line a auto-rotate\n" " r reset +/- zoom q quit left-drag orbit\n" " optional: %s file.obj\n", argv[0]); glutMainLoop(); return 0; }