Subversion Repositories OpenSees

Rev

Rev 1497 | Rev 3309 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* ****************************************************************** **
**    OpenSees - Open System for Earthquake Engineering Simulation    **
**          Pacific Earthquake Engineering Research Center            **
**                                                                    **
**                                                                    **
** (C) Copyright 1999, The Regents of the University of California    **
** All Rights Reserved.                                               **
**                                                                    **
** Commercial use of this program without express permission of the   **
** University of California, Berkeley, is strictly prohibited.  See   **
** file 'COPYRIGHT'  in main directory for information on usage and   **
** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
**                                                                    **
** Developed by:                                                      **
**   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
**   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
**   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
**                                                                    **
** ****************************************************************** */

                                                                       
// $Revision: 1.17 $
// $Date: 2004-06-03 19:52:41 $
// $Source: /usr/local/cvs/OpenSees/SRC/renderer/OpenGlRenderer.cpp,v $
                                                                       
                                                                       
// Written: fmk
// Created: 10/98
// Revision: A
//
// Description: This file contains the class definition for OpenGLRenderer.
// OpenGLRenderer is an class which diplays using X11 or openGL.
//
// What: "@(#) OpenGLRenderer.h, revA"

#include <OpenGLRenderer.h>
#include <ColorMap.h>
#include <stdio.h>
#include <stdlib.h>
#include <Matrix.h>
#include <iomanip>
using std::ios;

#ifdef _WGL
#include <windows.h>
#include <GL/glaux.h>
#include <GL/glu.h>
#include <GL/gl.h>

#elif _GLX

#include <GL/glu.h>

#endif

#define PARALLEL_MODE 0
#define PERSPECTIVE_MODE 1

#define WIRE_MODE 0
#define FILL_MODE 1

//#include <db.H>
#include <Vector.h>

OpenGLRenderer::OpenGLRenderer(const char *_title, int _xLoc, int _yLoc,
                               int _width, int _height,
                               ColorMap &_theMap)
  :Renderer(_title, _theMap),  
  windowTitle(0), height(_height), width(_width), xLoc(_xLoc), yLoc(_yLoc),
  count(-1), theOutputFileName(0),
  theDevice(0),
  vrp(3), vuv(3), vpn(3), cop(3), ViewMat(4,4),
  projectionMode(0), vpWindow(4), ProjMat(4,4),
  portWindow(4)
{

  // set the WindowDevices title, height, wdth, xLoc and yLoc
  windowTitle = new char [strlen(_title)+1];
  strcpy(windowTitle, _title);

  fillMode = WIRE_MODE;
  projectionMode = PARALLEL_MODE;
  portWindow(0) = -1.0; portWindow(1) = 1.0;
  portWindow(2) = -1.0;  portWindow(3) = 1.0;

  theDevice = new OpenGlDevice();
  theDevice->WINOPEN(_title, _xLoc, _yLoc, _width, _height);

  theDevice->CLEAR();
  glClearColor(1.0f,1.0f,1.0f,1.0f);

  glEnable(GL_DEPTH_TEST);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glFlush();
  theDevice->ENDIMAGE();
}




