opengl_renderer.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:64k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: opengl_renderer.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 18:28:52  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.79
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: opengl_renderer.cpp,v 1000.3 2004/06/01 18:28:52 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Authors:  Paul Thiessen
  35. *
  36. * File Description:
  37. *      Classes to hold the OpenGL rendering engine
  38. *
  39. * ===========================================================================
  40. */
  41. #ifdef _MSC_VER
  42. #pragma warning(disable:4018)   // disable signed/unsigned mismatch warning in MSVC
  43. #endif
  44. #include <ncbi_pch.hpp>
  45. #include <corelib/ncbistd.hpp>
  46. #include <corelib/ncbitime.hpp> // avoids some 'CurrentTime' conflict later on...
  47. #include <corelib/ncbiobj.hpp>
  48. #if defined(__WXMSW__)
  49. #include <windows.h>
  50. #include <GL/gl.h>
  51. #include <GL/glu.h>
  52. #elif defined(__WXGTK__)
  53. #include <GL/gl.h>
  54. #include <GL/glu.h>
  55. #include <GL/glx.h>
  56. #include <gdk/gdk.h>    // needed for GdkFont
  57. #elif defined(__WXMAC__)
  58. //#include <Fonts.h>
  59. #include <OpenGL/gl.h>
  60. #include <OpenGL/glu.h>
  61. #endif
  62. #include <math.h>
  63. #include <stdlib.h> // for rand, srand
  64. #include <objects/cn3d/Cn3d_GL_matrix.hpp>
  65. #include <objects/cn3d/Cn3d_vector.hpp>
  66. #include "opengl_renderer.hpp"
  67. #include "structure_window.hpp"
  68. #include "cn3d_glcanvas.hpp"
  69. #include "structure_set.hpp"
  70. #include "style_manager.hpp"
  71. #include "messenger.hpp"
  72. #include "cn3d_tools.hpp"
  73. #include "asn_converter.hpp"
  74. #include "cn3d_colors.hpp"
  75. USING_NCBI_SCOPE;
  76. USING_SCOPE(objects);
  77. BEGIN_SCOPE(Cn3D)
  78. static const double PI = acos(-1.0);
  79. static inline double DegreesToRad(double deg) { return deg*PI/180.0; }
  80. static inline double RadToDegrees(double rad) { return rad*180.0/PI; }
  81. const unsigned int OpenGLRenderer::NO_LIST = 0;
  82. const unsigned int OpenGLRenderer::FIRST_LIST = 1;
  83. const unsigned int OpenGLRenderer::FONT_BASE = 1000;
  84. static const unsigned int ALL_FRAMES = 4294967295;
  85. // it's easier to keep one global qobj for now
  86. static GLUquadricObj *qobj = NULL;
  87. // pick buffer
  88. const unsigned int OpenGLRenderer::NO_NAME = 0;
  89. static const int pickBufSize = 1024;
  90. static GLuint selectBuf[pickBufSize];
  91. /* these are used for both matrial colors and light colors */
  92. static const GLfloat Color_Off[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
  93. static const GLfloat Color_MostlyOff[4] = { 0.05f, 0.05f, 0.05f, 1.0f };
  94. static const GLfloat Color_MostlyOn[4] = { 0.95f, 0.95f, 0.95f, 1.0f };
  95. static const GLfloat Color_On[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
  96. static const GLfloat Color_Specular[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
  97. static const GLint Shininess = 40;
  98. // to cache registry values
  99. static int atomSlices, atomStacks, bondSides, wormSides, wormSegments, helixSides;
  100. static bool highlightsOn;
  101. static string projectionType;
  102. // matrix conversion utility functions
  103. // convert from Matrix to GL-matrix ordering
  104. static void Matrix2GL(const Matrix& m, GLdouble *g)
  105. {
  106.     g[0]=m.m[0];  g[4]=m.m[1];  g[8]=m.m[2];   g[12]=m.m[3];
  107.     g[1]=m.m[4];  g[5]=m.m[5];  g[9]=m.m[6];   g[13]=m.m[7];
  108.     g[2]=m.m[8];  g[6]=m.m[9];  g[10]=m.m[10]; g[14]=m.m[11];
  109.     g[3]=m.m[12]; g[7]=m.m[13]; g[11]=m.m[14]; g[15]=m.m[15];
  110. }
  111. // convert from GL-matrix to Matrix ordering
  112. static void GL2Matrix(GLdouble *g, Matrix *m)
  113. {
  114.     m->m[0]=g[0];  m->m[1]=g[4];  m->m[2]=g[8];   m->m[3]=g[12];
  115.     m->m[4]=g[1];  m->m[5]=g[5];  m->m[6]=g[9];   m->m[7]=g[13];
  116.     m->m[8]=g[2];  m->m[9]=g[6];  m->m[10]=g[10]; m->m[11]=g[14];
  117.     m->m[12]=g[3]; m->m[13]=g[7]; m->m[14]=g[11]; m->m[15]=g[15];
  118. }
  119. // OpenGLRenderer methods - initialization and setup
  120. OpenGLRenderer::OpenGLRenderer(Cn3DGLCanvas *parentGLCanvas) :
  121.     structureSet(NULL), glCanvas(parentGLCanvas),
  122.     selectMode(false), currentDisplayList(NO_LIST), cameraAngleRad(0.0), rotateSpeed(0.5),
  123.     stereoOn(false)
  124. {
  125.     // make sure a name will fit in a GLuint
  126.     if (sizeof(GLuint) < sizeof(unsigned int))
  127.         FATALMSG("Cn3D requires that sizeof(GLuint) >= sizeof(unsigned int)");
  128. }
  129. void OpenGLRenderer::Init(void) const
  130. {
  131.     glMatrixMode(GL_MODELVIEW);
  132.     glLoadIdentity();
  133.     // set up the lighting
  134.     // directional light (faster) when LightPosition[4] == 0.0
  135.     GLfloat LightPosition[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
  136.     glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
  137.     glLightfv(GL_LIGHT0, GL_AMBIENT, Color_Off);
  138.     glLightfv(GL_LIGHT0, GL_DIFFUSE, Color_MostlyOn);
  139.     glLightfv(GL_LIGHT0, GL_SPECULAR, Color_On);
  140.     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Color_On); // global ambience
  141.     glEnable(GL_LIGHTING);
  142.     glEnable(GL_LIGHT0);
  143.     // set these material colors
  144.     glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, Color_Off);
  145.     glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, Shininess);
  146.     // turn on culling to speed rendering
  147.     glEnable(GL_CULL_FACE);
  148.     glCullFace(GL_BACK);
  149.     glFrontFace(GL_CCW);
  150.     // misc options
  151.     glShadeModel(GL_SMOOTH);
  152.     glEnable(GL_DEPTH_TEST);
  153.     glDisable(GL_NORMALIZE);
  154.     glDisable(GL_SCISSOR_TEST);
  155.     RecreateQuadric();
  156. }
  157. // methods dealing with the view
  158. void OpenGLRenderer::NewView(double eyeTranslateToAngleDegrees) const
  159. {
  160.     if (cameraAngleRad <= 0.0) return;
  161.     GLint Viewport[4];
  162.     glGetIntegerv(GL_VIEWPORT, Viewport);
  163.     glMatrixMode(GL_PROJECTION);
  164.     glLoadIdentity();
  165.     if (selectMode) {
  166.         gluPickMatrix(static_cast<GLdouble>(selectX),
  167.                       static_cast<GLdouble>(Viewport[3] - selectY),
  168.                       1.0, 1.0, Viewport);
  169.     }
  170.     GLdouble aspect = (static_cast<GLdouble>(Viewport[2])) / Viewport[3];
  171.     // set camera angle/perspective
  172.     if (projectionType == "Perspective") {
  173.         gluPerspective(RadToDegrees(cameraAngleRad),    // viewing angle (degrees)
  174.                        aspect,                          // w/h aspect
  175.                        cameraClipNear,                  // near clipping plane
  176.                        cameraClipFar);                  // far clipping plane
  177.     } else { // Orthographic
  178.         GLdouble right, top;
  179.         top = ((cameraClipNear + cameraClipFar) / 2.0) * sin(cameraAngleRad / 2.0);
  180.         right = top * aspect;
  181.         glOrtho(-right,             // sides of viewing box, assuming eye is at (0,0,0)
  182.                 right,
  183.                 -top,
  184.                 top,
  185.                 cameraClipNear,     // near clipping plane
  186.                 cameraClipFar);     // far clipping plane
  187.     }
  188.     Vector cameraLoc(0.0, 0.0, cameraDistance);
  189.     if (stereoOn && eyeTranslateToAngleDegrees != 0.0) {
  190.         Vector view(cameraLookAtX, cameraLookAtY, -cameraDistance);
  191.         Vector translate = vector_cross(view, Vector(0.0, 1.0, 0.0));
  192.         translate.normalize();
  193.         translate *= view.length() * tan(DegreesToRad(eyeTranslateToAngleDegrees));
  194.         cameraLoc += translate;
  195.     }
  196.     // set camera position and direction
  197.     gluLookAt(cameraLoc.x, cameraLoc.y, cameraLoc.z,    // the camera position
  198.               cameraLookAtX, cameraLookAtY, 0.0,        // the "look-at" point
  199.               0.0, 1.0, 0.0);                           // the up direction
  200.     glMatrixMode(GL_MODELVIEW);
  201. }
  202. void OpenGLRenderer::Display(void)
  203. {
  204.     if (structureSet) {
  205.         const Vector& background = structureSet->styleManager->GetBackgroundColor();
  206.         glClearColor(background[0], background[1], background[2], 1.0);
  207.     } else
  208.         glClearColor(0.0, 0.0, 0.0, 1.0);
  209.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  210.     if (selectMode) {
  211.         glInitNames();
  212.         glPushName(0);
  213.     }
  214.     GLint viewport[4] = {0, 0, 0, 0};
  215.     double eyeSeparationDegrees = 0.0;
  216.     if (stereoOn) {
  217.         bool proximalStereo;
  218.         glGetIntegerv(GL_VIEWPORT, viewport);
  219.         if (!RegistryGetDouble(REG_ADVANCED_SECTION, REG_STEREO_SEPARATION, &eyeSeparationDegrees) ||
  220.             !RegistryGetBoolean(REG_ADVANCED_SECTION, REG_PROXIMAL_STEREO, &proximalStereo))
  221.         {
  222.             ERRORMSG("OpenGLRenderer::Display() - error getting stereo settings from registry");
  223.             return;
  224.         }
  225.         if (!proximalStereo)
  226.             eyeSeparationDegrees = -eyeSeparationDegrees;
  227.     }
  228.     int first = 1, last = stereoOn ? 2 : 1;
  229.     for (int e=first; e<=last; ++e) {
  230.         glLoadMatrixd(viewMatrix);
  231.         // adjust viewport & camera angle for stereo
  232.         if (stereoOn) {
  233.             if (e == first) {
  234.                 // left side
  235.                 glViewport(0, viewport[1], viewport[2] / 2, viewport[3]);
  236.                 NewView(eyeSeparationDegrees / 2);
  237.             } else {
  238.                 // right side
  239.                 glViewport(viewport[2] / 2, viewport[1], viewport[2] - viewport[2] / 2, viewport[3]);
  240.                 NewView(-eyeSeparationDegrees / 2);
  241.             }
  242.         }
  243.         if (structureSet) {
  244.             if (currentFrame == ALL_FRAMES) {
  245.                 for (unsigned int i=FIRST_LIST; i<=structureSet->lastDisplayList; ++i) {
  246.                     PushMatrix(*(structureSet->transformMap[i]));
  247.                     glCallList(i);
  248.                     PopMatrix();
  249.                     AddTransparentSpheresForList(i);
  250.                 }
  251.             } else {
  252.                 StructureSet::DisplayLists::const_iterator
  253.                     l, le=structureSet->frameMap[currentFrame].end();
  254.                 for (l=structureSet->frameMap[currentFrame].begin(); l!=le; ++l) {
  255.                     PushMatrix(*(structureSet->transformMap[*l]));
  256.                     glCallList(*l);
  257.                     PopMatrix();
  258.                     AddTransparentSpheresForList(*l);
  259.                 }
  260.             }
  261.             // draw transparent spheres, which are already stored in view-transformed coordinates
  262.             glLoadIdentity();
  263.             RenderTransparentSpheres();
  264.         }
  265.         // draw logo if no structure
  266.         else {
  267.             glCallList(FIRST_LIST);
  268.         }
  269.     }
  270.     glFlush();
  271.     // restore full viewport
  272.     if (stereoOn)
  273.         glViewport(0, viewport[1], viewport[2], viewport[3]);
  274. }
  275. void OpenGLRenderer::EnableStereo(bool enableStereo)
  276. {
  277.     TRACEMSG("turning " << (enableStereo ? "on" : "off" ) << " stereo");
  278.     stereoOn = enableStereo;
  279.     if (!stereoOn)
  280.         NewView();
  281. }
  282. void OpenGLRenderer::ResetCamera(void)
  283. {
  284.     // set up initial camera
  285.     glLoadIdentity();
  286.     cameraLookAtX = cameraLookAtY = 0.0;
  287.     if (structureSet) { // for structure
  288.         cameraAngleRad = DegreesToRad(35.0);
  289.         // calculate camera distance so that structure fits exactly in
  290.         // the window in any rotation (based on structureSet's maxDistFromCenter)
  291.         GLint Viewport[4];
  292.         glGetIntegerv(GL_VIEWPORT, Viewport);
  293.         double angle = cameraAngleRad, aspect = (static_cast<double>(Viewport[2])) / Viewport[3];
  294.         if (aspect < 1.0) angle *= aspect;
  295.         cameraDistance = structureSet->maxDistFromCenter / sin(angle/2);
  296.         // allow a little "extra" room between clipping planes
  297.         cameraClipNear = (cameraDistance - structureSet->maxDistFromCenter) * 0.66;
  298.         cameraClipFar = (cameraDistance + structureSet->maxDistFromCenter) * 1.2;
  299.         // move structureSet's center to origin
  300.         glTranslated(-structureSet->center.x, -structureSet->center.y, -structureSet->center.z);
  301.         structureSet->rotationCenter = structureSet->center;
  302.     } else { // for logo
  303.         cameraAngleRad = PI / 14;
  304.         cameraDistance = 200;
  305.         cameraClipNear = 0.5*cameraDistance;
  306.         cameraClipFar = 1.5*cameraDistance;
  307.     }
  308.     // reset matrix
  309.     glGetDoublev(GL_MODELVIEW_MATRIX, viewMatrix);
  310.     NewView();
  311. }
  312. void OpenGLRenderer::ChangeView(eViewAdjust control, int dX, int dY, int X2, int Y2)
  313. {
  314.     bool doTranslation = false;
  315.     Vector rotCenter;
  316.     double pixelSize;
  317.     GLint viewport[4];
  318.     // find out where rotation center is in current GL coordinates
  319.     if (structureSet && (control==eXYRotateHV || control==eZRotateH) &&
  320.         structureSet->rotationCenter != structureSet->center) {
  321.         Matrix m;
  322.         GL2Matrix(viewMatrix, &m);
  323.         rotCenter = structureSet->rotationCenter;
  324.         ApplyTransformation(&rotCenter, m);
  325.         doTranslation = true;
  326.     }
  327.     glLoadIdentity();
  328.     // rotate relative to rotationCenter
  329.     if (doTranslation) glTranslated(rotCenter.x, rotCenter.y, rotCenter.z);
  330. #define MIN_CAMERA_ANGLE 0.001
  331. #define MAX_CAMERA_ANGLE (0.999 * PI)
  332.     switch (control) {
  333.         case eXYRotateHV:
  334.             glRotated(rotateSpeed*dY, 1.0, 0.0, 0.0);
  335.             glRotated(rotateSpeed*dX, 0.0, 1.0, 0.0);
  336.             break;
  337.         case eZRotateH:
  338.             glRotated(rotateSpeed*dX, 0.0, 0.0, 1.0);
  339.             break;
  340.         case eXYTranslateHV:
  341.             glGetIntegerv(GL_VIEWPORT, viewport);
  342.             pixelSize = tan(cameraAngleRad / 2.0) * 2.0 * cameraDistance / viewport[3];
  343.             cameraLookAtX -= dX * pixelSize;
  344.             cameraLookAtY += dY * pixelSize;
  345.             NewView();
  346.             break;
  347.         case eZoomH:
  348.             cameraAngleRad *= 1.0 - 0.01 * dX;
  349.             if (cameraAngleRad < MIN_CAMERA_ANGLE) cameraAngleRad = MIN_CAMERA_ANGLE;
  350.             else if (cameraAngleRad > MAX_CAMERA_ANGLE) cameraAngleRad = MAX_CAMERA_ANGLE;
  351.             NewView();
  352.             break;
  353.         case eZoomHHVV:
  354.             break;
  355.         case eZoomOut:
  356.             cameraAngleRad *= 1.5;
  357.             if (cameraAngleRad > MAX_CAMERA_ANGLE) cameraAngleRad = MAX_CAMERA_ANGLE;
  358.             NewView();
  359.             break;
  360.         case eZoomIn:
  361.             cameraAngleRad /= 1.5;
  362.             if (cameraAngleRad < MIN_CAMERA_ANGLE) cameraAngleRad = MIN_CAMERA_ANGLE;
  363.             NewView();
  364.             break;
  365.         case eCenterCamera:
  366.             cameraLookAtX = cameraLookAtY = 0.0;
  367.             NewView();
  368.             break;
  369.     }
  370.     if (doTranslation) glTranslated(-rotCenter.x, -rotCenter.y, -rotCenter.z);
  371.     glMultMatrixd(viewMatrix);
  372.     glGetDoublev(GL_MODELVIEW_MATRIX, viewMatrix);
  373. }
  374. void OpenGLRenderer::CenterView(const Vector& viewCenter, double radius)
  375. {
  376.     ResetCamera();
  377.     structureSet->rotationCenter = viewCenter;
  378.     Vector cameraLocation(0.0, 0.0, cameraDistance);
  379.     Vector centerWRTcamera = viewCenter - structureSet->center;
  380.     Vector direction = centerWRTcamera - cameraLocation;
  381.     direction.normalize();
  382.     double cosAngleZ = -direction.z;
  383.     Vector lookAt = centerWRTcamera + direction * (centerWRTcamera.z / cosAngleZ);
  384.     cameraLookAtX = lookAt.x;
  385.     cameraLookAtY = lookAt.y;
  386.     cameraAngleRad = 2.0 * atan(radius / (cameraLocation - centerWRTcamera).length());
  387.     NewView();
  388.     TRACEMSG("looking at " << lookAt << " angle " << RadToDegrees(cameraAngleRad));
  389.     // do this so that this view is used upon restore
  390.     SaveToASNViewSettings(NULL);
  391. }
  392. void OpenGLRenderer::PushMatrix(const Matrix* m)
  393. {
  394.     glPushMatrix();
  395.     if (m) {
  396.         GLdouble g[16];
  397.         Matrix2GL(*m, g);
  398.         glMultMatrixd(g);
  399.     }
  400. }
  401. void OpenGLRenderer::PopMatrix(void)
  402. {
  403.     glPopMatrix();
  404. }
  405. // display list management stuff
  406. void OpenGLRenderer::StartDisplayList(unsigned int list)
  407. {
  408.     if (list >= FONT_BASE) {
  409.         ERRORMSG("OpenGLRenderer::StartDisplayList() - too many display lists;n"
  410.             << "increase OpenGLRenderer::FONT_BASE");
  411.         return;
  412.     }
  413.     ClearTransparentSpheresForList(list);
  414.     SetColor(GL_NONE); // reset color caches in SetColor
  415.     glNewList(list, GL_COMPILE);
  416.     currentDisplayList = list;
  417.     if (currentDisplayList >= displayListEmpty.size()) displayListEmpty.resize(currentDisplayList + 1, true);
  418.     displayListEmpty[currentDisplayList] = true;
  419. }
  420. void OpenGLRenderer::EndDisplayList(void)
  421. {
  422.     glEndList();
  423.     currentDisplayList = NO_LIST;
  424. }
  425. // frame management methods
  426. void OpenGLRenderer::ShowAllFrames(void)
  427. {
  428.     if (structureSet) currentFrame = ALL_FRAMES;
  429. }
  430. bool OpenGLRenderer::IsFrameEmpty(unsigned int frame) const
  431. {
  432.     if (!structureSet || structureSet->frameMap.size() <= frame) return false;
  433.     StructureSet::DisplayLists::const_iterator l, le=structureSet->frameMap[frame].end();
  434.     for (l=structureSet->frameMap[frame].begin(); l!=le; ++l)
  435.         if (!displayListEmpty[*l])
  436.             return false;
  437.     return true;
  438. }
  439. void OpenGLRenderer::ShowFirstFrame(void)
  440. {
  441.     if (!structureSet || structureSet->frameMap.size() == 0) return;
  442.     currentFrame = 0;
  443.     while (IsFrameEmpty(currentFrame) && currentFrame < structureSet->frameMap.size() - 1)
  444.         ++currentFrame;
  445. }
  446. void OpenGLRenderer::ShowLastFrame(void)
  447. {
  448.     if (!structureSet || structureSet->frameMap.size() == 0) return;
  449.     currentFrame = structureSet->frameMap.size() - 1;
  450.     while (IsFrameEmpty(currentFrame) && currentFrame > 0)
  451.         --currentFrame;
  452. }
  453. void OpenGLRenderer::ShowNextFrame(void)
  454. {
  455.     if (!structureSet || structureSet->frameMap.size() == 0) return;
  456.     if (currentFrame == ALL_FRAMES) currentFrame = structureSet->frameMap.size() - 1;
  457.     int originalFrame = currentFrame;
  458.     do {
  459.         if (currentFrame == structureSet->frameMap.size() - 1)
  460.             currentFrame = 0;
  461.         else
  462.             ++currentFrame;
  463.     } while (IsFrameEmpty(currentFrame) && currentFrame != originalFrame);
  464. }
  465. void OpenGLRenderer::ShowPreviousFrame(void)
  466. {
  467.     if (!structureSet || structureSet->frameMap.size() == 0) return;
  468.     if (currentFrame == ALL_FRAMES) currentFrame = 0;
  469.     int originalFrame = currentFrame;
  470.     do {
  471.         if (currentFrame == 0)
  472.             currentFrame = structureSet->frameMap.size() - 1;
  473.         else
  474.             --currentFrame;
  475.     } while (IsFrameEmpty(currentFrame) && currentFrame != originalFrame);
  476. }
  477. void OpenGLRenderer::ShowFrameNumber(int frame)
  478. {
  479.     if (!structureSet) return;
  480.     if (frame >= 0 && frame < structureSet->frameMap.size() && !IsFrameEmpty(frame))
  481.         currentFrame = frame;
  482.     else
  483.         currentFrame = ALL_FRAMES;
  484. }
  485. // process selection; return gl-name of result
  486. bool OpenGLRenderer::GetSelected(int x, int y, unsigned int *name)
  487. {
  488.     // render with GL_SELECT mode, to fill selection buffer
  489.     glSelectBuffer(pickBufSize, selectBuf);
  490.     glRenderMode(GL_SELECT);
  491.     selectMode = true;
  492.     selectX = x;
  493.     selectY = y;
  494.     NewView();
  495.     Display();
  496.     GLint hits = glRenderMode(GL_RENDER);
  497.     selectMode = false;
  498.     NewView();
  499.     // parse selection buffer to find name of selected item
  500.     int i, j, p=0, n, top=0;
  501.     GLuint minZ=0;
  502.     *name = NO_NAME;
  503.     for (i=0; i<hits; ++i) {
  504.         n = selectBuf[p++];                 // # names
  505.         if (i==0 || minZ > selectBuf[p]) {  // find item with min depth
  506.             minZ = selectBuf[p];
  507.             top = 1;
  508.         } else
  509.             top = 0;
  510.         ++p;
  511.         ++p;                                // skip max depth
  512.         for (j=0; j<n; ++j) {               // loop through n names
  513.             switch (j) {
  514.                 case 0:
  515.                     if (top) *name = static_cast<unsigned int>(selectBuf[p]);
  516.                     break;
  517.                 default:
  518.                     WARNINGMSG("GL select: Got more than 1 name!");
  519.             }
  520.             ++p;
  521.         }
  522.     }
  523.     if (*name != NO_NAME)
  524.         return true;
  525.     else
  526.         return false;
  527. }
  528. void OpenGLRenderer::AttachStructureSet(StructureSet *targetStructureSet)
  529. {
  530.     structureSet = targetStructureSet;
  531.     currentFrame = ALL_FRAMES;
  532.     if (!structureSet) initialViewFromASN.Reset();
  533.     Init();             // init GL system
  534.     Construct();        // draw structures
  535.     RestoreSavedView(); // load initial view if present
  536. }
  537. void OpenGLRenderer::RecreateQuadric(void) const
  538. {
  539.     if (qobj)
  540.         gluDeleteQuadric(qobj);
  541.     if (!(qobj = gluNewQuadric())) {
  542.         ERRORMSG("unable to create a new GLUQuadricObj");
  543.         return;
  544.     }
  545.     gluQuadricDrawStyle(qobj, (GLenum) GLU_FILL);
  546.     gluQuadricNormals(qobj, (GLenum) GLU_SMOOTH);
  547.     gluQuadricOrientation(qobj, (GLenum) GLU_OUTSIDE);
  548.     gluQuadricTexture(qobj, GL_FALSE);
  549. }
  550. void OpenGLRenderer::Construct(void)
  551. {
  552.     glMatrixMode(GL_MODELVIEW);
  553.     glLoadIdentity();
  554.     if (structureSet) {
  555.         // get quality values from registry - assumes some values have been set already!
  556.         if (!RegistryGetInteger(REG_QUALITY_SECTION, REG_QUALITY_ATOM_SLICES, &atomSlices) ||
  557.             !RegistryGetInteger(REG_QUALITY_SECTION, REG_QUALITY_ATOM_STACKS, &atomStacks) ||
  558.             !RegistryGetInteger(REG_QUALITY_SECTION, REG_QUALITY_BOND_SIDES, &bondSides) ||
  559.             !RegistryGetInteger(REG_QUALITY_SECTION, REG_QUALITY_WORM_SIDES, &wormSides) ||
  560.             !RegistryGetInteger(REG_QUALITY_SECTION, REG_QUALITY_WORM_SEGMENTS, &wormSegments) ||
  561.             !RegistryGetInteger(REG_QUALITY_SECTION, REG_QUALITY_HELIX_SIDES, &helixSides) ||
  562.             !RegistryGetBoolean(REG_QUALITY_SECTION, REG_HIGHLIGHTS_ON, &highlightsOn) ||
  563.             !RegistryGetString(REG_QUALITY_SECTION, REG_PROJECTION_TYPE, &projectionType))
  564.             ERRORMSG("OpenGLRenderer::Construct() - error getting quality setting from registry");
  565.         // do the drawing
  566.         structureSet->DrawAll();
  567.     } else {
  568.         SetColor(GL_NONE);
  569.         ConstructLogo();
  570.     }
  571.     GlobalMessenger()->UnPostStructureRedraws();
  572. }
  573. // set current GL color; don't change color if it's same as what's current
  574. void OpenGLRenderer::SetColor(int type, double red, double green, double blue, double alpha)
  575. {
  576.     static double pr, pg, pb, pa;
  577.     static GLenum pt = GL_NONE;
  578.     if (type == GL_NONE) {
  579.         pt = GL_NONE;
  580.         return;
  581.     }
  582.     if (alpha <= 0.0) WARNINGMSG("SetColor request alpha <= 0.0");
  583.     if (red != pr || green != pg || blue != pb || type != pt || alpha != pa) {
  584.         if (type != pt) {
  585.             if (type == GL_DIFFUSE) {
  586.                 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Color_MostlyOff);
  587.                 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
  588.                     highlightsOn ? Color_Specular : Color_Off);
  589.             } else if (type == GL_AMBIENT) {
  590.                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Color_Off);
  591.                 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Color_Off); // no specular for ambient coloring
  592.             } else {
  593.                 ERRORMSG("don't know how to handle material type " << type);
  594.             }
  595.             pt = (GLenum) type;
  596.         }
  597.         GLfloat rgba[4] = { red, green, blue, alpha };
  598.         glMaterialfv(GL_FRONT_AND_BACK, (GLenum) type, rgba);
  599.         // this is necessary so that fonts are rendered in correct
  600.         // color in SGI's OpenGL implementation, and maybe others
  601.         if (type == GL_AMBIENT) glColor4fv(rgba);
  602.         pr = red;
  603.         pg = green;
  604.         pb = blue;
  605.         pa = alpha;
  606.     }
  607. }
  608. /* create display list with logo */
  609. void OpenGLRenderer::ConstructLogo(void)
  610. {
  611.     static const GLfloat logoColor[3] = { 100.0f/255, 240.0f/255, 150.0f/255 };
  612.     static const int LOGO_SIDES = 36, segments = 180;
  613.     int i, n, s, g;
  614.     GLdouble bigRad = 12.0, height = 24.0,
  615.         minRad = 0.1, maxRad = 2.0,
  616.         ringPts[LOGO_SIDES * 3], *pRingPts = ringPts,
  617.         prevRing[LOGO_SIDES * 3], *pPrevRing = prevRing, *tmp,
  618.         ringNorm[LOGO_SIDES * 3], *pRingNorm = ringNorm,
  619.         prevNorm[LOGO_SIDES * 3], *pPrevNorm = prevNorm,
  620.         length, startRad, midRad, phase, currentRad, CR[3], H[3], V[3];
  621.     ClearTransparentSpheresForList(FIRST_LIST);
  622.     glNewList(FIRST_LIST, GL_COMPILE);
  623.     /* create logo */
  624.     SetColor(GL_DIFFUSE, logoColor[0], logoColor[1], logoColor[2]);
  625.     for (n = 0; n < 2; ++n) { /* helix strand */
  626.         if (n == 0) {
  627.             startRad = maxRad;
  628.             midRad = minRad;
  629.             phase = 0;
  630.         } else {
  631.             startRad = minRad;
  632.             midRad = maxRad;
  633.             phase = PI;
  634.         }
  635.         for (g = 0; g <= segments; ++g) { /* segment (bottom to top) */
  636.             if (g < segments/2)
  637.                 currentRad = startRad + (midRad - startRad) *
  638.                     (0.5 - 0.5 * cos(PI * g / (segments/2)));
  639.             else
  640.                 currentRad = midRad + (startRad - midRad) *
  641.                     (0.5 - 0.5 * cos(PI * (g - segments/2) / (segments/2)));
  642.             CR[1] = height * g / segments - height/2;
  643.             if (g > 0) phase += PI * 2 / segments;
  644.             CR[2] = bigRad * cos(phase);
  645.             CR[0] = bigRad * sin(phase);
  646.             /* make a strip around the strand circumference */
  647.             for (s = 0; s < LOGO_SIDES; ++s) {
  648.                 V[0] = CR[0];
  649.                 V[2] = CR[2];
  650.                 V[1] = 0;
  651.                 length = sqrt(V[0]*V[0] + V[1]*V[1] + V[2]*V[2]);
  652.                 for (i = 0; i < 3; ++i) V[i] /= length;
  653.                 H[0] = H[2] = 0;
  654.                 H[1] = 1;
  655.                 for (i = 0; i < 3; ++i) {
  656.                     pRingNorm[3*s + i] = V[i] * cos(PI * 2 * s / LOGO_SIDES) +
  657.                                          H[i] * sin(PI * 2 * s / LOGO_SIDES);
  658.                     pRingPts[3*s + i] = CR[i] + pRingNorm[3*s + i] * currentRad;
  659.                 }
  660.             }
  661.             if (g > 0) {
  662.                 glBegin(GL_TRIANGLE_STRIP);
  663.                 for (s = 0; s < LOGO_SIDES; ++s) {
  664.                     glNormal3d(pPrevNorm[3*s], pPrevNorm[3*s + 1], pPrevNorm[3*s + 2]);
  665.                     glVertex3d(pPrevRing[3*s], pPrevRing[3*s + 1], pPrevRing[3*s + 2]);
  666.                     glNormal3d(pRingNorm[3*s], pRingNorm[3*s + 1], pRingNorm[3*s + 2]);
  667.                     glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]);
  668.                 }
  669.                 glNormal3d(pPrevNorm[0], pPrevNorm[1], pPrevNorm[2]);
  670.                 glVertex3d(pPrevRing[0], pPrevRing[1], pPrevRing[2]);
  671.                 glNormal3d(pRingNorm[0], pRingNorm[1], pRingNorm[2]);
  672.                 glVertex3d(pRingPts[0], pRingPts[1], pRingPts[2]);
  673.                 glEnd();
  674.             }
  675.             /* cap the ends */
  676.             glBegin(GL_POLYGON);
  677.             if ((g == 0 && n == 0) || (g == segments && n == 1))
  678.                 glNormal3d(-1, 0, 0);
  679.             else
  680.                 glNormal3d(1, 0, 0);
  681.             if (g == 0) {
  682.                 for (s = 0; s < LOGO_SIDES; ++s)
  683.                     glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]);
  684.             } else if (g == segments) {
  685.                 for (s = LOGO_SIDES - 1; s >= 0; --s)
  686.                     glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]);
  687.             }
  688.             glEnd();
  689.             /* switch pointers to store previous ring */
  690.             tmp = pPrevRing;
  691.             pPrevRing = pRingPts;
  692.             pRingPts = tmp;
  693.             tmp = pPrevNorm;
  694.             pPrevNorm = pRingNorm;
  695.             pRingNorm = tmp;
  696.         }
  697.     }
  698.     glEndList();
  699. }
  700. // stuff dealing with rendering of transparent spheres
  701. void OpenGLRenderer::AddTransparentSphere(const Vector& color, unsigned int name,
  702.     const Vector& site, double radius, double alpha)
  703. {
  704.     if (currentDisplayList == NO_LIST) {
  705.         WARNINGMSG("OpenGLRenderer::AddTransparentSphere() - not called during display list creation");
  706.         return;
  707.     }
  708.     SphereList& spheres = transparentSphereMap[currentDisplayList];
  709.     spheres.resize(spheres.size() + 1);
  710.     SphereInfo& info = spheres.back();
  711.     info.site = site;
  712.     info.name = name;
  713.     info.color = color;
  714.     info.radius = radius;
  715.     info.alpha = alpha;
  716. }
  717. // add spheres associated with this display list; calculate distance from camera to each one
  718. void OpenGLRenderer::AddTransparentSpheresForList(unsigned int list)
  719. {
  720.     SphereMap::const_iterator sL = transparentSphereMap.find(list);
  721.     if (sL == transparentSphereMap.end()) return;
  722.     const SphereList& sphereList = sL->second;
  723.     Matrix view;
  724.     GL2Matrix(viewMatrix, &view);
  725.     transparentSpheresToRender.resize(transparentSpheresToRender.size() + sphereList.size());
  726.     SpherePtrList::reverse_iterator sph = transparentSpheresToRender.rbegin();
  727.     SphereList::const_iterator i, ie=sphereList.end();
  728.     const Matrix *slaveTransform;
  729.     for (i=sphereList.begin(); i!=ie; ++i, ++sph) {
  730.         sph->siteGL = i->site;
  731.         slaveTransform = *(structureSet->transformMap[list]);
  732.         if (slaveTransform)
  733.             ApplyTransformation(&(sph->siteGL), *slaveTransform);               // slave->master transform
  734.         ApplyTransformation(&(sph->siteGL), view);                              // current view transform
  735.         sph->distanceFromCamera = (Vector(0,0,cameraDistance) - sph->siteGL).length() - i->radius;
  736.         sph->ptr = &(*i);
  737.     }
  738. }
  739. void OpenGLRenderer::RenderTransparentSpheres(void)
  740. {
  741.     if (transparentSpheresToRender.size() == 0) return;
  742.     // sort spheres by distance from camera, via operator < defined for SpherePtr
  743.     transparentSpheresToRender.sort();
  744.     // turn on blending
  745.     glEnable(GL_BLEND);
  746.     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  747.     SetColor(GL_NONE); // reset color caches in SetColor
  748.     // render spheres in order (farthest first)
  749.     SpherePtrList::reverse_iterator i, ie=transparentSpheresToRender.rend();
  750.     for (i=transparentSpheresToRender.rbegin(); i!=ie; ++i) {
  751.         SetColor(GL_DIFFUSE, i->ptr->color[0], i->ptr->color[1], i->ptr->color[2], i->ptr->alpha);
  752.         glLoadName(static_cast<GLuint>(i->ptr->name));
  753.         glPushMatrix();
  754.         glTranslated(i->siteGL.x, i->siteGL.y, i->siteGL.z);
  755.         // apply a random spin so they're not all facing the same direction
  756.         srand(static_cast<unsigned int>(fabs(i->ptr->site.x * 1000)));
  757.         glRotated(360.0*rand()/RAND_MAX,
  758.             1.0*rand()/RAND_MAX - 0.5, 1.0*rand()/RAND_MAX - 0.5, 1.0*rand()/RAND_MAX - 0.5);
  759.         gluSphere(qobj, i->ptr->radius, atomSlices, atomStacks);
  760.         glPopMatrix();
  761.     }
  762.     // turn off blending
  763.     glDisable(GL_BLEND);
  764.     // clear list; recreate it upon each Display()
  765.     transparentSpheresToRender.clear();
  766. }
  767. void OpenGLRenderer::DrawAtom(const Vector& site, const AtomStyle& atomStyle)
  768. {
  769.     if (atomStyle.style == StyleManager::eNotDisplayed || atomStyle.radius <= 0.0)
  770.         return;
  771.     if (atomStyle.style == StyleManager::eSolidAtom) {
  772.         SetColor(GL_DIFFUSE, atomStyle.color[0], atomStyle.color[1], atomStyle.color[2]);
  773.         glLoadName(static_cast<GLuint>(atomStyle.name));
  774.         glPushMatrix();
  775.         glTranslated(site.x, site.y, site.z);
  776.         gluSphere(qobj, atomStyle.radius, atomSlices, atomStacks);
  777.         glPopMatrix();
  778.     }
  779.     // need to delay rendering of transparent spheres
  780.     else {
  781.         AddTransparentSphere(atomStyle.color, atomStyle.name, site, atomStyle.radius, atomStyle.alpha);
  782.         // but can put labels on now
  783.         if (atomStyle.centerLabel.size() > 0)
  784.             DrawLabel(atomStyle.centerLabel, site,
  785.                 (atomStyle.isHighlighted ? GlobalColors()->Get(Colors::eHighlight) : Vector(1,1,1)));
  786.     }
  787.     displayListEmpty[currentDisplayList] = false;
  788. }
  789. /* add a thick splined curve from point 1 *halfway* to point 2 */
  790. static void DrawHalfWorm(const Vector *p0, const Vector& p1,
  791.     const Vector& p2, const Vector *p3,
  792.     double radius, bool cap1, bool cap2,
  793.     double tension)
  794. {
  795.     int i, j, k, m, offset;
  796.     Vector R1, R2, Qt, p, dQt, H, V;
  797.     double len, MG[4][3], T[4], t, prevlen=0.0, cosj, sinj;
  798.     GLdouble *Nx = NULL, *Ny, *Nz, *Cx, *Cy, *Cz,
  799.         *pNx, *pNy, *pNz, *pCx, *pCy, *pCz, *tmp;
  800.     if (!p0 || !p3) {
  801.         ERRORMSG("DrawHalfWorm: got NULL 0th and/or 3rd coords for worm");
  802.         return;
  803.     }
  804.     /*
  805.      * The Hermite matrix Mh.
  806.      */
  807.     static double Mh[4][4] = {
  808.         { 2, -2,  1,  1},
  809.         {-3,  3, -2, -1},
  810.         { 0,  0,  1,  0},
  811.         { 1,  0,  0,  0}
  812.     };
  813.     /*
  814.      * Variables that affect the curve shape
  815.      *   a=b=0 = Catmull-Rom
  816.      */
  817.     double a = tension,         /* tension    (adjustable)  */
  818.         c = 0,                  /* continuity (should be 0) */
  819.         b = 0;                  /* bias       (should be 0) */
  820.     if (wormSides % 2) {
  821.         WARNINGMSG("worm sides must be an even number");
  822.         ++wormSides;
  823.     }
  824.     GLdouble *fblock = NULL;
  825.     /* First, calculate the coordinate points of the center of the worm,
  826.      * using the Kochanek-Bartels variant of the Hermite curve.
  827.      */
  828.     R1 = 0.5 * (1 - a) * (1 + b) * (1 + c) * (p1 - *p0) + 0.5 * (1 - a) * (1 - b) * (1 - c) * ( p2 - p1);
  829.     R2 = 0.5 * (1 - a) * (1 + b) * (1 - c) * (p2 -  p1) + 0.5 * (1 - a) * (1 - b) * (1 + c) * (*p3 - p2);
  830.     /*
  831.      * Multiply MG=Mh.Gh, where Gh = [ P(1) P(2) R(1) R(2) ]. This
  832.      * 4x1 matrix of vectors is constant for each segment.
  833.      */
  834.     for (i = 0; i < 4; ++i) {   /* calculate Mh.Gh */
  835.         MG[i][0] = Mh[i][0] * p1.x + Mh[i][1] * p2.x + Mh[i][2] * R1.x + Mh[i][3] * R2.x;
  836.         MG[i][1] = Mh[i][0] * p1.y + Mh[i][1] * p2.y + Mh[i][2] * R1.y + Mh[i][3] * R2.y;
  837.         MG[i][2] = Mh[i][0] * p1.z + Mh[i][1] * p2.z + Mh[i][2] * R1.z + Mh[i][3] * R2.z;
  838.     }
  839.     for (i = 0; i <= wormSegments; ++i) {
  840.         /* t goes from [0,1] from P(1) to P(2) (and we want to go halfway only),
  841.            and the function Q(t) defines the curve of this segment. */
  842.         t = (0.5 / wormSegments) * i;
  843.         /*
  844.            * Q(t)=T.(Mh.Gh), where T = [ t^3 t^2 t 1 ]
  845.          */
  846.         T[0] = t * t * t;
  847.         T[1] = t * t;
  848.         T[2] = t;
  849.         //T[3] = 1;
  850.         Qt.x = T[0] * MG[0][0] + T[1] * MG[1][0] + T[2] * MG[2][0] + MG[3][0] /* *T[3] */ ;
  851.         Qt.y = T[0] * MG[0][1] + T[1] * MG[1][1] + T[2] * MG[2][1] + MG[3][1] /* *T[3] */ ;
  852.         Qt.z = T[0] * MG[0][2] + T[1] * MG[1][2] + T[2] * MG[2][2] + MG[3][2] /* *T[3] */ ;
  853.         if (radius == 0.0) {
  854.             if (i > 0) {
  855.                 glBegin(GL_LINES);
  856.                 glVertex3d(p.x, p.y, p.z);
  857.                 glVertex3d(Qt.x, Qt.y, Qt.z);
  858.                 glEnd();
  859.             }
  860.             /* save to use as previous point for connecting points together */
  861.             p = Qt;
  862.         } else {
  863.             /* construct a circle of points centered at and
  864.                in a plane normal to the curve at t - these points will
  865.                be used to construct the "thick" worm */
  866.             /* allocate single block of storage for two circles of points */
  867.             if (!Nx) {
  868.                 fblock = new GLdouble[12 * wormSides];
  869.                 Nx = fblock;
  870.                 Ny = &Nx[wormSides];
  871.                 Nz = &Nx[wormSides * 2];
  872.                 Cx = &Nx[wormSides * 3];
  873.                 Cy = &Nx[wormSides * 4];
  874.                 Cz = &Nx[wormSides * 5];
  875.                 pNx = &Nx[wormSides * 6];
  876.                 pNy = &Nx[wormSides * 7];
  877.                 pNz = &Nx[wormSides * 8];
  878.                 pCx = &Nx[wormSides * 9];
  879.                 pCy = &Nx[wormSides * 10];
  880.                 pCz = &Nx[wormSides * 11];
  881.             }
  882.             /*
  883.              * The first derivative of Q(t), d(Q(t))/dt, is the slope
  884.              * (tangent) at point Q(t); now T = [ 3t^2 2t 1 0 ]
  885.              */
  886.             T[0] = t * t * 3;
  887.             T[1] = t * 2;
  888.             //T[2] = 1;
  889.             //T[3] = 0;
  890.             dQt.x = T[0] * MG[0][0] + T[1] * MG[1][0] + MG[2][0] /* *T[2] + T[3]*MG[3][0] */ ;
  891.             dQt.y = T[0] * MG[0][1] + T[1] * MG[1][1] + MG[2][1] /* *T[2] + T[3]*MG[3][1] */ ;
  892.             dQt.z = T[0] * MG[0][2] + T[1] * MG[1][2] + MG[2][2] /* *T[2] + T[3]*MG[3][2] */ ;
  893.             /* use cross prod't of [1,0,0] x normal as horizontal */
  894.             H.Set(0.0, -dQt.z, dQt.y);
  895.             if (H.length() < 0.000001) /* nearly colinear - use [1,0.1,0] instead */
  896.                 H.Set(0.1 * dQt.z, -dQt.z, dQt.y - 0.1 * dQt.x);
  897.             H.normalize();
  898.             /* and a vertical vector = normal x H */
  899.             V = vector_cross(dQt, H);
  900.             V.normalize();
  901.             /* finally, the worm circumference points (C) and normals (N) are
  902.                simple trigonometric combinations of H and V */
  903.             for (j = 0; j < wormSides; ++j) {
  904.                 cosj = cos(2 * PI * j / wormSides);
  905.                 sinj = sin(2 * PI * j / wormSides);
  906.                 Nx[j] = H.x * cosj + V.x * sinj;
  907.                 Ny[j] = H.y * cosj + V.y * sinj;
  908.                 Nz[j] = H.z * cosj + V.z * sinj;
  909.                 Cx[j] = Qt.x + Nx[j] * radius;
  910.                 Cy[j] = Qt.y + Ny[j] * radius;
  911.                 Cz[j] = Qt.z + Nz[j] * radius;
  912.             }
  913.             /* figure out which points on the previous circle "match" best
  914.                with these, to minimize envelope twisting */
  915.             if (i > 0) {
  916.                 for (m = 0; m < wormSides; ++m) {
  917.                     len = 0.0;
  918.                     for (j = 0; j < wormSides; ++j) {
  919.                         k = j + m;
  920.                         if (k >= wormSides)
  921.                             k -= wormSides;
  922.                         len += (Cx[k] - pCx[j]) * (Cx[k] - pCx[j]) +
  923.                                (Cy[k] - pCy[j]) * (Cy[k] - pCy[j]) +
  924.                                (Cz[k] - pCz[j]) * (Cz[k] - pCz[j]);
  925.                     }
  926.                     if (m == 0 || len < prevlen) {
  927.                         prevlen = len;
  928.                         offset = m;
  929.                     }
  930.                 }
  931.             }
  932.             /* create triangles from points along this and previous circle */
  933.             if (i > 0) {
  934.                 glBegin(GL_TRIANGLE_STRIP);
  935.                 for (j = 0; j < wormSides; ++j) {
  936.                     k = j + offset;
  937.                     if (k >= wormSides) k -= wormSides;
  938.                     glNormal3d(Nx[k], Ny[k], Nz[k]);
  939.                     glVertex3d(Cx[k], Cy[k], Cz[k]);
  940.                     glNormal3d(pNx[j], pNy[j], pNz[j]);
  941.                     glVertex3d(pCx[j], pCy[j], pCz[j]);
  942.                 }
  943.                 glNormal3d(Nx[offset], Ny[offset], Nz[offset]);
  944.                 glVertex3d(Cx[offset], Cy[offset], Cz[offset]);
  945.                 glNormal3d(pNx[0], pNy[0], pNz[0]);
  946.                 glVertex3d(pCx[0], pCy[0], pCz[0]);
  947.                 glEnd();
  948.             }
  949.             /* put caps on the end */
  950.             if (cap1 && i == 0) {
  951.                 glBegin(GL_POLYGON);
  952.                 dQt.normalize();
  953.                 glNormal3d(-dQt.x, -dQt.y, -dQt.z);
  954.                 for (j = wormSides - 1; j >= 0; --j) {
  955.                     glVertex3d(Cx[j], Cy[j], Cz[j]);
  956.                 }
  957.                 glEnd();
  958.             }
  959.             else if (cap2 && i == wormSegments) {
  960.                 glBegin(GL_POLYGON);
  961.                 dQt.normalize();
  962.                 glNormal3d(dQt.x, dQt.y, dQt.z);
  963.                 for (j = 0; j < wormSides; ++j) {
  964.                     k = j + offset;
  965.                     if (k >= wormSides) k -= wormSides;
  966.                     glVertex3d(Cx[k], Cy[k], Cz[k]);
  967.                 }
  968.                 glEnd();
  969.             }
  970.             /* store this circle as previous for next round; instead of copying
  971.                all values, just swap pointers */
  972. #define SWAPPTR(p1,p2) tmp=(p1); (p1)=(p2); (p2)=tmp
  973.             SWAPPTR(Nx, pNx);
  974.             SWAPPTR(Ny, pNy);
  975.             SWAPPTR(Nz, pNz);
  976.             SWAPPTR(Cx, pCx);
  977.             SWAPPTR(Cy, pCy);
  978.             SWAPPTR(Cz, pCz);
  979.         }
  980.     }
  981.     if (fblock) delete[] fblock;
  982. }
  983. static void DoCylinderPlacementTransform(const Vector& a, const Vector& b, double length)
  984. {
  985.     /* to translate into place */
  986.     glTranslated(a.x, a.y, a.z);
  987.     /* to rotate from initial position, so bond points right direction;
  988.        handle special case where both ends share ~same x,y */
  989.     if (fabs(a.y - b.y) < 0.000001 && fabs(a.x - b.x) < 0.000001) {
  990.         if (b.z - a.z < 0.0) glRotated(180.0, 1.0, 0.0, 0.0);
  991.     } else {
  992.         glRotated(RadToDegrees(acos((b.z - a.z) / length)),
  993.                   a.y - b.y, b.x - a.x, 0.0);
  994.     }
  995. }
  996. static void DrawHalfBond(const Vector& site1, const Vector& midpoint,
  997.     StyleManager::eDisplayStyle style, double radius,
  998.     bool cap1, bool cap2)
  999. {
  1000.     // straight line bond
  1001.     if (style == StyleManager::eLineBond || (style == StyleManager::eCylinderBond && radius <= 0.0)) {
  1002.         glBegin(GL_LINES);
  1003.         glVertex3d(site1.x, site1.y, site1.z);
  1004.         glVertex3d(midpoint.x, midpoint.y, midpoint.z);
  1005.         glEnd();
  1006.     }
  1007.     // cylinder bond
  1008.     else if (style == StyleManager::eCylinderBond) {
  1009.         double length = (site1 - midpoint).length();
  1010.         if (length <= 0.000001 || bondSides <= 1) return;
  1011.         glPushMatrix();
  1012.         DoCylinderPlacementTransform(site1, midpoint, length);
  1013.         gluCylinder(qobj, radius, radius, length, bondSides, 1);
  1014.         if (cap1) {
  1015.             glPushMatrix();
  1016.             glRotated(180.0, 0.0, 1.0, 0.0);
  1017.             gluDisk(qobj, 0.0, radius, bondSides, 1);
  1018.             glPopMatrix();
  1019.         }
  1020.         if (cap2) {
  1021.             glPushMatrix();
  1022.             glTranslated(0.0, 0.0, length);
  1023.             gluDisk(qobj, 0.0, radius, bondSides, 1);
  1024.             glPopMatrix();
  1025.         }
  1026.         glPopMatrix();
  1027.     }
  1028. }
  1029. void OpenGLRenderer::DrawBond(const Vector& site1, const Vector& site2,
  1030.     const BondStyle& style, const Vector *site0, const Vector* site3)
  1031. {
  1032.     GLenum colorType;
  1033.     Vector midpoint = (site1 + site2) / 2;
  1034.     if (style.end1.style != StyleManager::eNotDisplayed) {
  1035.         colorType =
  1036.             (style.end1.style == StyleManager::eLineBond ||
  1037.             style.end1.style == StyleManager::eLineWormBond ||
  1038.             style.end1.radius <= 0.0)
  1039.             ? GL_AMBIENT : GL_DIFFUSE;
  1040.         SetColor(colorType, style.end1.color[0], style.end1.color[1], style.end1.color[2]);
  1041.         glLoadName(static_cast<GLuint>(style.end1.name));
  1042.         if (style.end1.style == StyleManager::eLineWormBond ||
  1043.             style.end1.style == StyleManager::eThickWormBond)
  1044.             DrawHalfWorm(site0, site1, site2, site3,
  1045.                 (style.end1.style == StyleManager::eThickWormBond) ? style.end1.radius : 0.0,
  1046.                 style.end1.atomCap, style.midCap,
  1047.                 style.tension);
  1048.         else
  1049.             DrawHalfBond(site1, midpoint,
  1050.                 style.end1.style, style.end1.radius,
  1051.                 style.end1.atomCap, style.midCap);
  1052.         displayListEmpty[currentDisplayList] = false;
  1053.     }
  1054.     if (style.end2.style != StyleManager::eNotDisplayed) {
  1055.         colorType =
  1056.             (style.end2.style == StyleManager::eLineBond ||
  1057.             style.end2.style == StyleManager::eLineWormBond ||
  1058.             style.end2.radius <= 0.0)
  1059.             ? GL_AMBIENT : GL_DIFFUSE;
  1060.         SetColor(colorType, style.end2.color[0], style.end2.color[1], style.end2.color[2]);
  1061.         glLoadName(static_cast<GLuint>(style.end2.name));
  1062.         if (style.end2.style == StyleManager::eLineWormBond ||
  1063.             style.end2.style == StyleManager::eThickWormBond)
  1064.             DrawHalfWorm(site3, site2, site1, site0,
  1065.                 (style.end2.style == StyleManager::eThickWormBond) ? style.end2.radius : 0.0,
  1066.                 style.end2.atomCap, style.midCap,
  1067.                 style.tension);
  1068.         else
  1069.             DrawHalfBond(midpoint, site2,
  1070.                 style.end2.style, style.end2.radius,
  1071.                 style.midCap, style.end2.atomCap);
  1072.         displayListEmpty[currentDisplayList] = false;
  1073.     }
  1074. }
  1075. void OpenGLRenderer::DrawHelix(const Vector& Nterm, const Vector& Cterm, const HelixStyle& style)
  1076. {
  1077.     SetColor(GL_DIFFUSE, style.color[0], style.color[1], style.color[2]);
  1078.     glLoadName(static_cast<GLuint>(NO_NAME));
  1079.     double wholeLength = (Nterm - Cterm).length();
  1080.     if (wholeLength <= 0.000001) return;
  1081.     // transformation for whole helix
  1082.     glPushMatrix();
  1083.     DoCylinderPlacementTransform(Nterm, Cterm, wholeLength);
  1084.     // helix body
  1085.     double shaftLength =
  1086.         (style.style == StyleManager::eObjectWithArrow && style.arrowLength < wholeLength) ?
  1087.             wholeLength - style.arrowLength : wholeLength;
  1088.     gluCylinder(qobj, style.radius, style.radius, shaftLength, helixSides, 1);
  1089.     // Nterm cap
  1090.     glPushMatrix();
  1091.     glRotated(180.0, 0.0, 1.0, 0.0);
  1092.     gluDisk(qobj, 0.0, style.radius, helixSides, 1);
  1093.     glPopMatrix();
  1094.     // Cterm Arrow
  1095.     if (style.style == StyleManager::eObjectWithArrow && style.arrowLength < wholeLength) {
  1096.         // arrow base
  1097.         if (style.arrowBaseWidthProportion > 1.0) {
  1098.             glPushMatrix();
  1099.             glTranslated(0.0, 0.0, shaftLength);
  1100.             glRotated(180.0, 0.0, 1.0, 0.0);
  1101.             gluDisk(qobj, style.radius, style.radius * style.arrowBaseWidthProportion, helixSides, 1);
  1102.             glPopMatrix();
  1103.         }
  1104.         // arrow body
  1105.         glPushMatrix();
  1106.         glTranslated(0.0, 0.0, shaftLength);
  1107.         gluCylinder(qobj, style.radius * style.arrowBaseWidthProportion,
  1108.             style.radius * style.arrowTipWidthProportion, style.arrowLength, helixSides, 10);
  1109.         glPopMatrix();
  1110.         // arrow tip
  1111.         if (style.arrowTipWidthProportion > 0.0) {
  1112.             glPushMatrix();
  1113.             glTranslated(0.0, 0.0, wholeLength);
  1114.             gluDisk(qobj, 0.0, style.radius * style.arrowTipWidthProportion, helixSides, 1);
  1115.             glPopMatrix();
  1116.         }
  1117.     }
  1118.     // Cterm cap
  1119.     else {
  1120.         glPushMatrix();
  1121.         glTranslated(0.0, 0.0, wholeLength);
  1122.         gluDisk(qobj, 0.0, style.radius, helixSides, 1);
  1123.         glPopMatrix();
  1124.     }
  1125.     glPopMatrix();
  1126.     displayListEmpty[currentDisplayList] = false;
  1127. }
  1128. void OpenGLRenderer::DrawStrand(const Vector& Nterm, const Vector& Cterm,
  1129.     const Vector& unitNormal, const StrandStyle& style)
  1130. {
  1131.     GLdouble c000[3], c001[3], c010[3], c011[3],
  1132.              c100[3], c101[3], c110[3], c111[3], n[3];
  1133.     Vector a, h;
  1134.     int i;
  1135.     SetColor(GL_DIFFUSE, style.color[0], style.color[1], style.color[2]);
  1136.     glLoadName(static_cast<GLuint>(NO_NAME));
  1137.     /* in this brick's world coordinates, the long axis (N-C direction) is
  1138.        along +Z, with N terminus at Z=0; width is in the X direction, and
  1139.        thickness in Y. Arrowhead at C-terminus, of course. */
  1140.     a = Cterm - Nterm;
  1141.     a.normalize();
  1142.     h = vector_cross(unitNormal, a);
  1143.     Vector lCterm(Cterm);
  1144.     if (style.style == StyleManager::eObjectWithArrow)
  1145.         lCterm -= a * style.arrowLength;
  1146.     for (i=0; i<3; ++i) {
  1147.         c000[i] =  Nterm[i] - h[i]*style.width/2 - unitNormal[i]*style.thickness/2;
  1148.         c001[i] = lCterm[i] - h[i]*style.width/2 - unitNormal[i]*style.thickness/2;
  1149.         c010[i] =  Nterm[i] - h[i]*style.width/2 + unitNormal[i]*style.thickness/2;
  1150.         c011[i] = lCterm[i] - h[i]*style.width/2 + unitNormal[i]*style.thickness/2;
  1151.         c100[i] =  Nterm[i] + h[i]*style.width/2 - unitNormal[i]*style.thickness/2;
  1152.         c101[i] = lCterm[i] + h[i]*style.width/2 - unitNormal[i]*style.thickness/2;
  1153.         c110[i] =  Nterm[i] + h[i]*style.width/2 + unitNormal[i]*style.thickness/2;
  1154.         c111[i] = lCterm[i] + h[i]*style.width/2 + unitNormal[i]*style.thickness/2;
  1155.     }
  1156.     glBegin(GL_QUADS);
  1157.     for (i=0; i<3; ++i) n[i] = unitNormal[i];
  1158.     glNormal3dv(n);
  1159.     glVertex3dv(c010);
  1160.     glVertex3dv(c011);
  1161.     glVertex3dv(c111);
  1162.     glVertex3dv(c110);
  1163.     for (i=0; i<3; ++i) n[i] = -unitNormal[i];
  1164.     glNormal3dv(n);
  1165.     glVertex3dv(c000);
  1166.     glVertex3dv(c100);
  1167.     glVertex3dv(c101);
  1168.     glVertex3dv(c001);
  1169.     for (i=0; i<3; ++i) n[i] = h[i];
  1170.     glNormal3dv(n);
  1171.     glVertex3dv(c100);
  1172.     glVertex3dv(c110);
  1173.     glVertex3dv(c111);
  1174.     glVertex3dv(c101);
  1175.     for (i=0; i<3; ++i) n[i] = -h[i];
  1176.     glNormal3dv(n);
  1177.     glVertex3dv(c000);
  1178.     glVertex3dv(c001);
  1179.     glVertex3dv(c011);
  1180.     glVertex3dv(c010);
  1181.     for (i=0; i<3; ++i) n[i] = -a[i];
  1182.     glNormal3dv(n);
  1183.     glVertex3dv(c000);
  1184.     glVertex3dv(c010);
  1185.     glVertex3dv(c110);
  1186.     glVertex3dv(c100);
  1187.     if (style.style == StyleManager::eObjectWithoutArrow) {
  1188.         for (i=0; i<3; ++i) n[i] = a[i];
  1189.         glNormal3dv(n);
  1190.         glVertex3dv(c001);
  1191.         glVertex3dv(c101);
  1192.         glVertex3dv(c111);
  1193.         glVertex3dv(c011);
  1194.     } else {
  1195.         GLdouble FT[3], LT[3], RT[3], FB[3], LB[3], RB[3];
  1196.         for (i=0; i<3; ++i) {
  1197.             FT[i] = lCterm[i] + unitNormal[i]*style.thickness/2 +
  1198.                 a[i]*style.arrowLength;
  1199.             LT[i] = lCterm[i] + unitNormal[i]*style.thickness/2 +
  1200.                 h[i]*style.arrowBaseWidthProportion*style.width/2;
  1201.             RT[i] = lCterm[i] + unitNormal[i]*style.thickness/2 -
  1202.                 h[i]*style.arrowBaseWidthProportion*style.width/2;
  1203.             FB[i] = lCterm[i] - unitNormal[i]*style.thickness/2 +
  1204.                 a[i]*style.arrowLength;
  1205.             LB[i] = lCterm[i] - unitNormal[i]*style.thickness/2 +
  1206.                 h[i]*style.arrowBaseWidthProportion*style.width/2;
  1207.             RB[i] = lCterm[i] - unitNormal[i]*style.thickness/2 -
  1208.                 h[i]*style.arrowBaseWidthProportion*style.width/2;
  1209.         }
  1210.         // the back-facing rectangles on the base of the arrow
  1211.         for (i=0; i<3; ++i) n[i] = -a[i];
  1212.         glNormal3dv(n);
  1213.         glVertex3dv(c111);
  1214.         glVertex3dv(LT);
  1215.         glVertex3dv(LB);
  1216.         glVertex3dv(c101);
  1217.         glVertex3dv(c011);
  1218.         glVertex3dv(c001);
  1219.         glVertex3dv(RB);
  1220.         glVertex3dv(RT);
  1221.         // the left side of the arrow
  1222.         for (i=0; i<3; ++i) h[i] = FT[i] - LT[i];
  1223.         Vector nL = vector_cross(unitNormal, h);
  1224.         nL.normalize();
  1225.         for (i=0; i<3; ++i) n[i] = nL[i];
  1226.         glNormal3dv(n);
  1227.         glVertex3dv(FT);
  1228.         glVertex3dv(FB);
  1229.         glVertex3dv(LB);
  1230.         glVertex3dv(LT);
  1231.         // the right side of the arrow
  1232.         for (i=0; i<3; ++i) h[i] = FT[i] - RT[i];
  1233.         Vector nR = vector_cross(h, unitNormal);
  1234.         nR.normalize();
  1235.         for (i=0; i<3; ++i) n[i] = nR[i];
  1236.         glNormal3dv(n);
  1237.         glVertex3dv(FT);
  1238.         glVertex3dv(RT);
  1239.         glVertex3dv(RB);
  1240.         glVertex3dv(FB);
  1241.         glEnd();
  1242.         glBegin(GL_TRIANGLES);
  1243.         // the top and bottom arrow triangles
  1244.         for (i=0; i<3; ++i) n[i] = unitNormal[i];
  1245.         glNormal3dv(n);
  1246.         glVertex3dv(FT);
  1247.         glVertex3dv(LT);
  1248.         glVertex3dv(RT);
  1249.         for (i=0; i<3; ++i) n[i] = -unitNormal[i];
  1250.         glNormal3dv(n);
  1251.         glVertex3dv(FB);
  1252.         glVertex3dv(RB);
  1253.         glVertex3dv(LB);
  1254.     }
  1255.     glEnd();
  1256.     displayListEmpty[currentDisplayList] = false;
  1257. }
  1258. void OpenGLRenderer::DrawLabel(const string& text, const Vector& center, const Vector& color)
  1259. {
  1260.     int width, height, textCenterX = 0, textCenterY = 0;
  1261.     if (text.empty()) return;
  1262.     if (!glCanvas->MeasureText(text, &width, &height, &textCenterX, &textCenterY))
  1263.         WARNINGMSG("MeasureText() failed");
  1264.     SetColor(GL_AMBIENT, color[0], color[1], color[2]);
  1265.     glListBase(FONT_BASE);
  1266.     glRasterPos3d(center.x, center.y, center.z);
  1267.     glBitmap(0, 0, 0.0, 0.0, -textCenterX, -textCenterY, NULL);
  1268.     glCallLists(text.size(), GL_UNSIGNED_BYTE, text.data());
  1269.     glListBase(0);
  1270.     displayListEmpty[currentDisplayList] = false;
  1271. }
  1272. bool OpenGLRenderer::SaveToASNViewSettings(ncbi::objects::CCn3d_user_annotations *annotations)
  1273. {
  1274.     // save current camera settings
  1275.     initialViewFromASN.Reset(new CCn3d_view_settings());
  1276.     initialViewFromASN->SetCamera_distance(cameraDistance);
  1277.     initialViewFromASN->SetCamera_angle_rad(cameraAngleRad);
  1278.     initialViewFromASN->SetCamera_look_at_X(cameraLookAtX);
  1279.     initialViewFromASN->SetCamera_look_at_Y(cameraLookAtY);
  1280.     initialViewFromASN->SetCamera_clip_near(cameraClipNear);
  1281.     initialViewFromASN->SetCamera_clip_far(cameraClipFar);
  1282.     initialViewFromASN->SetMatrix().SetM0(viewMatrix[0]);
  1283.     initialViewFromASN->SetMatrix().SetM1(viewMatrix[1]);
  1284.     initialViewFromASN->SetMatrix().SetM2(viewMatrix[2]);
  1285.     initialViewFromASN->SetMatrix().SetM3(viewMatrix[3]);
  1286.     initialViewFromASN->SetMatrix().SetM4(viewMatrix[4]);
  1287.     initialViewFromASN->SetMatrix().SetM5(viewMatrix[5]);
  1288.     initialViewFromASN->SetMatrix().SetM6(viewMatrix[6]);
  1289.     initialViewFromASN->SetMatrix().SetM7(viewMatrix[7]);
  1290.     initialViewFromASN->SetMatrix().SetM8(viewMatrix[8]);
  1291.     initialViewFromASN->SetMatrix().SetM9(viewMatrix[9]);
  1292.     initialViewFromASN->SetMatrix().SetM10(viewMatrix[10]);
  1293.     initialViewFromASN->SetMatrix().SetM11(viewMatrix[11]);
  1294.     initialViewFromASN->SetMatrix().SetM12(viewMatrix[12]);
  1295.     initialViewFromASN->SetMatrix().SetM13(viewMatrix[13]);
  1296.     initialViewFromASN->SetMatrix().SetM14(viewMatrix[14]);
  1297.     initialViewFromASN->SetMatrix().SetM15(viewMatrix[15]);
  1298.     initialViewFromASN->SetRotation_center().SetX(structureSet->rotationCenter.x);
  1299.     initialViewFromASN->SetRotation_center().SetY(structureSet->rotationCenter.y);
  1300.     initialViewFromASN->SetRotation_center().SetZ(structureSet->rotationCenter.z);
  1301.     if (annotations) {
  1302.         // store copy in given annotations
  1303.         string err;
  1304.         CRef < CCn3d_view_settings > copy(CopyASNObject(*initialViewFromASN, &err));
  1305.         if (copy.Empty()) {
  1306.             ERRORMSG("OpenGLRenderer::SaveToASNViewSettings() - failed to copy settings:n" << err);
  1307.             return false;
  1308.         }
  1309.         annotations->SetView(*copy);
  1310.     }
  1311.     return true;
  1312. }
  1313. bool OpenGLRenderer::LoadFromASNViewSettings(const ncbi::objects::CCn3d_user_annotations& annotations)
  1314. {
  1315.     initialViewFromASN.Reset();
  1316.     if (!annotations.IsSetView()) return true;
  1317.     // save a copy of the view settings
  1318.     string err;
  1319.     initialViewFromASN.Reset(CopyASNObject(annotations.GetView(), &err));
  1320.     if (err.size() > 0 || initialViewFromASN.Empty()) {
  1321.         ERRORMSG("OpenGLRenderer::LoadFromASNViewSettings() - failed to copy settings:n" << err);
  1322.         return false;
  1323.     }
  1324.     return true;
  1325. }
  1326. void OpenGLRenderer::RestoreSavedView(void)
  1327. {
  1328.     if (initialViewFromASN.Empty() || !structureSet) {
  1329.         ResetCamera();
  1330.         return;
  1331.     }
  1332.     // restore current camera settings
  1333.     cameraDistance = initialViewFromASN->GetCamera_distance();
  1334.     cameraAngleRad = initialViewFromASN->GetCamera_angle_rad();
  1335.     cameraLookAtX = initialViewFromASN->GetCamera_look_at_X();
  1336.     cameraLookAtY = initialViewFromASN->GetCamera_look_at_Y();
  1337.     cameraClipNear = initialViewFromASN->GetCamera_clip_near();
  1338.     cameraClipFar = initialViewFromASN->GetCamera_clip_far();
  1339.     viewMatrix[0] = initialViewFromASN->GetMatrix().GetM0();
  1340.     viewMatrix[1] = initialViewFromASN->GetMatrix().GetM1();
  1341.     viewMatrix[2] = initialViewFromASN->GetMatrix().GetM2();
  1342.     viewMatrix[3] = initialViewFromASN->GetMatrix().GetM3();
  1343.     viewMatrix[4] = initialViewFromASN->GetMatrix().GetM4();
  1344.     viewMatrix[5] = initialViewFromASN->GetMatrix().GetM5();
  1345.     viewMatrix[6] = initialViewFromASN->GetMatrix().GetM6();
  1346.     viewMatrix[7] = initialViewFromASN->GetMatrix().GetM7();
  1347.     viewMatrix[8] = initialViewFromASN->GetMatrix().GetM8();
  1348.     viewMatrix[9] = initialViewFromASN->GetMatrix().GetM9();
  1349.     viewMatrix[10] = initialViewFromASN->GetMatrix().GetM10();
  1350.     viewMatrix[11] = initialViewFromASN->GetMatrix().GetM11();
  1351.     viewMatrix[12] = initialViewFromASN->GetMatrix().GetM12();
  1352.     viewMatrix[13] = initialViewFromASN->GetMatrix().GetM13();
  1353.     viewMatrix[14] = initialViewFromASN->GetMatrix().GetM14();
  1354.     viewMatrix[15] = initialViewFromASN->GetMatrix().GetM15();
  1355.     structureSet->rotationCenter.Set(
  1356.         initialViewFromASN->GetRotation_center().GetX(),
  1357.         initialViewFromASN->GetRotation_center().GetY(),
  1358.         initialViewFromASN->GetRotation_center().GetZ());
  1359.     NewView();
  1360. }
  1361. void OpenGLRenderer::GetViewport(int *viewport)
  1362. {
  1363.     glCanvas->SetCurrent();
  1364.     GLint viewportGL[4];    // just in case GLint != int
  1365.     glGetIntegerv(GL_VIEWPORT, viewportGL);
  1366.     for (int i=0; i<4; ++i) viewport[i] = (int) viewportGL[i];
  1367. }
  1368. const wxFont& OpenGLRenderer::GetGLFont(void) const
  1369. {
  1370.     return glCanvas->GetGLFont();
  1371. }
  1372. bool OpenGLRenderer::SetGLFont(int firstChar, int nChars, int fontBase)
  1373. {
  1374.     bool okay = true;
  1375. #if defined(__WXMSW__)
  1376.     HDC hdc = wglGetCurrentDC();
  1377.     HGDIOBJ currentFont = SelectObject(hdc, reinterpret_cast<HGDIOBJ>(GetGLFont().GetHFONT()));
  1378.     if (!wglUseFontBitmaps(hdc, firstChar, nChars, fontBase)) {
  1379.         ERRORMSG("OpenGLRenderer::SetGLFont() - wglUseFontBitmaps() failed");
  1380.         okay = false;
  1381.     }
  1382.     SelectObject(hdc, currentFont);
  1383. #elif defined(__WXGTK__)
  1384.     glXUseXFont(gdk_font_id(GetGLFont().GetInternalFont()), firstChar, nChars, fontBase);
  1385. #elif defined(__WXMAC__)
  1386.     wxFontRefData *fontRefData = (wxFontRefData *) GetGLFont().GetRefData();
  1387.     if (RealFont(fontRefData->m_macFontNum, fontRefData->m_macFontSize)) {
  1388.         if (aglUseFont(aglGetCurrentContext(),
  1389.                 (GLint) fontRefData->m_macFontNum,
  1390.                 fontRefData->m_macFontStyle, fontRefData->m_macFontSize,
  1391.                 firstChar, nChars, fontBase) != GL_TRUE) {
  1392.             ERRORMSG("OpenGLRenderer::SetGLFont() - aglUseFont() failed");
  1393.             okay = false;
  1394.         }
  1395.     } else {
  1396.         ERRORMSG("OpenGLRenderer::SetGLFont() - RealFont() returned false");
  1397.         okay = false;
  1398.     }
  1399. #endif
  1400.     return okay;
  1401. }
  1402. END_SCOPE(Cn3D)
  1403. /*
  1404. * ---------------------------------------------------------------------------
  1405. * $Log: opengl_renderer.cpp,v $
  1406. * Revision 1000.3  2004/06/01 18:28:52  gouriano
  1407. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.79
  1408. *
  1409. * Revision 1.79  2004/05/21 21:41:39  gorelenk
  1410. * Added PCH ncbi_pch.hpp
  1411. *
  1412. * Revision 1.78  2004/04/19 19:36:07  thiessen
  1413. * fix frame switch bug when no structures present
  1414. *
  1415. * Revision 1.77  2004/03/15 17:59:20  thiessen
  1416. * prefer prefix vs. postfix ++/-- operators
  1417. *
  1418. * Revision 1.76  2004/03/15 17:51:29  thiessen
  1419. * prefer prefix vs. postfix ++/-- operators
  1420. *
  1421. * Revision 1.75  2004/02/19 17:05:00  thiessen
  1422. * remove cn3d/ from include paths; add pragma to disable annoying msvc warning
  1423. *
  1424. * Revision 1.74  2003/12/04 15:58:36  thiessen
  1425. * fix const problem
  1426. *
  1427. * Revision 1.73  2003/12/04 15:49:40  thiessen
  1428. * fix stereo and PNG export problems on Mac
  1429. *
  1430. * Revision 1.72  2003/11/15 16:08:36  thiessen
  1431. * add stereo
  1432. *
  1433. * Revision 1.71  2003/10/06 22:05:52  thiessen
  1434. * fix max camera angle to < PI
  1435. *
  1436. * Revision 1.70  2003/05/22 19:08:17  thiessen
  1437. * add limits to camera angle
  1438. *
  1439. * Revision 1.69  2003/03/13 14:26:18  thiessen
  1440. * add file_messaging module; split cn3d_main_wxwin into cn3d_app, cn3d_glcanvas, structure_window, cn3d_tools
  1441. *
  1442. * Revision 1.68  2003/02/03 19:20:04  thiessen
  1443. * format changes: move CVS Log to bottom of file, remove std:: from .cpp files, and use new diagnostic macros
  1444. *
  1445. * Revision 1.67  2003/01/09 13:46:54  thiessen
  1446. * highlight atom labels
  1447. *
  1448. * Revision 1.66  2002/12/19 15:58:26  thiessen
  1449. * fix quadric problem on Mac
  1450. *
  1451. * Revision 1.65  2002/10/11 17:21:39  thiessen
  1452. * initial Mac OSX build
  1453. *
  1454. * Revision 1.64  2002/10/08 12:35:42  thiessen
  1455. * use delete[] for arrays
  1456. *
  1457. * Revision 1.63  2002/09/14 18:14:31  thiessen
  1458. * fix trigonometry error
  1459. *
  1460. * Revision 1.62  2002/09/14 17:03:07  thiessen
  1461. * center initial view on aligned residues
  1462. *
  1463. * Revision 1.61  2002/08/15 22:13:15  thiessen
  1464. * update for wx2.3.2+ only; add structure pick dialog; fix MultitextDialog bug
  1465. *
  1466. * Revision 1.60  2002/03/04 15:52:14  thiessen
  1467. * hide sequence windows instead of destroying ; add perspective/orthographic projection choice
  1468. *
  1469. * Revision 1.59  2002/02/01 13:55:54  thiessen
  1470. * fix view restore bug when new file loaded
  1471. *
  1472. * Revision 1.58  2002/01/11 15:48:58  thiessen
  1473. * update for Mac CW7
  1474. *
  1475. * Revision 1.57  2001/12/15 03:15:59  thiessen
  1476. * adjustments for slightly changed object loader Set...() API
  1477. *
  1478. * Revision 1.56  2001/12/12 14:04:14  thiessen
  1479. * add missing object headers after object loader change
  1480. *
  1481. * Revision 1.55  2001/11/30 14:02:05  thiessen
  1482. * progress on sequence imports to single structures
  1483. *
  1484. * Revision 1.54  2001/10/23 20:10:23  thiessen
  1485. * fix scaling of fonts in high-res PNG output
  1486. *
  1487. * Revision 1.53  2001/10/23 13:53:38  thiessen
  1488. * add PNG export
  1489. *
  1490. * Revision 1.52  2001/10/17 17:46:22  thiessen
  1491. * save camera setup and rotation center in files
  1492. *
  1493. * Revision 1.51  2001/09/06 18:15:44  thiessen
  1494. * fix OpenGL window initialization/OnSize to work on Mac
  1495. *
  1496. * Revision 1.50  2001/08/24 18:53:42  thiessen
  1497. * add filename to sequence viewer window titles
  1498. *
  1499. * Revision 1.49  2001/08/24 13:29:28  thiessen
  1500. * header and GTK font tweaks
  1501. *
  1502. * Revision 1.48  2001/08/24 00:41:35  thiessen
  1503. * tweak conservation colors and opengl font handling
  1504. *
  1505. * Revision 1.47  2001/08/21 01:10:45  thiessen
  1506. * add labeling
  1507. *
  1508. * Revision 1.46  2001/08/15 20:52:15  juran
  1509. * On the Mac, include OpenGL headers that can actually be located.
  1510. *
  1511. * Revision 1.45  2001/08/13 22:30:59  thiessen
  1512. * add structure window mouse drag/zoom; add highlight option to render settings
  1513. *
  1514. * Revision 1.44  2001/08/09 19:07:13  thiessen
  1515. * add temperature and hydrophobicity coloring
  1516. *
  1517. * Revision 1.43  2001/08/08 02:26:18  thiessen
  1518. * fixes for gnu ; make DrawHelix more logical
  1519. *
  1520. * Revision 1.42  2001/08/06 20:22:00  thiessen
  1521. * add preferences dialog ; make sure OnCloseWindow get wxCloseEvent
  1522. *
  1523. * Revision 1.41  2001/07/10 21:50:45  thiessen
  1524. * fix ambient/specular coloring
  1525. *
  1526. * Revision 1.40  2001/07/10 21:27:52  thiessen
  1527. * add some specular reflection
  1528. *
  1529. * Revision 1.39  2001/06/29 18:13:57  thiessen
  1530. * initial (incomplete) user annotation system
  1531. *
  1532. * Revision 1.38  2001/05/31 18:47:08  thiessen
  1533. * add preliminary style dialog; remove LIST_TYPE; add thread single and delete all; misc tweaks
  1534. *
  1535. * Revision 1.37  2001/05/25 15:18:24  thiessen
  1536. * fixes for visual id settings in wxGTK
  1537. *
  1538. * Revision 1.36  2001/05/25 01:38:16  thiessen
  1539. * minor fixes for compiling on SGI
  1540. *
  1541. * Revision 1.35  2001/05/22 19:09:31  thiessen
  1542. * many minor fixes to compile/run on Solaris/GTK
  1543. *
  1544. * Revision 1.34  2001/05/17 18:34:25  thiessen
  1545. * spelling fixes; change dialogs to inherit from wxDialog
  1546. *
  1547. * Revision 1.33  2001/05/15 23:48:37  thiessen
  1548. * minor adjustments to compile under Solaris/wxGTK
  1549. *
  1550. * Revision 1.32  2001/01/30 20:51:19  thiessen
  1551. * minor fixes
  1552. *
  1553. * Revision 1.31  2000/12/19 16:39:09  thiessen
  1554. * tweaks to show/hide
  1555. *
  1556. * Revision 1.30  2000/12/15 15:51:47  thiessen
  1557. * show/hide system installed
  1558. *
  1559. * Revision 1.29  2000/11/30 15:49:39  thiessen
  1560. * add show/hide rows; unpack sec. struc. and domain features
  1561. *
  1562. * Revision 1.28  2000/11/02 16:56:02  thiessen
  1563. * working editor undo; dynamic slave transforms
  1564. *
  1565. * Revision 1.27  2000/09/11 01:46:15  thiessen
  1566. * working messenger for sequence<->structure window communication
  1567. *
  1568. * Revision 1.26  2000/09/08 20:16:55  thiessen
  1569. * working dynamic alignment views
  1570. *
  1571. * Revision 1.25  2000/08/27 18:52:21  thiessen
  1572. * extract sequence information
  1573. *
  1574. * Revision 1.24  2000/08/25 14:22:00  thiessen
  1575. * minor tweaks
  1576. *
  1577. * Revision 1.23  2000/08/24 23:40:19  thiessen
  1578. * add 'atomic ion' labels
  1579. *
  1580. * Revision 1.22  2000/08/24 18:43:52  thiessen
  1581. * tweaks for transparent sphere display
  1582. *
  1583. * Revision 1.21  2000/08/21 17:22:38  thiessen
  1584. * add primitive highlighting for testing
  1585. *
  1586. * Revision 1.20  2000/08/19 02:59:04  thiessen
  1587. * fix transparent sphere bug
  1588. *
  1589. * Revision 1.19  2000/08/18 23:07:08  thiessen
  1590. * minor efficiency tweaks
  1591. *
  1592. * Revision 1.18  2000/08/18 18:57:39  thiessen
  1593. * added transparent spheres
  1594. *
  1595. * Revision 1.17  2000/08/17 14:24:06  thiessen
  1596. * added working StyleManager
  1597. *
  1598. * Revision 1.16  2000/08/16 14:18:46  thiessen
  1599. * map 3-d objects to molecules
  1600. *
  1601. * Revision 1.15  2000/08/13 02:43:01  thiessen
  1602. * added helix and strand objects
  1603. *
  1604. * Revision 1.14  2000/08/11 12:58:31  thiessen
  1605. * added worm; get 3d-object coords from asn1
  1606. *
  1607. * Revision 1.13  2000/08/07 14:13:15  thiessen
  1608. * added animation frames
  1609. *
  1610. * Revision 1.12  2000/08/07 00:21:17  thiessen
  1611. * add display list mechanism
  1612. *
  1613. * Revision 1.11  2000/08/04 22:49:03  thiessen
  1614. * add backbone atom classification and selection feedback mechanism
  1615. *
  1616. * Revision 1.10  2000/08/03 15:12:23  thiessen
  1617. * add skeleton of style and show/hide managers
  1618. *
  1619. * Revision 1.9  2000/07/27 13:30:51  thiessen
  1620. * remove 'using namespace ...' from all headers
  1621. *
  1622. * Revision 1.8  2000/07/18 16:50:11  thiessen
  1623. * more friendly rotation center setting
  1624. *
  1625. * Revision 1.7  2000/07/18 02:41:33  thiessen
  1626. * fix bug in virtual bonds and altConfs
  1627. *
  1628. * Revision 1.6  2000/07/18 00:06:00  thiessen
  1629. * allow arbitrary rotation center
  1630. *
  1631. * Revision 1.5  2000/07/17 22:37:18  thiessen
  1632. * fix vector_math typo; correctly set initial view
  1633. *
  1634. * Revision 1.4  2000/07/17 04:20:49  thiessen
  1635. * now does correct structure alignment transformation
  1636. *
  1637. * Revision 1.3  2000/07/16 23:19:11  thiessen
  1638. * redo of drawing system
  1639. *
  1640. * Revision 1.2  2000/07/12 23:27:49  thiessen
  1641. * now draws basic CPK model
  1642. *
  1643. * Revision 1.1  2000/07/12 14:11:30  thiessen
  1644. * added initial OpenGL rendering engine
  1645. *
  1646. */