/* vrmlview.C: simple VRML'97 model viewer */ #include "xrml.H" #include "oglrenderer.H" #include "ui.h" #include "uit.h" #include "render.h" #include "camera.h" #include "canvas.h" #include "matrix.H" #include "world.H" #include "vrml2_utf8/parser.H" #include "vrml2_utf8/exporter.H" #ifdef PLY #include "ply/importer.H" #endif #ifdef CSO #include "cso/importer.H" #endif #include "error.H" #include #include #include #include "options.h" static char* progname = 0; static double start_time = 0.; static class world *wrl = 0; static class opengl_renderer* render = 0; static bool first_frame = false; typedef enum IN_FILTER { IN_VRML, IN_PLY, IN_CSO } IN_FILTER; static ENUMDESC inFiltVals[] = { { IN_VRML, "vrml", 4 }, { IN_PLY, "ply" , 3 }, { IN_CSO, "so", 3 }, { 0, NULL, 0 } // sentinel }; MakeEnumOptTypeStruct(inFiltTypeStruct, inFiltVals); #define TInFilt (&inFiltTypeStruct) static xrml::importer* the_importer = 0; static void no_support(char *what) { xrml::Fatal(-1, NULL, "%s has been compiled without %s support", progname, what); } static void SetImporter(void *value) { IN_FILTER which = *(IN_FILTER*)value; switch (which) { case IN_VRML: the_importer = new vrml2_utf8::parser; break; case IN_PLY: #ifdef PLY the_importer = new ply::importer; #else no_support("ply input"); #endif break; case IN_CSO: #ifdef CSO the_importer = new cso::importer; #else no_support("C++/so input"); #endif break; default: cerr << "Unrecognized import filter identification number " << which << "\n"; exit(-1); } } // forward declaration static void ShowUsage(void*); static void SetIfsHackOpt(void* value) { renderopts.ifs_hack = TRUE; } static CMDLINEOPTDESC options[] = { {"-input-file-format", 2, TInFilt, NULL, SetImporter, "-input-file-format vrml|ply : input file format"}, {"-hack", 3, TYPELESS, NULL, SetIfsHackOpt, "-hack : hack for faster IndexedFaceSet rendering"}, {"-help", 3, TYPELESS, NULL, ShowUsage, "-help : explain usage of this program"}, {NULL , 0, TYPELESS, NULL, DEFAULT_ACTION, NULL} // sentinel }; static void ShowUsage(void*) { fprintf(stdout, "%s: quick and dirty 3D model viewer.\n", progname); fprintf(stdout, "\n"); fprintf(stdout, "Usage:\n"); fprintf(stdout, "\n"); fprintf(stdout, "\t%s [options] [input-file-names]\n", progname); fprintf(stdout, "\n"); fprintf(stdout, "Options:\n"); fprintf(stdout, "\n"); PrintOptions(stdout, options); fprintf(stdout, "\n"); fprintf(stdout, "%s reads the input files in order, converting them to\n", progname); fprintf(stdout, "an XRML scene graph and displays them. If no input files are\n"); fprintf(stdout, "given on the command line, input files still can be opened\n"); fprintf(stdout, "using the menus in the program.\n"); fprintf(stdout, "\n"); fprintf(stdout, "Note: not all input/output file formats listed above may be supported.\n"); fprintf(stdout, "\n"); exit(0); } // returns number of seconds since Januari, 1st, 1970. double get_time(void) { struct timeval t; struct timezone tz = {0, 0}; gettimeofday(&t, &tz); return (double)t.tv_sec + (double)t.tv_usec * 1e-6; } static double last_frame_time = 0.; double get_frame_time(void) { if (renderopts.animate) return last_frame_time = get_time(); else return last_frame_time; } void SetDefaultRenderOptions(void) { #ifndef DEFAULT_GAMMA #define DEFAULT_GAMMA 1.0 #endif RENDEROPTIONS default_renderopts = { FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, BC_ON, RED, YELLOW, BLACK, DEFAULT_GAMMA, 0., false }; renderopts = default_renderopts; } void SetDefaultCamera(void) { VECTOR eyep = {0., 0., 10.}, centre = {0., 0., 0.}, up = {0., 1., 0.}; RGB Black = BLACK; CameraSet(&Camera, &eyep, ¢re, &up, 45.0/2., -1, -1, &Black); } void SetBackfaceCulling(int mode) { renderopts.backface_culling = (BACKFACECULLINGMODE)mode; render->dynamicBackfaceCulling = (mode == BC_DYNAMIC); } void ReadScene(int nrfiles, char **fname) { if (wrl) delete wrl; wrl = new class world; // import the scene graph from the input files if (!the_importer) the_importer = new vrml2_utf8::parser; for (int i=0; iinstantiate(); cerr << "Parsing " << fname[i] << "\n"; if (!wrl->parse(fname[i], start_time, imp)) break; delete imp; } delete the_importer; if (!wrl->sceneGraph) // read the file. return; wrl->set_renderer(render); // get default viewpoint render->default_view = wrl->stacks->viewpoint.top(); NavigationInfo* ninfo = wrl->stacks->navigationInfo.top(); if (ninfo->headlight) renderopts.enable_headlight = TRUE; // initialize world bounding box render->min = Vec3(HUGE, HUGE, HUGE); render->max = Vec3(-HUGE, -HUGE, -HUGE); first_frame = true; RenderScene(); } CAMERA ViewCamera(Viewpoint *view) { CAMERA cam; Vec3 eye, centre, up; Mat4 view_orientation; view_orientation.rotate(Vec4(view->orientation)); eye = Vec3(view->position); centre = Vec3(0., 0., -10) * view_orientation + eye; up = Vec3(0., 1., 0.) * view_orientation; VECTOR ceyep = {eye.x, eye.y, eye.z}, clookp = {centre.x, centre.y, centre.z}, cupdir = {0., 1., 0.}; CameraSet(&cam, &ceyep, &clookp, &cupdir, view->fieldOfView * 180./M_PI / 2., Camera.hres, Camera.vres, &Camera.background); return cam; } void SetDefaultView(void) { if (wrl && wrl->stacks) Camera = ViewCamera(wrl->stacks->viewpoint.top()); } void SetPredefinedViews(void) { int i, nr = render->views.size; CAMERA *cams; cams = new CAMERA[nr]; char **descr; descr = new char *[nr]; for (i=0; iviews[i]); descr[i] = (char *)render->views[i]->description; } CreatePredefViewButtons(nr, cams, descr); delete[] cams; delete[] descr; } void SetInfo(void) { if (render->winfo) SetModelInfo((char *)render->winfo->title); else SetModelInfo("No model info"); } void RenderScene(void) { double start_render_time = get_time(); if (!RenderStartFrame()) return; if (first_frame) { start_time = wrl->time; } render->enable_headlight = renderopts.enable_headlight; render->disable_textures = renderopts.disable_textures; render->use_dlists = renderopts.use_display_lists; render->draw_outlines = renderopts.draw_outlines; CanvasPushMode(CANVASMODE_RENDER); if (wrl && wrl->sceneGraph) { Viewpoint *vp = render->default_view; Vec3 oldmin = render->min, oldmax = render->max; if (first_frame) { render->first_frame = true; wrl->set_time(last_frame_time = get_time()); start_time = wrl->time; wrl->newframe(); // render with time of parsing render->ninfo = 0; wrl->render(); SetPredefinedViews(); SetInfo(); SetDefaultView(); render->first_frame = first_frame = false; } wrl->set_time(get_frame_time()); wrl->newframe(); wrl->render(); if (!vp || render->min != oldmin || render->max != oldmax) { BOUNDINGBOX bounds = {render->min.x, render->min.y, render->min.z, render->max.x, render->max.y, render->max.z}; RenderSetBoundingBox(bounds); // clipping planes need to be changed ... RenderStartFrame(); wrl->render(); } RenderEndFrame(); } double render_time = get_time() - start_render_time; if (render_time > 0.) { char buf[100]; sprintf(buf, "vv: %.3g fps", 1./render_time); SetDialogTitle(topLevel, buf); } CanvasPullMode(); } int main(int argc, char **argv) { SetInfoCallback(printmsg); render = new opengl_renderer; char *slash = strrchr(argv[0], '/'); progname = slash ? slash+1 : argv[0]; // ParseOptions removes the arguments from argc/argv that // it recognizes. ParseOptions(options, &argc, argv); if (argc > 1) ReadScene(argc-1, argv+1); SetDefaultRenderOptions(); SetDefaultCamera(); StartUserInterface(argc, argv); return 0; /* StartUserInterface() actually never returns. */ }