OpenGLRenderer::OpenGLRenderer(const char *_title, int _xLoc, int _yLoc,
                               int _width, int _height,
                               ColorMap &_theMap,
                               const char *outputFileName,
                               const char *bitmapFileName)
  :Renderer(_title, _theMap),  
  windowTitle(0), height(_height), width(_width), xLoc(_xLoc), yLoc(_yLoc),
  count(-1), theOutputFileName(0),
  theDevice(0),
  vrp(3), vuv(3), vpn(3), cop(3), ViewMat(4,4),
  projectionMode(0), vpWindow(4), ProjMat(4,4),
  portWindow(4)
{
  // set the WindowDevices title, height, wdth, xLoc and yLoc
  windowTitle = new char [strlen(_title)+1];
  strcpy(windowTitle, _title);

  fillMode = WIRE_MODE;
  projectionMode = PARALLEL_MODE;
  portWindow(0) = -1.0; portWindow(1) = 1.0;
  portWindow(2) = -1.0;  portWindow(3) = 1.0;

  theDevice = new OpenGlDevice();
  if (bitmapFileName != 0) {
                opserr << "OpenGLRenderer:;OpenGlRenderer - feature to save image only to BMP removed\n";
  }
  theDevice->WINOPEN(_title, _xLoc, _yLoc, _width, _height);;
 
  theDevice->CLEAR();


  // open the file for  making the movie
  if (outputFileName != 0) {
    windowTitle = new char [strlen(_title)+1];
    theOutputFileName = new char [strlen(outputFileName)+1];

    strcpy(windowTitle, _title);
    strcpy(theOutputFileName, outputFileName);
    theFile.open(theOutputFileName, ios::out);
    if (theFile.bad()) {
      opserr << "WARNING - OpenGLRenderer::OpenGLRenderer() - could not open file: " << outputFileName << endln;
      theOutputFileName = 0;
    } else {
      theFile << windowTitle << endln;
      theFile << xLoc << " " << yLoc << " " << width << " " << height << endln;
    }
  }

  theDevice->CLEAR();
  glClearColor(1.0f,1.0f,1.0f,1.0f);

  glEnable(GL_DEPTH_TEST);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glFlush();
  theDevice->ENDIMAGE();
}

OpenGLRenderer::~OpenGLRenderer()
{
  if (theDevice != 0)
    delete theDevice;

  if (windowTitle != 0)
    delete [] windowTitle;

  if (theOutputFileName != 0) {
    theFile.close();
    delete [] theOutputFileName;
  }
}


int
OpenGLRenderer::clearImage(void)
{
  theDevice->CLEAR();
  glClearColor(1.0f,1.0f,1.0f,1.0f);

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
  glFlush();
 
#ifdef _UNIX
  theDevice->ENDIMAGE();
#endif

  return 0;
}

int
OpenGLRenderer::saveImage(const char *imageName)
{
  return theDevice->saveImage(imageName, 0);
}


