NCBI C++ ToolKit
opengl_renderer.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: opengl_renderer.cpp 60835 2013-12-06 15:35:58Z lanczyck $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Authors: Paul Thiessen
27 *
28 * File Description:
29 * Classes to hold the OpenGL rendering engine
30 *
31 * ===========================================================================
32 */
33 
34 #include <ncbi_pch.hpp>
35 #include <corelib/ncbistd.hpp>
36 #include <corelib/ncbitime.hpp> // avoids some 'CurrentTime' conflict later on...
37 #include <corelib/ncbiobj.hpp>
38 #include <corelib/ncbi_limits.h>
39 
40 #if defined(__WXMSW__)
41 #include <windows.h>
42 #include <GL/gl.h>
43 #include <GL/glu.h>
44 
45 #elif defined(__WXGTK__)
46 #include <GL/gl.h>
47 #include <GL/glu.h>
48 #include <GL/glx.h>
49 
50 #elif defined(__WXMAC__)
51 //#include <Fonts.h>
52 #include <AGL/agl.h>
53 //#include <OpenGL/gl.h>
54 #include <OpenGL/glu.h>
55 #endif
56 
57 #include <math.h>
58 #include <stdlib.h> // for rand, srand
59 
62 
63 #define GL_ENUM_TYPE GLenum
64 #define GL_INT_TYPE GLint
65 #define GL_DOUBLE_TYPE GLdouble
66 
68 
69 #include "opengl_renderer.hpp"
70 #include "structure_window.hpp"
71 #include "cn3d_glcanvas.hpp"
72 #include "structure_set.hpp"
73 #include "style_manager.hpp"
74 #include "messenger.hpp"
75 #include "cn3d_tools.hpp"
76 #include "cn3d_colors.hpp"
77 
80 
81 
82 BEGIN_SCOPE(Cn3D)
83 
84 // whether to use my (limited) GLU quadric functions, or the native ones
85 #define USE_MY_GLU_QUADS 1
86 
87 // enables "uniform data" gl calls - e.g. glMaterial for every vertex, not just when the color changes
88 #ifdef __WXMAC__
89 
90 #define MAC_GL_OPTIMIZE 1
91 #define MAC_GL_SETCOLOR SetColor(eUseCachedValues);
92 #ifndef USE_MY_GLU_QUADS
93 #define USE_MY_GLU_QUADS 1 // necessary for mac GL optimization
94 #endif
95 
96 #else // !__WXMAC__
97 
98 #define MAC_GL_SETCOLOR
99 
100 #endif // __WXMAC__
101 
102 #ifndef USE_MY_GLU_QUADS
103 // it's easier to keep one global qobj for now
104 static GLUquadricObj *qobj = NULL;
105 #endif
106 
107 static const double PI = acos(-1.0);
108 static inline double DegreesToRad(double deg) { return deg*PI/180.0; }
109 static inline double RadToDegrees(double rad) { return rad*180.0/PI; }
110 
111 const unsigned int OpenGLRenderer::NO_LIST = 0;
112 const unsigned int OpenGLRenderer::FIRST_LIST = 1;
113 const unsigned int OpenGLRenderer::FONT_BASE = 100000;
114 
115 static const unsigned int ALL_FRAMES = kMax_UInt;
116 
117 // pick buffer
118 const unsigned int OpenGLRenderer::NO_NAME = 0;
119 static const int pickBufSize = 1024;
120 static GLuint selectBuf[pickBufSize];
121 
122 /* these are used for both matrial colors and light colors */
123 static const GLfloat Color_Off[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
124 static const GLfloat Color_MostlyOff[4] = { 0.05f, 0.05f, 0.05f, 1.0f };
125 static const GLfloat Color_MostlyOn[4] = { 0.95f, 0.95f, 0.95f, 1.0f };
126 static const GLfloat Color_On[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
127 static const GLfloat Color_Specular[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
128 static const GLint Shininess = 40;
129 
130 // to cache registry values
132 static bool highlightsOn;
133 static string projectionType;
134 
135 
136 // matrix conversion utility functions
137 
138 // convert from Matrix to GL-matrix ordering
139 static void Matrix2GL(const Matrix& m, GLdouble *g)
140 {
141  g[0]=m.m[0]; g[4]=m.m[1]; g[8]=m.m[2]; g[12]=m.m[3];
142  g[1]=m.m[4]; g[5]=m.m[5]; g[9]=m.m[6]; g[13]=m.m[7];
143  g[2]=m.m[8]; g[6]=m.m[9]; g[10]=m.m[10]; g[14]=m.m[11];
144  g[3]=m.m[12]; g[7]=m.m[13]; g[11]=m.m[14]; g[15]=m.m[15];
145 }
146 
147 // convert from GL-matrix to Matrix ordering
148 static void GL2Matrix(GLdouble *g, Matrix *m)
149 {
150  m->m[0]=g[0]; m->m[1]=g[4]; m->m[2]=g[8]; m->m[3]=g[12];
151  m->m[4]=g[1]; m->m[5]=g[5]; m->m[6]=g[9]; m->m[7]=g[13];
152  m->m[8]=g[2]; m->m[9]=g[6]; m->m[10]=g[10]; m->m[11]=g[14];
153  m->m[12]=g[3]; m->m[13]=g[7]; m->m[14]=g[11]; m->m[15]=g[15];
154 }
155 
156 // my (limited) replacements for glu functions - these only do solid smooth objects
157 #if USE_MY_GLU_QUADS
158 
159 static const GLdouble origin[] = { 0.0, 0.0, 0.0 }, unitZ[] = { 0.0, 0.0, 1.0 };
160 
161 #define GLU_DISK(q, i, o, s, l) MyGluDisk((i), (o), (s), (l))
162 
163 void OpenGLRenderer::MyGluDisk(GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops)
164 {
165  if (slices < 3 || loops < 1 || innerRadius < 0.0 || innerRadius >= outerRadius) {
166  ERRORMSG("MyGluDisk() - bad parameters");
167  return;
168  }
169 
170  // calculate all the x,y coordinates (at radius 1)
171  vector < GLdouble > x(slices), y(slices);
172  int l = 0, s, i;
173  GLdouble f, f2, a;
174  for (s=0; s<slices; ++s) {
175  a = PI * 2 * s / slices;
176  x[s] = cos(a);
177  y[s] = sin(a);
178  }
179 
180  // if innerRadius is zero, then make the center a triangle fan
181  if (innerRadius == 0.0) {
182  f = innerRadius + (outerRadius - innerRadius) / loops;
183  glBegin(GL_TRIANGLE_FAN);
185  glNormal3dv(unitZ);
186  glVertex3dv(origin);
187  for (s=0; s<=slices; ++s) {
188  i = (s == slices) ? 0 : s;
190  glVertex3d(x[i] * f, y[i] * f, 0.0);
191  }
192  glEnd();
193  ++l;
194  }
195 
196  // outer loops (or all if innerRadius > zero) get quad strips
197  for (; l<loops; ++l) {
198  f = innerRadius + (outerRadius - innerRadius) * l / loops;
199  f2 = innerRadius + (outerRadius - innerRadius) * (l + 1) / loops;
200  glBegin(GL_QUAD_STRIP);
201  glNormal3dv(unitZ);
202  for (s=0; s<=slices; ++s) {
203  i = (s == slices) ? 0 : s;
205  glVertex3d(x[i] * f, y[i] * f, 0.0);
207  glVertex3d(x[i] * f2, y[i] * f2, 0.0);
208  }
209  glEnd();
210  }
211 }
212 
213 #define GLU_CYLINDER(q, b, t, h, l, k) MyGluCylinder((b), (t), (h), (l), (k))
214 
215 void OpenGLRenderer::MyGluCylinder(GLdouble baseRadius, GLdouble topRadius, GLdouble height, GLint slices, GLint stacks)
216 {
217  if (slices < 3 || stacks < 1 || height <= 0.0 || baseRadius < 0.0 || topRadius < 0.0 ||
218  (baseRadius == 0.0 && topRadius == 0.0)) {
219  ERRORMSG("MyGluCylinder() - bad parameters");
220  return;
221  }
222 
223  // calculate all the x,y coordinates (at radius 1)
224  vector < GLdouble > x(slices), y(slices);
225  vector < Vector > N(slices);
226  int k, s, i;
227  GLdouble f, f2, a;
228  Matrix r;
229  for (s=0; s<slices; ++s) {
230  a = PI * 2 * s / slices;
231  x[s] = cos(a);
232  y[s] = sin(a);
233  a += PI / 2;
234  SetRotationMatrix(&r, Vector(cos(a), sin(a), 0.0), atan((topRadius - baseRadius) / height));
235  N[s].Set(x[s], y[s], 0.0);
236  ApplyTransformation(&(N[s]), r);
237  }
238 
239  // create each stack out of a quad strip
240  for (k=0; k<stacks; ++k) {
241  f = baseRadius + (topRadius - baseRadius) * k / stacks;
242  f2 = baseRadius + (topRadius - baseRadius) * (k + 1) / stacks;
243  glBegin(GL_QUAD_STRIP);
244  for (s=0; s<=slices; ++s) {
245  i = (s == slices) ? 0 : s;
247  glNormal3d(N[i].x, N[i].y, N[i].z);
248  glVertex3d(x[i] * f2, y[i] * f2, height * (k + 1) / stacks);
250  glVertex3d(x[i] * f, y[i] * f, height * k / stacks);
251  }
252  glEnd();
253  }
254 }
255 
256 #define GLU_SPHERE(q, r, l, k) MyGluSphere((r), (l), (k))
257 
258 void OpenGLRenderer::MyGluSphere(GLdouble radius, GLint slices, GLint stacks)
259 {
260  if (slices < 3 || stacks < 2 || radius <= 0.0) {
261  ERRORMSG("MyGluSphere() - bad parameters");
262  return;
263  }
264 
265  // calculate all the x,y coordinates (at radius 1)
266  vector < vector < Vector > > N(stacks - 1);
267  int k, s, i;
268  GLdouble z, a, r;
269  for (k=0; k<stacks-1; ++k) {
270  N[k].resize(slices);
271  a = PI * (-0.5 + (1.0 + k) / stacks);
272  z = sin(a);
273  r = cos(a);
274  for (s=0; s<slices; ++s) {
275  a = PI * 2 * s / slices;
276  N[k][s].Set(cos(a) * r, sin(a) * r, z);
277  }
278  }
279 
280  // bottom triangle fan
281  glBegin(GL_TRIANGLE_FAN);
283  glNormal3d(0.0, 0.0, -1.0);
284  glVertex3d(0.0, 0.0, -radius);
285  for (s=slices; s>=0; --s) {
286  i = (s == slices) ? 0 : s;
287  const Vector& n = N[0][i];
289  glNormal3d(n.x, n.y, n.z);
290  glVertex3d(n.x * radius, n.y * radius, n.z * radius);
291  }
292  glEnd();
293 
294  // middle quad strips
295  for (k=0; k<stacks-2; ++k) {
296  glBegin(GL_QUAD_STRIP);
297  for (s=slices; s>=0; --s) {
298  i = (s == slices) ? 0 : s;
299  const Vector& n1 = N[k][i];
301  glNormal3d(n1.x, n1.y, n1.z);
302  glVertex3d(n1.x * radius, n1.y * radius, n1.z * radius);
303  const Vector& n2 = N[k + 1][i];
305  glNormal3d(n2.x, n2.y, n2.z);
306  glVertex3d(n2.x * radius, n2.y * radius, n2.z * radius);
307  }
308  glEnd();
309  }
310 
311  // top triangle fan
312  glBegin(GL_TRIANGLE_FAN);
314  glNormal3dv(unitZ);
315  glVertex3d(0.0, 0.0, radius);
316  for (s=0; s<=slices; ++s) {
317  i = (s == slices) ? 0 : s;
318  const Vector& n = N[stacks - 2][i];
320  glNormal3d(n.x, n.y, n.z);
321  glVertex3d(n.x * radius, n.y * radius, n.z * radius);
322  }
323  glEnd();
324 }
325 
326 #else // !USE_MY_GLU_QUADS
327 
328 #define GLU_DISK gluDisk
329 #define GLU_CYLINDER gluCylinder
330 #define GLU_SPHERE gluSphere
331 
332 #endif // USE_MY_GLU_QUADS
333 
334 // OpenGLRenderer methods - initialization and setup
335 
337  structureSet(NULL), glCanvas(parentGLCanvas),
338  cameraAngleRad(0.0), rotateSpeed(0.5), selectMode(false), currentDisplayList(NO_LIST),
339  stereoOn(false)
340 {
341  // make sure a name will fit in a GLuint
342  if (sizeof(GLuint) < sizeof(unsigned int))
343  FATALMSG("Cn3D requires that sizeof(GLuint) >= sizeof(unsigned int)");
344 }
345 
346 void OpenGLRenderer::Init(void) const
347 {
348  glMatrixMode(GL_MODELVIEW);
349  glLoadIdentity();
350 
351  // set up the lighting
352  // directional light (faster) when LightPosition[4] == 0.0
353  GLfloat LightPosition[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
354  glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
355  glLightfv(GL_LIGHT0, GL_AMBIENT, Color_Off);
356  glLightfv(GL_LIGHT0, GL_DIFFUSE, Color_MostlyOn);
357  glLightfv(GL_LIGHT0, GL_SPECULAR, Color_On);
358  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Color_On); // global ambience
359  glEnable(GL_LIGHTING);
360  glEnable(GL_LIGHT0);
361 
362  // set these material colors
363  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, Color_Off);
364  glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, Shininess);
365 #if MAC_GL_OPTIMIZE
366  glDisable(GL_COLOR_MATERIAL);
367 #else
368  glEnable(GL_COLOR_MATERIAL);
369 #endif
370 
371  // turn on culling to speed rendering
372  glEnable(GL_CULL_FACE);
373  glCullFace(GL_BACK);
374  glFrontFace(GL_CCW);
375 
376  // misc options
377  glShadeModel(GL_SMOOTH);
378  glEnable(GL_DEPTH_TEST);
379  glDisable(GL_NORMALIZE);
380  glDisable(GL_SCISSOR_TEST);
381 
382  RecreateQuadric();
383 }
384 
385 
386 // methods dealing with the view
387 
388 void OpenGLRenderer::NewView(double eyeTranslateToAngleDegrees) const
389 {
390  if (cameraAngleRad <= 0.0) return;
391 
392 // TRACEMSG("Camera_distance: " << cameraDistance);
393 // TRACEMSG("Camera_angle_rad: " << cameraAngleRad);
394 // TRACEMSG("Camera_look_at_X: " << cameraLookAtX);
395 // TRACEMSG("Camera_look_at_Y: " << cameraLookAtY);
396 // TRACEMSG("Camera_clip_near: " << cameraClipNear);
397 // TRACEMSG("Camera_clip_far: " << cameraClipFar);
398 // TRACEMSG("projection: " << projectionType);
399 
400  GLint Viewport[4];
401  glGetIntegerv(GL_VIEWPORT, Viewport);
402 
403  glMatrixMode(GL_PROJECTION);
404  glLoadIdentity();
405 
406  if (selectMode) {
407  gluPickMatrix(static_cast<GLdouble>(selectX),
408  static_cast<GLdouble>(Viewport[3] - selectY),
409  1.0, 1.0, Viewport);
410  }
411 
412  GLdouble aspect = (static_cast<GLdouble>(Viewport[2])) / Viewport[3];
413 
414  // set camera angle/perspective
415  if (projectionType == "Perspective") {
416  gluPerspective(RadToDegrees(cameraAngleRad), // viewing angle (degrees)
417  aspect, // w/h aspect
418  cameraClipNear, // near clipping plane
419  cameraClipFar); // far clipping plane
420  } else { // Orthographic
421  GLdouble right, top;
422  top = ((cameraClipNear + cameraClipFar) / 2.0) * sin(cameraAngleRad / 2.0);
423  right = top * aspect;
424  glOrtho(-right, // sides of viewing box, assuming eye is at (0,0,0)
425  right,
426  -top,
427  top,
428  cameraClipNear, // near clipping plane
429  cameraClipFar); // far clipping plane
430  }
431 
432  Vector cameraLoc(0.0, 0.0, cameraDistance);
433 
434  if (stereoOn && eyeTranslateToAngleDegrees != 0.0) {
436  Vector translate = vector_cross(view, Vector(0.0, 1.0, 0.0));
437  translate.normalize();
438  translate *= view.length() * tan(DegreesToRad(eyeTranslateToAngleDegrees));
439  cameraLoc += translate;
440  }
441 // TRACEMSG("Camera X: " << cameraLoc.x);
442 // TRACEMSG("Camera Y: " << cameraLoc.y);
443 // TRACEMSG("Camera Z: " << cameraLoc.z);
444 
445  // set camera position and direction
446  gluLookAt(cameraLoc.x, cameraLoc.y, cameraLoc.z, // the camera position
447  cameraLookAtX, cameraLookAtY, 0.0, // the "look-at" point
448  0.0, 1.0, 0.0); // the up direction
449 
450  glMatrixMode(GL_MODELVIEW);
451 }
452 
454 {
455 // for (unsigned int m=0; m<16; ++m)
456 // TRACEMSG("viewMatrix[" << m << "]: " << viewMatrix[m]);
457 
458  if (structureSet) {
459  const Vector& background = structureSet->styleManager->GetBackgroundColor();
460  glClearColor(background[0], background[1], background[2], 1.0);
461  } else
462  glClearColor(0.0, 0.0, 0.0, 1.0);
463  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
464 
465  if (selectMode) {
466  glInitNames();
467  glPushName(0);
468  }
469 
470  GLint viewport[4] = {0, 0, 0, 0};
471  double eyeSeparationDegrees = 0.0;
472  if (stereoOn) {
473  bool proximalStereo;
474  glGetIntegerv(GL_VIEWPORT, viewport);
475  if (!RegistryGetDouble(REG_ADVANCED_SECTION, REG_STEREO_SEPARATION, &eyeSeparationDegrees) ||
477  {
478  ERRORMSG("OpenGLRenderer::Display() - error getting stereo settings from registry");
479  return;
480  }
481  if (!proximalStereo)
482  eyeSeparationDegrees = -eyeSeparationDegrees;
483  }
484 
485  int first = 1, last = stereoOn ? 2 : 1;
486  for (int e=first; e<=last; ++e) {
487 
488  glLoadMatrixd(viewMatrix);
489 
490  // adjust viewport & camera angle for stereo
491  if (stereoOn) {
492  if (e == first) {
493  // left side
494  glViewport(0, viewport[1], viewport[2] / 2, viewport[3]);
495  NewView(eyeSeparationDegrees / 2);
496  } else {
497  // right side
498  glViewport(viewport[2] / 2, viewport[1], viewport[2] - viewport[2] / 2, viewport[3]);
499  NewView(-eyeSeparationDegrees / 2);
500  }
501  }
502 
503  if (structureSet) {
504  if (currentFrame == ALL_FRAMES) {
505  for (unsigned int i=FIRST_LIST; i<=structureSet->lastDisplayList; ++i) {
507  glCallList(i);
508  PopMatrix();
510  }
511  } else {
512  StructureSet::DisplayLists::const_iterator
514  for (l=structureSet->frameMap[currentFrame].begin(); l!=le; ++l) {
516  glCallList(*l);
517  PopMatrix();
519  }
520  }
521 
522  // draw transparent spheres, which are already stored in view-transformed coordinates
523  glLoadIdentity();
525  }
526 
527  // draw logo if no structure
528  else {
529  glCallList(FIRST_LIST);
530  }
531  }
532 
533  glFinish();
534  glFlush();
535 
536  // restore full viewport
537  if (stereoOn)
538  glViewport(0, viewport[1], viewport[2], viewport[3]);
539 }
540 
541 void OpenGLRenderer::EnableStereo(bool enableStereo)
542 {
543  TRACEMSG("turning " << (enableStereo ? "on" : "off" ) << " stereo");
544  stereoOn = enableStereo;
545  if (!stereoOn)
546  NewView();
547 }
548 
550 {
551  // set up initial camera
552  glLoadIdentity();
554 
555  if (structureSet) { // for structure
557  // calculate camera distance so that structure fits exactly in
558  // the window in any rotation (based on structureSet's maxDistFromCenter)
559  GLint Viewport[4];
560  glGetIntegerv(GL_VIEWPORT, Viewport);
561  double angle = cameraAngleRad, aspect = (static_cast<double>(Viewport[2])) / Viewport[3];
562  if (aspect < 1.0) angle *= aspect;
564  // allow a little "extra" room between clipping planes
567  // move structureSet's center to origin
568  glTranslated(-structureSet->center.x, -structureSet->center.y, -structureSet->center.z);
570 
571  } else { // for logo
572  cameraAngleRad = PI / 14;
573  cameraDistance = 200;
576  }
577 
578  // reset matrix
579  glGetDoublev(GL_MODELVIEW_MATRIX, viewMatrix);
580  NewView();
581 }
582 
583 void OpenGLRenderer::ChangeView(eViewAdjust control, int dX, int dY, int X2, int Y2)
584 {
585  bool doTranslation = false;
586  Vector rotCenter;
587  double pixelSize;
588  GLint viewport[4];
589 
590  // find out where rotation center is in current GL coordinates
591  if (structureSet && (control==eXYRotateHV || control==eZRotateH) &&
593  Matrix m;
594  GL2Matrix(viewMatrix, &m);
595  rotCenter = structureSet->rotationCenter;
596  ApplyTransformation(&rotCenter, m);
597  doTranslation = true;
598  }
599 
600  glLoadIdentity();
601 
602  // rotate relative to rotationCenter
603  if (doTranslation) glTranslated(rotCenter.x, rotCenter.y, rotCenter.z);
604 
605 #define MIN_CAMERA_ANGLE 0.001
606 #define MAX_CAMERA_ANGLE (0.999 * PI)
607 
608  switch (control) {
609  case eXYRotateHV:
610  glRotated(rotateSpeed*dY, 1.0, 0.0, 0.0);
611  glRotated(rotateSpeed*dX, 0.0, 1.0, 0.0);
612  break;
613 
614  case eZRotateH:
615  glRotated(rotateSpeed*dX, 0.0, 0.0, 1.0);
616  break;
617 
618  case eXYTranslateHV:
619  glGetIntegerv(GL_VIEWPORT, viewport);
620  pixelSize = tan(cameraAngleRad / 2.0) * 2.0 * cameraDistance / viewport[3];
621  cameraLookAtX -= dX * pixelSize;
622  cameraLookAtY += dY * pixelSize;
623  NewView();
624  break;
625 
626  case eZoomH:
627  cameraAngleRad *= 1.0 - 0.01 * dX;
630  NewView();
631  break;
632 
633  case eZoomHHVV:
634  break;
635 
636  case eZoomOut:
637  cameraAngleRad *= 1.5;
639  NewView();
640  break;
641 
642  case eZoomIn:
643  cameraAngleRad /= 1.5;
645  NewView();
646  break;
647 
648  case eCenterCamera:
650  NewView();
651  break;
652  }
653 
654  if (doTranslation) glTranslated(-rotCenter.x, -rotCenter.y, -rotCenter.z);
655 
656  glMultMatrixd(viewMatrix);
657  glGetDoublev(GL_MODELVIEW_MATRIX, viewMatrix);
658 }
659 
660 void OpenGLRenderer::CenterView(const Vector& viewCenter, double radius)
661 {
662  ResetCamera();
663 
664  structureSet->rotationCenter = viewCenter;
665 
666  Vector cameraLocation(0.0, 0.0, cameraDistance);
667  Vector centerWRTcamera = viewCenter - structureSet->center;
668  Vector direction = centerWRTcamera - cameraLocation;
669  direction.normalize();
670  double cosAngleZ = -direction.z;
671  Vector lookAt = centerWRTcamera + direction * (centerWRTcamera.z / cosAngleZ);
672  cameraLookAtX = lookAt.x;
673  cameraLookAtY = lookAt.y;
674 
675  cameraAngleRad = 2.0 * atan(radius / (cameraLocation - centerWRTcamera).length());
676 
677  NewView();
678  TRACEMSG("looking at " << lookAt << " angle " << RadToDegrees(cameraAngleRad));
679 
680  // do this so that this view is used upon restore
682 }
683 
685 {
688 }
689 
691 {
692  glPushMatrix();
693  if (m) {
694  GLdouble g[16];
695  Matrix2GL(*m, g);
696  glMultMatrixd(g);
697  }
698 }
699 
701 {
702  glPopMatrix();
703 }
704 
705 // display list management stuff
706 void OpenGLRenderer::StartDisplayList(unsigned int list)
707 {
708  if (list >= FONT_BASE) {
709  ERRORMSG("OpenGLRenderer::StartDisplayList() - too many display lists;\n"
710  << "increase OpenGLRenderer::FONT_BASE");
711  return;
712  }
714  SetColor(eResetCache); // reset color caches in SetColor
715 
716  glNewList(list, GL_COMPILE);
717  currentDisplayList = list;
718 
721 }
722 
724 {
725  glEndList();
727 }
728 
729 
730 // frame management methods
731 
733 {
735 }
736 
737 bool OpenGLRenderer::IsFrameEmpty(unsigned int frame) const
738 {
739  if (!structureSet || structureSet->frameMap.size() <= frame) return false;
740 
741  StructureSet::DisplayLists::const_iterator l, le=structureSet->frameMap[frame].end();
742  for (l=structureSet->frameMap[frame].begin(); l!=le; ++l)
743  if (!displayListEmpty[*l])
744  return false;
745  return true;
746 }
747 
749 {
750  if (!structureSet || structureSet->frameMap.size() == 0) return;
751  currentFrame = 0;
752  while (IsFrameEmpty(currentFrame) && currentFrame < structureSet->frameMap.size() - 1)
753  ++currentFrame;
754 }
755 
757 {
758  if (!structureSet || structureSet->frameMap.size() == 0) return;
759  currentFrame = structureSet->frameMap.size() - 1;
760  while (IsFrameEmpty(currentFrame) && currentFrame > 0)
761  --currentFrame;
762 }
763 
765 {
766  if (!structureSet || structureSet->frameMap.size() == 0) return;
768  unsigned int originalFrame = currentFrame;
769  do {
770  if (currentFrame == structureSet->frameMap.size() - 1)
771  currentFrame = 0;
772  else
773  ++currentFrame;
774  } while (IsFrameEmpty(currentFrame) && currentFrame != originalFrame);
775 }
776 
778 {
779  if (!structureSet || structureSet->frameMap.size() == 0) return;
781  unsigned int originalFrame = currentFrame;
782  do {
783  if (currentFrame == 0)
784  currentFrame = structureSet->frameMap.size() - 1;
785  else
786  --currentFrame;
787  } while (IsFrameEmpty(currentFrame) && currentFrame != originalFrame);
788 }
789 
791 {
792  if (!structureSet) return;
793  if (frame >= 0 && frame < (int)structureSet->frameMap.size() && !IsFrameEmpty(frame))
794  currentFrame = frame;
795  else
797 }
798 
799 // process selection; return gl-name of result
800 bool OpenGLRenderer::GetSelected(int x, int y, unsigned int *name)
801 {
802  // render with GL_SELECT mode, to fill selection buffer
803  glSelectBuffer(pickBufSize, selectBuf);
804  glRenderMode(GL_SELECT);
805  selectMode = true;
806  selectX = x;
807  selectY = y;
808  NewView();
809  Display();
810  GLint hits = glRenderMode(GL_RENDER);
811  selectMode = false;
812  NewView();
813 
814  // parse selection buffer to find name of selected item
815  int i, j, p=0, n, top=0;
816  GLuint minZ=0;
817  *name = NO_NAME;
818  for (i=0; i<hits; ++i) {
819  n = selectBuf[p++]; // # names
820  if (i==0 || minZ > selectBuf[p]) { // find item with min depth
821  minZ = selectBuf[p];
822  top = 1;
823  } else
824  top = 0;
825  ++p;
826  ++p; // skip max depth
827  for (j=0; j<n; ++j) { // loop through n names
828  switch (j) {
829  case 0:
830  if (top) *name = static_cast<unsigned int>(selectBuf[p]);
831  break;
832  default:
833  WARNINGMSG("GL select: Got more than 1 name!");
834  }
835  ++p;
836  }
837  }
838 
839  if (*name != NO_NAME)
840  return true;
841  else
842  return false;
843 }
844 
846 {
847  structureSet = targetStructureSet;
849  if (!structureSet) initialViewFromASN.Reset();
850 
851  if (IsWindowedMode()) {
852  Init(); // init GL system
853  Construct(); // draw structures
854  RestoreSavedView(); // load initial view if present
855  }
856 }
857 
859 {
860 #ifndef USE_MY_GLU_QUADS
861  if (qobj)
862  gluDeleteQuadric(qobj);
863  if (!(qobj = gluNewQuadric())) {
864  ERRORMSG("unable to create a new GLUQuadricObj");
865  return;
866  }
867  gluQuadricDrawStyle(qobj, (GLenum) GLU_FILL);
868  gluQuadricNormals(qobj, (GLenum) GLU_SMOOTH);
869  gluQuadricOrientation(qobj, (GLenum) GLU_OUTSIDE);
870  gluQuadricTexture(qobj, GL_FALSE);
871 #endif
872 }
873 
875 {
876  glMatrixMode(GL_MODELVIEW);
877  glLoadIdentity();
878 
879  if (structureSet) {
880 
881  // get quality values from registry - assumes some values have been set already!
890  ERRORMSG("OpenGLRenderer::Construct() - error getting quality setting from registry");
891 
892  // do the drawing
894 
895  } else {
897  ConstructLogo();
898  }
899 
901 }
902 
904  GLenum type, GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
905 {
906  static GLdouble cr, cg, cb, ca;
907  static GLenum cachedType = GL_NONE, lastType = GL_NONE;
908 
909  if (action == eResetCache) {
910  cachedType = lastType = GL_NONE;
911  return;
912  }
913 
914  if (action == eSetColorIfDifferent && type == lastType && red == cr && green == cg && blue == cb && alpha == ca)
915  return;
916 
917  if (action == eUseCachedValues) {
918  if (cachedType == GL_NONE) {
919  ERRORMSG("can't do SetColor(eUseCachedValues) w/o previously doing eSetCacheValues or eSetColorIfDifferent");
920  return;
921  }
922  } else { // eSetCacheValues, or eSetColorIfDifferent and is different
923  cachedType = (GLenum) type;
924  cr = red;
925  cg = green;
926  cb = blue;
927  ca = alpha;
928  if (action == eSetCacheValues)
929  return;
930  }
931 
932  if (cachedType != lastType) {
933  if (cachedType == GL_DIFFUSE) {
934 #ifndef MAC_GL_OPTIMIZE
935  glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); // needs to go before glMaterial calls for some reason, at least on PC
936 #endif
937  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Color_MostlyOff);
938  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, highlightsOn ? Color_Specular : Color_Off);
939  } else if (cachedType == GL_AMBIENT) {
940 #ifndef MAC_GL_OPTIMIZE
941  glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
942 #endif
943  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Color_Off);
944  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Color_Off);
945  } else {
946  ERRORMSG("don't know how to handle material type " << cachedType);
947  }
948  lastType = cachedType;
949  }
950 
951  GLfloat rgba[4] = { (GLfloat) cr, (GLfloat) cg, (GLfloat) cb, (GLfloat) ca };
952 #if MAC_GL_OPTIMIZE
953  glMaterialfv(GL_FRONT_AND_BACK, cachedType, rgba);
954 #endif
955  glColor4fv(rgba);
956 }
957 
958 /* create display list with logo */
960 {
961  static const GLfloat logoColor[3] = { 100.0f/255, 240.0f/255, 150.0f/255 };
962  static const int LOGO_SIDES = 36, segments = 180;
963  int i, n, s, g;
964  GLdouble bigRad = 12.0, height = 24.0,
965  minRad = 0.1, maxRad = 2.0,
966  ringPts[LOGO_SIDES * 3], *pRingPts = ringPts,
967  prevRing[LOGO_SIDES * 3], *pPrevRing = prevRing, *tmp,
968  ringNorm[LOGO_SIDES * 3], *pRingNorm = ringNorm,
969  prevNorm[LOGO_SIDES * 3], *pPrevNorm = prevNorm,
970  length, startRad, midRad, phase, currentRad, CR[3], H[3], V[3];
971 
973  glNewList(FIRST_LIST, GL_COMPILE);
974 
975  /* create logo */
976  SetColor(eSetColorIfDifferent, GL_DIFFUSE, logoColor[0], logoColor[1], logoColor[2]);
977 
978  for (n = 0; n < 2; ++n) { /* helix strand */
979  if (n == 0) {
980  startRad = maxRad;
981  midRad = minRad;
982  phase = 0;
983  } else {
984  startRad = minRad;
985  midRad = maxRad;
986  phase = PI;
987  }
988  for (g = 0; g <= segments; ++g) { /* segment (bottom to top) */
989 
990  if (g < segments/2)
991  currentRad = startRad + (midRad - startRad) *
992  (0.5 - 0.5 * cos(PI * g / (segments/2)));
993  else
994  currentRad = midRad + (startRad - midRad) *
995  (0.5 - 0.5 * cos(PI * (g - segments/2) / (segments/2)));
996 
997  CR[1] = height * g / segments - height/2;
998  if (g > 0) phase += PI * 2 / segments;
999  CR[2] = bigRad * cos(phase);
1000  CR[0] = bigRad * sin(phase);
1001 
1002  /* make a strip around the strand circumference */
1003  for (s = 0; s < LOGO_SIDES; ++s) {
1004  V[0] = CR[0];
1005  V[2] = CR[2];
1006  V[1] = 0;
1007  length = sqrt(V[0]*V[0] + V[1]*V[1] + V[2]*V[2]);
1008  for (i = 0; i < 3; ++i) V[i] /= length;
1009  H[0] = H[2] = 0;
1010  H[1] = 1;
1011  for (i = 0; i < 3; ++i) {
1012  pRingNorm[3*s + i] = V[i] * cos(PI * 2 * s / LOGO_SIDES) +
1013  H[i] * sin(PI * 2 * s / LOGO_SIDES);
1014  pRingPts[3*s + i] = CR[i] + pRingNorm[3*s + i] * currentRad;
1015  }
1016  }
1017  if (g > 0) {
1018  glBegin(GL_TRIANGLE_STRIP);
1019  for (s = 0; s < LOGO_SIDES; ++s) {
1020  glNormal3d(pPrevNorm[3*s], pPrevNorm[3*s + 1], pPrevNorm[3*s + 2]);
1021  glVertex3d(pPrevRing[3*s], pPrevRing[3*s + 1], pPrevRing[3*s + 2]);
1022  glNormal3d(pRingNorm[3*s], pRingNorm[3*s + 1], pRingNorm[3*s + 2]);
1023  glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]);
1024  }
1025  glNormal3d(pPrevNorm[0], pPrevNorm[1], pPrevNorm[2]);
1026  glVertex3d(pPrevRing[0], pPrevRing[1], pPrevRing[2]);
1027  glNormal3d(pRingNorm[0], pRingNorm[1], pRingNorm[2]);
1028  glVertex3d(pRingPts[0], pRingPts[1], pRingPts[2]);
1029  glEnd();
1030  }
1031 
1032  /* cap the ends */
1033  glBegin(GL_POLYGON);
1034  if ((g == 0 && n == 0) || (g == segments && n == 1))
1035  glNormal3d(-1, 0, 0);
1036  else
1037  glNormal3d(1, 0, 0);
1038  if (g == 0) {
1039  for (s = 0; s < LOGO_SIDES; ++s)
1040  glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]);
1041  } else if (g == segments) {
1042  for (s = LOGO_SIDES - 1; s >= 0; --s)
1043  glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]);
1044  }
1045  glEnd();
1046 
1047  /* switch pointers to store previous ring */
1048  tmp = pPrevRing;
1049  pPrevRing = pRingPts;
1050  pRingPts = tmp;
1051  tmp = pPrevNorm;
1052  pPrevNorm = pRingNorm;
1053  pRingNorm = tmp;
1054  }
1055  }
1056 
1057  glEndList();
1058 }
1059 
1060 // stuff dealing with rendering of transparent spheres
1061 
1062 void OpenGLRenderer::AddTransparentSphere(const Vector& color, unsigned int name,
1063  const Vector& site, double radius, double alpha)
1064 {
1065  if (currentDisplayList == NO_LIST) {
1066  WARNINGMSG("OpenGLRenderer::AddTransparentSphere() - not called during display list creation");
1067  return;
1068  }
1069 
1071  spheres.resize(spheres.size() + 1);
1072  SphereInfo& info = spheres.back();
1073  info.site = site;
1074  info.name = name;
1075  info.color = color;
1076  info.radius = radius;
1077  info.alpha = alpha;
1078 }
1079 
1080 // add spheres associated with this display list; calculate distance from camera to each one
1082 {
1083  SphereMap::const_iterator sL = transparentSphereMap.find(list);
1084  if (sL == transparentSphereMap.end()) return;
1085 
1086  const SphereList& sphereList = sL->second;
1087 
1088  Matrix view;
1089  GL2Matrix(viewMatrix, &view);
1090 
1091  transparentSpheresToRender.resize(transparentSpheresToRender.size() + sphereList.size());
1092  SpherePtrList::reverse_iterator sph = transparentSpheresToRender.rbegin();
1093 
1094  SphereList::const_iterator i, ie=sphereList.end();
1095  const Matrix *dependentTransform;
1096  for (i=sphereList.begin(); i!=ie; ++i, ++sph) {
1097  sph->siteGL = i->site;
1098  dependentTransform = *(structureSet->transformMap[list]);
1099  if (dependentTransform)
1100  ApplyTransformation(&(sph->siteGL), *dependentTransform); // dependent->master transform
1101  ApplyTransformation(&(sph->siteGL), view); // current view transform
1102  sph->distanceFromCamera = (Vector(0,0,cameraDistance) - sph->siteGL).length() - i->radius;
1103  sph->ptr = &(*i);
1104  }
1105 }
1106 
1108 {
1109  if (transparentSpheresToRender.size() == 0) return;
1110 
1111  // sort spheres by distance from camera, via operator < defined for SpherePtr
1113 
1114  // turn on blending
1115  glEnable(GL_BLEND);
1116  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1117 
1118  SetColor(eResetCache); // reset color caches in SetColor
1119 
1120  // render spheres in order (farthest first)
1121  SpherePtrList::reverse_iterator i, ie=transparentSpheresToRender.rend();
1122  for (i=transparentSpheresToRender.rbegin(); i!=ie; ++i) {
1123  glLoadName(static_cast<GLuint>(i->ptr->name));
1124  glPushMatrix();
1125  glTranslated(i->siteGL.x, i->siteGL.y, i->siteGL.z);
1126 
1127  // apply a random spin so they're not all facing the same direction
1128  srand(static_cast<unsigned int>(fabs(i->ptr->site.x * 1000)));
1129  glRotated(360.0*rand()/RAND_MAX,
1130  1.0*rand()/RAND_MAX - 0.5, 1.0*rand()/RAND_MAX - 0.5, 1.0*rand()/RAND_MAX - 0.5);
1131 
1132 #if MAC_GL_OPTIMIZE
1133  SetColor(eSetCacheValues, GL_DIFFUSE, i->ptr->color[0], i->ptr->color[1], i->ptr->color[2], i->ptr->alpha);
1134 #else
1135  SetColor(eSetColorIfDifferent, GL_DIFFUSE, i->ptr->color[0], i->ptr->color[1], i->ptr->color[2], i->ptr->alpha);
1136 #endif
1137  GLU_SPHERE(qobj, i->ptr->radius, atomSlices, atomStacks);
1138  glPopMatrix();
1139  }
1140 
1141  // turn off blending
1142  glDisable(GL_BLEND);
1143 
1144  // clear list; recreate it upon each Display()
1146 }
1147 
1148 void OpenGLRenderer::DrawAtom(const Vector& site, const AtomStyle& atomStyle)
1149 {
1150  if (atomStyle.style == StyleManager::eNotDisplayed || atomStyle.radius <= 0.0)
1151  return;
1152 
1153  if (atomStyle.style == StyleManager::eSolidAtom) {
1154 #if MAC_GL_OPTIMIZE
1155  SetColor(eSetCacheValues, GL_DIFFUSE, atomStyle.color[0], atomStyle.color[1], atomStyle.color[2]);
1156 #else
1157  SetColor(eSetColorIfDifferent, GL_DIFFUSE, atomStyle.color[0], atomStyle.color[1], atomStyle.color[2]);
1158 #endif
1159  glLoadName(static_cast<GLuint>(atomStyle.name));
1160  glPushMatrix();
1161  glTranslated(site.x, site.y, site.z);
1162  GLU_SPHERE(qobj, atomStyle.radius, atomSlices, atomStacks);
1163  glPopMatrix();
1164  }
1165  // need to delay rendering of transparent spheres
1166  else {
1167  AddTransparentSphere(atomStyle.color, atomStyle.name, site, atomStyle.radius, atomStyle.alpha);
1168  // but can put labels on now
1169  if (atomStyle.centerLabel.size() > 0)
1170  DrawLabel(atomStyle.centerLabel, site,
1171  (atomStyle.isHighlighted ? GlobalColors()->Get(Colors::eHighlight) : Vector(1,1,1)));
1172  }
1173 
1175 }
1176 
1177 /* add a thick splined curve from point 1 *halfway* to point 2 */
1178 void OpenGLRenderer::DrawHalfWorm(const Vector *p0, const Vector& p1,
1179  const Vector& p2, const Vector *p3,
1180  double radius, bool cap1, bool cap2,
1181  double tension)
1182 {
1183  int i, j, k, m, offset=0;
1184  Vector R1, R2, Qt, p, dQt, H, V;
1185  double len, MG[4][3], T[4], t, prevlen=0.0, cosj, sinj;
1186  GLdouble *Nx=NULL, *Ny=NULL, *Nz=NULL, *Cx=NULL, *Cy=NULL, *Cz=NULL,
1187  *pNx=NULL, *pNy=NULL, *pNz=NULL, *pCx=NULL, *pCy=NULL, *pCz=NULL, *tmp;
1188 
1189  if (!p0 || !p3) {
1190  ERRORMSG("DrawHalfWorm: got NULL 0th and/or 3rd coords for worm");
1191  return;
1192  }
1193 
1194  /*
1195  * The Hermite matrix Mh.
1196  */
1197  static double Mh[4][4] = {
1198  { 2, -2, 1, 1},
1199  {-3, 3, -2, -1},
1200  { 0, 0, 1, 0},
1201  { 1, 0, 0, 0}
1202  };
1203 
1204  /*
1205  * Variables that affect the curve shape
1206  * a=b=0 = Catmull-Rom
1207  */
1208  double a = tension, /* tension (adjustable) */
1209  c = 0, /* continuity (should be 0) */
1210  b = 0; /* bias (should be 0) */
1211 
1212  if (wormSides % 2) {
1213  WARNINGMSG("worm sides must be an even number");
1214  ++wormSides;
1215  }
1216  GLdouble *fblock = NULL;
1217 
1218  /* First, calculate the coordinate points of the center of the worm,
1219  * using the Kochanek-Bartels variant of the Hermite curve.
1220  */
1221  R1 = 0.5 * (1 - a) * (1 + b) * (1 + c) * (p1 - *p0) + 0.5 * (1 - a) * (1 - b) * (1 - c) * ( p2 - p1);
1222  R2 = 0.5 * (1 - a) * (1 + b) * (1 - c) * (p2 - p1) + 0.5 * (1 - a) * (1 - b) * (1 + c) * (*p3 - p2);
1223 
1224  /*
1225  * Multiply MG=Mh.Gh, where Gh = [ P(1) P(2) R(1) R(2) ]. This
1226  * 4x1 matrix of vectors is constant for each segment.
1227  */
1228  for (i = 0; i < 4; ++i) { /* calculate Mh.Gh */
1229  MG[i][0] = Mh[i][0] * p1.x + Mh[i][1] * p2.x + Mh[i][2] * R1.x + Mh[i][3] * R2.x;
1230  MG[i][1] = Mh[i][0] * p1.y + Mh[i][1] * p2.y + Mh[i][2] * R1.y + Mh[i][3] * R2.y;
1231  MG[i][2] = Mh[i][0] * p1.z + Mh[i][1] * p2.z + Mh[i][2] * R1.z + Mh[i][3] * R2.z;
1232  }
1233 
1234  for (i = 0; i <= wormSegments; ++i) {
1235 
1236  /* t goes from [0,1] from P(1) to P(2) (and we want to go halfway only),
1237  and the function Q(t) defines the curve of this segment. */
1238  t = (0.5 / wormSegments) * i;
1239  /*
1240  * Q(t)=T.(Mh.Gh), where T = [ t^3 t^2 t 1 ]
1241  */
1242  T[0] = t * t * t;
1243  T[1] = t * t;
1244  T[2] = t;
1245  //T[3] = 1;
1246  Qt.x = T[0] * MG[0][0] + T[1] * MG[1][0] + T[2] * MG[2][0] + MG[3][0] /* *T[3] */ ;
1247  Qt.y = T[0] * MG[0][1] + T[1] * MG[1][1] + T[2] * MG[2][1] + MG[3][1] /* *T[3] */ ;
1248  Qt.z = T[0] * MG[0][2] + T[1] * MG[1][2] + T[2] * MG[2][2] + MG[3][2] /* *T[3] */ ;
1249 
1250  if (radius == 0.0) {
1251  if (i > 0) {
1252  glBegin(GL_LINES);
1254  glVertex3d(p.x, p.y, p.z);
1256  glVertex3d(Qt.x, Qt.y, Qt.z);
1257  glEnd();
1258  }
1259  /* save to use as previous point for connecting points together */
1260  p = Qt;
1261 
1262  } else {
1263  /* construct a circle of points centered at and
1264  in a plane normal to the curve at t - these points will
1265  be used to construct the "thick" worm */
1266 
1267  /* allocate single block of storage for two circles of points */
1268  if (!Nx) {
1269  fblock = new GLdouble[12 * wormSides];
1270  Nx = fblock;
1271  Ny = &Nx[wormSides];
1272  Nz = &Nx[wormSides * 2];
1273  Cx = &Nx[wormSides * 3];
1274  Cy = &Nx[wormSides * 4];
1275  Cz = &Nx[wormSides * 5];
1276  pNx = &Nx[wormSides * 6];
1277  pNy = &Nx[wormSides * 7];
1278  pNz = &Nx[wormSides * 8];
1279  pCx = &Nx[wormSides * 9];
1280  pCy = &Nx[wormSides * 10];
1281  pCz = &Nx[wormSides * 11];
1282  }
1283 
1284  /*
1285  * The first derivative of Q(t), d(Q(t))/dt, is the slope
1286  * (tangent) at point Q(t); now T = [ 3t^2 2t 1 0 ]
1287  */
1288  T[0] = t * t * 3;
1289  T[1] = t * 2;
1290  //T[2] = 1;
1291  //T[3] = 0;
1292  dQt.x = T[0] * MG[0][0] + T[1] * MG[1][0] + MG[2][0] /* *T[2] + T[3]*MG[3][0] */ ;
1293  dQt.y = T[0] * MG[0][1] + T[1] * MG[1][1] + MG[2][1] /* *T[2] + T[3]*MG[3][1] */ ;
1294  dQt.z = T[0] * MG[0][2] + T[1] * MG[1][2] + MG[2][2] /* *T[2] + T[3]*MG[3][2] */ ;
1295 
1296  /* use cross prod't of [1,0,0] x normal as horizontal */
1297  H.Set(0.0, -dQt.z, dQt.y);
1298  if (H.length() < 0.000001) /* nearly colinear - use [1,0.1,0] instead */
1299  H.Set(0.1 * dQt.z, -dQt.z, dQt.y - 0.1 * dQt.x);
1300  H.normalize();
1301 
1302  /* and a vertical vector = normal x H */
1303  V = vector_cross(dQt, H);
1304  V.normalize();
1305 
1306  /* finally, the worm circumference points (C) and normals (N) are
1307  simple trigonometric combinations of H and V */
1308  for (j = 0; j < wormSides; ++j) {
1309  cosj = cos(2 * PI * j / wormSides);
1310  sinj = sin(2 * PI * j / wormSides);
1311  Nx[j] = H.x * cosj + V.x * sinj;
1312  Ny[j] = H.y * cosj + V.y * sinj;
1313  Nz[j] = H.z * cosj + V.z * sinj;
1314  Cx[j] = Qt.x + Nx[j] * radius;
1315  Cy[j] = Qt.y + Ny[j] * radius;
1316  Cz[j] = Qt.z + Nz[j] * radius;
1317  }
1318 
1319  /* figure out which points on the previous circle "match" best
1320  with these, to minimize envelope twisting */
1321  if (i > 0) {
1322  for (m = 0; m < wormSides; ++m) {
1323  len = 0.0;
1324  for (j = 0; j < wormSides; ++j) {
1325  k = j + m;
1326  if (k >= wormSides)
1327  k -= wormSides;
1328  len += (Cx[k] - pCx[j]) * (Cx[k] - pCx[j]) +
1329  (Cy[k] - pCy[j]) * (Cy[k] - pCy[j]) +
1330  (Cz[k] - pCz[j]) * (Cz[k] - pCz[j]);
1331  }
1332  if (m == 0 || len < prevlen) {
1333  prevlen = len;
1334  offset = m;
1335  }
1336  }
1337  }
1338 
1339  /* create triangles from points along this and previous circle */
1340  if (i > 0) {
1341  glBegin(GL_TRIANGLE_STRIP);
1342  for (j = 0; j < wormSides; ++j) {
1343  k = j + offset;
1344  if (k >= wormSides) k -= wormSides;
1346  glNormal3d(Nx[k], Ny[k], Nz[k]);
1347  glVertex3d(Cx[k], Cy[k], Cz[k]);
1349  glNormal3d(pNx[j], pNy[j], pNz[j]);
1350  glVertex3d(pCx[j], pCy[j], pCz[j]);
1351  }
1353  glNormal3d(Nx[offset], Ny[offset], Nz[offset]);
1354  glVertex3d(Cx[offset], Cy[offset], Cz[offset]);
1356  glNormal3d(pNx[0], pNy[0], pNz[0]);
1357  glVertex3d(pCx[0], pCy[0], pCz[0]);
1358  glEnd();
1359  }
1360 
1361  /* put caps on the end */
1362  if (cap1 && i == 0) {
1363  dQt.normalize();
1364  glBegin(GL_POLYGON);
1365  glNormal3d(-dQt.x, -dQt.y, -dQt.z);
1366  for (j = wormSides - 1; j >= 0; --j) {
1368  glVertex3d(Cx[j], Cy[j], Cz[j]);
1369  }
1370  glEnd();
1371  }
1372  else if (cap2 && i == wormSegments) {
1373  dQt.normalize();
1374  glBegin(GL_POLYGON);
1375  glNormal3d(dQt.x, dQt.y, dQt.z);
1376  for (j = 0; j < wormSides; ++j) {
1377  k = j + offset;
1378  if (k >= wormSides) k -= wormSides;
1380  glVertex3d(Cx[k], Cy[k], Cz[k]);
1381  }
1382  glEnd();
1383  }
1384 
1385  /* store this circle as previous for next round; instead of copying
1386  all values, just swap pointers */
1387 #define SWAPPTR(p1,p2) tmp=(p1); (p1)=(p2); (p2)=tmp
1388  SWAPPTR(Nx, pNx);
1389  SWAPPTR(Ny, pNy);
1390  SWAPPTR(Nz, pNz);
1391  SWAPPTR(Cx, pCx);
1392  SWAPPTR(Cy, pCy);
1393  SWAPPTR(Cz, pCz);
1394  }
1395  }
1396 
1397  if (fblock) delete[] fblock;
1398 }
1399 
1400 static void DoCylinderPlacementTransform(const Vector& a, const Vector& b, double length)
1401 {
1402  /* to translate into place */
1403  glTranslated(a.x, a.y, a.z);
1404 
1405  /* to rotate from initial position, so bond points right direction;
1406  handle special case where both ends share ~same x,y */
1407  if (fabs(a.y - b.y) < 0.000001 && fabs(a.x - b.x) < 0.000001) {
1408  if (b.z - a.z < 0.0) glRotated(180.0, 1.0, 0.0, 0.0);
1409  } else {
1410  glRotated(RadToDegrees(acos((b.z - a.z) / length)),
1411  a.y - b.y, b.x - a.x, 0.0);
1412  }
1413 }
1414 
1415 void OpenGLRenderer::DrawHalfBond(const Vector& site1, const Vector& midpoint,
1416  StyleManager::eDisplayStyle style, double radius,
1417  bool cap1, bool cap2)
1418 {
1419  // straight line bond
1420  if (style == StyleManager::eLineBond || (style == StyleManager::eCylinderBond && radius <= 0.0)) {
1421  glBegin(GL_LINES);
1423  glVertex3d(site1.x, site1.y, site1.z);
1425  glVertex3d(midpoint.x, midpoint.y, midpoint.z);
1426  glEnd();
1427  }
1428 
1429  // cylinder bond
1430  else if (style == StyleManager::eCylinderBond) {
1431  double length = (site1 - midpoint).length();
1432  if (length <= 0.000001 || bondSides <= 1) return;
1433  glPushMatrix();
1434  DoCylinderPlacementTransform(site1, midpoint, length);
1435  GLU_CYLINDER(qobj, radius, radius, length, bondSides, 1);
1436  if (cap1) {
1437  glPushMatrix();
1438  glRotated(180.0, 0.0, 1.0, 0.0);
1439  GLU_DISK(qobj, 0.0, radius, bondSides, 1);
1440  glPopMatrix();
1441  }
1442  if (cap2) {
1443  glPushMatrix();
1444  glTranslated(0.0, 0.0, length);
1445  GLU_DISK(qobj, 0.0, radius, bondSides, 1);
1446  glPopMatrix();
1447  }
1448  glPopMatrix();
1449  }
1450 }
1451 
1452 void OpenGLRenderer::DrawBond(const Vector& site1, const Vector& site2,
1453  const BondStyle& style, const Vector *site0, const Vector* site3)
1454 {
1455  GLenum colorType;
1456  Vector midpoint = (site1 + site2) / 2;
1457 
1458  if (style.end1.style != StyleManager::eNotDisplayed) {
1459  colorType =
1460  (style.end1.style == StyleManager::eLineBond ||
1462  style.end1.radius <= 0.0)
1463  ? GL_AMBIENT : GL_DIFFUSE;
1464 #if MAC_GL_OPTIMIZE
1465  SetColor(eSetCacheValues, colorType, style.end1.color[0], style.end1.color[1], style.end1.color[2]);
1466 #else
1467  SetColor(eSetColorIfDifferent, colorType, style.end1.color[0], style.end1.color[1], style.end1.color[2]);
1468 #endif
1469  glLoadName(static_cast<GLuint>(style.end1.name));
1470  if (style.end1.style == StyleManager::eLineWormBond ||
1472  DrawHalfWorm(site0, site1, site2, site3,
1473  (style.end1.style == StyleManager::eThickWormBond) ? style.end1.radius : 0.0,
1474  style.end1.atomCap, style.midCap,
1475  style.tension);
1476  else
1477  DrawHalfBond(site1, midpoint,
1478  style.end1.style, style.end1.radius,
1479  style.end1.atomCap, style.midCap);
1481  }
1482 
1483  if (style.end2.style != StyleManager::eNotDisplayed) {
1484  colorType =
1485  (style.end2.style == StyleManager::eLineBond ||
1487  style.end2.radius <= 0.0)
1488  ? GL_AMBIENT : GL_DIFFUSE;
1489 #if MAC_GL_OPTIMIZE
1490  SetColor(eSetCacheValues, colorType, style.end2.color[0], style.end2.color[1], style.end2.color[2]);
1491 #else
1492  SetColor(eSetColorIfDifferent, colorType, style.end2.color[0], style.end2.color[1], style.end2.color[2]);
1493 #endif
1494  glLoadName(static_cast<GLuint>(style.end2.name));
1495  if (style.end2.style == StyleManager::eLineWormBond ||
1497  DrawHalfWorm(site3, site2, site1, site0,
1498  (style.end2.style == StyleManager::eThickWormBond) ? style.end2.radius : 0.0,
1499  style.end2.atomCap, style.midCap,
1500  style.tension);
1501  else
1502  DrawHalfBond(midpoint, site2,
1503  style.end2.style, style.end2.radius,
1504  style.midCap, style.end2.atomCap);
1506  }
1507 }
1508 
1509 void OpenGLRenderer::DrawHelix(const Vector& Nterm, const Vector& Cterm, const HelixStyle& style)
1510 {
1511 #if MAC_GL_OPTIMIZE
1512  SetColor(eSetCacheValues, GL_DIFFUSE, style.color[0], style.color[1], style.color[2]);
1513 #else
1514  SetColor(eSetColorIfDifferent, GL_DIFFUSE, style.color[0], style.color[1], style.color[2]);
1515 #endif
1516  glLoadName(static_cast<GLuint>(NO_NAME));
1517 
1518  double wholeLength = (Nterm - Cterm).length();
1519  if (wholeLength <= 0.000001) return;
1520 
1521  // transformation for whole helix
1522  glPushMatrix();
1523  DoCylinderPlacementTransform(Nterm, Cterm, wholeLength);
1524 
1525  // helix body
1526  double shaftLength =
1527  (style.style == StyleManager::eObjectWithArrow && style.arrowLength < wholeLength) ?
1528  wholeLength - style.arrowLength : wholeLength;
1529  GLU_CYLINDER(qobj, style.radius, style.radius, shaftLength, helixSides, 1);
1530 
1531  // Nterm cap
1532  glPushMatrix();
1533  glRotated(180.0, 0.0, 1.0, 0.0);
1534  GLU_DISK(qobj, 0.0, style.radius, helixSides, 1);
1535  glPopMatrix();
1536 
1537  // Cterm Arrow
1538  if (style.style == StyleManager::eObjectWithArrow && style.arrowLength < wholeLength) {
1539  // arrow base
1540  if (style.arrowBaseWidthProportion > 1.0) {
1541  glPushMatrix();
1542  glTranslated(0.0, 0.0, shaftLength);
1543  glRotated(180.0, 0.0, 1.0, 0.0);
1544  GLU_DISK(qobj, style.radius, style.radius * style.arrowBaseWidthProportion, helixSides, 1);
1545  glPopMatrix();
1546  }
1547  // arrow body
1548  glPushMatrix();
1549  glTranslated(0.0, 0.0, shaftLength);
1550  GLU_CYLINDER(qobj, style.radius * style.arrowBaseWidthProportion,
1551  style.radius * style.arrowTipWidthProportion, style.arrowLength, helixSides, 10);
1552  glPopMatrix();
1553  // arrow tip
1554  if (style.arrowTipWidthProportion > 0.0) {
1555  glPushMatrix();
1556  glTranslated(0.0, 0.0, wholeLength);
1557  GLU_DISK(qobj, 0.0, style.radius * style.arrowTipWidthProportion, helixSides, 1);
1558  glPopMatrix();
1559  }
1560  }
1561 
1562  // Cterm cap
1563  else {
1564  glPushMatrix();
1565  glTranslated(0.0, 0.0, wholeLength);
1566  GLU_DISK(qobj, 0.0, style.radius, helixSides, 1);
1567  glPopMatrix();
1568  }
1569 
1570  glPopMatrix();
1572 }
1573 
1574 void OpenGLRenderer::DrawStrand(const Vector& Nterm, const Vector& Cterm,
1575  const Vector& unitNormal, const StrandStyle& style)
1576 {
1577  GLdouble c000[3], c001[3], c010[3], c011[3],
1578  c100[3], c101[3], c110[3], c111[3], n[3];
1579  Vector a, h;
1580  int i;
1581 
1582 #if MAC_GL_OPTIMIZE
1583  SetColor(eSetCacheValues, GL_DIFFUSE, style.color[0], style.color[1], style.color[2]);
1584 #else
1585  SetColor(eSetColorIfDifferent, GL_DIFFUSE, style.color[0], style.color[1], style.color[2]);
1586 #endif
1587  glLoadName(static_cast<GLuint>(NO_NAME));
1588 
1589  /* in this brick's world coordinates, the long axis (N-C direction) is
1590  along +Z, with N terminus at Z=0; width is in the X direction, and
1591  thickness in Y. Arrowhead at C-terminus, of course. */
1592 
1593  a = Cterm - Nterm;
1594  a.normalize();
1595  h = vector_cross(unitNormal, a);
1596 
1597  Vector lCterm(Cterm);
1599  lCterm -= a * style.arrowLength;
1600 
1601  for (i=0; i<3; ++i) {
1602  c000[i] = Nterm[i] - h[i]*style.width/2 - unitNormal[i]*style.thickness/2;
1603  c001[i] = lCterm[i] - h[i]*style.width/2 - unitNormal[i]*style.thickness/2;
1604  c010[i] = Nterm[i] - h[i]*style.width/2 + unitNormal[i]*style.thickness/2;
1605  c011[i] = lCterm[i] - h[i]*style.width/2 + unitNormal[i]*style.thickness/2;
1606  c100[i] = Nterm[i] + h[i]*style.width/2 - unitNormal[i]*style.thickness/2;
1607  c101[i] = lCterm[i] + h[i]*style.width/2 - unitNormal[i]*style.thickness/2;
1608  c110[i] = Nterm[i] + h[i]*style.width/2 + unitNormal[i]*style.thickness/2;
1609  c111[i] = lCterm[i] + h[i]*style.width/2 + unitNormal[i]*style.thickness/2;
1610  }
1611 
1612  glBegin(GL_QUADS);
1613 
1614  for (i=0; i<3; ++i) n[i] = unitNormal[i];
1616  glNormal3dv(n);
1617  glVertex3dv(c010);
1619  glVertex3dv(c011);
1621  glVertex3dv(c111);
1623  glVertex3dv(c110);
1624 
1625  for (i=0; i<3; ++i) n[i] = -unitNormal[i];
1627  glNormal3dv(n);
1628  glVertex3dv(c000);
1630  glVertex3dv(c100);
1632  glVertex3dv(c101);
1634  glVertex3dv(c001);
1635 
1636  for (i=0; i<3; ++i) n[i] = h[i];
1638  glNormal3dv(n);
1639  glVertex3dv(c100);
1641  glVertex3dv(c110);
1643  glVertex3dv(c111);
1645  glVertex3dv(c101);
1646 
1647  for (i=0; i<3; ++i) n[i] = -h[i];
1649  glNormal3dv(n);
1650  glVertex3dv(c000);
1652  glVertex3dv(c001);
1654  glVertex3dv(c011);
1656  glVertex3dv(c010);
1657 
1658  for (i=0; i<3; ++i) n[i] = -a[i];
1660  glNormal3dv(n);
1661  glVertex3dv(c000);
1663  glVertex3dv(c010);
1665  glVertex3dv(c110);
1667  glVertex3dv(c100);
1668 
1670  for (i=0; i<3; ++i) n[i] = a[i];
1672  glNormal3dv(n);
1673  glVertex3dv(c001);
1675  glVertex3dv(c101);
1677  glVertex3dv(c111);
1679  glVertex3dv(c011);
1680 
1681  } else {
1682  GLdouble FT[3], LT[3], RT[3], FB[3], LB[3], RB[3];
1683 
1684  for (i=0; i<3; ++i) {
1685  FT[i] = lCterm[i] + unitNormal[i]*style.thickness/2 +
1686  a[i]*style.arrowLength;
1687  LT[i] = lCterm[i] + unitNormal[i]*style.thickness/2 +
1688  h[i]*style.arrowBaseWidthProportion*style.width/2;
1689  RT[i] = lCterm[i] + unitNormal[i]*style.thickness/2 -
1690  h[i]*style.arrowBaseWidthProportion*style.width/2;
1691  FB[i] = lCterm[i] - unitNormal[i]*style.thickness/2 +
1692  a[i]*style.arrowLength;
1693  LB[i] = lCterm[i] - unitNormal[i]*style.thickness/2 +
1694  h[i]*style.arrowBaseWidthProportion*style.width/2;
1695  RB[i] = lCterm[i] - unitNormal[i]*style.thickness/2 -
1696  h[i]*style.arrowBaseWidthProportion*style.width/2;
1697  }
1698 
1699  // the back-facing rectangles on the base of the arrow
1700  for (i=0; i<3; ++i) n[i] = -a[i];
1702  glNormal3dv(n);
1703  glVertex3dv(c111);
1705  glVertex3dv(LT);
1707  glVertex3dv(LB);
1709  glVertex3dv(c101);
1710 
1712  glVertex3dv(c011);
1714  glVertex3dv(c001);
1716  glVertex3dv(RB);
1718  glVertex3dv(RT);
1719 
1720  // the left side of the arrow
1721  for (i=0; i<3; ++i) h[i] = FT[i] - LT[i];
1722  Vector nL = vector_cross(unitNormal, h);
1723  nL.normalize();
1724  for (i=0; i<3; ++i) n[i] = nL[i];
1726  glNormal3dv(n);
1727  glVertex3dv(FT);
1729  glVertex3dv(FB);
1731  glVertex3dv(LB);
1733  glVertex3dv(LT);
1734 
1735  // the right side of the arrow
1736  for (i=0; i<3; ++i) h[i] = FT[i] - RT[i];
1737  Vector nR = vector_cross(h, unitNormal);
1738  nR.normalize();
1739  for (i=0; i<3; ++i) n[i] = nR[i];
1741  glNormal3dv(n);
1742  glVertex3dv(FT);
1744  glVertex3dv(RT);
1746  glVertex3dv(RB);
1748  glVertex3dv(FB);
1749 
1750  glEnd();
1751 
1752 #ifdef __WXMAC__
1753 
1754  // the top and bottom arrow triangles; connect exactly to end points of base, otherwise
1755  // artifacts appear at junction on Mac (actually, they still do, but are much less obvious)
1756  glBegin(GL_TRIANGLE_FAN);
1757  for (i=0; i<3; ++i) n[i] = unitNormal[i];
1759  glNormal3dv(n);
1760  glVertex3dv(FT);
1762  glVertex3dv(LT);
1764  glVertex3dv(c011);
1766  glVertex3dv(c111);
1768  glVertex3dv(RT);
1769  glEnd();
1770 
1771  glBegin(GL_TRIANGLE_FAN);
1772  for (i=0; i<3; ++i) n[i] = -unitNormal[i];
1774  glNormal3dv(n);
1775  glVertex3dv(FB);
1777  glVertex3dv(RB);
1779  glVertex3dv(c101);
1781  glVertex3dv(c001);
1783  glVertex3dv(LB);
1784 
1785 #else
1786 
1787  glBegin(GL_TRIANGLES);
1788 
1789  // the top and bottom arrow triangles
1790  for (i=0; i<3; ++i) n[i] = unitNormal[i];
1791  glNormal3dv(n);
1792  glVertex3dv(FT);
1793  glVertex3dv(LT);
1794  glVertex3dv(RT);
1795 
1796  for (i=0; i<3; ++i) n[i] = -unitNormal[i];
1797  glNormal3dv(n);
1798  glVertex3dv(FB);
1799  glVertex3dv(RB);
1800  glVertex3dv(LB);
1801 
1802 #endif
1803  }
1804 
1805  glEnd();
1807 }
1808 
1809 void OpenGLRenderer::DrawLabel(const string& text, const Vector& center, const Vector& color)
1810 {
1811  int width, height, textCenterX = 0, textCenterY = 0;
1812 
1813  if (text.empty() || !glCanvas) return;
1814 
1815  if (!glCanvas->MeasureText(text, &width, &height, &textCenterX, &textCenterY))
1816  WARNINGMSG("MeasureText() failed, text may not be properly centered");
1817 
1818  SetColor(eSetColorIfDifferent, GL_AMBIENT, color[0], color[1], color[2]);
1819  glListBase(FONT_BASE);
1820  glRasterPos3d(center.x, center.y, center.z);
1821  glBitmap(0, 0, 0.0, 0.0, -textCenterX, -textCenterY, NULL);
1822  glCallLists(text.size(), GL_UNSIGNED_BYTE, text.data());
1823  glListBase(0);
1825 }
1826 
1827 bool OpenGLRenderer::SaveToASNViewSettings(ncbi::objects::CCn3d_user_annotations *annotations)
1828 {
1829  // save current camera settings
1831  initialViewFromASN->SetCamera_distance(cameraDistance);
1832  initialViewFromASN->SetCamera_angle_rad(cameraAngleRad);
1833  initialViewFromASN->SetCamera_look_at_X(cameraLookAtX);
1834  initialViewFromASN->SetCamera_look_at_Y(cameraLookAtY);
1835  initialViewFromASN->SetCamera_clip_near(cameraClipNear);
1836  initialViewFromASN->SetCamera_clip_far(cameraClipFar);
1837  initialViewFromASN->SetMatrix().SetM0(viewMatrix[0]);
1838  initialViewFromASN->SetMatrix().SetM1(viewMatrix[1]);
1839  initialViewFromASN->SetMatrix().SetM2(viewMatrix[2]);
1840  initialViewFromASN->SetMatrix().SetM3(viewMatrix[3]);
1841  initialViewFromASN->SetMatrix().SetM4(viewMatrix[4]);
1842  initialViewFromASN->SetMatrix().SetM5(viewMatrix[5]);
1843  initialViewFromASN->SetMatrix().SetM6(viewMatrix[6]);
1844  initialViewFromASN->SetMatrix().SetM7(viewMatrix[7]);
1845  initialViewFromASN->SetMatrix().SetM8(viewMatrix[8]);
1846  initialViewFromASN->SetMatrix().SetM9(viewMatrix[9]);
1847  initialViewFromASN->SetMatrix().SetM10(viewMatrix[10]);
1848  initialViewFromASN->SetMatrix().SetM11(viewMatrix[11]);
1849  initialViewFromASN->SetMatrix().SetM12(viewMatrix[12]);
1850  initialViewFromASN->SetMatrix().SetM13(viewMatrix[13]);
1851  initialViewFromASN->SetMatrix().SetM14(viewMatrix[14]);
1852  initialViewFromASN->SetMatrix().SetM15(viewMatrix[15]);
1853  initialViewFromASN->SetRotation_center().SetX(structureSet->rotationCenter.x);
1854  initialViewFromASN->SetRotation_center().SetY(structureSet->rotationCenter.y);
1855  initialViewFromASN->SetRotation_center().SetZ(structureSet->rotationCenter.z);
1856 
1857  // store copy in given annotations
1858  if (annotations)
1859  annotations->SetView().Assign(*initialViewFromASN);
1860 
1861  return true;
1862 }
1863 
1864 bool OpenGLRenderer::LoadFromASNViewSettings(const ncbi::objects::CCn3d_user_annotations& annotations)
1865 {
1866  initialViewFromASN.Reset();
1867  if (!annotations.IsSetView()) return true;
1868  TRACEMSG("Using view from incoming data...");
1869 
1870  // save a copy of the view settings
1872  initialViewFromASN->Assign(annotations.GetView());
1873  return true;
1874 }
1875 
1877 {
1878  if (initialViewFromASN.Empty() || !structureSet) {
1879  ResetCamera();
1880  return;
1881  }
1882 
1883  // restore current camera settings
1884  cameraDistance = initialViewFromASN->GetCamera_distance();
1885  cameraAngleRad = initialViewFromASN->GetCamera_angle_rad();
1886  cameraLookAtX = initialViewFromASN->GetCamera_look_at_X();
1887  cameraLookAtY = initialViewFromASN->GetCamera_look_at_Y();
1888  cameraClipNear = initialViewFromASN->GetCamera_clip_near();
1889  cameraClipFar = initialViewFromASN->GetCamera_clip_far();
1890  viewMatrix[0] = initialViewFromASN->GetMatrix().GetM0();
1891  viewMatrix[1] = initialViewFromASN->GetMatrix().GetM1();
1892  viewMatrix[2] = initialViewFromASN->GetMatrix().GetM2();
1893  viewMatrix[3] = initialViewFromASN->GetMatrix().GetM3();
1894  viewMatrix[4] = initialViewFromASN->GetMatrix().GetM4();
1895  viewMatrix[5] = initialViewFromASN->GetMatrix().GetM5();
1896  viewMatrix[6] = initialViewFromASN->GetMatrix().GetM6();
1897  viewMatrix[7] = initialViewFromASN->GetMatrix().GetM7();
1898  viewMatrix[8] = initialViewFromASN->GetMatrix().GetM8();
1899  viewMatrix[9] = initialViewFromASN->GetMatrix().GetM9();
1900  viewMatrix[10] = initialViewFromASN->GetMatrix().GetM10();
1901  viewMatrix[11] = initialViewFromASN->GetMatrix().GetM11();
1902  viewMatrix[12] = initialViewFromASN->GetMatrix().GetM12();
1903  viewMatrix[13] = initialViewFromASN->GetMatrix().GetM13();
1904  viewMatrix[14] = initialViewFromASN->GetMatrix().GetM14();
1905  viewMatrix[15] = initialViewFromASN->GetMatrix().GetM15();
1907  initialViewFromASN->GetRotation_center().GetX(),
1908  initialViewFromASN->GetRotation_center().GetY(),
1909  initialViewFromASN->GetRotation_center().GetZ());
1910 
1911  NewView();
1912 }
1913 
1914 const wxFont& OpenGLRenderer::GetGLFont(void) const
1915 {
1916  static const wxFont emptyFont;
1917  if (!glCanvas) {
1918  ERRORMSG("Can't call GetGLFont w/ NULL glCanvas");
1919  return emptyFont;
1920  }
1921  return glCanvas->GetGLFont();
1922 }
1923 
1924 bool OpenGLRenderer::SetGLFont(int firstChar, int nChars, int fontBase)
1925 {
1926  bool okay = true;
1927 
1928 #if defined(__WXMSW__)
1929  HDC hdc = wglGetCurrentDC();
1930  HGDIOBJ currentFont = SelectObject(hdc, reinterpret_cast<HGDIOBJ>(GetGLFont().GetHFONT()));
1931  if (!wglUseFontBitmaps(hdc, firstChar, nChars, fontBase)) {
1932  ERRORMSG("OpenGLRenderer::SetGLFont() - wglUseFontBitmaps() failed");
1933  okay = false;
1934  }
1935  SelectObject(hdc, currentFont);
1936 
1937 #elif defined(__WXGTK__)
1938 // need to somehow get X font from wxFont... ugh.
1939 //
1940 // PangoFont *pf = pango_font_map_load_font(
1941 // PangoFontMap *fontmap,
1942 // glCanvas->GtkGetPangoDefaultContext(),
1943 // GetGLFont().GetNativeFontInfo().description);
1944 //
1945 // glXUseXFont(gdk_font_id(GetGLFont().GetInternalFont()), firstChar, nChars, fontBase);
1946 
1947 #elif defined(__WXMAC__)
1948 
1949 // Offsets to font family, style determined empirically.
1950 // 'aglUseFont' deprecated w/o replacement as of OSX 10.5; code compiles but no longer
1951 // appears to do anything useful.
1952  int fontFamily = GetGLFont().GetFamily() - wxFONTFAMILY_DEFAULT;
1953  int fontSize = GetGLFont().GetPointSize();
1954  int fontStyle = GetGLFont().GetStyle() - wxFONTSTYLE_NORMAL;
1955 // TRACEMSG("OpenGLRenderer::SetGLFont() - fontBase/fontFamily/fontSize/fontStyle " << fontBase << "/" << fontFamily << "/" << fontSize << "/" << fontStyle);
1956 
1957 // As aglUseFont no longer returns GL_TRUE, do not annoy users w/ the error message.
1958  if (aglUseFont(aglGetCurrentContext(),
1959  (GLint) fontFamily,
1960  fontStyle, (GLint) fontSize,
1961  firstChar, nChars, fontBase) != GL_TRUE) {
1962 // ERRORMSG("OpenGLRenderer::SetGLFont() - aglUseFont() failed: " << aglErrorString(aglGetError()));
1963  okay = false;
1964  }
1965 #endif
1966 
1967  return okay;
1968 }
1969 
1970 END_SCOPE(Cn3D)
User-defined methods of the data storage class.
User-defined methods of the data storage class.
#define LT
std::string centerLabel
bool isHighlighted
unsigned int name
StyleManager::eDisplayStyle style
double tension
EndStyle end1
EndStyle end2
CCn3d_view_settings –.
const wxFont & GetGLFont(void) const
bool MeasureText(const std::string &text, int *width, int *height, int *centerX, int *centerY)
@ eHighlight
Definition: cn3d_colors.hpp:60
double arrowTipWidthProportion
double m[16]
void UnPostStructureRedraws(void)
Definition: messenger.cpp:117
double arrowBaseWidthProportion
StyleManager::eDisplayStyle style
double arrowLength
void MyGluSphere(double radius, int slices, int stacks)
void ConstructLogo(void)
bool GetSelected(int x, int y, unsigned int *name)
std::vector< bool > displayListEmpty
void PopMatrix(void)
void ShowPreviousFrame(void)
void DrawHalfBond(const Vector &site1, const Vector &midpoint, StyleManager::eDisplayStyle style, double radius, bool cap1, bool cap2)
void CenterView(const Vector &viewCenter, double radius)
void DrawAtom(const Vector &site, const AtomStyle &atomStyle)
void ResetCamera(void)
SpherePtrList transparentSpheresToRender
void RecreateQuadric(void) const
void AddTransparentSphere(const Vector &color, unsigned int name, const Vector &site, double radius, double alpha)
void AddTransparentSpheresForList(unsigned int list)
void ShowAllFrames(void)
void ShowLastFrame(void)
void SetColor(EColorAction action, int=0, double red=0.0, double green=0.0, double blue=0.0, double alpha=1.0)
void StartDisplayList(unsigned int list)
const wxFont & GetGLFont(void) const
void MyGluDisk(double innerRadius, double outerRadius, int slices, int loops)
SphereMap transparentSphereMap
void AttachStructureSet(StructureSet *targetStructureSet)
void Construct(void)
double viewMatrix[16]
void EndDisplayList(void)
void MyGluCylinder(double baseRadius, double topRadius, double height, int slices, int stacks)
Cn3DGLCanvas * glCanvas
void ShowFirstFrame(void)
void DrawBond(const Vector &site1, const Vector &site2, const BondStyle &style, const Vector *site0, const Vector *site3)
void DrawHalfWorm(const Vector *p0, const Vector &p1, const Vector &p2, const Vector *p3, double radius, bool cap1, bool cap2, double tension)
ncbi::CRef< ncbi::objects::CCn3d_view_settings > initialViewFromASN
void ChangeView(eViewAdjust control, int dX=0, int dY=0, int X2=0, int Y2=0)
bool LoadFromASNViewSettings(const ncbi::objects::CCn3d_user_annotations &annotations)
void PushMatrix(const Matrix *xform)
bool SetGLFont(int firstChar, int nChars, int fontBase)
void RestoreSavedView(void)
void ShowFrameNumber(int frame)
void Init(void) const
void EnableStereo(bool enableStereo)
void DrawHelix(const Vector &Nterm, const Vector &Cterm, const HelixStyle &helixStyle)
void ClearTransparentSpheresForList(unsigned int list)
bool IsFrameEmpty(unsigned int frame) const
void RenderTransparentSpheres(void)
void NewView(double eyeTranslateToAngleDegrees=0.0) const
static const unsigned int NO_NAME
void ComputeBestView(void)
bool SaveToASNViewSettings(ncbi::objects::CCn3d_user_annotations *annotations)
StructureSet * structureSet
static const unsigned int FIRST_LIST
unsigned int currentFrame
std::list< SphereInfo > SphereList
void DrawStrand(const Vector &Nterm, const Vector &Cterm, const Vector &unitNormal, const StrandStyle &strandStyle)
void DrawLabel(const std::string &text, const Vector &center, const Vector &color)
static const unsigned int NO_LIST
unsigned int currentDisplayList
void ShowNextFrame(void)
static const unsigned int FONT_BASE
OpenGLRenderer(Cn3DGLCanvas *parentGLCanvas)
virtual bool DrawAll(const AtomSet *atomSet=NULL) const
FrameMap frameMap
unsigned int lastDisplayList
TransformMap transformMap
void CenterViewOnStructure(void)
bool IsMultiStructure(void) const
bool CenterViewOnAlignedResidues(void)
Vector rotationCenter
StyleManager * styleManager
double maxDistFromCenter
const Vector & GetBackgroundColor(void) const
double y
Definition: vector_math.hpp:47
double x
Definition: vector_math.hpp:47
double length(void) const
double z
Definition: vector_math.hpp:47
void normalize(void)
void Set(double xs, double ys, double zs)
Definition: vector_math.hpp:62
bool IsWindowedMode(void)
Definition: cn3d_app.cpp:92
const Colors * GlobalColors(void)
Definition: cn3d_colors.cpp:52
bool RegistryGetDouble(const string &section, const string &name, double *value)
Definition: cn3d_tools.cpp:240
bool RegistryGetInteger(const string &section, const string &name, int *value)
Definition: cn3d_tools.cpp:228
bool RegistryGetBoolean(const string &section, const string &name, bool *value)
Definition: cn3d_tools.cpp:250
bool RegistryGetString(const string &section, const string &name, string *value)
Definition: cn3d_tools.cpp:263
static const std::string REG_QUALITY_ATOM_STACKS
Definition: cn3d_tools.hpp:174
static const std::string REG_QUALITY_ATOM_SLICES
Definition: cn3d_tools.hpp:173
static const std::string REG_QUALITY_SECTION
Definition: cn3d_tools.hpp:172
#define TRACEMSG(stream)
Definition: cn3d_tools.hpp:83
static const std::string REG_PROJECTION_TYPE
Definition: cn3d_tools.hpp:180
static const std::string REG_QUALITY_BOND_SIDES
Definition: cn3d_tools.hpp:175
static const std::string REG_HIGHLIGHTS_ON
Definition: cn3d_tools.hpp:179
static const std::string REG_QUALITY_WORM_SIDES
Definition: cn3d_tools.hpp:176
static const std::string REG_PROXIMAL_STEREO
Definition: cn3d_tools.hpp:199
static const std::string REG_QUALITY_HELIX_SIDES
Definition: cn3d_tools.hpp:178
#define WARNINGMSG(stream)
Definition: cn3d_tools.hpp:85
#define FATALMSG(stream)
Definition: cn3d_tools.hpp:87
static const std::string REG_ADVANCED_SECTION
Definition: cn3d_tools.hpp:191
static const std::string REG_QUALITY_WORM_SEGMENTS
Definition: cn3d_tools.hpp:177
#define ERRORMSG(stream)
Definition: cn3d_tools.hpp:86
static const std::string REG_STEREO_SEPARATION
Definition: cn3d_tools.hpp:198
Include a standard set of the NCBI C++ Toolkit most basic headers.
#define T(s)
Definition: common.h:230
static const unsigned long CR
#define false
Definition: bool.h:36
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
static DLIST_TYPE *DLIST_NAME() last(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:51
static char tmp[3200]
Definition: utf8.c:42
int offset
Definition: replacements.h:160
#define H(x, y, z)
Definition: md4.c:180
#define NULL
Definition: ncbistd.hpp:225
#define kMax_UInt
Definition: ncbi_limits.h:185
#define END_SCOPE(ns)
End the previously defined scope.
Definition: ncbistl.hpp:75
#define BEGIN_SCOPE(ns)
Define a new scope.
Definition: ncbistl.hpp:72
n background color
int i
yy_size_t n
int len
static void text(MDB_val *v)
Definition: mdb_dump.c:62
static MDB_envinfo info
Definition: mdb_load.c:37
Messenger * GlobalMessenger(void)
Definition: messenger.cpp:73
const TYPE & Get(const CNamedParameterList *param)
#define fabs(v)
Definition: ncbi_dispd.c:46
unsigned int a
Definition: ncbi_localip.c:102
EIPRangeType t
Definition: ncbi_localip.c:101
ESERV_Site site
Portable reference counted smart and weak pointers using CWeakRef, CRef, CObject and CObjectEx.
Defines: CTimeFormat - storage class for time format.
bool le(T x_, T y_, T round_)
Definition: njn_approx.hpp:84
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
double f(double x_, const double &y_)
Definition: njn_root.hpp:188
USING_SCOPE(objects)
static const GLfloat Color_MostlyOff[4]
static const GLdouble origin[]
#define SWAPPTR(p1, p2)
static const GLdouble unitZ[]
static int wormSides
static const GLfloat Color_Specular[4]
static const GLfloat Color_On[4]
static double DegreesToRad(double deg)
#define MAC_GL_SETCOLOR
static void GL2Matrix(GLdouble *g, Matrix *m)
static const unsigned int ALL_FRAMES
#define GLU_DISK(q, i, o, s, l)
static const int pickBufSize
static void DoCylinderPlacementTransform(const Vector &a, const Vector &b, double length)
#define MAX_CAMERA_ANGLE
static int atomStacks
static void Matrix2GL(const Matrix &m, GLdouble *g)
static const double PI
static int bondSides
static int atomSlices
#define GLU_CYLINDER(q, b, t, h, l, k)
#define MIN_CAMERA_ANGLE
static string projectionType
static const GLfloat Color_Off[4]
USING_NCBI_SCOPE
static const GLint Shininess
static const GLfloat Color_MostlyOn[4]
static bool highlightsOn
static int wormSegments
static double RadToDegrees(double rad)
static GLuint selectBuf[pickBufSize]
static int helixSides
#define GLU_SPHERE(q, r, l, k)
StyleManager::eDisplayStyle style
Definition: type.c:6
int g(Seg_Gsm *spe, Seq_Mtf *psm, Thd_Gsm *tdg)
Definition: thrddgri.c:44
void SetRotationMatrix(Matrix *m, const Vector &v, double rad, int n)
Definition: vector_math.cpp:62
void ApplyTransformation(Vector *v, const Matrix &m)
Definition: vector_math.cpp:91
#define N
Definition: crc32.c:57
Modified on Wed Apr 24 14:16:42 2024 by modify_doxy.py rev. 669887