OpenGlDevice.cpp

Go to the documentation of this file.
00001 /* ****************************************************************** **
00002 **    OpenSees - Open System for Earthquake Engineering Simulation    **
00003 **          Pacific Earthquake Engineering Research Center            **
00004 **                                                                    **
00005 **                                                                    **
00006 ** (C) Copyright 1999, The Regents of the University of California    **
00007 ** All Rights Reserved.                                               **
00008 **                                                                    **
00009 ** Commercial use of this program without express permission of the   **
00010 ** University of California, Berkeley, is strictly prohibited.  See   **
00011 ** file 'COPYRIGHT'  in main directory for information on usage and   **
00012 ** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
00013 **                                                                    **
00014 ** Developed by:                                                      **
00015 **   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
00016 **   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
00017 **   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
00018 **                                                                    **
00019 ** ****************************************************************** */
00020                                                                         
00021 // $Revision: 1.15 $
00022 // $Date: 2005/07/05 17:37:04 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/renderer/OpenGlDevice.cpp,v $
00024                                                                         
00025                                                                         
00026 #include <OpenGlDevice.h>
00027 #include <OPS_Globals.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <stdio.h>
00031 
00032 #ifdef _GLX
00033 #define _PNG
00034 #include <png.h>
00035 #endif
00036 
00037 
00038 int OpenGlDevice::numWindows(0);
00039 // GLuint OpenGlDevice::FontBase(0);
00040 
00041 
00042 #ifdef _WGL
00043 LONG WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00044 { 
00045     LONG        lRet = 1;
00046     PAINTSTRUCT ps;
00047 
00048     switch(uMsg) {
00049     case WM_CREATE:
00050         break; 
00051 
00052     case WM_DESTROY:
00053         break; 
00054 
00055     case WM_PAINT: 
00056         BeginPaint(hWnd, &ps); 
00057         EndPaint(hWnd, &ps); 
00058         break; 
00059 
00060     default: 
00061         lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); 
00062         break; 
00063     }
00064 
00065     return lRet;
00066 }
00067 
00068 
00069 /* oglPixelFormat()
00070  *  Sets the pixel format for the context
00071  */
00072 int oglSetPixelFormat(HDC hDC, BYTE type, DWORD flags)
00073 {
00074     int pf;
00075     PIXELFORMATDESCRIPTOR pfd;
00076 
00077     /* fill in the pixel format descriptor */
00078     pfd.nSize        = sizeof(PIXELFORMATDESCRIPTOR);
00079     pfd.nVersion     = 1;                   /* version (should be 1) */
00080     pfd.dwFlags      = flags | /* draw to window (not bitmap) */
00081                        PFD_SUPPORT_OPENGL;  /* draw using opengl */
00082     pfd.iPixelType   = type;                /* PFD_TYPE_RGBA or COLORINDEX */
00083     pfd.cColorBits   = 24;
00084     pfd.cRedBits = 8;
00085     pfd.cGreenBits = 8;
00086     pfd.cBlueBits = 8;
00087     pfd.cDepthBits = 16;
00088     /* other criteria here */
00089     
00090     /* get the appropriate pixel format */
00091     pf = ChoosePixelFormat(hDC, &pfd);
00092     if (pf == 0) {
00093        MessageBox(NULL,
00094                   "ChoosePixelFormat() failed:  Cannot find format specified.",
00095                   "Error", MB_OK); 
00096        return 0;
00097     } 
00098  
00099     /* set the pixel format */
00100     if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
00101         MessageBox(NULL,
00102                    "SetPixelFormat() failed:  Cannot set format specified.",
00103                    "Error", MB_OK);
00104         return 0;
00105     } 
00106 
00107     return pf;
00108 }    
00109 
00110 
00111 /* oglCreateWindow
00112  *  Create a window suitable for OpenGL rendering
00113  */
00114 HWND oglCreateWindow(char* title, int x, int y, int width, int height,
00115                                          HGLRC *hRC, HDC *hDC)
00116 {
00117     WNDCLASS  wc;
00118     HWND hWnd;
00119     HINSTANCE hInstance;
00120 
00121     /* get this modules instance */
00122     hInstance = GetModuleHandle(NULL);
00123 
00124     /* fill in the window class structure */
00125     wc.style         = CS_HREDRAW | CS_VREDRAW;  // to redraw if moved
00126     wc.lpfnWndProc   = (WNDPROC)WndProc;         /* event handler */
00127     wc.cbClsExtra    = 0;                           /* no extra class data */
00128     wc.cbWndExtra    = 0;                           /* no extra window data */
00129     wc.hInstance     = hInstance;                   /* instance */
00130     wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO); /* load a default icon */
00131     wc.hCursor       = LoadCursor(NULL, IDC_ARROW); /* load a default cursor */
00132     wc.hbrBackground = NULL;                        /* redraw our own bg */
00133     wc.lpszMenuName  = NULL;                        /* no menu */
00134     wc.lpszClassName = title;                       /* use a special class */
00135 
00136     /* register the window class */
00137     if (!RegisterClass(&wc)) {
00138       MessageBox(NULL, 
00139                    "RegisterClass() failed:  Cannot register window class,",
00140                    "Error", MB_OK);
00141         return NULL;
00142     }
00143 
00144     /* create a window */
00145     hWnd = CreateWindow(title,          /* class */
00146                         title,          /* title (caption) */
00147                         WS_CLIPSIBLINGS | WS_CLIPCHILDREN,  /* style */
00148                         x, y, width, height, /* dimensions */
00149                         NULL,           /* no parent */
00150                         NULL,           /* no menu */
00151                         hInstance,      /* instance */
00152                         NULL);          /* don't pass anything to WM_CREATE */
00153 
00154     /* make sure we got a window */
00155     if (hWnd == NULL) {
00156         MessageBox(NULL,
00157                    "CreateWindow() failed:  Cannot create a window.",
00158                    "Error", MB_OK);
00159         return NULL;
00160     }
00161 
00162     /* show the window (map it) */
00163     ShowWindow(hWnd, SW_SHOW);
00164 
00165     /* send an initial WM_PAINT message (expose) */
00166     UpdateWindow(hWnd);
00167 
00168             /* get the device context */
00169     *hDC = GetDC(hWnd);
00170         
00171     /* set the pixel format */
00172     if (oglSetPixelFormat(*hDC, PFD_TYPE_RGBA, 
00173                                 PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER) == 0)
00174       exit(1);
00175 
00176     /* create an OpenGL context */
00177     *hRC = wglCreateContext(*hDC);
00178         wglMakeCurrent(*hDC, *hRC);
00179     glClearColor(1.0f,1.0f,1.0f,1.0f);
00180     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00181     glViewport(0, 0, (GLsizei)width, (GLsizei)height);
00182     glMatrixMode(GL_PROJECTION);
00183     glLoadIdentity();
00184     gluOrtho2D(0.0, (GLdouble)width, 0.0, (GLdouble)height);
00185     glFlush();
00186  
00187     return hWnd;
00188 }
00189 
00190 
00191 /* oglCreateWindow
00192  *  Create a window suitable for OpenGL rendering
00193  */
00194 int oglDestroyWindow(char* title, HWND hWnd, HGLRC hRC, HDC hDC)
00195 {
00196     HINSTANCE hInstance;
00197 
00198     /* get this modules instance */
00199     hInstance = GetModuleHandle(NULL);
00200 
00201     /*
00202          * now release the device context, destroy the rendering context
00203          * and destroy the window.
00204          */
00205         wglMakeCurrent(NULL, NULL);     //make the gl context 'un-'current 
00206     ReleaseDC(hWnd, hDC);               //release handle to DC 
00207     wglDeleteContext(hRC);              //delete the rendering context 
00208     DestroyWindow(hWnd);            // destroy the window
00209         
00210         /* unregister the window class - so can use window name again*/    
00211         if (!UnregisterClass(title, hInstance)) {
00212       MessageBox(NULL, 
00213                    "UnregisterClass() failed:  Cannot unregister window class,",
00214                    "Error", MB_OK);
00215         return -1;
00216     }
00217         
00218         return 0;
00219 }
00220 
00221 
00222 /* oglCreateWindow
00223  *  Create a window suitable for OpenGL rendering
00224  */
00225 int oglCreateBitmap(int width, int height, HGLRC *hRC, HDC *hDC, 
00226                     HBITMAP *theBitmap, BITMAPINFO *info, GLubyte **bits)
00227 {
00228 
00229         *hDC = CreateCompatibleDC(NULL);
00230 
00231 
00232 //      memset(&info, 0, sizeof(BITMAPINFO));
00233         
00234         GLint Width = width;
00235         GLint Height = height;
00236 
00237         info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
00238         info->bmiHeader.biPlanes = 1;
00239         info->bmiHeader.biBitCount = 24;
00240         info->bmiHeader.biCompression = BI_RGB;
00241         info->bmiHeader.biXPelsPerMeter = 11808;
00242         info->bmiHeader.biYPelsPerMeter = 11808;
00243         info->bmiHeader.biClrUsed = 0;
00244         info->bmiHeader.biClrImportant = 0;
00245         info->bmiHeader.biWidth = width;
00246         info->bmiHeader.biHeight = height;
00247 
00248         /*
00249         if ((*bits = (GLubyte *)(calloc(width*height, 1))) == 0){
00250                 opserr << "BITS ZERO\n";
00251                 return -1;
00252         }
00253         */
00254         void *theBits = *bits;
00255 //      void **theBitsPtr = &theBits;
00256 
00257         *theBitmap = CreateDIBSection(*hDC, info, DIB_RGB_COLORS, &theBits, NULL, 0);
00258         *bits = (GLubyte *)theBits;
00259 
00260         SelectObject(*hDC, *theBitmap);
00261    /* set the pixel format */
00262     if (oglSetPixelFormat(*hDC, PFD_TYPE_RGBA, PFD_DRAW_TO_BITMAP) == 0)
00263       exit(1);
00264 
00265     /* create an OpenGL context */
00266     *hRC = wglCreateContext(*hDC);
00267   
00268     return 0;
00269 }
00270 
00271 
00272 /* oglCreateWindow
00273  *  Create a window suitable for OpenGL rendering
00274  */
00275 int oglDestroyBitmap(HBITMAP *theBitmap, HGLRC hRC, HDC hDC)
00276 {
00277     /*
00278          * now release the device context, destroy the rendering context
00279          * and destroy the bitmap.
00280          */
00281         wglMakeCurrent(NULL, NULL);     //make the gl context 'un-'current 
00282     wglDeleteContext(hRC);              //delete the rendering context 
00283     DeleteObject(theBitmap);// destroy the window
00284         
00285 
00286         return 0;
00287 }
00288 
00289 #elif _GLX
00290 
00291 static int attributeListSgl[] = {
00292         GLX_RGBA,
00293         GLX_RED_SIZE,   1, /*get the deepest buffer with 1 red bit*/
00294         GLX_GREEN_SIZE, 1,
00295         GLX_BLUE_SIZE,  1,
00296         None };
00297 
00298 static int attributeListDbl[] = {
00299         GLX_RGBA,
00300         GLX_DOUBLEBUFFER, /*In case single buffering is not supported*/
00301         GLX_RED_SIZE,   1,
00302         GLX_GREEN_SIZE, 1,
00303         GLX_BLUE_SIZE,  1,
00304         None };
00305 
00306 static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
00307         return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
00308 }
00309 
00310 static const char *FontName = "fixed";
00311 
00312 //XFontStruct *OpenGlDevice::fontInfo(0);
00313 
00314 #else
00315 
00316 #endif
00317 
00318 
00319 
00320 
00321 
00322 
00323 
00324 
00325 
00326 
00327 OpenGlDevice::OpenGlDevice()
00328   :FontBase(0), winOpen(1), width(0), height(0), windowTitle(0)
00329 {
00330 
00331 #ifdef _WGL
00332 
00333 #elif _GLX
00334   fontInfo = 0;
00335 #else
00336 
00337 #endif
00338 
00339   // if this is the first window to open call init windows
00340   if (numWindows == 0)
00341     this->initWindow();
00342 
00343   numWindows++;
00344 }
00345 
00346 OpenGlDevice::~OpenGlDevice()
00347 {
00348   numWindows--;
00349 
00350 #ifdef _WGL
00351   if (winOpen == 0) { // we must close the window
00352       oglDestroyWindow(windowTitle,theWND, theHRC, theHDC);
00353   }
00354 
00355   if (FontBase != 0) {
00356     glDeleteLists(FontBase, 256);
00357   }
00358 #elif _GLX
00359 
00360   if (fontInfo != 0) {
00361     Font id;
00362     unsigned int first, last;    
00363 
00364     id = fontInfo->fid;
00365     first = fontInfo->min_char_or_byte2;
00366     last = fontInfo->max_char_or_byte2;
00367   
00368     glDeleteLists(FontBase, (GLuint) last + 1);
00369     XFreeFont(theDisplay, fontInfo);
00370   }
00371 
00372   if (winOpen == 0) { // we must close the old window
00373     XFreeGC(theDisplay, theGC);
00374     XDestroyWindow(theDisplay, theWindow); 
00375     XCloseDisplay(theDisplay);
00376   }
00377 
00378   if (windowTitle != 0)
00379     delete [] windowTitle;
00380 
00381 #else
00382 
00383 #endif
00384 
00385 }
00386 
00387 void
00388 OpenGlDevice::WINOPEN(const char *_title, int _xLoc, int _yLoc, int _width, int _height)
00389 {
00390   if (windowTitle != 0)
00391     delete [] windowTitle;
00392   
00393   windowTitle = new char[strlen(_title)+1];
00394   strcpy(windowTitle, _title);
00395 
00396   width = _width;
00397   height = _height;
00398 
00399 #ifdef _WGL
00400   xLoc = _xLoc;
00401   yLoc = _yLoc;
00402 
00403   if (winOpen == 0)
00404     oglDestroyWindow(windowTitle,theWND, theHRC, theHDC);      
00405  
00406   theWND = oglCreateWindow(windowTitle, _xLoc, _yLoc, _width, _height, &theHRC, &theHDC);
00407   if (theWND == NULL)
00408     exit(1);
00409   winOpen = 0;
00410   wglMakeCurrent(theHDC, theHRC);
00411 
00412   FontBase = glGenLists((GLuint) 256);
00413   if (!FontBase) {
00414     printf("Error: unable to allocate display lists\n");
00415     exit(0);
00416   }
00417 
00418   wglUseFontBitmaps(theHDC, 0, 256, FontBase);
00419 
00420 #elif _GLX
00421 
00422   theDisplay = XOpenDisplay("");      // init a display connection
00423   if (theDisplay == 0) {              // and check we got one
00424     opserr << "OpenGlDevice::initX11() - could not connect to display\n";
00425     exit(-1);
00426   }
00427 
00428   theScreen = DefaultScreen(theDisplay);
00429 
00430   //XVisualInfo *visual;
00431   XSetWindowAttributes swa;
00432   swap_flag = GL_FALSE;
00433   //Colormap cmap; //this overrides the other color map
00434   //GLXContext cx;
00435   //XEvent event;
00436 
00437   if (winOpen == 0) { // we must close the old window
00438     XFreeGC(theDisplay, theGC);
00439     XDestroyWindow(theDisplay, theWindow);
00440   }
00441 
00442   /* get an appropriate visual*/
00443   visual = glXChooseVisual(theDisplay, theScreen, attributeListDbl);
00444   swap_flag = GL_TRUE;
00445   if (visual == NULL) {
00446     visual = glXChooseVisual(theDisplay, theScreen, attributeListSgl);
00447     swap_flag = GL_FALSE;
00448   }
00449 
00450   if(visual == NULL) {
00451     opserr << "OpenGlDevice::WINOPEN - unable to get visual\n";
00452     exit(2);
00453   }
00454 
00455   /* create a color map */
00456   //  cmap = XCreateColormap(theDisplay, RootWindow(theDisplay, visual->screen),
00457   //             visual->visual, AllocNone);
00458   
00459   /* create a window */
00460   swa.colormap = XCreateColormap(theDisplay, RootWindow(theDisplay, visual->screen),
00461                                  visual->visual, AllocNone);
00462 
00463   swa.border_pixel = 0;
00464   swa.event_mask = StructureNotifyMask;
00465 
00466   unsigned long mask;
00467   mask =  CWBackPixel|CWBorderPixel|CWColormap|CWEventMask;
00468   theWindow = XCreateWindow(theDisplay, RootWindow(theDisplay, visual->screen), 
00469                             _xLoc, _yLoc, _width, _height,
00470                             0, visual->depth, InputOutput, visual->visual,
00471                             mask, &swa);
00472 
00473   if (theWindow == 0) {
00474     opserr << "OpenGlDevice::WINOPEN() - could not open a window\n";
00475     exit(-1);
00476   }
00477     
00478   // define the position and size of the window - only hints
00479   hints.x = _xLoc;
00480   hints.y = _yLoc;
00481   hints.width = _width;
00482   hints.height = _height;
00483   hints.flags = PPosition | PSize;
00484   XSetNormalHints(theDisplay, theWindow, &hints);
00485   XSetStandardProperties(theDisplay, theWindow, windowTitle, windowTitle, None, 0, 0, &hints);
00486 
00487   /* create a GLX context */
00488   cx = glXCreateContext(theDisplay, visual, NULL, GL_TRUE);
00489   if (cx == 0) {
00490     opserr << "OpenGlDevice::WINOPEN() - could not create a glx context\n";
00491     exit(-1);
00492   }    
00493 
00494   
00495   XMapWindow(theDisplay, theWindow);
00496     
00497   /* connect the context to the window */
00498   glXMakeCurrent(theDisplay, theWindow, cx);
00499 
00500   // create a graphical context
00501   theGC = XCreateGC(theDisplay, theWindow, 0, 0);
00502   winOpen = 0;
00503 
00504   XVisualInfo visual; 
00505   visual.visual = 0;
00506   int depth = DefaultDepth(theDisplay, theScreen);
00507 
00508   XMapWindow(theDisplay,theWindow);
00509   XClearWindow(theDisplay, theWindow);      
00510   XFlush(theDisplay);
00511 
00512   Font id;
00513   unsigned int first, last;
00514 
00515   fontInfo = XLoadQueryFont(theDisplay, FontName);
00516   if (!fontInfo) {
00517     printf("Error: font %s not found\n", FontName);
00518     exit(0);
00519   }
00520 
00521   id = fontInfo->fid;
00522   first = fontInfo->min_char_or_byte2;
00523   last = fontInfo->max_char_or_byte2;
00524 
00525   FontBase = glGenLists((GLuint) last + 1);
00526   if (!FontBase) {
00527     printf("Error: unable to allocate display lists\n");
00528     exit(0);
00529   }
00530 
00531   glXUseXFont(id, first, last - first + 1, FontBase + first);
00532 
00533 #else
00534 
00535 #endif
00536 
00537 
00538 }
00539 
00540 
00541 
00542 
00543 void
00544 
00545 OpenGlDevice::CLEAR()
00546 {
00547 #ifdef _WGL
00548     wglMakeCurrent(theHDC, theHRC);
00549 
00550 #elif _GLX
00551     glXMakeCurrent(theDisplay, theWindow, cx);
00552 #else
00553 
00554 #endif
00555 
00556 }
00557 
00558 void
00559 OpenGlDevice::STARTIMAGE()
00560 {
00561 #ifdef _WGL
00562     wglMakeCurrent(theHDC, theHRC);
00563 #elif _GLX
00564     glXMakeCurrent(theDisplay, theWindow, cx);
00565 #else
00566 
00567 #endif
00568 }
00569 
00570 void
00571 OpenGlDevice::ENDIMAGE()
00572 {
00573 #ifdef _WGL
00574     wglMakeCurrent(theHDC, theHRC);
00575     SwapBuffers(theHDC);
00576 #elif _GLX
00577     if (swap_flag == GL_TRUE)
00578       glXSwapBuffers(theDisplay, theWindow);
00579     glXMakeCurrent(theDisplay, theWindow, cx);
00580 #else
00581 
00582 #endif
00583 }
00584 
00585 
00586 int
00587 OpenGlDevice::GetWidth()
00588 {
00589   return width;
00590 }
00591 
00592 int
00593 OpenGlDevice::GetHeight()
00594 {
00595   return height;
00596 }
00597   
00598 
00599 
00600 void
00601 OpenGlDevice::initWindow(void) {
00602   // set the display and screen variables
00603 
00604 #ifdef _WGL
00605 
00606 #elif _GLX
00607 
00608 #else
00609 
00610 #endif
00611 }    
00612         
00613     
00614 void
00615 OpenGlDevice::drawText(float x, float y, float z, char *text, int length,
00616                        char horizontalJustify, char verticalJustify)
00617 {
00618 
00619 #ifdef _WGL
00620   glColor3f(0.0,0.0,0.0);
00621   glRasterPos3f(x,y,z);
00622   glListBase(FontBase);
00623   glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
00624 #elif _GLX
00625 
00626   // set color and raster position
00627   glColor3f(0.0, 0.0 , 0.0);
00628   glRasterPos3f(x,y,z);
00629 
00630   // now we move the raster position based on text justification
00631   int moveX = 0;
00632   int moveY = 0;
00633 
00634   int height = fontInfo->ascent;  
00635   if (horizontalJustify != 'l') {
00636     char *s;
00637     int width = 0;
00638     for (s=text; *s; s++) {
00639       width += fontInfo->per_char[*s].width;
00640     }
00641     if (horizontalJustify == 'r')
00642       moveX = -width;
00643     else
00644       moveX = -width/2;
00645   }
00646 
00647   if (verticalJustify != 'b') {
00648     if (verticalJustify == 't')
00649       moveY = -height - 1;
00650     else
00651       moveY = -height/2;
00652   } else
00653     moveY = +2;
00654 
00655   glBitmap(0, 0, 0, 0, (GLfloat)moveX, (GLfloat)moveY, NULL);
00656 
00657   // finally draw the text
00658   glListBase(FontBase);
00659   glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
00660 #else
00661 
00662 #endif
00663 }
00664 
00665 
00666 int 
00667 OpenGlDevice::saveImage(const char *fileName, int type)
00668 {
00669   // make the context current
00670 #ifdef _WGL
00671   return this->saveImageAsBMP(fileName);
00672 #elif _GLX
00673   return this->saveImageAsPNG(fileName);
00674 #else
00675 
00676 #endif
00677 
00678   return 0;
00679 }
00680 
00681 int 
00682 OpenGlDevice::saveImageAsBMP(const char *fileName)
00683 {
00684   // make the context current
00685 #ifdef _WGL
00686     wglMakeCurrent(theHDC, theHRC);
00687 #elif _GLX
00688     glXMakeCurrent(theDisplay, theWindow, cx);
00689 #else
00690 
00691 #endif
00692 
00693     // create the file name 'bmpFileName$count.BMP'
00694     char *newFileName = new char[strlen(fileName)+4];
00695     if (newFileName == 0) {
00696       opserr << "OpenGlDevice::saveImageAsBMP() failed to open file: " << fileName << endln;
00697       return -1;
00698     }   
00699     strcpy(newFileName, fileName);
00700     strcat(newFileName,".BMP");
00701 
00702     // open the file
00703     FILE *fp;
00704     if ((fp = fopen(newFileName,"wb")) == NULL) {
00705       opserr << "OpenGLDevice::saveBmpImage() - could not open file named" <<  newFileName << endln;
00706         return -1;
00707     }   
00708 
00709 #ifdef _WGL     
00710     int bitsize = (info.bmiHeader.biWidth *
00711                    info.bmiHeader.biBitCount + 7) / 8 *
00712                   abs(info.bmiHeader.biHeight);
00713     int infosize;
00714     infosize = sizeof(BITMAPINFOHEADER);
00715     switch (info.bmiHeader.biCompression) {
00716         case BI_BITFIELDS :
00717             infosize += 12; /* Add 3 RGB doubleword masks */
00718             if (info.bmiHeader.biClrUsed == 0)
00719               break;
00720         case BI_RGB :
00721             if (info.bmiHeader.biBitCount > 8 &&
00722                 info.bmiHeader.biClrUsed == 0)
00723               break;
00724         case BI_RLE8 :
00725         case BI_RLE4 :
00726             if (info.bmiHeader.biClrUsed == 0)
00727               infosize += (1 << info.bmiHeader.biBitCount) * 4;
00728             else
00729               infosize += info.bmiHeader.biClrUsed * 4;
00730             break;
00731     }
00732 
00733     int size = sizeof(BITMAPFILEHEADER) + infosize + bitsize;
00734 
00735     // check the bit map header info has been created, if not create one
00736 /*    if (info == 0) {
00737         if ((info = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER))) < 0) {
00738             opserr << "OpenGLDevice::saveBmpImage() - %s\n",
00739                                     "out of memory creating BITMAPINFO struct");
00740             count = -1;
00741             return -2;
00742         }
00743         info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
00744         info->bmiHeader.biPlanes = 1;
00745         info->bmiHeader.biBitCount = 24;
00746         info->bmiHeader.biCompression = BI_RGB;
00747         info->bmiHeader.biXPelsPerMeter = 2952;
00748         info->bmiHeader.biYPelsPerMeter = 2952;
00749         info->bmiHeader.biClrUsed = 0;
00750         info->bmiHeader.biClrImportant = 0;
00751     }
00752     
00753     // determine the number of bits needed to save the image
00754     width = viewport[2]*3;
00755     width = (width+3) & ~3;
00756     bitsize = width * viewport[3];
00757 
00758     // check the bits pointeris of correct size, if not
00759     // delete the old and create a new one
00760     if (bitsize != currentBitSize) {
00761         if (currentBitSize != 0)
00762             free (bits);
00763         if ((bits = (GLubyte *)calloc(bitsize, 1)) == 0) {
00764             opserr << "OpenGLDevice::saveBmpImage() - %s\n",
00765                                     "out of memory creating BITMAPINFO struct");
00766             count = -1;
00767             free (info);
00768             info = 0;
00769             return -3;      
00770         }
00771         currentBitSize = bitsize;
00772     }
00773 
00774     // set the info for the bit map header
00775     info->bmiHeader.biWidth = viewport[2];
00776     info->bmiHeader.biHeight = viewport[3];    
00777     info->bmiHeader.biSizeImage = currentBitSize;        
00778 */
00779     // read the pixels from the frame buffer
00780     glFinish();
00781     glPixelStorei(GL_PACK_ALIGNMENT, 4);
00782     glPixelStorei(GL_PACK_ROW_LENGTH, 0);
00783     glPixelStorei(GL_PACK_SKIP_ROWS, 0);
00784     glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
00785 
00786     if (bits == 0) opserr << "BITS ZERO\n";
00787 
00788     glReadPixels(0, 0, info.bmiHeader.biWidth, info.bmiHeader.biHeight,
00789                 GL_BGR_EXT, GL_UNSIGNED_BYTE, bits);
00790         
00791 
00792     currentBitSize = info.bmiHeader.biWidth * info.bmiHeader.biHeight;
00793     // create a header for the BMP file
00794     BITMAPFILEHEADER header;
00795     header.bfType      = 'MB'; /* Non-portable... sigh */
00796     header.bfSize      = size;
00797     header.bfReserved1 = 0;
00798     header.bfReserved2 = 0;
00799     header.bfOffBits   = sizeof(BITMAPFILEHEADER) + infosize;
00800 
00801     if (fwrite(&header, 1, sizeof(BITMAPFILEHEADER), fp) < sizeof(BITMAPFILEHEADER))
00802         {
00803     // write the header to the file
00804 //    if (fwrite(&header, 1, sizeof(BITMAPFILEHEADER), fp) < sizeof(BITMAPFILEHEADER)) {
00805             opserr << "OpenGLDevice::saveBmpImage() - failed to write BITMAPHEADER" << endln;
00806             fclose(fp);
00807             return -4;
00808         }
00809     if (fwrite(&info, 1, infosize, fp) < infosize)
00810         {
00811     // write the bit map information to the file
00812 //    if (fwrite(&info, 1, sizeof(BITMAPINFOHEADER), fp) < sizeof(BITMAPINFOHEADER)) {
00813             opserr << "OpenGLDevice::saveBmpImage() - failed to write BITMAPINFOHEADER" << endln;
00814             fclose(fp);
00815             return -5;      
00816         }    
00817     if (fwrite(bits, 1, bitsize, fp) < bitsize)
00818         {
00819     // now we write the bits
00820     //if (fwrite(bits, 1, currentBitSize, fp) < currentBitSize) {
00821         opserr << "OpenGLDevice::saveBmpImage() - failed to write BITMAPINFOHEADER" << endln;
00822         fclose(fp);
00823         return -6;      
00824     }        
00825     // if get here we are done .. close file and return ok
00826 #endif
00827     
00828     delete [] newFileName;
00829     fclose(fp);
00830     return 0;
00831 }
00832 
00833 
00834 
00835 int 
00836 OpenGlDevice::saveImageAsPNG(const char *fileName)
00837 {
00838 
00839   // make the context current
00840 #ifdef _WGL
00841     wglMakeCurrent(theHDC, theHRC);
00842 #elif _GLX
00843     glXMakeCurrent(theDisplay, theWindow, cx);
00844 #else
00845 
00846 #endif
00847 
00848   //
00849   // first we read the image from the buffer
00850   //
00851 
00852   // create some memory to store the image
00853   char *image;
00854   image = new char[3*width*height];
00855   if (image == 0) {
00856     opserr << "OpenGlDevice::failed to allocate memory for image\n";
00857     return(-1);
00858   }
00859   
00860   // read into the buffer
00861   glReadBuffer(GL_BACK_LEFT);
00862   glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
00863 
00864 
00865   //
00866   // now we write the file to a png
00867   //   .. code for this from Greg Roelofs book: PNG: The Definitive Guide published by O'Reilly.
00868   // 
00869 
00870   // open the file
00871   FILE *fp;
00872   char *newFileName = new char (strlen(fileName+4));
00873   if (newFileName == 0) {
00874     opserr << "OpenGlDevice::saveImageAsPNG() failed to open file: " << fileName << endln;
00875     delete [] image;
00876     return -1;
00877   }
00878     
00879   strcpy(newFileName, fileName);
00880   strcat(newFileName, ".png");
00881 
00882   if((fp = fopen(newFileName, "wb"))==NULL) {
00883     opserr << "OpenGlDevice::saveImageAsPNG() failed to open file: " << fileName << endln;
00884     delete [] image;
00885     return -1;
00886   }
00887 
00888 #ifdef _PNG  
00889   // Allocate write & info structures
00890   png_structp png_ptr = png_create_write_struct
00891     (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00892   if(!png_ptr) {
00893     delete [] image;
00894     fclose(fp);
00895     opserr << "OpenGlDevice::saveImageAsPNG() - out of memery creating write structure\n";
00896     return -1;
00897   }
00898   
00899   png_infop info_ptr = png_create_info_struct(png_ptr);
00900   if(!info_ptr) {
00901     png_destroy_write_struct(&png_ptr,
00902                              (png_infopp)NULL);
00903     delete [] image;
00904     fclose(fp);
00905     opserr << "OpenGlDevice::saveImageAsPNG() - out of memery creating info structure\n";
00906 
00907     return -1;
00908   }
00909 
00910   // setjmp() must be called in every function that calls a PNG-writing
00911   // libpng function, unless an alternate error handler was installed--
00912   // but compatible error handlers must either use longjmp() themselves
00913   // (as in this program) or exit immediately, so here we go: */
00914 
00915   if(setjmp(png_jmpbuf(png_ptr))) {
00916     png_destroy_write_struct(&png_ptr, &info_ptr);
00917     fclose(fp);
00918     opserr << "OpenGlDevice::saveImageAsPNG() - setjmp problem\n";
00919     return 2;
00920   }
00921 
00922   // make sure outfile is (re)opened in BINARY mode 
00923   png_init_io(png_ptr, fp);
00924 
00925   // set the compression levels--in general, always want to leave filtering
00926   // turned on (except for palette images) and allow all of the filters,
00927   // which is the default; want 32K zlib window, unless entire image buffer
00928   // is 16K or smaller (unknown here)--also the default; usually want max
00929   // compression (NOT the default); and remaining compression flags should
00930   // be left alone
00931 
00932   png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
00933   //
00934   // this is default for no filtering; Z_FILTERED is default otherwise:
00935   // png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
00936   //  these are all defaults:
00937   //   png_set_compression_mem_level(png_ptr, 8);
00938   //   png_set_compression_window_bits(png_ptr, 15);
00939   //   png_set_compression_method(png_ptr, 8);
00940 
00941 
00942   // Set some options: color_type, interlace_type
00943   int color_type, interlace_type, numChannels;
00944 
00945   //  color_type = PNG_COLOR_TYPE_GRAY;
00946   //  color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
00947   color_type = PNG_COLOR_TYPE_RGB; numChannels = 3;
00948   // color_type = PNG_COLOR_TYPE_RGB_ALPHA;
00949 
00950   interlace_type =  PNG_INTERLACE_NONE;
00951   // interlace_type = PNG_INTERLACE_ADAM7;
00952   
00953 
00954   int bit_depth = 8;
00955   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, 
00956                color_type,
00957                interlace_type,
00958                PNG_COMPRESSION_TYPE_BASE, 
00959                PNG_FILTER_TYPE_BASE);
00960   
00961   // Optional gamma chunk is strongly suggested if you have any guess
00962   // as to the correct gamma of the image. (we don't have a guess)
00963   //
00964   // png_set_gAMA(png_ptr, info_ptr, image_gamma);
00965   
00966   // write all chunks up to (but not including) first IDAT 
00967   png_write_info(png_ptr, info_ptr);
00968   
00969 
00970   // set up the row pointers for the image so we can use png_write_image
00971 
00972   png_bytep* row_pointers = new png_bytep[height];
00973   if (row_pointers == 0) {
00974     png_destroy_write_struct(&png_ptr, &info_ptr);
00975     delete [] image;
00976     fclose(fp);
00977     opserr << "OpenGlDevice::failed to allocate memory for row pointers\n";
00978     return(-1);
00979   }
00980 
00981   unsigned int row_stride = width*numChannels;
00982   unsigned char *rowptr = (unsigned char*) image;
00983   for (int row = height-1; row >=0 ; row--) {
00984     row_pointers[row] = rowptr;
00985     rowptr += row_stride;
00986   }
00987 
00988   // now we just write the whole image; libpng takes care of interlacing for us
00989   png_write_image(png_ptr, row_pointers);
00990   
00991   // since that's it, we also close out the end of the PNG file now--if we
00992   // had any text or time info to write after the IDATs, second argument
00993   // would be info_ptr, but we optimize slightly by sending NULL pointer: */
00994 
00995   png_write_end(png_ptr, info_ptr);
00996   
00997   //
00998   // clean up after the write
00999   //    free any memory allocated & close the file
01000   //
01001   png_destroy_write_struct(&png_ptr, &info_ptr);
01002   
01003   delete [] row_pointers;
01004 
01005 #endif
01006 
01007   delete [] image;
01008   delete [] newFileName;
01009   fclose(fp);
01010   
01011   return 0;
01012 }
01013 
01014 
01015 

Generated on Mon Oct 23 15:05:27 2006 for OpenSees by doxygen 1.5.0