int
OpenGLRenderer::startImage(void)
{
  theMap->startImage();

  theDevice->STARTIMAGE();

  if (fillMode == WIRE_MODE) {
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  } else {
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  }

  // glEnable(GL_BLEND);
  // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  // glEnable(GL_LINE_SMOOTH);
  // glEnable(GL_POINT_SMOOTH);
  // glEnable(GL_POLYGON_SMOOTH);

    //
    // set up the viewing transformation
    //
    static Vector u(3), v(3), n(3);

    // vpnCopy used to store vpn, if no vpn yet specified vpn = VRP-PRP
    static Vector vpnCopy(3);

    if (vpn(0) == 0.0 && vpn(1) == 0.0 && vpn(2) == 0.0) {
      vpnCopy(0) = cop(0) - vrp(0);
      vpnCopy(1) = cop(1) - vrp(1);
      vpnCopy(2) = cop(2) - vrp(2);
    } else {
      vpnCopy(0) = vpn(0);
      vpnCopy(1) = vpn(1);
      vpnCopy(2) = vpn(2);
    }

    for (int i=0; i<3; i++) {
        n(i) = vpnCopy(i);
        v(i) = vuv(i);
    }

    if (n.Normalize() != 0) {
        opserr << "View::update() - VPN cannot have zero length\n";
        return -1;
    }

    // u = v % n;
    u(0) = v(1)*n(2) - v(2)*n(1) ;
    u(1) = v(2)*n(0) - v(0)*n(2) ;
    u(2) = v(0)*n(1) - v(1)*n(0) ;

    if (u.Normalize() != 0) {
        opserr << "View::update() - VUV X VPN cannot have zero length\n";
        return -1;
    }

    //v = n % u;
    v(0) = n(1)*u(2) - n(2)*u(1) ;
    v(1) = n(2)*u(0) - n(0)*u(2) ;
    v(2) = n(0)*u(1) - n(1)*u(0) ;

    v.Normalize();
   
    ViewMat(0,0) = u(0); ViewMat(0,1) = u(1); ViewMat(0,2) = u(2); ViewMat(0,3) = -(vrp^u);
    ViewMat(1,0) = v(0); ViewMat(1,1) = v(1); ViewMat(1,2) = v(2); ViewMat(1,3) = -(vrp^v);
    ViewMat(2,0) = n(0); ViewMat(2,1) = n(1); ViewMat(2,2) = n(2); ViewMat(2,3) = -(vrp^n);
    ViewMat(3,0) =  0.0; ViewMat(3,1) =  0.0; ViewMat(3,2) = 0.0;  ViewMat(3,3) =  1.0;

    for (int j=0; j<4; j++)
        for (int k=0; k<4; k++)
            viewData[j+k*4] = ViewMat(j,k);
   
    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(viewData);

   //
   // set up the projection transformation
   //

    float midU, midV, dopU, dopV, dopN, shU, shV, F, B;
    midU = (vpWindow(0) + vpWindow(1))/2;
    midV = (vpWindow(2) + vpWindow(3))/2;

    // PRP (COP) in viewing system
    float PRPu = u(0)*cop(0) + u(1)*cop(1) + u(2)*cop(2) + ViewMat(0,3);
    float PRPv = v(0)*cop(0) + v(1)*cop(1) + v(2)*cop(2) + ViewMat(1,3);
    float PRPn = n(0)*cop(0) + n(1)*cop(1) + n(2)*cop(2) + ViewMat(2,3);

    float diffU, diffV;// prpN;
       
    diffU = vpWindow(1)-vpWindow(0);
    diffV = vpWindow(3)-vpWindow(2);      

    dopU = midU - PRPu;
    dopV = midV - PRPv;
    dopN = -PRPn;

    shU = dopU/dopN;
    shV = dopV/dopN;
    F = clippingPlanes[0];
    B = clippingPlanes[1];

    /******* the equiv of the viewData transformation using glu **************
    glLoadIdentity();
    gluLookAt(cop[0),cop[1),cop[2),vrp[0),vrp[1),vrp[2),vuv[0),vuv[1),vuv[2));
    glTranslatef(0.0, 0.0, PRPn);  // note the PRPn transformation here
    **************************************************************************/


    if (projectionMode == PARALLEL_MODE) {

      ProjMat(0,0) = 2.0/diffU; ProjMat(0,1) = 0.0; ProjMat(0,2) = 2.0*shU/diffU;
      ProjMat(0,3) = -2*midU/diffU,

        ProjMat(1,0) = 0.0; ProjMat(1,1) = 2/diffV; ProjMat(1,2) = 2*shV/diffV;
        ProjMat(1,3) = -2*midV/diffV;

        ProjMat(2,0) =  0.0; ProjMat(2,1) =  0.0; ProjMat(2,2) = 1.0;  ProjMat(2,3) =  0.0;
        ProjMat(3,0) =  0.0; ProjMat(3,1) =  0.0; ProjMat(3,2) = 0.0;  ProjMat(3,3) =  1.0;
     
        for (int jj=0; jj<4; jj++)
          for (int kk=0; kk<4; kk++)
            projData[jj+kk*4] = ProjMat(jj,kk);

        glMatrixMode(GL_PROJECTION);
        glLoadMatrixf(projData);
        glOrtho(-1.0, 1.0, -1.0, 1.0, -F, -B);

    } else { // perspective projection

        double VRPn = -PRPn;  // VRP after T(-PRP)
        float near2 = PRPn-F;
        float far2  = PRPn-B;
        float zMin = near2/far2;

        /**************** Having trouble with the following transformation ******
        float a,b,c,e,f,g,h;

        a = 2.0*PRPn/(diffU * far);
        b = 2.0*PRPn/(diffV * far);
        c = -1.0/far;

        e = 1/(1-zMin);
        f = -zMin * e;
       
        g = PRPu - shU * PRPn;
        h = PRPv - shV * PRPn;

        ProjMat.Set(     a,   0.0,         0.0,    0.0,
                       0.0,     b,         0.0,    0.0,
                     a*shU, b*shV,         e*c,     -c,
                       -a*g,  -b*h, e*c*PRPn+f, -c*PRPn);  

        for (int jj=0; jj<4; jj++)
          for (int kk=0; kk<4; kk++)
            projData[jj*4+kk) = ProjMat.m(jj)[kk);

        glMatrixMode(GL_PROJECTION);
        glLoadMatrixf(projData);
        ******* so in the meantime use the following - NO SHEARING  **************/


        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(cop(0),cop(1),cop(2),vrp(0),vrp(1),vrp(2),vuv(0),vuv(1),vuv(2));

        glMatrixMode(GL_PROJECTION);
        float left = near2*diffU/VRPn/2;
        float bottom = near2*diffV/VRPn/2;
        float right = -left;
        float top = -bottom;
        glLoadIdentity();
        glFrustum(left,right,bottom,top,near2,far2);   

    }

    int xMin = floor((portWindow(0)+1) * width/2.0);
    int xDiff = floor((portWindow(1)-portWindow(0)) * width/2.0);
    int yMin = floor((portWindow(2)+1) * height/2.0);
    int yDiff = floor((portWindow(3)-portWindow(2)) * height/2.0);

    glViewport((GLsizei) xMin, (GLsizei) yMin, (GLsizei) xDiff, (GLsizei) yDiff);

    if (theOutputFileName != 0) {
        theFile << "StartImage\n";
        theFile << "VRP " << vrp(0) << " " << vrp(1) << " "
            << vrp(2) << " " << endln;
        theFile << "VPN " << vpn(0) << " " << vpn(1) << " "
            << vpn(2) << " " << endln;
        theFile << "VUV " << vuv(0) << " " << vuv(1) << " "
            << vuv(2) << " " << endln;
        theFile << "COP " << cop(0) << " " << cop(1) << " "
            << cop(2) << " " << endln;
       
        theFile << "PROJECTIONMODE " << projectionMode << endln;
        theFile << "VPWINDOW " << vpWindow(0) << " " << vpWindow(1) << " "
            << vpWindow(2) << " " << vpWindow(3) << " " << endln;
        theFile << "PLANES " << clippingPlanes[0] << " " << clippingPlanes[1] << "\n";
        theFile << "PORTWINDOW " << portWindow(0) << " " << portWindow(1) << " "
            << portWindow(2) << " " << portWindow(3) << " " << endln;
    }
 
    // done
    return 0;
}


