/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ /*********************************************************************/ /* I.B.M. CONFIENTIAL */ /*********************************************************************/ #include /*---------------------------------------------------------------------------*\ $Source: /home/gda/dxcvs/dx/src/exec/hwrender/opengl/hwInteractorEchoOGL.c,v $ These are the Open GL implementations of the direct interactor echos, along with miscellaneous utility routines. Each function needs to be ported to the native graphics API of the target system in order to provide support for direct interactors. Applications such as DX can be ported as a first step without direct interactor facilities by stubbing out everything here. \*---------------------------------------------------------------------------*/ #include "hwDeclarations.h" #include "hwMatrix.h" #include "hwInteractor.h" #include "hwCursorInteractor.h" #include "hwRotateInteractor.h" #include "hwZoomInteractor.h" #include "hwGlobeEchoDef.h" #include "hwPortLayer.h" #include "hwWindow.h" #include "hwPortOGL.h" #include "hwDebug.h" static void _dxf_SET_WORLD_SCREEN (void *ctx, int w, int h) { /* * This routine can be ignored if the API can write directly to DC, * otherwise, it must set up transforms for screen mode. * * The caller of this routine is expected to restore the current * model/view/projection/viewport transforms if necessary. */ ENTRY(("_dxf_SET_WORLD_SCREEN(0x%x, %d, %d)",ctx, w, h)); SET_WORLD_SCREEN(w, h) ; EXIT(("")); } static void _dxf_READ_BUFFER (void *ctx, int llx, int lly, int urx, int ury, void *buff) { /* * DX hardware renderer expects pixels to be packed into 32-bit integers, * so we use GL_RGBA format with a type of GL_UNSIGNED_BYTE. Default * read buffer is GL_BACK, so we must explicitly set GL_FRONT. */ ENTRY(("_dxf_READ_BUFFER (0x%x, %d, %d, %d, %d, 0x%x)", ctx, llx, lly, urx, ury, buff)); #if !defined(alphax) /* * On DEC alpha this call causes the HW window * not to move -- *AND* it's removal seems to * have no effect. */ glReadBuffer(GL_FRONT) ; #endif glReadPixels (llx, lly, (urx-llx)+1, (ury-lly)+1, GL_RGBA, GL_UNSIGNED_BYTE, buff) ; EXIT(("")); } static void _dxf_WRITE_BUFFER (void *ctx, int llx, int lly, int urx, int ury, void *buff) { DEFCONTEXT(ctx) ; /* * DX hardware renderer expects pixels to be packed into 32-bit integers, * so we use GL_RGBA format with a type of GL_UNSIGNED_BYTE. Bitmaps * and images are always placed at the current raster position, which * must be expressed in model/view coordinates. */ ENTRY(("_dxf_WRITE_BUFFER(0x%x, %d, %d, %d, %d, 0x%x)", ctx, llx, lly, urx, ury, buff)); SET_RASTER_SCREEN (llx, lly) ; glDrawPixels ((urx-llx)+1, (ury-lly)+1, GL_RGBA, GL_UNSIGNED_BYTE, buff) ; EXIT(("")); } static void _dxf_BUFFER_CONFIG (void *ctx, void *image, int llx, int lly, int urx, int ury, int *CurrentDisplayMode, int *CurrentBufferMode, tdmInteractorRedrawMode redrawMode) { /* * Direct interactor echos use this and following routine to manage * double buffering. */ ENTRY(("_dxf_BUFFER_CONFIG(0x%x, 0x%x, %d, %d, %d, %d, 0x%x, 0x%x, %d)", ctx, image, llx, lly, urx, ury, CurrentDisplayMode, CurrentBufferMode, redrawMode)); /* record current GL buffer mode */ glGetIntegerv (GL_DRAW_BUFFER, CurrentBufferMode) ; PRINT(("value glGetIntegerv(GL_DRAW_BUFFER) = %d",CurrentBufferMode)); if (redrawMode == tdmBothBufferDraw || redrawMode == tdmFrontBufferDraw) { PRINT(("%s", (redrawMode == tdmBothBufferDraw) ? "tdmBothBufferDraw" : "tdmFrontBufferDraw")); /* * tdmBothBufferDraw is supposed to draw into both the front and * back buffers. This is no longer necessary since we don't swap * buffers when animating the gnomon and globe now. */ glDrawBuffer(GL_FRONT); } else if (redrawMode == tdmBackBufferDraw || redrawMode == tdmViewEchoMode) { PRINT(("%s", (redrawMode == tdmViewEchoMode) ? "tdmViewEchoMode" : "tdmBackBufferDraw")); /* tdmBackBufferDraw is no longer different from tdmViewEchoMode */ glDrawBuffer(GL_BACK) ; } else PRINT(("ignoring redraw mode")) ; EXIT(("")); } static void _dxf_BUFFER_RESTORE_CONFIG (void *ctx, int OrigDisplayMode, int OrigBufferMode, tdmInteractorRedrawMode redrawMode) { /* * Restore frame buffer configuration. */ ENTRY(("_dxf_BUFFER_RESTORE_CONFIG (0x%x, %d, %d, %d)", ctx, OrigDisplayMode, OrigBufferMode, redrawMode)); if (redrawMode == tdmBothBufferDraw || redrawMode == tdmFrontBufferDraw) { PRINT(("current interactor redraw mode is \"%s\"", (redrawMode == tdmFrontBufferDraw) ? "tdmFrontBufferDraw" : "tdmBothBufferDraw")); /* * Call glFlush() so everything written to the front buffer becomes * visible. There's no need to do this if we're currently writing * to the back buffer, as an implicit flush occurs when swapping * the back buffer to the front. */ glFlush() ; if (OrigBufferMode == GL_BACK || OrigBufferMode == GL_BACK_LEFT) { PRINT(("restoring to original back buffer draw")); glDrawBuffer(GL_BACK) ; } else { PRINT(("remaining in original front buffer draw")); } } else if (redrawMode == tdmBackBufferDraw || redrawMode == tdmViewEchoMode) { PRINT(("current interactor redraw mode is \"%s\"", (redrawMode == tdmViewEchoMode) ? "tdmViewEchoMode" : "tdmBackBufferDraw")); if (OrigBufferMode == GL_FRONT || OrigBufferMode == GL_FRONT_LEFT) { PRINT(("restoring to original front buffer draw")); glDrawBuffer(GL_FRONT) ; } else { PRINT(("remaining in original back buffer draw")); } } else { PRINT(("ignoring redraw mode")); } EXIT(("")); } /* sine of arrowhead join angle of 150 degrees */ #define SIN 0.5 /* cosine of arrowhead join angle of 150 degrees */ #define COS -0.8660254 /* length of arrowhead lines relative to axis length */ #define ALENGTH 0.20 #define DRAW_ARROW(axis) \ { \ glBegin(GL_LINES) ; \ glVertex2f (0, 0) ; \ glVertex2fv(axis) ; \ glEnd() ; \ \ axc = axis[0] * COS ; \ axs = axis[0] * SIN ; \ ayc = axis[1] * COS ; \ ays = axis[1] * SIN ; \ \ glBegin(GL_LINE_STRIP) ; \ glVertex2f (axis[0] + ALENGTH*(axc-ays), axis[1] + ALENGTH*(axs+ayc)) ; \ glVertex2fv(axis) ; \ glVertex2f (axis[0] + ALENGTH*(axc+ays), axis[1] + ALENGTH*(ayc-axs)) ; \ glEnd() ; \ } static void _dxf_DRAW_GNOMON (tdmInteractor I, void *udata, float rot[4][4], int draw) { /* * draw == 1 to draw gnomon, draw == 0 to undraw. This is done with * two separate calls in order to support explicit erasure of edges for * some implementations. A draw is always preceded by an undraw and * the pair of invocations is atomic. * * Computations are done in normalized screen coordinates in order to * render arrow heads conveniently. */ DEFDATA(I,tdmRotateData) ; DEFPORT(I_PORT_HANDLE) ; int dummy = 0 ; float xaxis[2], yaxis[2], zaxis[2] ; float xlabel[2], ylabel[2], zlabel[2] ; float axc, ays, axs, ayc ; ENTRY(("_dxf_DRAW_GNOMON (0x%x, 0x%x, 0x%x, %d)", I, udata, rot, draw)); if (PDATA(font) == -1) { PDATA(font) = 0 ; /* 1 pixel in normalized coordinates */ PDATA(nudge) = 1.0/(float)GNOMONRADIUS ; /* approx. font offset for axes labels in normalized coordinates */ PDATA(swidth) = 10 * PDATA(nudge) ; } if (draw) { glColor3f(1.0, 1.0, 1.0) ; glLineWidth(1.0) ; } else { if (PDATA(redrawmode) != tdmViewEchoMode) { /* * In tdmViewEchoMode (DX's Execute On Change), we are drawing * the gnomon echo on top of a background image that is redrawn * with every frame of a direct interaction. * * If we're not in that mode, the background image is static * while the gnomon echo rotates in front of it, so erasing the * gnomon means we have to repair damage to the background. We * do this by blitting a portion of the static image to the * back buffer, drawing the gnomon over that, then blitting the * combined results back to the front buffer. */ /* force graphics output into back buffer */ glDrawBuffer(GL_BACK) ; /* erase gnomon background */ _dxf_WRITE_BUFFER (PORT_CTX, PDATA(illx), PDATA(illy), PDATA(iurx), PDATA(iury), PDATA(background)) ; } /* draw wide black lines to ensure visibility against background */ glColor3f(0.0, 0.0, 0.0) ; glLineWidth(3.0) ; } xaxis[0] = 0.7 * rot[0][0] ; xaxis[1] = 0.7 * rot[0][1] ; yaxis[0] = 0.7 * rot[1][0] ; yaxis[1] = 0.7 * rot[1][1] ; zaxis[0] = 0.7 * rot[2][0] ; zaxis[1] = 0.7 * rot[2][1] ; xlabel[0] = 0.8 * rot[0][0] ; xlabel[1] = 0.8 * rot[0][1] ; ylabel[0] = 0.8 * rot[1][0] ; ylabel[1] = 0.8 * rot[1][1] ; zlabel[0] = 0.8 * rot[2][0] ; zlabel[1] = 0.8 * rot[2][1] ; glPushMatrix() ; glLoadIdentity() ; DRAW_ARROW(xaxis) ; DRAW_ARROW(yaxis) ; DRAW_ARROW(zaxis) ; /* move labels if they interfere with axes rendering */ if (xlabel[0] <= 0) xlabel[0] -= PDATA(swidth) ; if (xlabel[1] <= 0) xlabel[1] -= PDATA(swidth) ; if (ylabel[0] <= 0) ylabel[0] -= PDATA(swidth) ; if (ylabel[1] <= 0) ylabel[1] -= PDATA(swidth) ; if (zlabel[0] <= 0) zlabel[0] -= PDATA(swidth) ; if (zlabel[1] <= 0) zlabel[1] -= PDATA(swidth) ; if (!draw) { /* offset text slightly for shadow */ xlabel[0] += PDATA(nudge) ; xlabel[1] -= PDATA(nudge) ; ylabel[0] += PDATA(nudge) ; ylabel[1] -= PDATA(nudge) ; zlabel[0] += PDATA(nudge) ; zlabel[1] -= PDATA(nudge) ; } glRasterPos2f (xlabel[0], xlabel[1]) ; glCallList('X'+FONTLISTBASE) ; glRasterPos2f (ylabel[0], ylabel[1]) ; glCallList('Y'+FONTLISTBASE) ; glRasterPos2f (zlabel[0], zlabel[1]) ; glCallList('Z'+FONTLISTBASE) ; glPopMatrix() ; if (draw && PDATA(redrawmode) != tdmViewEchoMode) { /* copy rendered gnomon from back buffer to front buffer */ glReadBuffer(GL_BACK) ; glDrawBuffer(GL_FRONT) ; SET_RASTER_SCREEN (PDATA(illx), PDATA(illy)) ; glCopyPixels (PDATA(illx), PDATA(illy), (PDATA(iurx)-PDATA(illx))+1, (PDATA(iury)-PDATA(illy))+1, GL_COLOR) ; /* * Restore original buffer config (PDATA(buffermode)) from * tdmFrontBufferDraw (which is equivalent to GL_FRONT). This also * causes all output so far to be flushed. */ _dxf_BUFFER_RESTORE_CONFIG (PORT_CTX, dummy, PDATA(buffermode), tdmFrontBufferDraw) ; } EXIT(("")); } static void _dxf_DRAW_GLOBE (tdmInteractor I, void *udata, float rot[4][4], int draw) { /* * draw == 1 to draw globe, draw == 0 to undraw. This is done with two * separate calls in order to support explicit erasure of edges for * some implementations. A draw is always preceded by an undraw and * the pair of invocations is atomic. */ DEFDATA(I,tdmRotateData) ; DEFPORT(I_PORT_HANDLE) ; int u, v, on, dummy = 0 ; /* globe edge visibility flags. all globe instance share this data. */ static struct { int latvis, longvis ; } edges[LATS][LONGS] ; /* globe and globeface defined in tdmGlobeEchoDef.h */ register float (*Globe)[LONGS][3] = globe ; register struct Face (*Globeface)[LONGS] = globeface ; /* view normal */ register float z0, z1, z2 ; ENTRY(("_dxf_DRAW_GLOBE (0x%x, 0x%x, 0x%x, %d)", I, udata, rot, draw)); z0 = rot[0][2] ; z1 = rot[1][2] ; z2 = rot[2][2] ; #define FACEVISIBLE(u,v,z0,z1,z2) \ (Globeface[u][v].norm[0] * z0 + \ Globeface[u][v].norm[1] * z1 + \ Globeface[u][v].norm[2] * z2 > 0.0) if (draw) { glColor3f(1.0, 1.0, 1.0) ; glLineWidth(1.0) ; } else { if(PDATA(redrawmode) != tdmViewEchoMode) { /* * In tdmViewEchoMode (DX's Execute On Change), we are drawing * the globe echo on top of a background image that is redrawn * with every frame of a direct interaction. * * If we're not in that mode, the background image is static * while the globe echo rotates in front of it, so erasing the * globe means we have to repair damage to the background. We * do this by blitting a portion of the static image to the * back buffer, drawing the globe over that, then blitting the * combined results back to the front buffer. */ /* force graphics output into back buffer */ glDrawBuffer(GL_BACK) ; /* erase globe background */ _dxf_WRITE_BUFFER (PORT_CTX, PDATA(illx), PDATA(illy), PDATA(iurx), PDATA(iury), PDATA(background)) ; } /* draw wide black lines to ensure visibility against background */ glColor3f(0.0, 0.0, 0.0) ; glLineWidth(3.0) ; } /* * Compute face visibility and flag edges. Flags are used for both the * undraw and draw invocations. */ if (!draw) { for (u=0 ; u 0.0) for (v=0 ; v(iw-1) ? iw-1 : PDATA(x1))) ; x2 = (PDATA(x2)<0 ? 0 : (PDATA(x2)>(iw-1) ? iw-1 : PDATA(x2))) ; y1 = (PDATA(y1)<0 ? 0 : (PDATA(y1)>(ih-1) ? ih-1 : PDATA(y1))) ; y2 = (PDATA(y2)<0 ? 0 : (PDATA(y2)>(ih-1) ? ih-1 : PDATA(y2))) ; /* Top Row */ glRasterPos2i (x1, y1) ; CHECK_RASTER_POS(); glDrawPixels ((x2-x1)+1, 1, GL_RGBA, GL_UNSIGNED_BYTE, image+(x1+y1*iw)) ; if(y1(iw-1) ? iw-1 : PDATA(x1))) ; x2 = (PDATA(x2)<0 ? 0 : (PDATA(x2)>(iw-1) ? iw-1 : PDATA(x2))) ; y1 = (PDATA(y1)<0 ? 0 : (PDATA(y1)>(ih-1) ? ih-1 : PDATA(y1))) ; y2 = (PDATA(y2)<0 ? 0 : (PDATA(y2)>(ih-1) ? ih-1 : PDATA(y2))) ; /* Top Row */ glReadPixels (x1, y1, (x2-x1)+1, 1, GL_RGBA, GL_UNSIGNED_BYTE, image+(x1+y1*iw)) ; if(y1 */ /* (J) (:Q= The Additional 0.5 Does Not FIX, but Rather Simplifies */ glVertex2f ((float)PDATA(x1)+0.5, (float)PDATA(y1)+0.5) ; glVertex2f ((float)PDATA(x2)+0.5, (float)PDATA(y1)+0.5) ; glVertex2f ((float)PDATA(x2)+0.5, (float)PDATA(y2)+0.5) ; glVertex2f ((float)PDATA(x1)+0.5, (float)PDATA(y2)+0.5) ; glVertex2f ((float)PDATA(x1)+0.5, (float)PDATA(y1)+0.5) ; glEnd() ; glFlush() ; } else _dxf_restoreZoomBox(I, udata, rot); EXIT(("")); } /* * STUB SECTION */ static void _dxf_SET_LINE_COLOR_WHITE (void *ctx) { /* obsolete entry: do not use in new code */ ENTRY(("_dxf_SET_LINE_COLOR_WHITE(0x%x)",ctx)); glColor3f(1.0, 1.0, 1.0) ; EXIT(("ERROR: stub")); } static void _dxf_SET_LINE_COLOR_GRAY (void *ctx) { /* obsolete entry: do not use in new code */ ENTRY(("_dxf_SET_LINE_COLOR_GRAY(0x%x)",ctx)); glColor3f(0.5, 0.5, 0.5) ; EXIT(("ERROR: stub")); } static void _dxf_SET_SOLID_FILL_PATTERN (void *ctx) { /* obsolete for OpenGL port */ ENTRY(("_dxf_SET_SOLID_FILL_PATTERN (0x%x)",ctx)); EXIT(("Error: stub")); } static void _dxf_DRAW_ARROWHEAD (void* ctx, float ax, float ay) { /* obsolete for OpenGL port */ ENTRY(("_dxf_DRAW_ARROWHEAD (0x%x, %f, %f)",ctx,ax,ay)); EXIT(("Error: stub")); } /* * Port handle section. */ #define STRUCTURES_ONLY #include "hwInteractorEcho.h" tdmInteractorEchoT _dxd_hwInteractorEchoPortOGL = { /* BufferConfig */ _dxf_BUFFER_CONFIG, /* BufferRestoreConfig */ _dxf_BUFFER_RESTORE_CONFIG, /* CreateCursorPixmaps */ _dxf_CREATE_CURSOR_PIXMAPS, /* DrawArrowhead */ _dxf_DRAW_ARROWHEAD, /* DrawCursorCoords */ _dxf_DRAW_CURSOR_COORDS, /* DrawGlobe */ _dxf_DRAW_GLOBE, /* DrawGnomon */ _dxf_DRAW_GNOMON, /* DrawLine */ _dxf_DRAW_LINE, /* DrawMarker */ _dxf_DRAW_MARKER, /* DrawZoombox */ _dxf_DRAW_ZOOMBOX, /* EraseCursor */ _dxf_ERASE_CURSOR, /* ErasePreviousMarks */ _dxf_ERASE_PREVIOUS_MARKS, /* GetMaxscreen */ _dxf_GET_MAXSCREEN, /* GetWindowOrigin */ _dxf_GET_WINDOW_ORIGIN, /* GetZbufferStatus */ _dxf_GET_ZBUFFER_STATUS, /* PointerInvisible */ _dxf_POINTER_INVISIBLE, /* PointerVisible */ _dxf_POINTER_VISIBLE, /* ReadBuffer */ _dxf_READ_BUFFER, /* SetLineColorGray */ _dxf_SET_LINE_COLOR_GRAY, /* SetLineColorWhite */ _dxf_SET_LINE_COLOR_WHITE, /* SetSolidFillPattern */ _dxf_SET_SOLID_FILL_PATTERN, /* SetWorldScreen */ _dxf_SET_WORLD_SCREEN, /* SetZbufferStatus */ _dxf_SET_ZBUFFER_STATUS, /* WarpPointer */ _dxf_WARP_POINTER, /* WriteBuffer */ _dxf_WRITE_BUFFER, /* SetLineAttributes */ _dxf_SET_LINE_ATTRIBUTES };