/* starbase.c: graphics driver for HP/starbase. Tested only with a CRX48Z * graphics adapter. */ /* define the DLISTS symbol if you want to compile in display list support. * I had problems with it: delete_segment and refresh_segment were not * found during linking. Strange, isn't it ??? [PhB, 21 Aug 98] */ /* #define DLISTS */ #include #include #include "render.h" #include "canvas.h" #include "camera.h" #include "error.h" #include "pools.h" #include "scene.h" #include "radiance.h" #include "image.h" /* starbase file descriptor and nr of passes needed to render something */ static int fildes=-1, passes, buf; static int sbinited = FALSE; static int dlistid = -1; /* finds the visual and colormap to be used for Iris GL rendering on the specified * screen */ Boolean RenderGetVisualInfoAndColormap(Screen *screen, XVisualInfo *visual_info, Colormap *colormap) { return False; /* no non-default visual required */ } /* starbase initialisation */ void RenderInitWindow(Display *display, Window window, XVisualInfo *visinfo) { if (fildes < 0) { /* This will e.g. be the case for external canvas windows. * Try to initialize starbase on it. */ char *path = make_X11_gopen_string(display, window); fildes = gopen(path, OUTDEV, NULL, INIT|THREE_D|MODEL_XFORM|ACCELERATED); if (fildes < 0) { /* really can't open starbase, sorry! */ Error(NULL, "Error initializing starbase:\n%s", strerror(errno)); return; } } clip_indicator(fildes,CLIP_TO_VIEWPORT); clear_control(fildes,CLEAR_VIEWPORT); /* 24-bit colors with shading */ shade_mode(fildes, CMAP_FULL|INIT, FALSE); clear_control(fildes,CLEAR_DISPLAY_SURFACE|CLEAR_ZBUFFER); background_color(fildes, Camera.background.r, Camera.background.g, Camera.background.b); /* enable double buffering */ double_buffer(fildes, TRUE|INIT, 24 /*bitplanes for each buffer*/); buf = 0; /* Use the hardware Z-buffer and backface culling if wanted. */ passes = hidden_surface(fildes, TRUE, renderopts.backface_culling); sbinited = TRUE; dlistid = -1; } static void StarbaseInitCallback(Widget canvas, XtPointer client_data, XtPointer call_data) { XtVaGetValues(canvas, XgNfildes, &fildes, NULL); RenderInitWindow(XtDisplay(canvas), XtWindow(canvas), NULL); XtRemoveCallback(canvas, XmNexposeCallback, StarbaseInitCallback, (XtPointer)NULL); } /* invoked when the canvas window is destroyed */ static void StarbaseTerminateCallback(Widget canvas, XtPointer client_data, XtPointer call_data) { gclose(fildes); } /* create window for rendering */ Widget RenderCreateWindow(Widget parent) { Widget canvas; canvas = XtVaCreateManagedWidget("canvas", xgStarbaseWidgetClass, parent, XgNshadeMode, XgCMAP_FULL, XgNopenMode, XgTHREE_D|XgMODEL_XFORM, NULL); /* initialize starbase on first expose event */ sbinited = FALSE; fildes = -1; XtAddCallback(canvas, XmNexposeCallback, StarbaseInitCallback, (XtPointer)NULL); /* window destroy event */ XtAddCallback(canvas, XmNdestroyCallback, StarbaseTerminateCallback, (XtPointer)NULL); return canvas; } /* creates an offscreen window for rendering */ void RenderCreateOffscreenWindow(int hres, int vres) { Fatal(1, NULL, "Offscreen rendering is only supported through the Mesa library.\nRe-link the program with the Mesa library if you want it"); } int RenderInitialized(void) { return sbinited; } /* clear the canvas window and Z buffer */ void RenderClearWindow(void) { hidden_surface(fildes, FALSE, renderopts.backface_culling); vdc_extent(fildes, -0.5, -0.5, 0.0, (float)Camera.hres+0.5, (float)Camera.vres+0.5, 1.0); background_color(fildes, Camera.background.r, Camera.background.g, Camera.background.b); clear_view_surface(fildes); hidden_surface(fildes, TRUE, renderopts.backface_culling); } /* to make a right handed coordinate system */ static float right_handed_coord_matrix[4][4] = { {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0,-1.0, 0.0}, {0.0, 0.0, 0.0, 1.0} }; /* passes the current virtual camera position, focus point, fov etc... * to the graphics hardware */ void RenderSetCamera(void) { camera_arg camera; RenderClearWindow(); /* determine distance to front- and backclipping plane */ RenderGetNearFar(&Camera.near, &Camera.far); camera.camx = Camera.eyep.x; camera.camy = Camera.eyep.y; camera.camz = -Camera.eyep.z; camera.refx = Camera.lookp.x; camera.refy = Camera.lookp.y; camera.refz = -Camera.lookp.z; camera.upx = Camera.updir.x; camera.upy = Camera.updir.y; camera.upz = -Camera.updir.z; camera.front = Camera.near - Camera.viewdist; camera.back = Camera.far - Camera.viewdist; camera.projection = CAM_PERSPECTIVE; camera.field_of_view = Camera.vfov * 2; view_camera(fildes, &camera); view_matrix3d(fildes, right_handed_coord_matrix, PRE_CONCAT_VW); } /* sets the current color */ void RenderSetColor(RGB *rgb) { RGB corrected_rgb; corrected_rgb = *rgb; RGBGAMMACORRECT(corrected_rgb, renderopts.gamma); fill_color(fildes, corrected_rgb.r, corrected_rgb.g, corrected_rgb.b); perimeter_color(fildes, corrected_rgb.r, corrected_rgb.g, corrected_rgb.b); } /* Sets starbase vertex format according to whether flat or gouraud shading is * desired. */ typedef enum {UNDEFINED, FLAT, GOURAUD} SHADEMODEL; static void ShadeModel(SHADEMODEL model) { static int current_shademodel = UNDEFINED; if (model != current_shademodel) { switch (model) { case FLAT: vertex_format(fildes, 0, /* no extra coordinates */ 0, /* no extra coordinates to be used*/ 0, /* rgb */ FALSE, CLOCKWISE); break; case GOURAUD: vertex_format(fildes, 3, /* 3 extra coordinates */ 3, /* use 3 extra coordinates */ 1, /* rgb */ FALSE, /* normal is determined automatically */ CLOCKWISE); /* vertex order - see manpage */ break; default: Fatal(-1, "RenderSwicthMode", "Something dirty wrong here!"); } current_shademodel = model; } } /* sets starbase interior style and draw perimeter flag if different than previous time */ static void InteriorStyle(int style, int peri) { static int current_style=-1, current_peri=-1; if (style!=current_style || peri!=current_peri) { interior_style(fildes, style, peri); current_style = style; current_peri = peri; } } void RenderBeginTriangleStrip(void) { Error("RenderBeginTriangleStrip", "to be implemented"); } void RenderNextTrianglePoint(POINT *point, RGB *col) { } void RenderTriangleStrip(int N,POINT *point, RGB *col) { } void RenderEndTriangleStrip(void) { } /* renders a convex polygon flat shaded in the current color */ void RenderPolygonFlat(int nrverts, POINT *verts) { InteriorStyle(INT_SOLID, FALSE); ShadeModel(FLAT); polygon3d(fildes, (float *)verts, nrverts, FALSE); } /* renders a convex polygon with Gouraud shading */ void RenderPolygonGouraud(int nrverts, POINT *verts, RGB *vertcols) { int i; float clist[256][6]; RGB corrected_rgb; InteriorStyle(INT_SOLID, FALSE); ShadeModel(GOURAUD); for (i=0; inrvertices; i++) { clist[i][0] = patch->vertex[i]->point->x; clist[i][1] = patch->vertex[i]->point->y; clist[i][2] = patch->vertex[i]->point->z; } rgb = patch->color; RGBGAMMACORRECT(rgb, renderopts.gamma); fill_color(fildes, rgb.r, rgb.g, rgb.b); polygon3d(fildes, clist, patch->nrvertices, FALSE); } void RenderPatchFlat(PATCH *patch) { InteriorStyle(INT_SOLID, FALSE); DoRenderPatchFlat(patch); } /* renders the patch as a solid polygon, smooth shaded using the colors computed * for its vertices */ static void DoRenderPatchSmooth(PATCH *patch) { int i; float clist[PATCHMAXVERTICES][6]; RGB corrected_rgb; ShadeModel(GOURAUD); for (i=0; inrvertices; i++) { clist[i][0] = patch->vertex[i]->point->x; clist[i][1] = patch->vertex[i]->point->y; clist[i][2] = patch->vertex[i]->point->z; corrected_rgb = patch->vertex[i]->color; RGBGAMMACORRECT(corrected_rgb, renderopts.gamma); clist[i][3] = corrected_rgb.r; clist[i][4] = corrected_rgb.g; clist[i][5] = corrected_rgb.b; } polygon3d(fildes, clist, patch->nrvertices, FALSE); } void RenderPatchSmooth(PATCH *patch) { InteriorStyle(INT_SOLID, FALSE); DoRenderPatchSmooth(patch); } /* renders the patch outline in the current color */ void RenderPatchOutline(PATCH *patch) { InteriorStyle(INT_HOLLOW, TRUE); DoRenderPatchFlat(patch); } /* renders a patch */ void RenderPatch(PATCH *patch) { if (renderopts.draw_outlines) { RenderSetColor(&renderopts.outline_color); InteriorStyle(INT_SOLID, TRUE); } else InteriorStyle(INT_SOLID, FALSE); if (renderopts.smooth_shading) DoRenderPatchSmooth(patch); else DoRenderPatchFlat(patch); } void RenderNewDisplayList(void) { #ifdef DLISTS /* refresh_segment and delete_segment not found during linking !!! */ if (dlistid >= 0) delete_segment(fildes, dlistid); dlistid = -1; #else static int wgiv = 0; if (!wgiv) { Warning(NULL, "The starbase driver has been compiled without display list support"); wgiv = 1; } #endif renderopts.render_raytraced_image = FALSE; } static void DoRenderScene(void) { if (!Radiance || !Radiance->RenderScene) { if (renderopts.smooth_shading) { PatchListIterate(Patches, DoRenderPatchSmooth); } else { PatchListIterate(Patches, DoRenderPatchFlat); } } else Radiance->RenderScene(); } static void RenderRadiance(void) { hidden_surface(fildes, FALSE, renderopts.backface_culling); double_buffer(fildes, TRUE, 24); passes = hidden_surface(fildes, TRUE, renderopts.backface_culling); RenderSetCamera(); ShadeModel(renderopts.smooth_shading ? GOURAUD : FLAT); if (renderopts.draw_outlines) { RenderSetColor(&renderopts.outline_color); InteriorStyle(INT_SOLID, TRUE); } else InteriorStyle(INT_SOLID, FALSE); #ifdef DLISTS /* refresh_segment and delete_segment not found during linking !!! */ if (renderopts.use_display_lists) { if (dlistid < 0) { dlistid = 1; open_segment(fildes, dlistid, FALSE, TRUE); DoRenderScene(); close_segment(fildes); } else execute_segment(fildes, dlistid); } else #endif DoRenderScene(); if (renderopts.draw_bounding_boxes) RenderBoundingBoxHierarchy(); if (renderopts.draw_clusters) RenderClusterHierarchy(); dbuffer_switch(fildes,buf++); hidden_surface(fildes, FALSE, renderopts.backface_culling); double_buffer(fildes, TRUE|DFRONT, 24); passes = hidden_surface(fildes, TRUE, renderopts.backface_culling); } /* renders the whole scene */ void RenderScene(void) { /* don't draw if starbase has not yet been initialized */ if (!sbinited) return; CanvasPushMode(CANVASMODE_RENDER); if (Camera.changed) renderopts.render_raytraced_image = FALSE; if (!renderopts.render_raytraced_image || !RenderRayTraced()) RenderRadiance(); CanvasPullMode(); } void RenderFinish(void) { /* to be implemented */ } /* renders a line of n pixels starting at column x on row y, used eg while * raytracing */ void RenderPixels(int x, int y, int n, int m, RGB *rgb) { unsigned char *scan[3]; int k, j; RGB corrected_rgb; scan[0] = (unsigned char *)Alloc(n*m); scan[1] = (unsigned char *)Alloc(n*m); scan[2] = (unsigned char *)Alloc(n*m); for (j=0; jx, p->y, p->z); draw3d(fildes, q->x, q->y, q->z); } void RenderAALine(POINT *p, POINT *q) { /* To implement */ RenderLine(p,q); } void SaveScreen(char *fname, FILE *fp, int ispipe) { ImageOutputHandle *img; int i,j,k; unsigned char *scan[3], *buf; if (!fp || !(img = CreateImageOutputHandle(fname, fp, ispipe, Camera.hres, Camera.vres))) return; scan[0] = (unsigned char *)Alloc(Camera.hres); scan[1] = (unsigned char *)Alloc(Camera.hres); scan[2] = (unsigned char *)Alloc(Camera.hres); buf = (unsigned char *)Alloc(3 * Camera.hres); for (i=0; iid )&0xff) / 255.; rgb.g = (float)(((unsigned)patch->id >> 8 )&0xff) / 255.; rgb.b = (float)(((unsigned)patch->id >> 16)&0xff) / 255.; fill_color(fildes, rgb.r ,rgb.g, rgb.b); for (i=0; inrvertices; i++) { clist[i][0] = patch->vertex[i]->point->x; clist[i][1] = patch->vertex[i]->point->y; clist[i][2] = patch->vertex[i]->point->z; } polygon3d(fildes, clist, patch->nrvertices, FALSE); } /* Patch ID rendering. Returns an array of size (*x)*(*y) containing the IDs of * the patches visible through each pixel or 0 if the background is visible through * the pixel. x and y, determining the size of the array are returned. */ unsigned long *RenderIds(long *x, long *y) { unsigned long *ids; *x = *y = 0; /* don't draw if starbase has not yet been initialized */ if (!sbinited) return (unsigned long *)NULL; CanvasPushMode(CANVASMODE_RENDER); hidden_surface(fildes, FALSE, renderopts.backface_culling); double_buffer(fildes, TRUE, 24); passes = hidden_surface(fildes, TRUE, renderopts.backface_culling); RenderSetCamera(); ShadeModel(FLAT); InteriorStyle(INT_SOLID, FALSE); PatchListIterate(Patches, RenderPatchId); dbuffer_switch(fildes,buf++); hidden_surface(fildes, FALSE, renderopts.backface_culling); double_buffer(fildes, TRUE|DFRONT, 24); passes = hidden_surface(fildes, TRUE, renderopts.backface_culling); CanvasPullMode(); ids = GetIds(x, y); RenderScene(); return ids; }