int
OpenGLRenderer::doneImage(void)
{
  if (theOutputFileName != 0) {
    theFile << "DoneImage\n";
  }
   
  if (count != -1) {
    count++;
  }

  theDevice->ENDIMAGE();    
  return 0;
}

int
OpenGLRenderer::drawPoint(const Vector &pos1, float V1, int numPixels)
{
    glPointSize(numPixels);

    glBegin(GL_POINTS);
    float r, g, b;

    theMap->getRGB(V1, r, g, b);
    glColor3f(r,g,b);
    glVertex3f(pos1(0),pos1(1),pos1(2));
   
    if (theOutputFileName != 0) {
        theFile << "Point\n" << pos1(0) << " " << pos1(1) << " " << pos1(2)
            << " " << r << " " << g << " " << b << " " << endln;
    }

    glEnd();

    return 0;  
}


int
OpenGLRenderer::drawPoint(const Vector &pos1, const Vector &rgb, int numPixels)
{
    glPointSize(numPixels);

    glBegin(GL_POINTS);
    float r, g, b;
    r = rgb(0);
    g = rgb(1);
    b = rgb(2);

    glColor3f(r,g,b);
    glVertex3f(pos1(0),pos1(1),pos1(2));
   
    if (theOutputFileName != 0) {
        theFile << "Point\n" << pos1(0) << " " << pos1(1) << " " << pos1(2)
            << " " << r << " " << g << " " << b << " " << endln;
    }

    glEnd();

    return 0;  
}



int
OpenGLRenderer::drawLine(const Vector &pos1, const Vector &pos2,
                         float V1, float V2, int width, int style)
{
    // open gl does a divide by zero error if points are the same - so check
    if (pos1(0) == pos2(0) && pos1(1) == pos2(1) && pos1(2) == pos2(2))
      return 0;

    glLineWidth(width);

    glBegin(GL_LINES);
    float r, g, b;

    theMap->getRGB(V1, r, g, b);
    glColor3f(r,g,b);

    glVertex3f(pos1(0),pos1(1),pos1(2));
   
    if (theOutputFileName != 0) {
        theFile << "Line\n" << pos1(0) << " " << pos1(1) << " " << pos1(2)
            << " " << r << " " << g << " " << b << " " << endln;
    }

    theMap->getRGB(V2, r, g, b);
    glColor3f(r,g,b);

    glVertex3f(pos2(0),pos2(1),pos2(2));
    glEnd();

    if (theOutputFileName != 0) {
        theFile << pos2(0) << " " << pos2(1) << " " << pos2(2) << " " << r
            << " " << g << " " << b << " " << endln;
    }

    return 0;  
}



int
OpenGLRenderer::drawLine(const Vector &end1, const Vector &end2,
                         const Vector &rgb1, const Vector &rgb2,
                         int width, int style)
{
    // open gl does a divide by zero error if points are the same
    if (end1(0) == end2(0) && end1(1) == end2(1) && end1(2) == end2(2))
      return 0;

    glLineWidth(width);

    glBegin(GL_LINES);
    float r, g, b;
    r = rgb1(0);
    g = rgb1(1);
    b = rgb1(2);
 
    if (theOutputFileName != 0) {
        theFile << "Line\n" << end1(0) << " " << end1(1) << " " << end1(2)
            << " " << r << " " << g << " " << b << " " << endln;
    }
    glColor3f(r,g,b);
    glVertex3f(end1(0),end1(1),end1(2));

    r = rgb2(0);
    g = rgb2(1);
    b = rgb2(2);
 
    if (theOutputFileName != 0) {
        theFile << end2(0) << " " << end2(1) << " " << end2(2) << " " << r
            << " " << g << " " << b << " " << endln;
    }
    glColor3f(r,g,b);

    glVertex3f(end2(0),end2(1),end2(2));
    glEnd();

    return 0;
}



int
OpenGLRenderer::drawPolygon(const Matrix &pos, const Vector &data)

{
#ifdef _G3DEBUG
  if (pos.noCols() != 3) {
    opserr << "OpenGLRenderer::drawPolygon - matrix needs 3 cols\n";
    return -1;
  }
  if (pos.noRows() != data.Size()) {
    opserr << "OpenGLRenderer::drawPolygon - matrix & vector incompatable\n";
    return -1;
  }
#endif

  double posX, posY, posZ, value;
  float r,g,b;

    glBegin(GL_POLYGON);
    int numRows = pos.noRows();
    for (int i=0; i<numRows; i++) {
      posX = pos(i,0);
      posY = pos(i,1);
      posZ = pos(i,2);
      value = data(i);
      theMap->getRGB(value, r, g, b);

    if (theOutputFileName != 0) {
        theFile << posX << " " << posY << " " << posZ << " " << r
            << " " << g << " " << b << " " << endln;
    }
      glColor3f(r,g,b);
      glVertex3f(posX, posY, posZ);
    }

    glEnd();

    return 0;
}


int
OpenGLRenderer::drawPolygon(const Matrix &pos, const Matrix &rgbData)

{
#ifdef _G3DEBUG
  if (pos.noCols() != 3 || rgbData.noCols() != 3) {
    opserr << "OpenGLRenderer::drawPolygon - matrix needs 3 cols\n";
    return -1;
  }
  if (pos.noRows() != rgbData.noRows()) {
    opserr << "OpenGLRenderer::drawPolygon - matrix & vector incompatable\n";
    return -1;
  }
#endif

  double posX, posY, posZ;
  float r,g,b;

    glBegin(GL_POLYGON);
    int numRows = pos.noRows();
    for (int i=0; i<numRows; i++) {
      posX = pos(i,0);
      posY = pos(i,1);
      posZ = pos(i,2);
      r = rgbData(i,0);
      g = rgbData(i,1);
      b = rgbData(i,2);

    if (theOutputFileName != 0) {
        theFile << posX << " " << posY << " " << posZ << " " << r
            << " " << g << " " << b << " " << endln;
    }
      glColor3f(r,g,b);
      glVertex3f(posX, posY, posZ);
    }

    glEnd();

    return 0;
}



int
OpenGLRenderer::drawText(const Vector &pos, char *text, int length,
                         char horizontalJustify, char verticalJustify)
{
    // add POINTs to the FACE  
    int size = pos.Size();
    float x,y,z;
    if (size == 1) {
        x = pos(0);
        y = 0;
        z = 0;
    } else if (size == 2) {
        x = pos(0);
        y = pos(1);
        z = 0;
    } else {
        x = pos(0);
        y = pos(1);
        z = pos(2);
    }  

    theDevice->drawText(x,y,z, text, length, horizontalJustify, verticalJustify);

    return 0;
}

int
OpenGLRenderer::setVRP(float x, float y, float z)
{
  vrp(0) = x;
  vrp(1) = y;
  vrp(2) = z;

  return 0;
}

int
OpenGLRenderer::setVPN(float x, float y, float z)
{
  vpn(0) = x;
  vpn(1) = y;
  vpn(2) = z;

  return 0;
}

int
OpenGLRenderer::setVUP(float x, float y, float z)
{
  vuv(0) = x;
  vuv(1) = y;
  vuv(2) = z;

  return 0;
}

int
OpenGLRenderer::setViewWindow(float umin, float umax, float vmin, float vmax)
{
  if (umin > umax || vmin > vmax) {
      opserr << "OpenGLRenderer::setViewWindow() - invalid window ";
      opserr << umin << " "<< umax << " "<< vmin << " "<< vmax << endln;
      return -1;
  }

  vpWindow(0) = umin;
  vpWindow(1) = umax;
  vpWindow(2) = vmin;
  vpWindow(3) = vmax;

  return 0;
}

int
OpenGLRenderer::setPlaneDist(float anear, float afar)
{
  if ((anear < afar)) {
      opserr << "OpenGLRenderer::setClippingPlanes() - invalid planes";
      opserr << anear << " " << afar << endln;
      return -1;
  }

  clippingPlanes[0] = anear;
  clippingPlanes[1] = afar;

  return 0;
}

int
OpenGLRenderer::setProjectionMode(const char *newMode)
{
  if ((strcmp(newMode, "parallel") == 0) || (strcmp(newMode, "Parallel") == 0))
    projectionMode = PARALLEL_MODE;
  else if ((strcmp(newMode, "perspective") == 0) || (strcmp(newMode, "Perspective") == 0))
    projectionMode = PERSPECTIVE_MODE;
  return 0;
}

int
OpenGLRenderer::setFillMode(const char *newMode)
{
  if ((strcmp(newMode, "wire") == 0) || (strcmp(newMode, "Wire") == 0))
    fillMode = WIRE_MODE;
  else if ((strcmp(newMode, "fill") == 0) || (strcmp(newMode, "Fill") == 0))
    fillMode = FILL_MODE;

  return 0;
}

// eye location
int
OpenGLRenderer::setPRP(float u, float v, float n){
  cop(0) = u;
  cop(1) = v;
  cop(2) = n;

  return 0;
}
   
int
OpenGLRenderer::setPortWindow(float left, float right,
                             float bottom, float top)
{
  if (left < -1 || right > 1 || bottom < -1 || top > 1
      || left > right || bottom > top) {
     
      opserr << "OpenGLRenderer::setPortWindow() - bounds invalid ";
      opserr << left << " "<< right << " "<< bottom << " "<< top << endln;
      return -1;
  }

  portWindow(0) = left;
  portWindow(1) = right;
  portWindow(2) = bottom;
  portWindow(3) = top;

  return 0;
}