1 /* shim3d.c
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information (NCBI)
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 do not place any restriction on its use or reproduction.
13 * We would, however, appreciate having the NCBI and the author cited in
14 * any work or product based on this material
15 *
16 * Although all reasonable efforts have been taken to ensure the accuracy
17 * and reliability of the software and data, the NLM and the U.S.
18 * Government do not and cannot warrant the performance or results that
19 * may be obtained by using this software or data. The NLM and the U.S.
20 * Government disclaim all warranties, express or implied, including
21 * warranties of performance, merchantability or fitness for any particular
22 * purpose.
23 *
24 * ===========================================================================
25 *
26 * File Name: shim3d.c
27 *
28 * Author: Lewis Geer
29 *
30 * Version Creation Date: 1/26/99
31 *
32 * $Revision: 6.81 $
33 *
34 * File Description: Shim functions to replace Viewer3D with OpenGL
35 *
36 * Modifications:
37 * --------------------------------------------------------------------------
38 * $Log: shim3d.c,v $
39 * Revision 6.81 2016/09/02 15:08:15 ucko
40 * shim3d.c (OGL_Reset): conditionally call OGL_ClearBoundBox, to avoid a
41 * (historical?) potential crash, per a long-standing Debian/Ubuntu patch
42 * that might be redundant nowadays.
43 *
44 * Revision 6.80 2016/09/02 15:06:30 ucko
45 * shim3d.c: accommodate newer versions of libpng, which don't directly
46 * expose the jmpbuf field, as already done in Debian/Ubuntu packages.
47 *
48 * Revision 6.79 2002/03/28 13:35:48 kans
49 * only include MoreCarbonAccessors.h if not OS_UNIX_DARWIN
50 *
51 * Revision 6.78 2001/05/25 19:46:58 vakatov
52 * Nested comment typo fixed
53 *
54 * Revision 6.77 2001/04/23 16:05:45 juran
55 * Include MoreCarbonAccessors.h, which now has GetPortText{Font,Face,Size}().
56 *
57 * Revision 6.76 2001/04/21 02:36:10 juran
58 * Very simple Carbon fixes.
59 *
60 * Revision 6.75 2001/04/18 16:33:54 kans
61 * moved define to first column
62 *
63 * Revision 6.74 2000/07/28 21:05:54 lewisg
64 * more c++ fixes
65 *
66 * Revision 6.73 2000/07/27 16:34:46 lewisg
67 * more c++ fixes
68 *
69 * Revision 6.72 2000/07/27 13:37:31 lewisg
70 * more c++ fixes
71 *
72 * Revision 6.71 2000/07/25 12:38:26 thiessen
73 * change C++-style comments to C
74 *
75 * Revision 6.70 2000/07/24 22:31:21 thiessen
76 * fix header conflict
77 *
78 * Revision 6.69 2000/07/22 20:13:42 thiessen
79 * fix header conflict
80 *
81 * Revision 6.68 2000/07/21 18:55:58 thiessen
82 * allow dynamic slave->master transformation
83 *
84 * Revision 6.67 2000/05/16 17:38:44 thiessen
85 * do glGenLists after context init on X11 - for Mesa 3.2
86 *
87 * Revision 6.66 2000/04/20 18:53:57 thiessen
88 * misc tweaks/fixes
89 *
90 * Revision 6.65 2000/04/20 17:47:18 thiessen
91 * tweak OpenGL drawing region position
92 *
93 * Revision 6.64 2000/04/19 17:56:46 thiessen
94 * added background color in OpenGL
95 *
96 * Revision 6.63 2000/04/17 15:54:27 thiessen
97 * add cylinder arrows; misc graphics tweaks
98 *
99 * Revision 6.62 2000/04/03 18:23:46 thiessen
100 * add arrowheads to strand bricks
101 *
102 * Revision 6.61 2000/03/27 14:47:31 thiessen
103 * widen logo slightly
104 *
105 * Revision 6.60 2000/03/24 20:34:59 lewisg
106 * add blast from file, bug fixes, get rid of redundant code, etc.
107 *
108 * Revision 6.59 2000/03/24 19:59:20 thiessen
109 * draw new logo in OpenGL
110 *
111 * Revision 6.58 2000/03/22 23:42:22 lewisg
112 * timing loop for animation
113 *
114 * Revision 6.57 2000/03/15 16:59:53 thiessen
115 * fix highlighting, other minor bugs
116 *
117 * Revision 6.56 2000/03/09 17:55:18 thiessen
118 * changes to palette handling for 8-bit OpenGL
119 *
120 * Revision 6.55 2000/03/08 21:46:13 lewisg
121 * cn3d saves viewport, misc bugs
122 *
123 * Revision 6.54 2000/03/06 18:35:22 thiessen
124 * fixes for 8-bit color
125 *
126 * Revision 6.53 2000/02/28 19:53:08 kans
127 * if macintosh, include <gl.h> and <glu.h>, not equivalent <GL/gl.h> and <GL/glu.h>
128 *
129 * Revision 6.52 2000/02/26 13:30:41 thiessen
130 * capped cylinders and worms for visible ends
131 *
132 * Revision 6.51 2000/02/26 00:01:41 thiessen
133 * OpenGL improvements, progress on cleanup of Show/Hide
134 *
135 * Revision 6.50 2000/02/16 14:01:40 thiessen
136 * warning on OGL color black or alpha 0 (if _DEBUG)
137 *
138 * Revision 6.49 2000/02/10 17:48:10 thiessen
139 * added OGL zoom out
140 *
141 * Revision 6.48 2000/01/25 22:58:13 thiessen
142 * added animation of conf-ensembles
143 *
144 * Revision 6.47 2000/01/19 15:22:33 thiessen
145 * working off-screen GL rendering and PNG output on Mac
146 *
147 * Revision 6.46 2000/01/18 14:57:41 lewisg
148 * move OGL_qobj initialization to OGL_CreateViewer
149 *
150 * Revision 6.45 2000/01/14 21:40:39 lewisg
151 * add translucent spheres, ion labels, new cpk, fix misc bugs
152 *
153 * Revision 6.44 2000/01/12 15:13:00 thiessen
154 * fixed minor OpenGL memory leak
155 *
156 * Revision 6.43 2000/01/12 14:58:14 thiessen
157 * added progress monitor for PNG save
158 *
159 * Revision 6.42 2000/01/11 02:55:15 thiessen
160 * working off-screen OpenGL rendering on Win32
161 *
162 * Revision 6.41 2000/01/07 19:37:06 thiessen
163 * fix minor OpenGL problems
164 *
165 * Revision 6.40 2000/01/07 16:28:36 thiessen
166 * fixed broken header conflicts
167 *
168 * Revision 6.39 2000/01/07 00:22:45 thiessen
169 * fixes for LessTif and OpenGL X visual selection
170 *
171 * Revision 6.38 2000/01/06 17:41:53 kans
172 * Mac complained about True and False, changed to TRUE and FALSE
173 *
174 * Revision 6.37 2000/01/06 17:23:36 thiessen
175 * various OpenGL improvements
176 *
177 * Revision 6.36 2000/01/06 00:04:41 lewisg
178 * selection bug fixes, update message outbound, animation APIs moved to vibrant
179 *
180 * Revision 6.35 2000/01/03 14:41:10 thiessen
181 * fixed selection pointer inaccuracy
182 *
183 * Revision 6.34 1999/12/17 20:25:01 thiessen
184 * put in preliminary PNG output (for Cn3D)
185 *
186 * Revision 6.33 1999/12/15 20:02:49 thiessen
187 * added missing prototype
188 *
189 * Revision 6.32 1999/12/15 19:18:48 thiessen
190 * bug fix for previous revision
191 *
192 * Revision 6.30 1999/12/08 22:57:59 thiessen
193 * added quality settings for OpenGL rendering
194 *
195 * Revision 6.29 1999/12/07 19:18:58 thiessen
196 * fixed font color problem in OpenGL on SGI
197 *
198 * Revision 6.28 1999/12/07 15:46:17 thiessen
199 * fonts working in OpenGL on Mac
200 *
201 * Revision 6.27 1999/12/06 14:43:59 thiessen
202 * made OpenGL font selection work in X/Motif
203 *
204 * Revision 6.26 1999/12/03 15:55:01 thiessen
205 * added font styles and prettified OpenGL label panel
206 *
207 * Revision 6.25 1999/12/02 23:56:52 thiessen
208 * added font selection for OpenGL/Win32 labels
209 *
210 * Revision 6.24 1999/11/23 21:18:04 thiessen
211 * fixed Mac prototype problem
212 *
213 * Revision 6.23 1999/11/23 19:24:16 thiessen
214 * better solution to OpenGL render rect setting on Mac
215 *
216 * Revision 6.22 1999/11/23 18:41:34 thiessen
217 * fixed Mac OpenGL render rect bug
218 *
219 * Revision 6.21 1999/11/19 18:07:23 thiessen
220 * added label capability for OpenGL version on Mac and Motif
221 *
222 * Revision 6.20 1999/11/16 14:30:28 thiessen
223 * avoid white-blanking of OpenGL window on redraw
224 *
225 * Revision 6.19 1999/11/14 19:26:29 thiessen
226 * fixed broken select mode in OpenGL
227 *
228 * Revision 6.18 1999/11/10 17:17:27 thiessen
229 * fixed diffuse/ambient coloring in 8-bit opengl
230 *
231 * Revision 6.17 1999/11/10 15:25:38 thiessen
232 * partial fix for 8-bit OpenGL coloring
233 *
234 * Revision 6.16 1999/11/09 14:36:59 lewisg
235 * NT faults on write of const array
236 *
237 * Revision 6.15 1999/11/08 20:43:05 thiessen
238 * added much more thorough (but optional) GL error checking; see #define DEBUG_GL
239 *
240 * Revision 6.14 1999/11/08 19:46:30 thiessen
241 * fixed OpenGL transformation bug; also added check for GL error flag
242 *
243 * Revision 6.13 1999/11/08 16:43:20 thiessen
244 * major rearrangement of OpenGL color/material/lighting; also added 3-d (thick) brick
245 *
246 * Revision 6.12 1999/11/03 17:00:39 thiessen
247 * added capped cylinders for 'helix' object
248 *
249 * Revision 6.11 1999/10/31 22:39:34 thiessen
250 * added wifreframe worm capability to viewer3d
251 *
252 * Revision 6.10 1999/10/15 17:37:43 thiessen
253 * put in splined 'worm' model for virtual BB
254 *
255 * Revision 6.9 1999/10/04 18:05:34 thiessen
256 * fix minor glX problem with Motif
257 *
258 * Revision 6.8 1999/10/04 14:27:16 thiessen
259 * hacked partial compatibility with Mesa OpenGL implementation - does *not* work when rendering inside vibrant window in Motif
260 *
261 * Revision 6.7 1999/09/27 18:28:29 thiessen
262 * Made 24-bit and doublebuffered OpenGL modes work on Mac; also should select
263 * mode like X
264 *
265 * Revision 6.6 1999/09/27 16:29:29 thiessen
266 * added OpenGL buffer swap for X
267 *
268 * Revision 6.5 1999/09/22 14:22:49 lewisg
269 * fixed forward declaration of TOGL_Layers to compile on SGI
270 *
271 * Revision 6.4 1999/09/21 13:45:31 thiessen
272 * port of Lewis's OpenGL code to X/Motif
273 *
274 * Revision 6.3 1999/09/20 20:12:56 lewisg
275 * change typedefs for a colorcell, add triangle generator, fix incorrect return values
276 *
277 * Revision 6.2 1999/06/14 23:15:11 lewisg
278 * moved useful helper functions out of the ifdef
279 *
280 * Revision 6.1 1999/04/06 14:23:28 lewisg
281 * add opengl replacement for viewer3d
282 *
283 *
284 */
285
286 #ifdef _OPENGL
287
288 #if defined(WIN32) /* braindead windows dependency */
289 #include <windows.h>
290
291 #elif defined(macintosh)
292 #include <agl.h>
293 #include <fonts.h>
294 # if !defined(OS_UNIX_DARWIN)
295 #include "MoreCarbonAccessors.h"
296 #endif
297
298 #elif defined(WIN_MOTIF)
299 #include <GL/glx.h>
300 #include <X11/Xlib.h>
301 #ifdef Status /* avoid name conflict from Xlib */
302 #undef Status
303 #endif
304
305 #endif
306
307 /*
308 * Include the GL dependencies. GL has its own typedef's for basic types, just like the toolkit.
309 * If you get warnings about type mismatch, this should be investigated. The GL typedef's can't
310 * be included in general toolkit code because of the windows.h dependency for WIN32 which
311 * causes all sorts of name collisions.
312 */
313
314 #if defined(macintosh)
315 #include <gl.h>
316 #include <glu.h>
317 #else
318 #include <GL/gl.h>
319 #include <GL/glu.h>
320 #endif
321
322 #ifdef _PNG
323 #include <png.h> /* must go berore ncbi headers */
324 #ifndef png_jmpbuf
325 #define png_jmpbuf(x) ((x)->jmpbuf)
326 #endif
327 #endif
328
329 /* from ncbimisc.h */
330 #include <ncbi.h>
331 NLM_EXTERN void LIBCALL Nlm_HeapSort PROTO((VoidPtr base, size_t nel, size_t width,
332 int (LIBCALLBACK *cmp) (VoidPtr, VoidPtr) ));
333
334 #endif /* _OPENGL */
335
336 #include <math.h>
337 #include <shim3d.h>
338 #include <stdio.h>
339 #include <ddvcolor.h>
340
341 #if defined(_OPENGL) && defined(_PNG)
342 TOGL_Data *Cn3D_GetCurrentOGLData(void); /* in cn3dxprt.c */
343 #endif
344
345
346 /* VRML functions */
347
VRML_ColorToString(Char * pString,DDV_ColorCell * pColor)348 void VRML_ColorToString(Char * pString, DDV_ColorCell * pColor)
349 {
350 sprintf(pString, "%f %f %f", pColor->rgb[0] / 255.0,
351 pColor->rgb[1] / 255.0, pColor->rgb[2] / 255.0);
352 }
353
VRML_AddSphere3D(DDV_ColorCell * pColor,FloatHi x,FloatHi y,FloatHi z,FloatHi radius)354 void VRML_AddSphere3D(DDV_ColorCell * pColor, FloatHi x, FloatHi y,
355 FloatHi z, FloatHi radius)
356 {
357 Char szColor[256];
358
359 printf("Transform {\ntranslation %f %f %f\nchildren [\nShape{\n", x, y,
360 z);
361 printf("appearance Appearance {\nmaterial Material {\n");
362 VRML_ColorToString(szColor, pColor);
363 printf("diffuseColor %s\n}\n}\n", szColor);
364 printf("geometry Sphere {\n radius %f\n}\n", radius);
365 printf("}\n]\n}\n");
366 }
367
VRML_AddCylinder3D(DDV_ColorCell * pColor,Nlm_FloatHi x1,Nlm_FloatHi y1,Nlm_FloatHi z1,Nlm_FloatHi x2,Nlm_FloatHi y2,Nlm_FloatHi z2,Nlm_FloatHi radius)368 void VRML_AddCylinder3D(DDV_ColorCell * pColor,
369 Nlm_FloatHi x1, Nlm_FloatHi y1, Nlm_FloatHi z1,
370 Nlm_FloatHi x2, Nlm_FloatHi y2, Nlm_FloatHi z2,
371 Nlm_FloatHi radius)
372 {
373 Char szColor[256];
374 FloatHi Rotate[16], Translate[3], length, *Cross;
375 FloatHi z[3] = { 0.0, 0.0, 1.0 };
376
377 OGL_CreateCTransform(x1, y1, z1, x2, y2, z2, Rotate, Translate,
378 &length);
379
380 Cross = OGL_CrossProduct(&Rotate[8], z);
381 if (Cross == NULL)
382 return;
383
384 printf("Transform {\nrotation %f %f %f %f", Cross[0], Cross[1],
385 Cross[2], acos(Rotate[10]));
386 printf("\ntranslation %f %f %f\nchildren [\nShape{\n", Translate[0],
387 Translate[1], Translate[2]);
388 printf("appearance Appearance {\nmaterial Material {\n");
389 VRML_ColorToString(szColor, pColor);
390 printf("diffuseColor %s\n}\n}\n", szColor);
391 printf("geometry Cylinder {\n radius %f\nheight %f\ntop FALSE\n}\n",
392 radius, length);
393 printf("}\n]\n}\n");
394
395 MemFree(Cross);
396 }
397
398
399 /* function in common with vrml and opengl */
400
OGL_CrossProduct(Nlm_FloatHi * v1,Nlm_FloatHi * v2)401 FloatHi *OGL_CrossProduct(Nlm_FloatHi * v1, Nlm_FloatHi * v2)
402 {
403 Nlm_FloatHi *RetVal;
404
405 if (v1 == NULL || v2 == NULL)
406 return NULL;
407 RetVal = MemNew(3 * sizeof(Nlm_FloatHi));
408 if (RetVal == NULL)
409 return NULL;
410
411 RetVal[0] = v1[1] * v2[2] - v1[2] * v2[1];
412 RetVal[1] = v1[2] * v2[0] - v1[0] * v2[2];
413 RetVal[2] = v1[0] * v2[1] - v1[1] * v2[0];
414
415 return RetVal;
416 }
417
OGL_CreateCTransform(Nlm_FloatHi x1,Nlm_FloatHi y1,Nlm_FloatHi z1,Nlm_FloatHi x2,Nlm_FloatHi y2,Nlm_FloatHi z2,Nlm_FloatHi * Rotate,Nlm_FloatHi * Translate,Nlm_FloatHi * length)418 void OGL_CreateCTransform(Nlm_FloatHi x1, Nlm_FloatHi y1, Nlm_FloatHi z1,
419 Nlm_FloatHi x2, Nlm_FloatHi y2, Nlm_FloatHi z2,
420 Nlm_FloatHi * Rotate, Nlm_FloatHi * Translate,
421 Nlm_FloatHi * length)
422 {
423 FloatHi a, b, c; /* the normal z */
424 FloatHi yy2, yy3; /* the normal y */
425 FloatHi xx1, xx2, xx3; /* the normal x */
426 Int4 iCount;
427
428 if (Rotate == NULL || Translate == NULL || length == NULL)
429 return;
430
431 Translate[0] = (x1 + x2) / 2;
432 Translate[1] = (y1 + y2) / 2;
433 Translate[2] = (z1 + z2) / 2;
434
435 *length =
436 sqrt(OGL_SQR(x1 - x2) + OGL_SQR(y1 - y2) + OGL_SQR(z1 - z2)) / 2.0;
437
438 for (iCount = 0; iCount < 16; iCount++)
439 Rotate[iCount] = 0.0;
440 Rotate[15] = 1; /* identity */
441
442 /* create the normal z */
443 a = (x1 - Translate[0]) / (*length);
444 b = (y1 - Translate[1]) / (*length);
445 c = (z1 - Translate[2]) / (*length);
446
447 /* create the normal y */
448
449 yy2 = sqrt(1.0 / (1.0 + OGL_SQR(b) / OGL_SQR(c)));
450 yy3 = -(b / c) * yy2;
451
452 /* create the normal x */
453
454 xx2 =
455 sqrt(1.0 /
456 (pow(c, 4.0) / (OGL_SQR(a) * OGL_SQR(b)) +
457 2.0 * OGL_SQR(c) / OGL_SQR(a)
458 + OGL_SQR(b) / OGL_SQR(a) + 1 + OGL_SQR(c) / OGL_SQR(b)));
459 xx3 = xx2 * c / b;
460 xx1 = (-OGL_SQR(c) / (a * b) - b / a) * xx2;
461
462
463 /* now use the normals to make the rotation matrix */
464
465 Rotate[0] = xx1;
466 Rotate[1] = xx2;
467 Rotate[2] = xx3;
468
469 Rotate[4] = 0.0;
470 Rotate[5] = yy2;
471 Rotate[6] = yy3;
472
473 Rotate[8] = a;
474 Rotate[9] = b;
475 Rotate[10] = c;
476 }
477
478
479
480 #ifdef _OPENGL
481
482
483 static Nlm_VoidPtr OGL_CurrentName = NULL;
484
485
486
487 /* define this to do (frequent) checking of GL error status - but this is
488 very expensive, so be sure to turn off for production! */
489 /* #define DEBUG_GL 1 */
490 #if defined(_DEBUG) && !defined(DEBUG_GL)
491 #define DEBUG_GL 1
492 #endif
493
494 /* for now, just print warning if any GL error flag is set */
OGL_CheckForErrors(void)495 static Boolean OGL_CheckForErrors(void)
496 {
497 GLenum errCode;
498 const GLubyte *errString;
499 Boolean hadErrors = FALSE;
500
501 while ((errCode = glGetError()) != GL_NO_ERROR) {
502 errString = gluErrorString(errCode);
503 Message(MSG_POST, "OpenGL error: %s", errString);
504 hadErrors = TRUE;
505 }
506 return hadErrors;
507 }
508
509 /*
510 * Various helper functions used in drawing
511 */
512
513 typedef struct _TOGL_Layers
514 /* this struct contains the information used to manage the different layers of the display */
515 {
516 GLuint FirstLayer;
517 GLuint LastLayer;
518 GLuint SelectedLayer;
519 Nlm_Boolean IsOn[OGLMAXLAYERS];
520 } TOGL_Layers;
521
522
OGL_Normalize(Nlm_FloatHi * v)523 void OGL_Normalize(Nlm_FloatHi * v)
524 /* normalize a vector */
525 {
526 Nlm_FloatHi Length;
527
528 if (v == NULL)
529 return;
530 Length = sqrt(OGL_SQR(v[0]) + OGL_SQR(v[1]) + OGL_SQR(v[2]));
531 v[0] /= Length;
532 v[1] /= Length;
533 v[2] /= Length;
534 }
535
536
OGL_MakeNormal(Nlm_FloatHi * origin,Nlm_FloatHi * v1,Nlm_FloatHi * v2)537 FloatHi *OGL_MakeNormal(Nlm_FloatHi * origin, Nlm_FloatHi * v1,
538 Nlm_FloatHi * v2)
539 /* creates a normal to the given 3 vertices */
540 {
541 Nlm_FloatHi Vector1[3], Vector2[3], *RetValue;
542
543 if (origin == NULL || v1 == NULL || v2 == NULL)
544 return NULL;
545 Vector1[0] = v1[0] - origin[0];
546 Vector1[1] = v1[1] - origin[1];
547 Vector1[2] = v1[2] - origin[2];
548
549 Vector2[0] = v2[0] - origin[0];
550 Vector2[1] = v2[1] - origin[1];
551 Vector2[2] = v2[2] - origin[2];
552
553 RetValue = OGL_CrossProduct(Vector1, Vector2);
554 OGL_Normalize(RetValue);
555 return RetValue;
556 }
557
558
ColorCell2Array(GLfloat * array,DDV_ColorCell * color)559 static void ColorCell2Array(GLfloat * array, DDV_ColorCell * color)
560 /* copies a color cell to a GL array */
561 {
562 if (array == NULL || color == NULL)
563 return;
564 array[0] = (GLfloat) (color->rgb[0] / 255.0);
565 array[1] = (GLfloat) (color->rgb[1] / 255.0);
566 array[2] = (GLfloat) (color->rgb[2] / 255.0);
567 }
568
569
570 /* these are used for both matrial colors and light colors */
571 static const GLfloat Color_Off[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
572 static const GLfloat Color_MostlyOff[4] = { 0.05f, 0.05f, 0.05f, 1.0f };
573 static const GLfloat Color_MostlyOn[4] = { 0.95f, 0.95f, 0.95f, 1.0f };
574 static const GLfloat Color_On[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
575
576 /* cache previous color, to avoid unnecessary calls to glMaterial */
OGL_SetColor(TOGL_Data * OGL_Data,DDV_ColorCell * color,GLenum type,GLfloat alpha)577 void OGL_SetColor(TOGL_Data * OGL_Data, DDV_ColorCell * color, GLenum type,
578 GLfloat alpha)
579 {
580 #ifdef DEBUG_GL
581 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering SetColor");
582 #endif
583
584 if (!OGL_Data) return;
585 if (OGL_Data->IndexMode == FALSE ) {
586 static GLfloat pr, pg, pb, pa;
587 static GLenum pt = GL_NONE;
588 static GLfloat rgb[4];
589
590 if (!color) {
591 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Color_Off);
592 pt = GL_NONE;
593 return;
594 }
595 ColorCell2Array(rgb, color);
596
597 #ifdef _DEBUG
598 if (rgb[0] == 0.0 && rgb[1] == 0.0 && rgb[2] == 0.0)
599 Message(MSG_POST, "Warning: OGL_Setcolor request color (0,0,0)");
600 if (alpha == 0.0)
601 Message(MSG_POST, "Warning: OGL_SetColor request alpha 0.0");
602 #endif
603
604 rgb[3] = alpha;
605 if (rgb[0] != pr || rgb[1] != pg || rgb[2] != pb || rgb[3] != pa || type != pt) {
606 if (type != pt) {
607 if (type == GL_DIFFUSE) {
608 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Color_MostlyOff);
609 } else if (type == GL_AMBIENT) {
610 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Color_Off);
611 } else {
612 printf("don't know how to handle material type %i\n",type);
613 }
614 pt = type;
615 }
616 glMaterialfv(GL_FRONT_AND_BACK, type, rgb);
617 if (type == GL_AMBIENT) {
618 /* this is necessary so that fonts are rendered in correct
619 color in SGI's OpenGL implementation, and maybe others */
620 glColor4f(rgb[0], rgb[1], rgb[2], rgb[3]);
621 }
622 pr = rgb[0];
623 pg = rgb[1];
624 pb = rgb[2];
625 pa = rgb[3];
626 }
627
628 } else { /* color index mode */
629 ValNodePtr PaletteIndex;
630 GLint indx[3];
631 static GLint pi0 = -1, pi1, pi2;
632 static GLint pt;
633
634 if (!color) {
635 pi0 = -1;
636 return;
637 }
638
639 PaletteIndex = OGL_SearchPaletteIndex(OGL_Data->PaletteIndex, color);
640 if (!PaletteIndex) {
641 Message(MSG_POST, "Couldn't find color in PaletteIndex!");
642 return;
643 }
644 if (type == GL_DIFFUSE) {
645 indx[0] = ((TOGL_PaletteIndex *) (PaletteIndex->data.ptrvalue))->Begin;
646 indx[1] = ((TOGL_PaletteIndex *) (PaletteIndex->data.ptrvalue))->End;
647 indx[2] = ((TOGL_PaletteIndex *) (PaletteIndex->data.ptrvalue))->End;
648 } else if (type == GL_AMBIENT) {
649 indx[0] = ((TOGL_PaletteIndex *) (PaletteIndex->data.ptrvalue))->End;
650 indx[1] = ((TOGL_PaletteIndex *) (PaletteIndex->data.ptrvalue))->End;
651 indx[2] = ((TOGL_PaletteIndex *) (PaletteIndex->data.ptrvalue))->End;
652 } else {
653 Message(MSG_POST, "don't know how to handle material type %i\n",type);
654 }
655
656 #ifdef WIN32
657 /* on Windows, need to skip over the first ten static palette colors */
658 indx[0] += 10;
659 indx[1] += 10;
660 indx[2] += 10;
661 #endif
662
663 if (indx[0] != pi0 || indx[1] != pi1 || indx[2] != pi2 || type != pt) {
664 glMaterialiv(GL_FRONT_AND_BACK, GL_COLOR_INDEXES, indx);
665 pi0 = indx[0];
666 pi1 = indx[1];
667 pi2 = indx[2];
668 pt = type;
669 }
670 }
671
672 #ifdef DEBUG_GL
673 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving SetColor");
674 #endif
675 }
676
677 /* only need single once-allocated quadric */
678 static GLUquadricObj *OGL_qobj = NULL;
679
680 /*
681 * Functions used to draw various primitives
682 */
683
OGL_AddQuad3D(TOGL_Data * OGL_Data,DDV_ColorCell * color,Nlm_FloatHi * v1,Nlm_FloatHi * v2,Nlm_FloatHi * v3,Nlm_FloatHi * v4)684 void OGL_AddQuad3D(TOGL_Data * OGL_Data, DDV_ColorCell * color,
685 Nlm_FloatHi * v1, Nlm_FloatHi * v2, Nlm_FloatHi * v3,
686 Nlm_FloatHi * v4)
687 /* draws a quadralateral with the 4 given vertices of form double v1[3] */
688 {
689 Nlm_FloatHi *Normal;
690
691 if (v1 == NULL || v2 == NULL || v3 == NULL || v4 == NULL
692 || OGL_Data == NULL || color == NULL)
693 return;
694
695 OGL_SetColor(OGL_Data, color, GL_DIFFUSE, 1.0);
696
697 /*glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);*/
698
699 glBegin(GL_QUADS);
700 Normal = OGL_MakeNormal(v1, v2, v4);
701 if (Normal != NULL) {
702 glNormal3dv(Normal);
703 MemFree(Normal);
704 }
705 glVertex3dv(v1);
706 glVertex3dv(v2);
707 glVertex3dv(v3);
708 glVertex3dv(v4);
709 glEnd();
710
711 /*glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);*/
712 }
713
OGL_AddBrick3D(TOGL_Data * OGL_Data,DDV_ColorCell * color,Nlm_FloatHi * Nterm,Nlm_FloatHi * Cterm,Nlm_FloatHi * norm,Nlm_FloatHi width,Nlm_FloatHi thickness,Nlm_Boolean doArrow)714 void OGL_AddBrick3D(TOGL_Data * OGL_Data, DDV_ColorCell * color,
715 Nlm_FloatHi * Nterm, Nlm_FloatHi * Cterm,
716 Nlm_FloatHi * norm, Nlm_FloatHi width,
717 Nlm_FloatHi thickness, Nlm_Boolean doArrow)
718 {
719 static const double arrowLen = 2.8, arrowWidthProp = 1.6;
720
721 GLdouble c000[3], c001[3], c010[3], c011[3],
722 c100[3], c101[3], c110[3], c111[3], n[3];
723 Nlm_FloatHi a[3], *h;
724 int i;
725
726 #ifdef DEBUG_GL
727 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering AddBrick");
728 #endif
729
730 if (Nterm == NULL || Cterm == NULL || norm == NULL ||
731 OGL_Data == NULL || color == NULL ||
732 width*thickness == 0.0)
733 return;
734
735 OGL_SetColor(OGL_Data, color, GL_DIFFUSE, 1.0);
736
737 /* in this brick's world coordinates, the long axis (N-C direction) is
738 along +Z, with N terminus at Z=0; width is in the X direction, and
739 thickness in Y. Arrowhead at C-terminus, of course. */
740
741 OGL_Normalize(norm);
742
743 for (i=0; i<3; i++) {
744 a[i] = Cterm[i] - Nterm[i];
745 }
746 OGL_Normalize(a);
747 h = OGL_CrossProduct(norm, a);
748 if (!h) return;
749
750 if (doArrow)
751 for (i=0; i<3; i++)
752 Cterm[i] -= a[i] * arrowLen;
753
754 for (i=0; i<3; i++) {
755 c000[i] = Nterm[i] - h[i]*width/2 - norm[i]*thickness/2;
756 c001[i] = Cterm[i] - h[i]*width/2 - norm[i]*thickness/2;
757 c010[i] = Nterm[i] - h[i]*width/2 + norm[i]*thickness/2;
758 c011[i] = Cterm[i] - h[i]*width/2 + norm[i]*thickness/2;
759 c100[i] = Nterm[i] + h[i]*width/2 - norm[i]*thickness/2;
760 c101[i] = Cterm[i] + h[i]*width/2 - norm[i]*thickness/2;
761 c110[i] = Nterm[i] + h[i]*width/2 + norm[i]*thickness/2;
762 c111[i] = Cterm[i] + h[i]*width/2 + norm[i]*thickness/2;
763 }
764
765 glBegin(GL_QUADS);
766
767 for (i=0; i<3; i++) n[i] = norm[i];
768 glNormal3dv(n);
769 glVertex3dv(c010);
770 glVertex3dv(c011);
771 glVertex3dv(c111);
772 glVertex3dv(c110);
773
774 for (i=0; i<3; i++) n[i] = -norm[i];
775 glNormal3dv(n);
776 glVertex3dv(c000);
777 glVertex3dv(c100);
778 glVertex3dv(c101);
779 glVertex3dv(c001);
780
781 for (i=0; i<3; i++) n[i] = h[i];
782 glNormal3dv(n);
783 glVertex3dv(c100);
784 glVertex3dv(c110);
785 glVertex3dv(c111);
786 glVertex3dv(c101);
787
788 for (i=0; i<3; i++) n[i] = -h[i];
789 glNormal3dv(n);
790 glVertex3dv(c000);
791 glVertex3dv(c001);
792 glVertex3dv(c011);
793 glVertex3dv(c010);
794
795 for (i=0; i<3; i++) n[i] = -a[i];
796 glNormal3dv(n);
797 glVertex3dv(c000);
798 glVertex3dv(c010);
799 glVertex3dv(c110);
800 glVertex3dv(c100);
801
802 if (!doArrow) {
803 for (i=0; i<3; i++) n[i] = a[i];
804 glNormal3dv(n);
805 glVertex3dv(c001);
806 glVertex3dv(c101);
807 glVertex3dv(c111);
808 glVertex3dv(c011);
809
810 } else {
811 GLdouble FT[3], LT[3], RT[3], FB[3], LB[3], RB[3];
812 Nlm_FloatHi *nL, *nR;
813
814 for (i=0; i<3; i++) {
815 FT[i] = Cterm[i] + norm[i]*thickness/2 + a[i]*arrowLen;
816 LT[i] = Cterm[i] + norm[i]*thickness/2 + h[i]*arrowWidthProp*width/2;
817 RT[i] = Cterm[i] + norm[i]*thickness/2 - h[i]*arrowWidthProp*width/2;
818 FB[i] = Cterm[i] - norm[i]*thickness/2 + a[i]*arrowLen;
819 LB[i] = Cterm[i] - norm[i]*thickness/2 + h[i]*arrowWidthProp*width/2;
820 RB[i] = Cterm[i] - norm[i]*thickness/2 - h[i]*arrowWidthProp*width/2;
821 }
822
823 for (i=0; i<3; i++) n[i] = -a[i];
824 glNormal3dv(n);
825 glVertex3dv(c111);
826 glVertex3dv(LT);
827 glVertex3dv(LB);
828 glVertex3dv(c101);
829
830 glVertex3dv(c011);
831 glVertex3dv(c001);
832 glVertex3dv(RB);
833 glVertex3dv(RT);
834
835 for (i=0; i<3; i++) h[i] = FT[i] - LT[i];
836 if (!(nL = OGL_CrossProduct(norm, h))) return;
837 OGL_Normalize(nL);
838 for (i=0; i<3; i++) n[i] = nL[i];
839 glNormal3dv(n);
840 glVertex3dv(FT);
841 glVertex3dv(FB);
842 glVertex3dv(LB);
843 glVertex3dv(LT);
844 MemFree(nL);
845
846 for (i=0; i<3; i++) h[i] = FT[i] - RT[i];
847 if (!(nR = OGL_CrossProduct(h, norm))) return;
848 OGL_Normalize(nR);
849 for (i=0; i<3; i++) n[i] = nR[i];
850 glNormal3dv(n);
851 glVertex3dv(FT);
852 glVertex3dv(RT);
853 glVertex3dv(RB);
854 glVertex3dv(FB);
855 MemFree(nR);
856
857 glEnd();
858 glBegin(GL_TRIANGLES);
859
860 for (i=0; i<3; i++) n[i] = norm[i];
861 glNormal3dv(n);
862 glVertex3dv(FT);
863 glVertex3dv(LT);
864 glVertex3dv(RT);
865
866 for (i=0; i<3; i++) n[i] = -norm[i];
867 glNormal3dv(n);
868 glVertex3dv(FB);
869 glVertex3dv(RB);
870 glVertex3dv(LB);
871 }
872
873 glEnd();
874
875 MemFree(h);
876
877 #ifdef DEBUG_GL
878 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving AddBrick");
879 #endif
880 }
881
OGL_AddTri3D(TOGL_Data * OGL_Data,DDV_ColorCell * color,Nlm_FloatHi * v1,Nlm_FloatHi * v2,Nlm_FloatHi * v3,Nlm_FloatHi * Normal)882 void OGL_AddTri3D(TOGL_Data * OGL_Data, DDV_ColorCell * color,
883 Nlm_FloatHi * v1, Nlm_FloatHi * v2, Nlm_FloatHi * v3,
884 Nlm_FloatHi * Normal)
885 /* draws a triangle given 3 vertices of form double v1[3] and the normal */
886 {
887 if (v1 == NULL || v2 == NULL || v3 == NULL || OGL_Data == NULL ||
888 color == NULL)
889 return;
890
891 OGL_SetColor(OGL_Data, color, GL_DIFFUSE, 1.0);
892
893 /*glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);*/
894
895 glBegin(GL_TRIANGLES);
896 if (Normal != NULL)
897 glNormal3dv(Normal);
898 glVertex3dv(v1);
899 glVertex3dv(v2);
900 glVertex3dv(v3);
901 glEnd();
902
903 /*glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);*/
904 }
905
906
OGL_AddCylinder3D(TOGL_Data * OGL_Data,DDV_ColorCell * color,Nlm_FloatHi x1,Nlm_FloatHi y1,Nlm_FloatHi z1,Nlm_Boolean cap1,Nlm_FloatHi x2,Nlm_FloatHi y2,Nlm_FloatHi z2,Nlm_Boolean cap2,Nlm_FloatHi radius,Nlm_Int4 sides,Nlm_Boolean doArrow)907 void OGL_AddCylinder3D(TOGL_Data * OGL_Data, DDV_ColorCell * color,
908 Nlm_FloatHi x1, Nlm_FloatHi y1, Nlm_FloatHi z1, Nlm_Boolean cap1,
909 Nlm_FloatHi x2, Nlm_FloatHi y2, Nlm_FloatHi z2, Nlm_Boolean cap2,
910 Nlm_FloatHi radius, Nlm_Int4 sides, Nlm_Boolean doArrow)
911 /* create a cylinder with given endcaps and radius */
912 {
913 static const double arrowLen = 4.0,
914 arrowWidthPropBase = 1.2, arrowWidthPropTip = 0.4;
915
916 Nlm_Int4 iCount;
917 GLdouble length;
918
919 #ifdef DEBUG_GL
920 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering AddCylinder");
921 #endif
922
923 if (OGL_Data == NULL || color == NULL)
924 return;
925
926 OGL_SetColor(OGL_Data, color, GL_DIFFUSE, 1.0);
927
928 glPushMatrix();
929
930 length = sqrt(
931 (x2 - x1) * (x2 - x1) +
932 (y2 - y1) * (y2 - y1) +
933 (z2 - z1) * (z2 - z1)
934 );
935 if (length < 0.000001) return;
936
937 /* to translate into place */
938 glTranslated(x1, y1, z1);
939
940 /* to rotate from initial position, so bond points right direction;
941 handle special case where both ends share ~same x,y */
942 #define DEGREES(rad) ((rad)*180.0/3.14159265358979323846)
943 if (fabs(y1 - y2) < 0.000001 &&
944 fabs(x2 - x1) < 0.000001) {
945 if (z2 - z1 < 0.0) glRotated(180.0,1.0,0.0,0.0);
946 } else {
947 glRotated(DEGREES(acos((z2 - z1) / length)),
948 y1 - y2, x2 - x1, 0.0);
949 }
950
951 if (doArrow) length -= arrowLen;
952 gluCylinder(OGL_qobj, radius, radius, length, sides, 1);
953
954 if (cap1) {
955 glPushMatrix();
956 glRotated(180.0, 0.0, 1.0, 0.0);
957 gluDisk(OGL_qobj, 0.0, radius, sides, 1);
958 glPopMatrix();
959 }
960 if (doArrow) {
961 glPushMatrix();
962 glTranslated(0.0, 0.0, length);
963 if (arrowWidthPropBase > 1.0) {
964 glPushMatrix();
965 glRotated(180.0, 0.0, 1.0, 0.0);
966 gluDisk(OGL_qobj, 0.0, radius*arrowWidthPropBase, sides, 1);
967 glPopMatrix();
968 }
969 gluCylinder(OGL_qobj, radius*arrowWidthPropBase,
970 radius*arrowWidthPropTip, arrowLen, sides, 10);
971 if (arrowWidthPropTip > 0.0) {
972 glTranslated(0.0, 0.0, arrowLen);
973 gluDisk(OGL_qobj, 0.0, radius*arrowWidthPropTip, sides, 1);
974 }
975 glPopMatrix();
976 } else if (cap2) {
977 glPushMatrix();
978 glTranslated(0.0, 0.0, length);
979 gluDisk(OGL_qobj, 0.0, radius, sides, 1);
980 glPopMatrix();
981 }
982
983 glPopMatrix();
984
985 #ifdef DEBUG_GL
986 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving AddCylinder");
987 #endif
988 }
989
990
OGL_AddLine3D(TOGL_Data * OGL_Data,DDV_ColorCell * color,Nlm_FloatHi x1,Nlm_FloatHi y1,Nlm_FloatHi z1,Nlm_FloatHi x2,Nlm_FloatHi y2,Nlm_FloatHi z2)991 void OGL_AddLine3D(TOGL_Data * OGL_Data, DDV_ColorCell * color,
992 Nlm_FloatHi x1, Nlm_FloatHi y1, Nlm_FloatHi z1,
993 Nlm_FloatHi x2, Nlm_FloatHi y2, Nlm_FloatHi z2)
994 /* draw a single line */
995 {
996 #ifdef DEBUG_GL
997 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering AddLine");
998 #endif
999
1000 if (OGL_Data == NULL || color == NULL)
1001 return;
1002
1003 OGL_SetColor(OGL_Data, color, GL_AMBIENT, 1.0);
1004
1005 glBegin(GL_LINES);
1006 glVertex3d(x1, y1, z1);
1007 glVertex3d(x2, y2, z2);
1008 glEnd();
1009
1010 #ifdef DEBUG_GL
1011 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving AddLine");
1012 #endif
1013 }
1014
1015
1016 typedef struct _TransparentSphereData {
1017 DDV_ColorCell color;
1018 Nlm_FloatHi x, y, z, radius, alpha, distFromCamera;
1019 Nlm_Int4 slices, stacks;
1020 Nlm_Int1 layer;
1021 Nlm_VoidPtr name;
1022 ValNodePtr transforms;
1023 struct _TransparentSphereData *next;
1024 } TransparentSphereData, PNTR TransparentSphereDataPtr;
1025
1026 static TransparentSphereDataPtr OGL_transSpheresTail = NULL,
1027 OGL_transSpheresHead = NULL,
1028 *OGL_transSpheresList = NULL;
1029
OGL_DistCompareFunc(Nlm_VoidPtr va,Nlm_VoidPtr vb)1030 int LIBCALLBACK OGL_DistCompareFunc(Nlm_VoidPtr va, Nlm_VoidPtr vb)
1031 {
1032 TransparentSphereDataPtr a = *((TransparentSphereDataPtr *) va),
1033 b = *((TransparentSphereDataPtr *) vb);
1034
1035 if (a->distFromCamera > b->distFromCamera) return -1;
1036 else if (a->distFromCamera < b->distFromCamera) return 1;
1037 else return 0;
1038 }
1039
1040 Nlm_Boolean OGL_GetLayer(TOGL_Data *, Nlm_Int4);
1041
OGL_RenderTransparentSpheres(TOGL_Data * OGL_Data)1042 static void OGL_RenderTransparentSpheres(TOGL_Data *OGL_Data)
1043 {
1044 #ifdef DEBUG_GL
1045 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering OGL_RenderTransparentSpheres");
1046 #endif
1047
1048 if (OGL_Data && OGL_transSpheresHead) {
1049 TransparentSphereDataPtr sph;
1050 int i, n, iList;
1051 GLdouble m[16];
1052 Nlm_FloatHi x, y, z;
1053 Nlm_Boolean show;
1054
1055 /* make an array of pointers to sphere data; sort by distance from camera */
1056 for (n=0, sph=OGL_transSpheresHead; sph; n++, sph = sph->next) {
1057
1058 /* transform model's xyz into GL-frame coordinates */
1059 OGL_PushTransformation(sph->transforms);
1060 glGetDoublev(GL_MODELVIEW_MATRIX, m);
1061 OGL_PopTransformation();
1062
1063 x = m[0]*sph->x + m[4]*sph->y + m[8]*sph->z + m[12];
1064 y = m[1]*sph->x + m[5]*sph->y + m[9]*sph->z + m[13];
1065 z = m[2]*sph->x + m[6]*sph->y + m[10]*sph->z + m[14];
1066 sph->distFromCamera =
1067 sqrt((x * x) + (y * y) +
1068 ((z - OGL_Data->CameraDistance) *
1069 (z - OGL_Data->CameraDistance)))
1070 - sph->radius;
1071 }
1072
1073 if (!OGL_transSpheresList) {
1074 OGL_transSpheresList = (TransparentSphereDataPtr *)
1075 MemNew(n * sizeof(TransparentSphereDataPtr));
1076 if (!OGL_transSpheresList) return;
1077 for (n=0, sph=OGL_transSpheresHead; sph; n++, sph=sph->next)
1078 OGL_transSpheresList[n] = sph;
1079 }
1080 Nlm_HeapSort((Nlm_VoidPtr) OGL_transSpheresList, n,
1081 sizeof(TransparentSphereDataPtr), OGL_DistCompareFunc);
1082
1083 /* turn on blending */
1084 glEnable(GL_BLEND);
1085 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1086
1087 /* render the spheres in order, and only for turned-on layers */
1088 for (i = 0; i < n; i++) {
1089 show = FALSE;
1090 if (OGL_Data->Layers->SelectedLayer) {
1091 if (OGL_Data->Layers->SelectedLayer - OGL_Data->Layers->FirstLayer ==
1092 OGL_transSpheresList[i]->layer) {
1093 show = TRUE;
1094 }
1095 } else {
1096 for (iList = OGL_Data->Layers->FirstLayer;
1097 iList <= OGL_Data->Layers->LastLayer;
1098 iList++) {
1099 if (iList - OGL_Data->Layers->FirstLayer == OGL_transSpheresList[i]->layer &&
1100 OGL_GetLayer(OGL_Data, iList - OGL_Data->Layers->FirstLayer)) {
1101 show = TRUE;
1102 break;
1103 }
1104 }
1105 }
1106 if (show) {
1107 OGL_LoadName(OGL_transSpheresList[i]->name);
1108 OGL_SetColor(OGL_Data, &(OGL_transSpheresList[i]->color),
1109 GL_DIFFUSE, OGL_transSpheresList[i]->alpha);
1110 OGL_PushTransformation(OGL_transSpheresList[i]->transforms);
1111 glTranslated(OGL_transSpheresList[i]->x, OGL_transSpheresList[i]->y,
1112 OGL_transSpheresList[i]->z);
1113 gluSphere(OGL_qobj, OGL_transSpheresList[i]->radius,
1114 OGL_transSpheresList[i]->slices, OGL_transSpheresList[i]->stacks);
1115 OGL_PopTransformation();
1116 }
1117 }
1118
1119 /* blending back off now */
1120 glDisable(GL_BLEND);
1121 }
1122
1123 #ifdef DEBUG_GL
1124 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving OGL_RenderTransparentSpheres");
1125 #endif
1126 }
1127
1128 static Nlm_Int1 OGL_currentLayer;
1129
OGL_AddTransparentSphere(DDV_ColorCell * color,Nlm_FloatHi x,Nlm_FloatHi y,Nlm_FloatHi z,Nlm_FloatHi radius,Nlm_Int4 slices,Nlm_Int4 stacks,Nlm_FloatHi alpha,Nlm_VoidPtr name,ValNodePtr transforms)1130 static void OGL_AddTransparentSphere(DDV_ColorCell * color,
1131 Nlm_FloatHi x, Nlm_FloatHi y, Nlm_FloatHi z,
1132 Nlm_FloatHi radius, Nlm_Int4 slices, Nlm_Int4 stacks,
1133 Nlm_FloatHi alpha, Nlm_VoidPtr name, ValNodePtr transforms)
1134 {
1135 TransparentSphereDataPtr newSphere = (TransparentSphereDataPtr)
1136 MemNew(sizeof(TransparentSphereData));
1137 if (newSphere) {
1138 DDV_CopyColorCell(&(newSphere->color), color);
1139 newSphere->x = x;
1140 newSphere->y = y;
1141 newSphere->z = z;
1142 newSphere->transforms = transforms;
1143 newSphere->radius = radius;
1144 newSphere->slices = slices;
1145 newSphere->stacks = stacks;
1146 newSphere->alpha = alpha;
1147 newSphere->layer = OGL_currentLayer;
1148 newSphere->name = name;
1149 newSphere->next = NULL;
1150 if (OGL_transSpheresTail)
1151 OGL_transSpheresTail = OGL_transSpheresTail->next = newSphere;
1152 else
1153 OGL_transSpheresTail = OGL_transSpheresHead = newSphere;
1154 }
1155 }
1156
OGL_ClearTransparentSpheres(void)1157 void OGL_ClearTransparentSpheres(void)
1158 {
1159 TransparentSphereDataPtr sph = OGL_transSpheresHead, tmp;
1160
1161 while (sph) {
1162 tmp = sph->next;
1163 MemFree(sph);
1164 sph = tmp;
1165 }
1166 OGL_transSpheresHead = OGL_transSpheresTail = NULL;
1167 if (OGL_transSpheresList) {
1168 MemFree(OGL_transSpheresList);
1169 OGL_transSpheresList = NULL;
1170 }
1171 }
1172
1173
OGL_AddSphere3D(TOGL_Data * OGL_Data,DDV_ColorCell * color,Nlm_FloatHi x,Nlm_FloatHi y,Nlm_FloatHi z,Nlm_FloatHi radius,Nlm_Int4 slices,Nlm_Int4 stacks,Nlm_FloatHi alpha,ValNodePtr transforms)1174 void OGL_AddSphere3D(TOGL_Data * OGL_Data, DDV_ColorCell * color,
1175 Nlm_FloatHi x, Nlm_FloatHi y, Nlm_FloatHi z,
1176 Nlm_FloatHi radius, Nlm_Int4 slices, Nlm_Int4 stacks,
1177 Nlm_FloatHi alpha, ValNodePtr transforms)
1178 /* draws a sphere */
1179 {
1180 #ifdef DEBUG_GL
1181 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering AddSphere");
1182 #endif
1183
1184 if (OGL_Data == NULL || color == NULL)
1185 return;
1186
1187 if(!OGL_Data->IndexMode && alpha < 1.0) /* no transparency in index mode */
1188 OGL_AddTransparentSphere(color, x, y, z, radius, slices, stacks,
1189 alpha, OGL_CurrentName, transforms);
1190 else {
1191 OGL_SetColor(OGL_Data, color, GL_DIFFUSE, 1.0);
1192 glPushMatrix();
1193 glTranslated(x, y, z);
1194 gluSphere(OGL_qobj, radius, slices, stacks);
1195 glPopMatrix();
1196 }
1197
1198 #ifdef DEBUG_GL
1199 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving AddSphere");
1200 #endif
1201 }
1202
1203
OGL_AddText3D(TOGL_Data * OGL_Data,DDV_ColorCell * color,Nlm_CharPtr string,Nlm_FloatHi x,Nlm_FloatHi y,Nlm_FloatHi z,Nlm_Int2 flags)1204 void OGL_AddText3D(TOGL_Data * OGL_Data, DDV_ColorCell * color,
1205 Nlm_CharPtr string, Nlm_FloatHi x, Nlm_FloatHi y,
1206 Nlm_FloatHi z, Nlm_Int2 flags)
1207 {
1208 Nlm_Int4 Length, i;
1209
1210 if (OGL_Data == NULL || color == NULL || string == NULL)
1211 return;
1212
1213 OGL_SetColor(OGL_Data, color, GL_AMBIENT, 1.0);
1214
1215 glListBase(OGLFONTBASE);
1216
1217 Length = Nlm_StrLen(string);
1218 glRasterPos3d(x, y, z);
1219 if (flags & OGLTEXT3D_CENTER) {
1220 glBitmap(0, 0, 0.0, 0.0,
1221 (GLfloat) -0.5 * Length * OGL_Data->SpaceWidth, 0.0,
1222 NULL);
1223 }
1224 if (flags & OGLTEXT3D_MIDDLE)
1225 glBitmap(0, 0, 0.0, 0.0,
1226 0.0f, (GLfloat) (-0.5 * OGL_Data->SpaceHeight),
1227 NULL);
1228
1229 glCallLists(Length, GL_UNSIGNED_BYTE, string);
1230
1231 glListBase(0);
1232 }
1233
1234
OGL_PushTransformation(ValNodePtr transforms)1235 void OGL_PushTransformation(ValNodePtr transforms)
1236 {
1237 FloatLoPtr pflv;
1238 FloatLoPtr *ppflm;
1239 GLfloat xmat[16];
1240
1241 glPushMatrix();
1242
1243 while (transforms) {
1244 if (transforms->choice == 2) { /* Move_translate */
1245 pflv = (FloatLoPtr) transforms->data.ptrvalue;
1246 glTranslatef(pflv[0], pflv[1], pflv[2]);
1247
1248 } else if (transforms->choice == 1) { /* Move_rotate */
1249 ppflm = (FloatLoPtr *) transforms->data.ptrvalue;
1250 xmat[0]=ppflm[0][0]; xmat[4]=ppflm[1][0]; xmat[8]= ppflm[2][0]; xmat[12]=0;
1251 xmat[1]=ppflm[0][1]; xmat[5]=ppflm[1][1]; xmat[9]= ppflm[2][1]; xmat[13]=0;
1252 xmat[2]=ppflm[0][2]; xmat[6]=ppflm[1][2]; xmat[10]=ppflm[2][2]; xmat[14]=0;
1253 xmat[3]=0; xmat[7]=0; xmat[11]=0; xmat[15]=1;
1254 glMultMatrixf(xmat);
1255 }
1256
1257 transforms = transforms->next;
1258 }
1259 }
1260
OGL_PopTransformation(void)1261 void OGL_PopTransformation(void)
1262 {
1263 glPopMatrix();
1264 }
1265
1266 /*
1267 * Functions used to manage display lists
1268 */
1269
OGL_Start(TOGL_Data * OGL_Data,Nlm_Int1 List)1270 void OGL_Start(TOGL_Data * OGL_Data, Nlm_Int1 List)
1271 {
1272 #ifdef DEBUG_GL
1273 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering OGL_Start");
1274 #endif
1275
1276 if (OGL_Data == NULL)
1277 return;
1278
1279 /* begin a display list */
1280 if (List >= OGLMAXLAYERS)
1281 return;
1282 glNewList(List + OGL_Data->Layers->FirstLayer, GL_COMPILE);
1283 OGL_SetLayer(OGL_Data, List, TRUE);
1284 OGL_currentLayer = List;
1285
1286 /* clear all color states */
1287 OGL_SetColor(OGL_Data, NULL, GL_NONE, 1.0);
1288
1289 #ifdef DEBUG_GL
1290 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving OGL_Start");
1291 #endif
1292 }
1293
OGL_End()1294 void OGL_End()
1295 /* end a display list */
1296 {
1297 #ifdef DEBUG_GL
1298 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering OGL_End");
1299 #endif
1300 glEndList();
1301 #ifdef DEBUG_GL
1302 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving OGL_End");
1303 #endif
1304 }
1305
1306
OGL_SetLayers(TOGL_Data * OGL_Data,Nlm_Boolean Status)1307 void OGL_SetLayers(TOGL_Data * OGL_Data, Nlm_Boolean Status)
1308 /* set the status of all the layers */
1309 {
1310 Nlm_Int4 i;
1311
1312 if (OGL_Data == NULL)
1313 return;
1314 for (i = 0; i < OGLMAXLAYERS; i++)
1315 OGL_Data->Layers->IsOn[i] = Status;
1316 return;
1317 }
1318
OGL_SetLayer(TOGL_Data * OGL_Data,Nlm_Int4 i,Nlm_Boolean Status)1319 void OGL_SetLayer(TOGL_Data * OGL_Data, Nlm_Int4 i, Nlm_Boolean Status)
1320 /* set the status of a particular layer -- is it on or off? */
1321 {
1322 if (OGL_Data == NULL)
1323 return;
1324 OGL_Data->Layers->IsOn[i] = Status;
1325 return;
1326 }
1327
OGL_GetLayer(TOGL_Data * OGL_Data,Nlm_Int4 i)1328 Nlm_Boolean OGL_GetLayer(TOGL_Data * OGL_Data, Nlm_Int4 i)
1329 /* return layer status */
1330 {
1331 if (OGL_Data == NULL)
1332 return FALSE;
1333 return OGL_Data->Layers->IsOn[i];
1334 }
1335
1336
OGL_SetLayerTop3D(TOGL_Data * OGL_Data,Nlm_Int4 TopLayer)1337 void OGL_SetLayerTop3D(TOGL_Data * OGL_Data, Nlm_Int4 TopLayer)
1338 /* set the highest value layer used */
1339 {
1340 if (OGL_Data == NULL)
1341 return;
1342 OGL_Data->Layers->LastLayer = TopLayer + OGL_Data->Layers->FirstLayer;
1343 return;
1344 }
1345
OGL_AllLayerOnProc(TOGL_Data * OGL_Data)1346 void OGL_AllLayerOnProc(TOGL_Data * OGL_Data)
1347 /* turn on all used layers */
1348 {
1349 if (OGL_Data == NULL)
1350 return;
1351 OGL_Data->Layers->SelectedLayer = 0;
1352 OGL_SetLayers(OGL_Data, TRUE);
1353 return;
1354 }
1355
OGL_RewindLayerProc(TOGL_Data * OGL_Data)1356 void OGL_RewindLayerProc(TOGL_Data * OGL_Data)
1357 /* rewind to the first layer */
1358 {
1359 if (OGL_Data == NULL)
1360 return;
1361 OGL_Data->Layers->SelectedLayer = OGL_Data->Layers->FirstLayer;
1362 return;
1363 }
1364
1365
OGL_PrevLayerProc(TOGL_Data * OGL_Data)1366 void OGL_PrevLayerProc(TOGL_Data * OGL_Data)
1367 /* go back to the previous layer */
1368 {
1369 if (OGL_Data == NULL)
1370 return;
1371 if (OGL_Data->Layers->SelectedLayer) {
1372 if (OGL_Data->Layers->SelectedLayer > OGL_Data->Layers->FirstLayer)
1373 OGL_Data->Layers->SelectedLayer--;
1374 else
1375 OGL_Data->Layers->SelectedLayer = OGL_Data->Layers->LastLayer;
1376 } else
1377 OGL_Data->Layers->SelectedLayer = OGL_Data->Layers->FirstLayer;
1378
1379 return;
1380 }
1381
1382
OGL_NextLayerProc(TOGL_Data * OGL_Data)1383 void OGL_NextLayerProc(TOGL_Data * OGL_Data)
1384 /* go to the next layer */
1385 {
1386 if (OGL_Data == NULL)
1387 return;
1388 if (OGL_Data->Layers->SelectedLayer) {
1389 if (OGL_Data->Layers->SelectedLayer < OGL_Data->Layers->LastLayer)
1390 OGL_Data->Layers->SelectedLayer++;
1391 else
1392 OGL_Data->Layers->SelectedLayer = OGL_Data->Layers->FirstLayer;
1393 } else
1394 OGL_Data->Layers->SelectedLayer = OGL_Data->Layers->FirstLayer;
1395
1396 return;
1397 }
1398
1399
OGL_Play(TOGL_Data * OGL_Data)1400 void OGL_Play(TOGL_Data * OGL_Data)
1401 /* used to flip through layers in endless loop */
1402 {
1403 if (OGL_Data == NULL)
1404 return;
1405 if (OGL_Data->Layers->SelectedLayer) {
1406 if (OGL_Data->Layers->SelectedLayer < OGL_Data->Layers->LastLayer)
1407 OGL_Data->Layers->SelectedLayer++;
1408 else
1409 OGL_Data->Layers->SelectedLayer = OGL_Data->Layers->FirstLayer;
1410 } else
1411 OGL_Data->Layers->SelectedLayer = OGL_Data->Layers->FirstLayer;
1412
1413 return;
1414 }
1415
1416
1417 /*
1418 * Color manipulation functions
1419 */
1420
1421
OGL_SearchPaletteIndex(ValNodePtr PaletteIndex,DDV_ColorCell * pColorCell)1422 ValNodePtr OGL_SearchPaletteIndex(ValNodePtr PaletteIndex,
1423 DDV_ColorCell * pColorCell)
1424 {
1425 if (PaletteIndex == NULL || pColorCell == NULL)
1426 return NULL;
1427 for (; PaletteIndex; PaletteIndex = PaletteIndex->next)
1428 if (((TOGL_PaletteIndex *) (PaletteIndex->data.ptrvalue))->
1429 ColorCell.rgb[0] == pColorCell->rgb[0]
1430 && ((TOGL_PaletteIndex *) (PaletteIndex->data.ptrvalue))->
1431 ColorCell.rgb[1] == pColorCell->rgb[1]
1432 && ((TOGL_PaletteIndex *) (PaletteIndex->data.ptrvalue))->
1433 ColorCell.rgb[2] == pColorCell->rgb[2]) {
1434 return PaletteIndex;
1435 }
1436 return NULL;
1437 }
1438
1439
1440 /*
1441 * The mouse and rotation/translation/zoom code
1442 */
1443
MAToOGL(MAPtr ma)1444 static TOGL_Data *MAToOGL(MAPtr ma)
1445 /* extracts OGL_Data out of the extra pointer in the mouse data */
1446 {
1447 return (TOGL_Data *) MA_GetExtra(ma);
1448 }
1449
1450
PanelToOGL(Nlm_PaneL panel)1451 static TOGL_Data *PanelToOGL(Nlm_PaneL panel)
1452 /* extract OGL_Data out of the panel data */
1453 {
1454 MAPtr ma;
1455 Nlm_GetPanelExtra(panel, &ma);
1456
1457 return MAToOGL(ma);
1458 }
1459
1460
OGL_DrawViewer3D_CB(Nlm_PaneL panel)1461 static void OGL_DrawViewer3D_CB(Nlm_PaneL panel)
1462 /* callback */
1463 {
1464 OGL_DrawViewer3D(PanelToOGL(panel));
1465 }
1466
1467
1468 /*
1469 * Move
1470 */
OGL_Move3D(TOGL_Data * OGL_Data,Nlm_Int2 dx,Nlm_Int2 dy)1471 static void OGL_Move3D(TOGL_Data * OGL_Data, Nlm_Int2 dx, Nlm_Int2 dy)
1472 {
1473 GLint viewport[4];
1474 Nlm_FloatHi pixelSize;
1475
1476 glGetIntegerv(GL_VIEWPORT, viewport);
1477
1478 pixelSize =
1479 tan(OGL_Data->CameraAngle / 2.0) *
1480 2.0 * OGL_Data->CameraDistance /
1481 viewport[3];
1482
1483 OGL_Data->CameraDirection[0] -= dx * pixelSize;
1484 OGL_Data->CameraDirection[1] += dy * pixelSize;
1485
1486 OGL_Data->NeedCameraSetup = TRUE;
1487 }
1488
1489
1490 /*
1491 * Zoom
1492 */
1493 extern void Nlm_GetRect (Nlm_GraphiC a, Nlm_RectPtr r);
1494
OGL_Zoom3D(TOGL_Data * OGL_Data,Nlm_Int2 x1,Nlm_Int2 y1,Nlm_Int2 x2,Nlm_Int2 y2)1495 static void OGL_Zoom3D(TOGL_Data * OGL_Data, Nlm_Int2 x1, Nlm_Int2 y1,
1496 Nlm_Int2 x2, Nlm_Int2 y2)
1497 {
1498 Nlm_FloatHi zoom;
1499 Nlm_RecT rect;
1500 GLint viewport[4];
1501
1502 /* translate window coords as passed to this function into coords
1503 relative to OpenGL area (the Panel) coords */
1504 Nlm_GetRect((Nlm_GraphiC)OGL_Data->Panel, &rect);
1505 x1 -= rect.left;
1506 x2 -= rect.left;
1507 y1 -= rect.top;
1508 y2 -= rect.top;
1509
1510 /* set new camera direction ... */
1511 glGetIntegerv(GL_VIEWPORT, viewport);
1512 OGL_Move3D(OGL_Data,
1513 (viewport[2] - (x1 + x2)) / 2,
1514 (viewport[3] - (y1 + y2)) / 2);
1515
1516 /* ... and angle. (This assumes zoom box aspect ratio is correct!) */
1517 zoom = ((Nlm_FloatHi) abs(y1 - y2)) / viewport[3];
1518 OGL_Data->CameraAngle = atan(zoom * tan(OGL_Data->CameraAngle));
1519
1520 OGL_Data->NeedCameraSetup = TRUE;
1521 }
1522
OGL_ZoomOut(TOGL_Data * OGL_Data)1523 NLM_EXTERN void OGL_ZoomOut(TOGL_Data *OGL_Data)
1524 {
1525 OGL_Data->CameraAngle *= 1.5;
1526 OGL_Data->NeedCameraSetup = TRUE;
1527 OGL_DrawViewer3D(OGL_Data);
1528 }
1529
OGL_ZoomIn(TOGL_Data * OGL_Data)1530 NLM_EXTERN void OGL_ZoomIn(TOGL_Data *OGL_Data)
1531 {
1532 OGL_Data->CameraAngle /= 1.5;
1533 OGL_Data->NeedCameraSetup = TRUE;
1534 OGL_DrawViewer3D(OGL_Data);
1535 }
1536
1537 /*
1538 * Rotation
1539 */
1540
1541
1542 typedef enum {
1543 ROTATE_X,
1544 ROTATE_Y,
1545 ROTATE_Z
1546 } OGL_enumRotate3D;
1547
1548 typedef struct {
1549 OGL_enumRotate3D H; /* horizontal dragging */
1550 OGL_enumRotate3D V; /* vertical dragging */
1551 } OGL_RotatePivots3D, *OGL_RotatePivots3DPtr;
1552
1553
OGL_Rotate(TOGL_Data * OGL_Data,Nlm_Int4 dAngle,OGL_enumRotate3D pivot)1554 static void OGL_Rotate(TOGL_Data * OGL_Data, Nlm_Int4 dAngle,
1555 OGL_enumRotate3D pivot)
1556 {
1557 #ifdef DEBUG_GL
1558 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering OGL_Rotate");
1559 #endif
1560
1561 if (!dAngle)
1562 return;
1563 if (OGL_Data == NULL)
1564 return;
1565
1566 glLoadIdentity();
1567
1568 switch (pivot) {
1569 case ROTATE_X:
1570 glRotatef((GLfloat) (dAngle), 1.0f, 0.0f, 0.0f);
1571 break;
1572 case ROTATE_Y:
1573 glRotatef((GLfloat) (dAngle), 0.0f, 1.0f, 0.0f);
1574 break;
1575 case ROTATE_Z:
1576 glRotatef((GLfloat) (dAngle), 0.0f, 0.0f, 1.0f);
1577 break;
1578 }
1579
1580 glMultMatrixd((GLdouble *) OGL_Data->ModelMatrix);
1581
1582 glGetDoublev(GL_MODELVIEW_MATRIX, (GLdouble *) OGL_Data->ModelMatrix);
1583
1584 #ifdef DEBUG_GL
1585 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving OGL_Rotate");
1586 #endif
1587 }
1588
1589
1590
OGL_ViewerRotate(Nlm_SlatE panel,Nlm_Int4 delta,OGL_enumRotate3D pivot,Nlm_Boolean adjust_scrollbar,Nlm_Boolean redraw)1591 static void OGL_ViewerRotate(Nlm_SlatE panel, Nlm_Int4 delta,
1592 OGL_enumRotate3D pivot,
1593 Nlm_Boolean adjust_scrollbar,
1594 Nlm_Boolean redraw)
1595 {
1596 TOGL_Data *OGL_Data;
1597
1598 if (panel == NULL ||
1599 !Nlm_Visible(panel) || !Nlm_AllParentsVisible(panel)) return;
1600
1601 OGL_Data = PanelToOGL((Nlm_PaneL) panel);
1602
1603 if (adjust_scrollbar) { /* adjust the relevant rotation scrollbar, if any */
1604 Nlm_BaR sbar = NULL;
1605 switch (pivot) {
1606 case ROTATE_X:
1607 sbar = Nlm_GetSlateVScrollBar(panel);
1608 break;
1609 case ROTATE_Y:
1610 sbar = Nlm_GetSlateHScrollBar(panel);
1611 break;
1612 case ROTATE_Z:
1613 sbar = OGL_Data->Z_rotate;
1614 break;
1615 }
1616
1617 if (sbar) {
1618 Nlm_ResetClip();
1619 Nlm_CorrectBarValue(sbar,
1620 (Nlm_GetValue(sbar) + delta + 360) % 360);
1621 }
1622 }
1623
1624 /* the coordination transformation (rotation) */
1625 if (pivot == ROTATE_X)
1626 delta = -delta;
1627 OGL_Rotate(OGL_Data, delta, pivot);
1628
1629 if (redraw) { /* Draw the viewer */
1630 OGL_DrawViewer3D(OGL_Data);
1631 }
1632
1633 /* Nlm_DiagReset(); */
1634 }
1635
1636
1637
1638 /* scrollbar callbacks */
OGL_ViewerVScrollProc(Nlm_BaR sb,Nlm_SlatE viewer,Nlm_Int2 newval,Nlm_Int2 oldval)1639 static void OGL_ViewerVScrollProc(Nlm_BaR sb, Nlm_SlatE viewer,
1640 Nlm_Int2 newval, Nlm_Int2 oldval)
1641 {
1642 OGL_ViewerRotate(viewer, newval - oldval, ROTATE_X, FALSE, TRUE);
1643 }
1644
OGL_ViewerHScrollProc(Nlm_BaR sb,Nlm_SlatE viewer,Nlm_Int2 newval,Nlm_Int2 oldval)1645 static void OGL_ViewerHScrollProc(Nlm_BaR sb, Nlm_SlatE viewer,
1646 Nlm_Int2 newval, Nlm_Int2 oldval)
1647 {
1648 OGL_ViewerRotate(viewer, newval - oldval, ROTATE_Y, FALSE, TRUE);
1649 }
1650
OGL_ViewerZScrollProc(Nlm_BaR sb,Nlm_GraphiC group,Nlm_Int2 newval,Nlm_Int2 oldval)1651 static void OGL_ViewerZScrollProc(Nlm_BaR sb, Nlm_GraphiC group,
1652 Nlm_Int2 newval, Nlm_Int2 oldval)
1653 {
1654 Nlm_SlatE viewer = (Nlm_SlatE) Nlm_GetObjectExtra(sb);
1655 OGL_ViewerRotate(viewer, newval - oldval, ROTATE_Z, FALSE, TRUE);
1656 }
1657
1658
1659
1660
1661 /*
1662 * MOUSE EVENT HANDLERS
1663 */
1664
1665
1666
1667 /*
1668 * MOVE
1669 */
1670
OGL_Move_DrawTrace(MA_TracePtr trace)1671 static void OGL_Move_DrawTrace(MA_TracePtr trace)
1672 {
1673 if (Nlm_EqualPt(trace->start, trace->end))
1674 return;
1675
1676 #ifdef WIN_MOTIF
1677 Nlm_SetColor(0xf1);
1678 #endif
1679 Nlm_InvertMode(); /* turn on xor */
1680 Nlm_DrawLine(trace->start, trace->end); /* draw to current hdc */
1681 Nlm_CopyMode(); /* turn off xor */
1682 }
1683
1684
OGL_Move_PressMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1685 static void OGL_Move_PressMA(MAPtr ma,
1686 MA_TracePtr trace, Nlm_PoinT point,
1687 Nlm_VoidPtr extra)
1688 {
1689 trace->start = trace->end = point;
1690 }
1691
1692
OGL_Move_DragMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1693 static void OGL_Move_DragMA(MAPtr ma,
1694 MA_TracePtr trace, Nlm_PoinT point,
1695 Nlm_VoidPtr extra)
1696 {
1697 OGL_Move_DrawTrace(trace);
1698 trace->end = point;
1699 OGL_Move_DrawTrace(trace);
1700 }
1701
1702
OGL_Move_ReleaseMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1703 static void OGL_Move_ReleaseMA(MAPtr ma,
1704 MA_TracePtr trace, Nlm_PoinT point,
1705 Nlm_VoidPtr extra)
1706 {
1707 OGL_Move_DrawTrace(trace);
1708 trace->end = point;
1709
1710 if (Nlm_EqualPt(trace->start, trace->end))
1711 return;
1712
1713 { /* do the move transform */
1714 TOGL_Data *OGL_Data = MAToOGL(ma);
1715
1716 OGL_Move3D(OGL_Data, (Int2) (trace->end.x - trace->start.x),
1717 (Int2) (trace->end.y - trace->start.y));
1718 OGL_DrawViewer3D(OGL_Data);
1719
1720 }
1721
1722 trace->start = trace->end;
1723 }
1724
1725
OLG_Move_CancelMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1726 static void OLG_Move_CancelMA(MAPtr ma,
1727 MA_TracePtr trace, Nlm_PoinT point,
1728 Nlm_VoidPtr extra)
1729 {
1730 OGL_Move_DrawTrace(trace);
1731 }
1732
1733
1734 /*
1735 * ZOOM
1736 */
1737
OGL_Zoom_DrawTrace(MA_TracePtr trace)1738 static void OGL_Zoom_DrawTrace(MA_TracePtr trace)
1739 {
1740 Nlm_RecT rubber_box;
1741 if (Nlm_EqualPt(trace->start, trace->end))
1742 return;
1743
1744 #ifdef WIN_MOTIF
1745 Nlm_SetColor(0xf1);
1746 #endif
1747 Nlm_InvertMode();
1748 Nlm_LoadRect(&rubber_box, trace->start.x, trace->start.y,
1749 trace->end.x, trace->end.y);
1750 Nlm_FrameRect(&rubber_box); /* draw the frame */
1751 Nlm_CopyMode();
1752 }
1753
OGL_Zoom_PressMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1754 static void OGL_Zoom_PressMA(MAPtr ma,
1755 MA_TracePtr trace, Nlm_PoinT point,
1756 Nlm_VoidPtr extra)
1757 {
1758 trace->start = trace->end = point;
1759 }
1760
1761
1762 /* constrain the rubber band shape as it's dragged to match the aspect
1763 ratio of the OpenGL region */
OGL_Zoom_DragMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1764 static void OGL_Zoom_DragMA(MAPtr ma,
1765 MA_TracePtr trace, Nlm_PoinT point,
1766 Nlm_VoidPtr extra)
1767 {
1768 TOGL_Data *OGL_Data = MAToOGL(ma);
1769 GLint viewport[4];
1770
1771 glGetIntegerv(GL_VIEWPORT, viewport);
1772
1773 OGL_Zoom_DrawTrace(trace);
1774 if (point.y >= trace->start.y)
1775 point.y = trace->start.y +
1776 abs(trace->end.x - trace->start.x) *
1777 viewport[3] / viewport[2];
1778 else
1779 point.y = trace->start.y -
1780 abs(trace->end.x - trace->start.x) *
1781 viewport[3] / viewport[2];
1782 trace->end = point;
1783 OGL_Zoom_DrawTrace(trace);
1784 }
1785
1786
OGL_Zoom_ReleaseMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1787 static void OGL_Zoom_ReleaseMA(MAPtr ma,
1788 MA_TracePtr trace, Nlm_PoinT point,
1789 Nlm_VoidPtr extra)
1790 {
1791 OGL_Zoom_DrawTrace(trace);
1792
1793 if (Nlm_EqualPt(trace->start, trace->end))
1794 return;
1795
1796 { /* do the zoom */
1797 TOGL_Data *OGL_Data = MAToOGL(ma);
1798
1799 OGL_Zoom3D(OGL_Data, trace->start.x, trace->start.y,
1800 trace->end.x, trace->end.y);
1801 OGL_DrawViewer3D(OGL_Data);
1802
1803 }
1804 }
1805
OGL_Zoom_CancelMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1806 static void OGL_Zoom_CancelMA(MAPtr ma,
1807 MA_TracePtr trace, Nlm_PoinT point,
1808 Nlm_VoidPtr extra)
1809 {
1810 OGL_Zoom_DrawTrace(trace);
1811 }
1812
1813
1814 /*
1815 * ROTATE
1816 */
1817
1818
OGL_Rotate_PressMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1819 static void OGL_Rotate_PressMA(MAPtr ma,
1820 MA_TracePtr trace, Nlm_PoinT point,
1821 Nlm_VoidPtr extra)
1822 {
1823 trace->start = point;
1824 }
1825
1826
1827
OGL_Rotate_DragMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1828 static void OGL_Rotate_DragMA(MAPtr ma,
1829 MA_TracePtr trace, Nlm_PoinT point,
1830 Nlm_VoidPtr extra)
1831 {
1832 TOGL_Data *OGL_Data;
1833 GLint viewport[4];
1834
1835 OGL_RotatePivots3DPtr pivot;
1836 if (Nlm_EqualPt(trace->start, point))
1837 return;
1838
1839 OGL_Data = MAToOGL(ma);
1840 pivot = (OGL_RotatePivots3DPtr) extra;
1841
1842 glGetIntegerv(GL_VIEWPORT, viewport);
1843
1844 OGL_ViewerRotate((Nlm_SlatE) OGL_Data->Panel,
1845 (Int4) ((180.0 * (point.x - trace->start.x)) /
1846 viewport[2]), pivot->H, TRUE, FALSE);
1847
1848 OGL_ViewerRotate((Nlm_SlatE) OGL_Data->Panel,
1849 (Int4) ((180.0 * (trace->start.y - point.y)) /
1850 viewport[3]), pivot->V, TRUE, TRUE);
1851 trace->start = point;
1852 }
1853
1854
1855 /*
1856 * RESET
1857 */
1858
OGL_ResetMA(MAPtr ma,MA_TracePtr trace,Nlm_PoinT point,Nlm_VoidPtr extra)1859 static void OGL_ResetMA(MAPtr ma,
1860 MA_TracePtr trace, Nlm_PoinT point,
1861 Nlm_VoidPtr extra)
1862 {
1863 VERIFY(MA_UnsetAll(ma));
1864 }
1865
1866
OGL_SetStdMouse(TOGL_Data * OGL_Data,Nlm_enumStdMAOGL action)1867 static Nlm_Boolean OGL_SetStdMouse(TOGL_Data * OGL_Data,
1868 Nlm_enumStdMAOGL action)
1869 {
1870 if (OGL_Data == NULL)
1871 return FALSE;
1872 return MA_SetGroup(OGL_Data->ma_std_group[action]);
1873 }
1874
1875
1876
1877 /* Initialize MA for the viewer
1878 */
1879
OGL_InitializeMA(TOGL_Data * OGL_Data)1880 static Nlm_Boolean OGL_InitializeMA(TOGL_Data * OGL_Data)
1881 {
1882 MAPtr ma = OGL_Data->ma;
1883
1884 /* rotate */
1885 MActionPtr rotate_press =
1886 MA_AddAction(ma, MK_Normal, MA_Press, OGL_Rotate_PressMA, NULL,
1887 NULL);
1888
1889 static OGL_RotatePivots3D RotateDrag_YX = { ROTATE_Y, ROTATE_X };
1890 MActionPtr rotate_drag_YX =
1891 MA_AddAction(ma, MK_Normal, MA_Drag, OGL_Rotate_DragMA,
1892 &RotateDrag_YX, NULL);
1893 MA_GroupPtr rotate_group_YX = MA_AddGroup(ma, "Rotate_YX",
1894 rotate_press, MA_ONLY,
1895 rotate_drag_YX, MA_ONLY,
1896 NULL);
1897
1898 static OGL_RotatePivots3D RotateDrag_ZX = { ROTATE_Z, ROTATE_X };
1899 MActionPtr rotate_drag_ZX =
1900 MA_AddAction(ma, MK_Normal, MA_Drag, OGL_Rotate_DragMA,
1901 &RotateDrag_ZX, NULL);
1902 MA_GroupPtr rotate_group_ZX = MA_AddGroup(ma, "Rotate_ZX",
1903 rotate_press, MA_ONLY,
1904 rotate_drag_ZX, MA_ONLY,
1905 NULL);
1906
1907 static OGL_RotatePivots3D RotateDrag_YZ = { ROTATE_Y, ROTATE_Z };
1908 MActionPtr rotate_drag_YZ =
1909 MA_AddAction(ma, MK_Normal, MA_Drag, OGL_Rotate_DragMA,
1910 &RotateDrag_YZ, NULL);
1911 MA_GroupPtr rotate_group_YZ = MA_AddGroup(ma, "Rotate_YZ",
1912 rotate_press, MA_ONLY,
1913 rotate_drag_YZ, MA_ONLY,
1914 NULL);
1915
1916 /* move */
1917 MActionPtr move_press =
1918 MA_AddAction(ma, MK_Shift, MA_Press, OGL_Move_PressMA, NULL, NULL);
1919 MActionPtr move_drag =
1920 MA_AddAction(ma, MK_Shift, MA_Drag, OGL_Move_DragMA, NULL, NULL);
1921 MActionPtr move_release =
1922 MA_AddAction(ma, MK_Shift, MA_Release, OGL_Move_ReleaseMA, NULL,
1923 NULL);
1924 MActionPtr move_cancel =
1925 MA_AddAction(ma, MK_Shift, MA_Cancel, OLG_Move_CancelMA, NULL,
1926 NULL);
1927
1928 MA_GroupPtr move_group = MA_AddGroup(ma, "Move",
1929 move_press, MA_ONLY,
1930 move_drag, MA_ONLY,
1931 move_release, MA_ONLY,
1932 move_cancel, MA_ONLY,
1933 NULL);
1934
1935 /* zoom */
1936 MActionPtr zoom_press =
1937 MA_AddAction(ma, MK_Ctrl, MA_Press, OGL_Zoom_PressMA, NULL, NULL);
1938 MActionPtr zoom_drag =
1939 MA_AddAction(ma, MK_Ctrl, MA_Drag, OGL_Zoom_DragMA, NULL, NULL);
1940 MActionPtr zoom_release =
1941 MA_AddAction(ma, MK_Ctrl, MA_Release, OGL_Zoom_ReleaseMA, NULL,
1942 NULL);
1943 MActionPtr zoom_cancel =
1944 MA_AddAction(ma, MK_Ctrl, MA_Cancel, OGL_Zoom_CancelMA, NULL,
1945 NULL);
1946
1947 MA_GroupPtr zoom_group = MA_AddGroup(ma, "Zoom",
1948 zoom_press, MA_ONLY,
1949 zoom_drag, MA_ONLY,
1950 zoom_release, MA_ONLY,
1951 zoom_cancel, MA_ONLY,
1952 NULL);
1953
1954 /* miscellaneous actions */
1955 /*
1956 this is done in the main program. move it here after deleting viewer3d
1957 MActionPtr bg_hl_dclick =
1958 MA_AddAction(ma, MK_Normal, MA_DClick, NULL, NULL,
1959 "Highlight-Prim or Background");
1960 */
1961
1962 /* this group disables all mouse actions when set */
1963 MActionPtr reset_init =
1964 MA_AddAction(ma, MK_Normal, MA_Init, OGL_ResetMA, NULL, NULL);
1965
1966 MA_GroupPtr reset_group = MA_AddGroup(ma, "No Action",
1967 reset_init, MA_SHARED,
1968 NULL);
1969
1970 if (OGL_Data == NULL)
1971 return FALSE;
1972
1973 { { /* "No-Action"s */
1974 int i, j;
1975 for (i = 0; i < MK_Default; i++)
1976 for (j = 0; j < MA_Init; j++) {
1977 VERIFY(MA_AddAction(ma, (enumMKey) i, (enumMAction) j,
1978 DoNothingMA, NULL, "No Action"));
1979 }
1980 }
1981 }
1982
1983 /* register the set of standard 3D-viewer groups */
1984 OGL_Data->ma_std_group[MouseOGL_DoNothing] = reset_group;
1985 OGL_Data->ma_std_group[MouseOGL_RotateYX] = rotate_group_YX;
1986 OGL_Data->ma_std_group[MouseOGL_RotateZX] = rotate_group_ZX;
1987 OGL_Data->ma_std_group[MouseOGL_RotateYZ] = rotate_group_YZ;
1988 OGL_Data->ma_std_group[MouseOGL_Move] = move_group;
1989 OGL_Data->ma_std_group[MouseOGL_Zoom] = zoom_group;
1990
1991 /* Test, Setup defaults and Link viewer panel to MA */
1992 if (!rotate_press ||
1993 !rotate_drag_YX || !rotate_group_YX ||
1994 !rotate_drag_ZX || !rotate_group_ZX ||
1995 !rotate_drag_YZ || !rotate_group_YZ ||
1996 !move_press || !move_drag || !move_release ||
1997 !move_cancel || !move_group ||
1998 !zoom_press || !zoom_drag || !zoom_release ||
1999 !zoom_cancel || !zoom_group ||
2000 /* !bg_hl_dclick ||*/
2001 !reset_group ||
2002 !OGL_SetStdMouse(OGL_Data, MouseOGL_RotateYX) ||
2003 !OGL_SetStdMouse(OGL_Data, MouseOGL_Move) ||
2004 !OGL_SetStdMouse(OGL_Data, MouseOGL_Zoom) ||
2005 /* !MA_SetAction(bg_hl_dclick, FALSE) ||*/
2006 !MA_LinkPanel(ma, OGL_Data->Panel)) {
2007 MA_Reset(ma);
2008 return FALSE;
2009 }
2010
2011 return TRUE;
2012 }
2013
2014
2015 /*
2016 * Doing selection in OpenGL
2017 */
2018
OGL_Select(TOGL_Data * OGL_Data,Nlm_Boolean SelectMode)2019 void OGL_Select(TOGL_Data * OGL_Data, Nlm_Boolean SelectMode)
2020 {
2021 if (OGL_Data == NULL)
2022 return;
2023 OGL_Data->SelectMode = SelectMode;
2024 return;
2025 }
2026
2027
OGL_LoadName(Nlm_VoidPtr PtrValue)2028 void OGL_LoadName(Nlm_VoidPtr PtrValue)
2029 /* load a pointer onto the name stack. compensate for possible long long */
2030 {
2031 Nlm_Int4 i;
2032
2033 for (i = 0; i < sizeof(Nlm_VoidPtr) / sizeof(GLuint); i++)
2034 glPopName();
2035
2036 for (i = 0; i < sizeof(Nlm_VoidPtr) / sizeof(GLuint); i++)
2037 glPushName((GLuint) (((long) PtrValue) >> (i * sizeof(GLuint) * 8))); /* 64 bits? */
2038
2039 OGL_CurrentName = PtrValue;
2040 }
2041
2042
OGL_Hit(TOGL_Data * OGL_Data)2043 Nlm_VoidPtr OGL_Hit(TOGL_Data * OGL_Data)
2044 /* this function looks through the hit stack and extracts the nearest hit */
2045 {
2046 GLuint *Hits, nNames, hit, p = 0, j, ZMin;
2047 long ZMinName = 0; /* this is a hack, but should work for 64 bits */
2048
2049 if (OGL_Data == NULL || OGL_Data->SelectBuffer == NULL)
2050 return NULL;
2051
2052 Hits = (GLuint *) OGL_Data->SelectBuffer;
2053 for (hit=0; hit < OGL_Data->SelectHits; hit++) { /* loop over all hits */
2054 nNames = Hits[p];
2055 p++; /* move to zmin */
2056 /* look for *minimum* depth - that's the top object on the screen */
2057 if (hit == 0 || Hits[p] < ZMin) {
2058 ZMin = Hits[p];
2059 p += 2; /* skip over zmax to name stack */
2060 ZMinName = 0;
2061 /* currently only looks at the top of the name stack */
2062 for (j = 0; j < sizeof(Nlm_VoidPtr) / sizeof(GLuint); j++) {
2063 ZMinName = ZMinName << (sizeof(GLuint) * 8);
2064 ZMinName |= Hits[p + j];
2065 }
2066 p += nNames * sizeof(Nlm_VoidPtr) / sizeof(GLuint);
2067 } else
2068 p += nNames * sizeof(Nlm_VoidPtr) / sizeof(GLuint) + 2;
2069 }
2070 return (Nlm_VoidPtr) ZMinName;
2071 }
2072
2073
OGL_SetSelectPoint(TOGL_Data * OGL_Data,Nlm_PoinT Point)2074 void OGL_SetSelectPoint(TOGL_Data * OGL_Data, Nlm_PoinT Point)
2075 {
2076 Nlm_RecT rect;
2077
2078 if (OGL_Data == NULL)
2079 return;
2080
2081 OGL_Data->SelectPoint.x = Point.x;
2082 OGL_Data->SelectPoint.y = Point.y;
2083
2084 /* translate window coords as passed to this function into coords
2085 relative to OpenGL area (the Panel) coords */
2086 Nlm_GetRect((Nlm_GraphiC)OGL_Data->Panel, &rect);
2087 OGL_Data->SelectPoint.x -= rect.left;
2088 OGL_Data->SelectPoint.y -= rect.top;
2089
2090 #ifdef WIN_MSWIN
2091 /* For some reason, windows requires a fudge to get the mouse pointer
2092 to be more accurate */
2093 OGL_Data->SelectPoint.x += 1;
2094 OGL_Data->SelectPoint.y -= 4;
2095 #endif
2096 }
2097
2098
2099 /*
2100 * functions used to create, do, and finish drawing
2101 */
2102
2103
OGL_DeleteViewer3D(TOGL_Data * OGL_Data)2104 static void OGL_DeleteViewer3D(TOGL_Data * OGL_Data)
2105 /* delete OGL_Data */
2106 {
2107 if (OGL_Data == NULL)
2108 return;
2109
2110 MA_Destroy(OGL_Data->ma);
2111
2112 /* to do: someone else is getting rid of Panel
2113 if ( OGL_Data->Panel )
2114 Nlm_Remove( OGL_Data->Panel );
2115 */
2116
2117 /* delete the display lists */
2118 #ifndef MESA
2119 /* There's some bug (?) in Mesa that causes a crash here, maybe because
2120 we're trying to delete non-existent lists? Dunno... */
2121 glDeleteLists(OGL_Data->Layers->FirstLayer - 1, OGLMAXLAYERS);
2122 #endif
2123
2124 /* free items on the heap */
2125 MemFree(OGL_Data->Layers);
2126 MemFree(OGL_Data->ModelMatrix);
2127 MemFree(OGL_Data);
2128 }
2129
2130
OGL_ResetViewerProc_CB(Nlm_PaneL panel)2131 static void OGL_ResetViewerProc_CB(Nlm_PaneL panel)
2132 {
2133 TOGL_Data *OGL_Data = PanelToOGL(panel);
2134 if (!OGL_Data)
2135 return;
2136
2137 OGL_Data = NULL;
2138 OGL_DeleteViewer3D(PanelToOGL(panel));
2139 }
2140
2141
2142 typedef struct {
2143 #ifdef WIN_MAC
2144 int familyID;
2145 #else
2146 char *name;
2147 #endif
2148 } OGLFontListItem;
2149
2150 #define MAXFONTS 1000
2151 static OGLFontListItem OGLFontList[MAXFONTS]; /* should really be dynamic... */
2152 static int nFonts = 0;
2153
2154 #if defined(WIN32)
Nlm_FindFontCB(ENUMLOGFONTEX * lpelfe,NEWTEXTMETRICEX * lpntme,DWORD FontType,LPARAM lParam)2155 int CALLBACK Nlm_FindFontCB(
2156 ENUMLOGFONTEX *lpelfe,
2157 NEWTEXTMETRICEX *lpntme,
2158 DWORD FontType,
2159 LPARAM lParam )
2160 {
2161 OGLFontList[nFonts].name = strdup(lpelfe->elfLogFont.lfFaceName);
2162 Nlm_PopupItem((Nlm_PopuP)lParam, OGLFontList[nFonts].name);
2163 nFonts++;
2164 if (nFonts == MAXFONTS)
2165 return 0;
2166 else
2167 return 1;
2168 }
2169
2170 #elif defined(WIN_MOTIF)
2171 static char *standardXFont = "9x15";
2172 #endif
2173
2174 /* called during app initialization, to set up font family menu */
Nlm_FindAvailableFonts(Nlm_PopuP pupmenu)2175 NLM_EXTERN void Nlm_FindAvailableFonts(Nlm_PopuP pupmenu)
2176 {
2177 #if defined(WIN32)
2178 LOGFONT lf;
2179 HDC hdc = wglGetCurrentDC();
2180 /* to enumerate all styles of all fonts for the ANSI character set */
2181 lf.lfFaceName[0] = '\0';
2182 lf.lfCharSet = ANSI_CHARSET;
2183 lf.lfPitchAndFamily = 0;
2184 EnumFontFamiliesEx((HDC)hdc, (LPLOGFONT)&lf, (FONTENUMPROC)Nlm_FindFontCB,
2185 (LPARAM)pupmenu, (DWORD)0);
2186
2187 #elif defined(WIN_MAC)
2188 int i;
2189 char name[255];
2190
2191 #define ADD_FONT(str,ID) do { \
2192 OGLFontList[nFonts].familyID = (ID); \
2193 Nlm_PopupItem(pupmenu, (str)); \
2194 nFonts++; \
2195 if (nFonts == MAXFONTS) return; \
2196 } while (0)
2197
2198 /* There's gotta be a better way to get a list of
2199 available fonts... this takes forever even on a fast mac! */
2200 for (i=2; i<=16383; i++) {
2201 if (i==256) i=1024;
2202 if (!RealFont(i,12)) continue;
2203 memset(name, '\0', 255);
2204 GetFontName(i, (unsigned char *)name);
2205 if (name[0] != '\0') {
2206 ADD_FONT(name+1, i); /* for some reason, name starts at 2nd character? */
2207 }
2208 }
2209
2210 #elif defined(WIN_MOTIF)
2211 extern Display *Nlm_currentXDisplay;
2212 char **list, fnd_fam[256], *p;
2213 int i, j, tot;
2214 XFontStruct *xfs;
2215
2216 #define ADD_FONT(str) do { \
2217 OGLFontList[nFonts].name = strdup((str)); \
2218 Nlm_PopupItem(pupmenu, (str)); \
2219 nFonts++; \
2220 if (nFonts == MAXFONTS) return; \
2221 } while (0);
2222
2223 xfs = XLoadQueryFont(Nlm_currentXDisplay, standardXFont);
2224 if (xfs) {
2225 ADD_FONT(standardXFont);
2226 XFreeFont(Nlm_currentXDisplay, xfs);
2227 }
2228 list = XListFonts(Nlm_currentXDisplay,
2229 "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
2230 100000, &tot);
2231 for (i=0; i<tot; i++) {
2232 strncpy(fnd_fam,list[i]+1,256);
2233 p = strchr(fnd_fam,'-');
2234 if (!p) continue;
2235 p = strchr(p+1,'-');
2236 if (!p) continue;
2237 *p = '\0';
2238 /* use foundry-family pair (i.e., adobe-courier)
2239 as "name" of font to store */
2240 for (j=0; j<nFonts; j++) {
2241 if (strcmp(OGLFontList[j].name,fnd_fam) == 0) break;
2242 }
2243 if (j == nFonts) ADD_FONT(fnd_fam);
2244 }
2245 XFreeFontNames(list);
2246 #endif
2247 }
2248
SetOGLFont(TOGL_Data * OGL_Data,Nlm_Int2 fontNameIndex,Nlm_Int2 fontSize,Nlm_Boolean isBold,Nlm_Boolean isItalic,Nlm_Boolean isUnderlined)2249 NLM_EXTERN void SetOGLFont(TOGL_Data *OGL_Data, Nlm_Int2 fontNameIndex, Nlm_Int2 fontSize,
2250 Nlm_Boolean isBold, Nlm_Boolean isItalic, Nlm_Boolean isUnderlined)
2251 {
2252 static Nlm_Int2 currentIndex = -1, currentSize = -1;
2253 static Nlm_Boolean currentBold = FALSE, currentItalic = FALSE,
2254 currentUnderlined = FALSE;
2255
2256 fontNameIndex--; /* vibrant menus start at one */
2257 if (fontNameIndex == currentIndex && currentSize == fontSize &&
2258 isBold == currentBold && isItalic == currentItalic &&
2259 isUnderlined == currentUnderlined)
2260 return; /* only switch fonts if necessary */
2261 currentIndex = fontNameIndex;
2262 currentSize = fontSize;
2263 currentBold = isBold;
2264 currentItalic = isItalic;
2265 currentUnderlined = isUnderlined;
2266
2267 #if defined(WIN32)
2268 {
2269 HDC hdc;
2270 HGDIOBJ currentFont;
2271 static HGDIOBJ newFont = NULL;
2272 SIZE TextSize;
2273
2274 /* delete font used in previous call */
2275 if (newFont) DeleteObject(newFont);
2276
2277 hdc = wglGetCurrentDC();
2278 newFont =
2279 CreateFont(
2280 -MulDiv(currentSize, GetDeviceCaps(hdc, LOGPIXELSY), 72),
2281 0, 0, 0, currentBold ? FW_BOLD : FW_NORMAL,
2282 currentItalic ? TRUE : FALSE,
2283 currentUnderlined ? TRUE : FALSE, FALSE, ANSI_CHARSET,
2284 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
2285 FF_DONTCARE, (LPCTSTR) OGLFontList[currentIndex].name
2286 );
2287 currentFont = SelectObject(hdc, newFont);
2288 wglUseFontBitmaps(hdc, 0, 255, OGLFONTBASE);
2289
2290 /* Get the size of an average character */
2291 GetTextExtentPoint32(hdc, "A", 1, &TextSize);
2292 OGL_Data->SpaceWidth = TextSize.cx;
2293 OGL_Data->SpaceHeight = TextSize.cy;
2294
2295 /* restore previous font */
2296 SelectObject(hdc, currentFont);
2297 }
2298 #elif defined(WIN_MAC)
2299 {
2300 FontInfo fInfo;
2301 GrafPtr currentPort;
2302 GLint ID = OGLFontList[currentIndex].familyID;
2303 Style face = 0;
2304
2305 if (!RealFont(ID, currentSize))
2306 return;
2307
2308 if (isBold) face |= bold;
2309 if (isItalic) face |= italic;
2310 if (isUnderlined) face |= underline;
2311
2312 aglUseFont(aglGetCurrentContext(),
2313 ID, face, currentSize,
2314 0, 256, OGLFONTBASE);
2315
2316 GetPort(¤tPort); /* store the current port's font info */
2317 TextFont(ID);
2318 TextFace(face);
2319 TextSize(currentSize);
2320 OGL_Data->SpaceWidth = CharWidth('A');
2321 GetFontInfo(&fInfo);
2322 OGL_Data->SpaceHeight = fInfo.ascent + fInfo.descent;
2323 TextFont(GetPortTextFont(currentPort)); /* restore previous font */
2324 TextFace(GetPortTextFace(currentPort));
2325 TextSize(GetPortTextSize(currentPort));
2326 }
2327
2328 #elif defined(WIN_MOTIF)
2329 {
2330 static XFontStruct *fontInfo = NULL;
2331 extern Display *Nlm_currentXDisplay;
2332 char query[256], **list, *pos;
2333 int nFound, ii, ib, size, diff, mindiff, closest;
2334 static const char
2335 *bold[] = { "bold", "black", NULL },
2336 *unbold[] = { "medium", "regular", NULL }, **boldSel,
2337 *ital[] = { "i", "o", NULL },
2338 *unital[] = { "r", NULL }, **italSel;
2339
2340 if (fontInfo) XFreeFont(Nlm_currentXDisplay, fontInfo);
2341
2342 if (strcmp(OGLFontList[currentIndex].name, standardXFont) == 0) {
2343 fontInfo = XLoadQueryFont(Nlm_currentXDisplay, standardXFont);
2344 } else {
2345
2346 /* first find fonts with right typeface; bold, italic if possible */
2347 boldSel = currentBold ? bold : unbold;
2348 italSel = currentItalic ? ital : unital;
2349 for (ib = 0; boldSel[ib] ; ib++) {
2350 for (ii = 0; italSel[ii] ; ii++) {
2351 sprintf(query,"-%s-%s-%s-*-*-*-*-*-*-*-*-*-*",
2352 OGLFontList[currentIndex].name,
2353 boldSel[ib], italSel[ii]);
2354 list = XListFonts(Nlm_currentXDisplay, query, 1000, &nFound);
2355 if (nFound) break;
2356 }
2357 if (nFound) break;
2358 }
2359 if (!nFound) { /* can't find any of this style; use any available */
2360 sprintf(query,"-%s-*-*-*-*-*-*-*-*-*-*-*-*",
2361 OGLFontList[currentIndex].name);
2362 list = XListFonts(Nlm_currentXDisplay, query, 1000, &nFound);
2363 }
2364 /* now find closest pixelsize to that requested */
2365 for (ii = 0; ii < nFound; ii++) {
2366 /* find start of pixelsize field of font string */
2367 pos = list[ii];
2368 for (ib = 0; ib < 6; ib++) pos = strchr(pos+1, '-');
2369 pos++;
2370 /* store closest size match to requested */
2371 size = atoi(pos);
2372 /* use 2 * menu size setting as pixel size */
2373 diff = abs(size - currentSize*2);
2374 if (ii == 0 || diff < mindiff) {
2375 mindiff = diff;
2376 closest = ii;
2377 }
2378 }
2379 fontInfo = XLoadQueryFont(Nlm_currentXDisplay, list[closest]);
2380 XFreeFontNames(list);
2381 }
2382
2383 if (fontInfo->per_char == NULL) {
2384 OGL_Data->SpaceWidth = fontInfo->max_bounds.width;
2385 OGL_Data->SpaceHeight = fontInfo->max_bounds.ascent +
2386 fontInfo->max_bounds.descent;
2387 } else {
2388 XCharStruct *charA = &(fontInfo->per_char['A']);
2389 OGL_Data->SpaceWidth = charA->width;
2390 OGL_Data->SpaceHeight = charA->ascent + charA->descent;
2391 }
2392
2393 glXUseXFont(fontInfo->fid,
2394 fontInfo->min_char_or_byte2,
2395 fontInfo->max_char_or_byte2 -
2396 fontInfo->min_char_or_byte2 + 1,
2397 OGLFONTBASE + fontInfo->min_char_or_byte2);
2398 }
2399 #endif
2400 }
2401
2402
OGL_CreateViewer(Nlm_GrouP prnt,Uint2Ptr width,Uint2 height,Int4 flags,Nlm_MenU ma_group_menu,Nlm_MenU ma_action_menu,Nlm_MAInitOGLFunc ma_init_func,VoidPtr ma_init_data)2403 TOGL_Data *OGL_CreateViewer(Nlm_GrouP prnt,
2404 Uint2Ptr width, Uint2 height,
2405 Int4 flags,
2406 Nlm_MenU ma_group_menu,
2407 Nlm_MenU ma_action_menu,
2408 Nlm_MAInitOGLFunc ma_init_func,
2409 VoidPtr ma_init_data)
2410 /* initialize the OpenGL library */
2411 {
2412 TOGL_Data *OGL_Data;
2413 Nlm_Uint2 x_width;
2414
2415 OGL_Data = (TOGL_Data *) MemNew(sizeof(TOGL_Data));
2416 if (OGL_Data == NULL)
2417 return NULL;
2418
2419 OGL_Data->ModelMatrix = (Nlm_VoidPtr) MemNew(16 * sizeof(GLdouble));
2420 if (OGL_Data->ModelMatrix == NULL)
2421 return NULL;
2422 OGL_Data->NeedCameraSetup = FALSE;
2423
2424 OGL_Data->Layers = (TOGL_Layers *) MemNew(sizeof(TOGL_Layers));
2425 if (OGL_Data->Layers == NULL)
2426 return NULL;
2427
2428 OGL_Data->Layers->SelectedLayer = 0;
2429 OGL_SetLayers(OGL_Data, FALSE); /* null all the layers out */
2430
2431 OGL_Data->IsPlaying = FALSE; /* animation off */
2432 OGL_Data->Tick = 0.01;
2433 OGL_Data->ParentWindow = Nlm_ParentWindow((Nlm_Handle) prnt);
2434 OGL_Data->PaletteExpanded = NULL;
2435 OGL_Data->PaletteIndex = NULL;
2436
2437 OGL_Data->SelectMode = FALSE;
2438 OGL_Data->SelectBuffer =
2439 (Nlm_VoidPtr) MemNew(OGLSELECTBUFFER * sizeof(GLuint));
2440 if (OGL_Data->SelectBuffer == NULL)
2441 return NULL;
2442
2443 OGL_Data->Panel = Nlm_Autonomous3DPanel(prnt,
2444 (Int2) * width, (Int2) height,
2445 OGL_DrawViewer3D_CB,
2446 ((flags & Y_ROTATE_SBAR) ?
2447 OGL_ViewerVScrollProc : NULL),
2448 ((flags & X_ROTATE_SBAR) ?
2449 OGL_ViewerHScrollProc : NULL),
2450 sizeof(MAPtr),
2451 OGL_ResetViewerProc_CB, NULL,
2452 &OGL_Data->IndexMode, &OGL_Data->display,
2453 &OGL_Data->visinfo);
2454
2455
2456 if (flags & Z_ROTATE_SBAR) {
2457 OGL_Data->Z_rotate =
2458 Nlm_ScrollBar(prnt, 1, 0, OGL_ViewerZScrollProc);
2459 if (!OGL_Data->Z_rotate) {
2460 MemFree(OGL_Data);
2461 if (OGL_Data->Panel)
2462 Nlm_Remove(OGL_Data->Panel);
2463 return NULL;
2464 }
2465 Nlm_SetObjectExtra(OGL_Data->Z_rotate, OGL_Data->Panel, NULL);
2466 }
2467 {
2468 Nlm_RecT rect;
2469 Nlm_GetPosition(OGL_Data->Panel, &rect);
2470 rect.right = (Int2) (rect.left + *width);
2471 rect.bottom = (Int2) (rect.top + height);
2472 OGL_SetPosition3D(OGL_Data, &rect);
2473 x_width = (Uint2) (rect.right - rect.left);
2474 }
2475
2476 if (flags & X_ROTATE_SBAR) {
2477 Nlm_BaR sb = Nlm_GetSlateHScrollBar((Nlm_SlatE) OGL_Data->Panel);
2478 Nlm_CorrectBarValue(sb, 0);
2479 Nlm_SetRange(sb, 10, 10, 360);
2480 }
2481 if (flags & Y_ROTATE_SBAR) {
2482 Nlm_BaR sb = Nlm_GetSlateVScrollBar((Nlm_SlatE) OGL_Data->Panel);
2483 Nlm_CorrectBarValue(sb, 0);
2484 Nlm_SetRange(sb, 10, 10, 360);
2485 }
2486 if (flags & Z_ROTATE_SBAR) {
2487 Nlm_SetRange(OGL_Data->Z_rotate, 10, 10, 360);
2488 Nlm_CorrectBarValue(OGL_Data->Z_rotate, 180);
2489 }
2490
2491 OGL_Data->ma = MA_Create(ma_group_menu, ma_action_menu);
2492 MA_SetExtra(OGL_Data->ma, OGL_Data);
2493
2494 if (!OGL_InitializeMA(OGL_Data)) {
2495 MemFree(OGL_Data);
2496 if (OGL_Data->Z_rotate)
2497 Nlm_Remove(OGL_Data->Z_rotate);
2498 if (OGL_Data->Panel)
2499 Nlm_Remove(OGL_Data->Panel);
2500 return NULL;
2501 }
2502
2503 if (ma_init_func && !(*ma_init_func) (OGL_Data->ma, ma_init_data)) {
2504 MemFree(OGL_Data);
2505 if (OGL_Data->Z_rotate)
2506 Nlm_Remove(OGL_Data->Z_rotate);
2507 if (OGL_Data->Panel)
2508 Nlm_Remove(OGL_Data->Panel);
2509 return NULL;
2510 }
2511
2512 *width = x_width;
2513
2514 if (!OGL_qobj) {
2515 /* allocate quadric object (once only) */
2516 OGL_qobj = gluNewQuadric();
2517 if (!OGL_qobj) return NULL;
2518 gluQuadricDrawStyle(OGL_qobj, GLU_FILL);
2519 gluQuadricNormals(OGL_qobj, GLU_SMOOTH);
2520 gluQuadricOrientation(OGL_qobj, GLU_OUTSIDE);
2521 }
2522
2523 return OGL_Data;
2524 }
2525
OGL_InitializeLists(TOGL_Data * OGL_Data)2526 void OGL_InitializeLists(TOGL_Data * OGL_Data)
2527 {
2528 OGL_Data->Layers->FirstLayer = glGenLists((GLsizei) OGLMAXLAYERS);
2529 OGL_Data->Layers->FirstLayer++; /* avoid weird bug in windows OpenGL */
2530 OGL_Data->Layers->LastLayer = OGL_Data->Layers->FirstLayer;
2531 }
2532
2533 #ifdef WIN_MAC
2534 static Nlm_Boolean drawingOffscreen = FALSE;
2535 #endif
2536
OGL_DrawViewer3D(TOGL_Data * OGL_Data)2537 void OGL_DrawViewer3D(TOGL_Data * OGL_Data)
2538 /* does the drawing */
2539 {
2540 GLint Viewport[4];
2541 static GLint prevW = -1, prevH = -1;
2542 GLfloat LightPosition[4], aspect;
2543 Nlm_Int4 TotalColors;
2544 Nlm_Uint4 iList;
2545 int i;
2546
2547 #ifdef DEBUG_GL
2548 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error entering DrawViewer3D");
2549 #endif
2550
2551 if (OGL_Data == NULL) return;
2552
2553 #ifdef WIN_MOTIF
2554 /* need to know if in color index mode - i.e., after context established */
2555 if (!glXGetCurrentContext()) return;
2556 #endif
2557
2558 #ifdef WIN_MAC
2559 if (drawingOffscreen) {
2560 aglDisable(aglGetCurrentContext(), AGL_BUFFER_RECT);
2561 } else {
2562 /* HACK to limit opengl to correct region of the (Cn3D) window */
2563 GLint wrect[4];
2564 Nlm_RecT r;
2565 AGLContext ctx = aglGetCurrentContext();
2566 Nlm_GetRect((Nlm_GraphiC) OGL_Data->Panel, &r);
2567 wrect[0] = r.left;
2568 wrect[1] = r.top - Nlm_hScrollBarHeight - 4; /* this last column is simply tweaks */
2569 wrect[2] = r.right - r.left + 1 - 2; /* to make window position look nice */
2570 wrect[3] = r.bottom - r.top + 1 - 3;
2571 aglSetInteger(ctx, AGL_BUFFER_RECT, wrect);
2572 aglEnable(ctx, AGL_BUFFER_RECT);
2573 }
2574 #endif
2575
2576 /* set background color */
2577 if (OGL_Data->IndexMode) {
2578 TotalColors = ValNodeLen(OGL_Data->PaletteExpanded);
2579 #ifdef WIN32
2580 glClearIndex((GLfloat) (TotalColors + 10));
2581 #else
2582 glClearIndex((GLfloat) TotalColors);
2583 #endif
2584
2585 } else {
2586 glClearColor(1.0*OGL_Data->Background.rgb[0]/255,
2587 1.0*OGL_Data->Background.rgb[1]/255,
2588 1.0*OGL_Data->Background.rgb[2]/255, 1.0);
2589 }
2590
2591 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2592
2593 glGetIntegerv(GL_VIEWPORT, Viewport);
2594
2595 /* only do this (expensive) stuff if we have to */
2596 if (Viewport[2] != prevW || Viewport[3] != prevH ||
2597 OGL_Data->SelectMode || OGL_Data->NeedCameraSetup) {
2598
2599 prevW = Viewport[2];
2600 prevH = Viewport[3];
2601 if (OGL_Data->SelectMode)
2602 OGL_Data->NeedCameraSetup = TRUE; /* will need to redo camera next time */
2603 else
2604 OGL_Data->NeedCameraSetup = FALSE;
2605
2606 glMatrixMode(GL_PROJECTION);
2607 glLoadIdentity();
2608
2609 if (OGL_Data->SelectMode) {
2610 glSelectBuffer((GLsizei) OGLSELECTBUFFER,
2611 (GLuint *) OGL_Data->SelectBuffer);
2612 glRenderMode(GL_SELECT);
2613 glInitNames();
2614 for (i = 0; i < sizeof(Nlm_VoidPtr) / sizeof(GLuint); i++)
2615 glPushName(0);
2616 gluPickMatrix((GLdouble) (OGL_Data->SelectPoint.x),
2617 (GLdouble) (Viewport[3] - OGL_Data->SelectPoint.y),
2618 1.0, 1.0, Viewport);
2619 }
2620
2621 aspect = ((GLfloat)(Viewport[2])) / Viewport[3];
2622 gluPerspective(OGL_Data->CameraAngle * 180.0/acos(-1), /* viewing angle (degrees) */
2623 aspect, /* w/h aspect */
2624 0.5 * OGL_Data->CameraDistance, /* near clipping plane */
2625 1.5 * OGL_Data->CameraDistance); /* far clipping plane */
2626 gluLookAt(0.0,0.0,OGL_Data->CameraDistance, /* the camera position */
2627 OGL_Data->CameraDirection[0], /* the "look-at" point */
2628 OGL_Data->CameraDirection[1],
2629 0.0,
2630 0.0,1.0,0.0); /* the up direction */
2631
2632 glMatrixMode(GL_MODELVIEW);
2633 glLoadIdentity();
2634
2635 /* set up the lighting */
2636 LightPosition[0] = 0.0; /* same as eye */
2637 LightPosition[1] = 0.0;
2638 LightPosition[2] = OGL_Data->CameraDistance;
2639 LightPosition[3] = 0.0; /* directional light (faster) when 0.0 */
2640 glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
2641
2642
2643 if (OGL_Data->IndexMode == FALSE) {
2644 glLightfv(GL_LIGHT0, GL_AMBIENT, Color_Off);
2645 glLightfv(GL_LIGHT0, GL_DIFFUSE, Color_MostlyOn);
2646 glLightfv(GL_LIGHT0, GL_SPECULAR, Color_Off);
2647
2648 /* clear these material colors */
2649 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, Color_Off);
2650 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Color_Off);
2651
2652 } else { /* color index mode */
2653 glLightfv(GL_LIGHT0, GL_AMBIENT, Color_Off);
2654 glLightfv(GL_LIGHT0, GL_DIFFUSE, Color_On);
2655 glLightfv(GL_LIGHT0, GL_SPECULAR, Color_Off);
2656 }
2657
2658 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Color_On); /* global ambience */
2659 glEnable(GL_LIGHTING);
2660 glEnable(GL_LIGHT0);
2661
2662 glShadeModel(GL_SMOOTH);
2663 glEnable(GL_DEPTH_TEST);
2664
2665 /* turn on culling to speed rendering */
2666 glEnable(GL_CULL_FACE);
2667 glCullFace(GL_BACK);
2668 glFrontFace(GL_CCW);
2669 }
2670
2671 glLoadIdentity();
2672 glMultMatrixd((GLdouble *) OGL_Data->ModelMatrix);
2673
2674 /* selectively display the layers */
2675 if (OGL_Data->Layers->SelectedLayer) {
2676 glCallList(OGL_Data->Layers->SelectedLayer);
2677 } else {
2678 for (iList = OGL_Data->Layers->FirstLayer;
2679 iList <= OGL_Data->Layers->LastLayer; iList++) {
2680 if (OGL_GetLayer(OGL_Data, iList - OGL_Data->Layers->FirstLayer)) {
2681 glCallList(iList);
2682 }
2683 }
2684 }
2685
2686 /* display transparent spheres */
2687 if (!OGL_Data->IndexMode) {
2688 OGL_SetColor(OGL_Data, NULL, GL_NONE, 1.0); /* clear all color states */
2689 OGL_RenderTransparentSpheres(OGL_Data);
2690 }
2691
2692 OGL_CheckForErrors(); /* check GL error status */
2693
2694 glFlush();
2695
2696 if (OGL_Data->SelectMode)
2697 OGL_Data->SelectHits = glRenderMode(GL_RENDER);
2698
2699 else { /* regular rendering mode */
2700 /* swap when double buffering */
2701 #if defined(WIN32)
2702 wglSwapLayerBuffers(wglGetCurrentDC(), WGL_SWAP_MAIN_PLANE);/**/
2703 /*SwapBuffers(wglGetCurrentDC());*/
2704 #elif defined(WIN_MOTIF)
2705 glXSwapBuffers((Display *) OGL_Data->display, glXGetCurrentDrawable());
2706 #elif defined(WIN_MAC)
2707 aglSwapBuffers(aglGetCurrentContext());
2708 #endif
2709
2710 }
2711
2712 #ifdef DEBUG_GL
2713 if (OGL_CheckForErrors()) Message(MSG_POST, "GL error leaving DrawViewer3D");
2714 #endif
2715 }
2716
2717
OGL_Reset(TOGL_Data * OGL_Data)2718 void OGL_Reset(TOGL_Data * OGL_Data)
2719 /* reset the transform matrix */
2720 {
2721 Nlm_FloatLo diff;
2722
2723 if (OGL_Data == NULL)
2724 return;
2725
2726 if (!OGL_Data->BoundBox.set)
2727 OGL_ClearBoundBox(&(OGL_Data->BoundBox));
2728
2729 OGL_Data->MaxSize = (Nlm_FloatLo)
2730 fabs(OGL_Data->BoundBox.x[0] - OGL_Data->BoundBox.x[1]);
2731 diff = fabs(OGL_Data->BoundBox.y[0] - OGL_Data->BoundBox.y[1]);
2732 if (diff > OGL_Data->MaxSize)
2733 OGL_Data->MaxSize = diff;
2734 diff = fabs(OGL_Data->BoundBox.z[0] - OGL_Data->BoundBox.z[1]);
2735 if (diff > OGL_Data->MaxSize)
2736 OGL_Data->MaxSize = diff;
2737
2738 /* set up the initial view point */
2739 OGL_Data->CameraDistance = (GLfloat) 5.0 *OGL_Data->MaxSize;
2740 OGL_Data->CameraDirection[0] = 0.0;
2741 OGL_Data->CameraDirection[1] = 0.0;
2742 OGL_Data->CameraAngle = 2.0 *
2743 atan((fabs(OGL_Data->BoundBox.y[0] - OGL_Data->BoundBox.y[1]) / 2.0) /
2744 OGL_Data->CameraDistance);
2745 OGL_Data->NeedCameraSetup = TRUE;
2746
2747 /* translate model so origin is at bounding box center */
2748 glMatrixMode(GL_MODELVIEW);
2749 glLoadIdentity();
2750 glTranslatef(
2751 (GLfloat) -((OGL_Data->BoundBox.x[0] + OGL_Data->BoundBox.x[1]) / 2.0),
2752 (GLfloat) -((OGL_Data->BoundBox.y[0] + OGL_Data->BoundBox.y[1]) / 2.0),
2753 (GLfloat) -((OGL_Data->BoundBox.z[0] + OGL_Data->BoundBox.z[1]) / 2.0)
2754 );
2755 glGetDoublev(GL_MODELVIEW_MATRIX, (GLdouble *) OGL_Data->ModelMatrix);
2756 }
2757
2758
OGL_SetPosition3D(TOGL_Data * OGL_Data,Nlm_RectPtr rect)2759 Boolean OGL_SetPosition3D(TOGL_Data * OGL_Data, Nlm_RectPtr rect)
2760 /* resizes and positions the 3D window */
2761 {
2762 Nlm_Int4 width = rect->right - rect->left + 1;
2763 Nlm_Int4 height = rect->bottom - rect->top + 1;
2764
2765 if (OGL_Data == NULL || rect == NULL)
2766 return FALSE;
2767
2768 if (OGL_Data->Z_rotate) {
2769 rect->top += Nlm_hScrollBarHeight;
2770 height -= Nlm_hScrollBarHeight;
2771 }
2772
2773 if (Nlm_GetSlateVScrollBar((Nlm_SlatE) OGL_Data->Panel))
2774 width -= Nlm_vScrollBarWidth + 3;
2775 if (Nlm_GetSlateHScrollBar((Nlm_SlatE) OGL_Data->Panel))
2776 height -= Nlm_hScrollBarHeight + 3;
2777
2778 if (width < 16 || height < 16)
2779 return FALSE;
2780
2781 #if defined(WIN_MOTIF) && defined(MESA)
2782 if (glXGetCurrentContext())
2783 #endif
2784 glViewport(0, 0, width, height);
2785
2786 rect->right = (Nlm_Int2) (rect->left + width + 3);
2787 rect->bottom = (Nlm_Int2) (rect->top + height + 3);
2788 if (Nlm_GetSlateVScrollBar((Nlm_SlatE) OGL_Data->Panel))
2789 rect->right += Nlm_vScrollBarWidth;
2790 if (Nlm_GetSlateHScrollBar((Nlm_SlatE) OGL_Data->Panel))
2791 rect->bottom += Nlm_hScrollBarHeight;
2792
2793 Nlm_SetPosition(OGL_Data->Panel, rect); /* resize the panel */
2794 Nlm_ProcessUpdatesFirst(FALSE);
2795 Nlm_AdjustPrnt(OGL_Data->Panel, rect, FALSE);
2796
2797 if (OGL_Data->Z_rotate) { /* if there is a z rotation scroll bar */
2798 rect->bottom = rect->top;
2799 rect->top -= Nlm_hScrollBarHeight;
2800 Nlm_SetPosition(OGL_Data->Z_rotate, rect);
2801 }
2802
2803 return TRUE;
2804 }
2805
2806
OGL_ClearOGL_Data(TOGL_Data * OGL_Data)2807 void OGL_ClearOGL_Data(TOGL_Data * OGL_Data)
2808 /* clear the transforms and bound box in OGL_Data structure */
2809 {
2810 if (OGL_Data == NULL)
2811 return;
2812
2813 OGL_ClearBoundBox(&(OGL_Data->BoundBox));
2814 OGL_Data->MaxSize = 2.0 * OGL_DEFAULT_SIZE;
2815 OGL_Data->Background.rgb[0] = 0;
2816 OGL_Data->Background.rgb[1] = 0;
2817 OGL_Data->Background.rgb[2] = 0;
2818 }
2819
2820
OGL_ClearBoundBox(TOGL_BoundBox * BoundBox)2821 void OGL_ClearBoundBox(TOGL_BoundBox * BoundBox)
2822 /* initialize a bounds box */
2823 {
2824 Nlm_Int4 i;
2825
2826 if (BoundBox == NULL)
2827 return;
2828 for (i = 0; i < 2; i++) {
2829 BoundBox->x[i] = (Nlm_FloatLo) ((i * 2 - 1) * OGL_DEFAULT_SIZE);
2830 BoundBox->y[i] = (Nlm_FloatLo) ((i * 2 - 1) * OGL_DEFAULT_SIZE);
2831 BoundBox->z[i] = (Nlm_FloatLo) ((i * 2 - 1) * OGL_DEFAULT_SIZE);
2832 }
2833 BoundBox->set = TRUE; /* we've set up the default values */
2834 }
2835
2836 /* function to start, stop, and check if animation is playing */
2837
OGL_IsPlaying(TOGL_Data * pOGL_Data)2838 NLM_EXTERN Nlm_Boolean OGL_IsPlaying(TOGL_Data *pOGL_Data)
2839 {
2840 #ifdef WIN_MAC
2841 return FALSE;
2842 #else
2843 return pOGL_Data->IsPlaying;
2844 #endif
2845 }
2846
OGL_StopPlaying(TOGL_Data * pOGL_Data)2847 NLM_EXTERN void OGL_StopPlaying(TOGL_Data *pOGL_Data)
2848 {
2849 #ifndef WIN_MAC
2850 pOGL_Data->IsPlaying = FALSE;
2851 #endif
2852 }
2853
OGL_StartPlaying(TOGL_Data * pOGL_Data)2854 NLM_EXTERN void OGL_StartPlaying(TOGL_Data *pOGL_Data)
2855 {
2856 #ifndef WIN_MAC
2857 Nlm_StopWatchPtr pStopwatch;
2858 Nlm_FloatHi newtime;
2859
2860 pOGL_Data->IsPlaying = TRUE;
2861 pStopwatch = Nlm_StopWatchNew();
2862 Nlm_StopWatchStart(pStopwatch);
2863 while (!Nlm_QuittingProgram() && OGL_IsPlaying(pOGL_Data)) {
2864 OGL_Play(pOGL_Data);
2865 OGL_DrawViewer3D(pOGL_Data);
2866 if(pOGL_Data->Tick != 0.0L) {
2867 do {
2868 Nlm_StopWatchStop(pStopwatch);
2869 newtime = Nlm_GetElapsedTime(pStopwatch);
2870 if (Nlm_EventAvail()) Nlm_ProcessAnEvent();
2871 } while (newtime < pOGL_Data->Tick);
2872 Nlm_StopWatchStart(pStopwatch);
2873 }
2874 while (Nlm_EventAvail())
2875 Nlm_ProcessAnEvent();
2876 }
2877 Nlm_StopWatchFree(pStopwatch);
2878 #endif
2879 }
2880
2881
2882 #ifdef _PNG
2883
2884 /* callback used by PNG library to report errors */
writepng_error_handler(png_structp png_ptr,png_const_charp msg)2885 static void writepng_error_handler(png_structp png_ptr, png_const_charp msg)
2886 {
2887 Message(MSG_ERROR, "PNG Error: %s", msg);
2888 }
2889
2890 #ifdef WIN_MOTIF
2891 static Nlm_Boolean gotAnXError;
2892
OGL_XErrorHandler(Display * dpy,XErrorEvent * error)2893 int OGL_XErrorHandler(Display *dpy, XErrorEvent *error)
2894 {
2895 gotAnXError = TRUE;
2896 return 0;
2897 }
2898 #endif /* WIN_MOTIF */
2899
2900 static Nlm_MonitorPtr row_monitor;
2901 static int nRows;
2902
write_row_callback(png_structp png_ptr,png_uint_32 row,int pass)2903 void write_row_callback(png_structp png_ptr, png_uint_32 row, int pass)
2904 {
2905 char message[256];
2906 float progress;
2907
2908 if (nRows < 0) { /* if negative, then we're doing interlacing */
2909 float start, end;
2910 switch (pass + 1) {
2911 case 1: start = 0; end = 1; break;
2912 case 2: start = 1; end = 2; break;
2913 case 3: start = 2; end = 3; break;
2914 case 4: start = 3; end = 5; break;
2915 case 5: start = 5; end = 7; break;
2916 case 6: start = 7; end = 11; break;
2917 case 7: start = 11; end = 15; break;
2918 }
2919 progress = 100.0 * (
2920 (start / 15) +
2921 (((float) row) / (-nRows)) * ((end - start) / 15)
2922 );
2923 } else { /* not interlaced */
2924 progress = 100.0 * row / nRows;
2925 }
2926 sprintf(message, "Writing PNG file (%i%%) ...", (int) progress);
2927 Nlm_MonitorStrValue(row_monitor, message);
2928 Nlm_Update();
2929 }
2930
2931 /* saves current OpenGL context window to PNG file */
Nlm_SaveImagePNG(Nlm_Char * fname)2932 void Nlm_SaveImagePNG(Nlm_Char *fname)
2933 {
2934 GLint viewport[4];
2935 GLboolean isRGBA;
2936 Nlm_Uchar *row = NULL;
2937 FILE *out = NULL;
2938 int i, bytesPerPixel = 3;
2939 png_structp png_ptr = NULL;
2940 png_infop info_ptr = NULL;
2941 Nlm_Boolean doInterlacing = TRUE;
2942 TOGL_Data *OGL_Data = (TOGL_Data *)(Cn3D_GetCurrentOGLData());
2943
2944 #if defined(WIN_MOTIF)
2945 GLint glSize;
2946 int nAttribs, attribs[20];
2947 XVisualInfo *visinfo;
2948 Nlm_Boolean localVI = FALSE;
2949 Pixmap xPixmap;
2950 GLXContext currentCtx, glCtx = NULL;
2951 GLXPixmap glxPixmap;
2952 GLXDrawable currentXdrw;
2953 extern Display *Nlm_currentXDisplay;
2954 extern int Nlm_currentXScreen;
2955 int (*currentXErrHandler)(Display *, XErrorEvent *);
2956
2957 #elif defined(WIN_MSWIN)
2958 HDC current_hdc = NULL, hdc = NULL;
2959 HGDIOBJ current_hgdiobj = NULL;
2960 HBITMAP hbm = NULL;
2961 PIXELFORMATDESCRIPTOR pfd;
2962 int nPixelFormat;
2963 HGLRC hglrc = NULL, current_hglrc = NULL;
2964
2965 #elif defined(WIN_MAC)
2966 Nlm_Uchar *base = NULL;
2967 GLint attrib[20], glSize;
2968 int na = 0;
2969 AGLPixelFormat fmt = NULL;
2970 AGLContext ctx = NULL, currentCtx;
2971
2972 #endif
2973
2974 glGetBooleanv(GL_RGBA_MODE, &isRGBA);
2975 if (!isRGBA) {
2976 /* turn this off till I figure out good way to retrieve colormap */
2977 Message(MSG_ERROR, "8-Bit PNG output currently unavailable");
2978 return;
2979 }
2980
2981 /* determine the size of the window and allocate (platform-dependent)
2982 off-screen rendering area */
2983 glGetIntegerv(GL_VIEWPORT, viewport);
2984 /*
2985 viewport[2] *= 3;
2986 viewport[3] *= 3;
2987 */
2988
2989 #if defined(WIN_MOTIF)
2990 currentCtx = glXGetCurrentContext(); /* save current context info */
2991 currentXdrw = glXGetCurrentDrawable();
2992
2993 currentXErrHandler = XSetErrorHandler(OGL_XErrorHandler);
2994 gotAnXError = FALSE;
2995
2996 /* first, try to get a non-doublebuffered visual, to economize on memory */
2997 nAttribs = 0;
2998 attribs[nAttribs++] = GLX_USE_GL;
2999 attribs[nAttribs++] = GLX_RGBA;
3000 attribs[nAttribs++] = GLX_RED_SIZE;
3001 glGetIntegerv(GL_RED_BITS, &glSize);
3002 attribs[nAttribs++] = glSize;
3003 attribs[nAttribs++] = GLX_GREEN_SIZE;
3004 attribs[nAttribs++] = glSize;
3005 attribs[nAttribs++] = GLX_BLUE_SIZE;
3006 attribs[nAttribs++] = glSize;
3007 attribs[nAttribs++] = GLX_DEPTH_SIZE;
3008 glGetIntegerv(GL_DEPTH_BITS, &glSize);
3009 attribs[nAttribs++] = glSize;
3010 attribs[nAttribs++] = None;
3011 visinfo = glXChooseVisual((Display *) OGL_Data->display,
3012 DefaultScreen((Display *) OGL_Data->display),
3013 attribs);
3014
3015 /* if that fails, just revert to the one used for the regular window */
3016 if (visinfo)
3017 localVI = TRUE;
3018 else
3019 visinfo = (XVisualInfo *) (OGL_Data->visinfo);
3020
3021 xPixmap = XCreatePixmap((Display *) OGL_Data->display,
3022 RootWindow((Display *) OGL_Data->display, Nlm_currentXScreen),
3023 viewport[2], viewport[3], visinfo->depth);
3024 glxPixmap = glXCreateGLXPixmap((Display *) OGL_Data->display,
3025 visinfo, xPixmap);
3026 if (gotAnXError) {
3027 Message(MSG_ERROR, "Got an X error creating GLXPixmap context");
3028 goto cleanup;
3029 }
3030 glCtx = glXCreateContext((Display *) OGL_Data->display,
3031 visinfo,
3032 currentCtx, /* share display list with "regular" context */
3033 GL_FALSE);
3034 if (!glCtx || !glXMakeCurrent((Display *) OGL_Data->display,
3035 glxPixmap, glCtx)) {
3036 Message(MSG_ERROR, "Failed to make current GLXPixmap rendering context");
3037 goto cleanup;
3038 }
3039
3040 #elif defined(WIN_MSWIN)
3041 current_hglrc = wglGetCurrentContext(); /* save to restore later */
3042 current_hdc = wglGetCurrentDC();
3043
3044 /* create bitmap of same color type as current rendering context */
3045 hbm = CreateCompatibleBitmap(current_hdc, viewport[2], viewport[3]);
3046 if (!hbm) {
3047 Message(MSG_ERROR, "Failed to create rendering BITMAP");
3048 goto cleanup;
3049 }
3050 memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
3051 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
3052 pfd.nVersion = 1;
3053 /* NOT doublebuffered, to save memory */
3054 pfd.dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL;
3055 pfd.iPixelType = PFD_TYPE_RGBA;
3056 pfd.cColorBits = GetDeviceCaps(current_hdc, BITSPIXEL);
3057 pfd.iLayerType = PFD_MAIN_PLANE;
3058
3059 hdc = CreateCompatibleDC(current_hdc);
3060 if (!hdc) {
3061 Message(MSG_ERROR, "CreateCompatibleDC failed");
3062 goto cleanup;
3063 }
3064
3065 current_hgdiobj = SelectObject(hdc, hbm);
3066 if (!current_hgdiobj) {
3067 Message(MSG_ERROR, "SelectObject failed");
3068 goto cleanup;
3069 }
3070 nPixelFormat = ChoosePixelFormat(hdc, &pfd);
3071 if (!nPixelFormat) {
3072 Message(MSG_ERROR, "ChoosePixelFormat failed: %i", GetLastError());
3073 goto cleanup;
3074 }
3075 if (!SetPixelFormat(hdc, nPixelFormat, &pfd)) {
3076 Message(MSG_ERROR, "SetPixelFormat failed: %i", GetLastError());
3077 goto cleanup;
3078 }
3079 /*DescribePixelFormat(hdc, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);*/
3080 hglrc = wglCreateContext(hdc);
3081 if (!hglrc) {
3082 Message(MSG_ERROR, "wglCreateContext failed: %i", GetLastError());
3083 goto cleanup;
3084 }
3085 /* need to share display lists with regular window */
3086 if (!wglShareLists(current_hglrc, hglrc)) {
3087 Message(MSG_ERROR, "wglShareLists failed: %i", GetLastError());
3088 goto cleanup;
3089 }
3090 if (!wglMakeCurrent(hdc, hglrc)) {
3091 Message(MSG_ERROR, "wglMakeCurrent failed: %i", GetLastError());
3092 goto cleanup;
3093 }
3094
3095 #elif defined(WIN_MAC)
3096 currentCtx = aglGetCurrentContext();
3097
3098 /* Mac pixels seem to always be 32-bit */
3099 bytesPerPixel = 4;
3100
3101 base = (Nlm_Uchar *) MemNew(viewport[2] * viewport[3] * bytesPerPixel);
3102 if (!base) {
3103 Message(MSG_ERROR, "Failed to allocate image buffer");
3104 goto cleanup;
3105 }
3106
3107 /* create an off-screen rendering context (NOT doublebuffered) */
3108 attrib[na++] = AGL_OFFSCREEN;
3109 attrib[na++] = AGL_RGBA;
3110 glGetIntegerv(GL_RED_BITS, &glSize);
3111 attrib[na++] = AGL_RED_SIZE;
3112 attrib[na++] = glSize;
3113 attrib[na++] = AGL_GREEN_SIZE;
3114 attrib[na++] = glSize;
3115 attrib[na++] = AGL_BLUE_SIZE;
3116 attrib[na++] = glSize;
3117 glGetIntegerv(GL_DEPTH_BITS, &glSize);
3118 attrib[na++] = AGL_DEPTH_SIZE;
3119 attrib[na++] = glSize;
3120 attrib[na++] = AGL_NONE;
3121
3122 if ((fmt=aglChoosePixelFormat(NULL, 0, attrib)) == NULL) {
3123 Message(MSG_ERROR, "aglChoosePixelFormat failed");
3124 goto cleanup;
3125 }
3126 /* share display lists with current "regular" context */
3127 if ((ctx=aglCreateContext(fmt, currentCtx)) == NULL) {
3128 Message(MSG_ERROR, "aglCreateContext failed");
3129 goto cleanup;
3130 }
3131
3132 /* attach off-screen buffer to this context */
3133 if (!aglSetOffScreen(ctx, viewport[2], viewport[3],
3134 bytesPerPixel * viewport[2], base)) {
3135 Message(MSG_ERROR, "aglSetOffScreen failed");
3136 goto cleanup;
3137 }
3138 if (!aglSetCurrentContext(ctx)) {
3139 Message(MSG_ERROR, "aglSetCurrentContext failed");
3140 goto cleanup;
3141 }
3142
3143 #endif
3144
3145 row = (Nlm_Uchar *) MemNew(viewport[2] * bytesPerPixel);
3146 if (!row) {
3147 Message(MSG_ERROR, "Failed to allocate pixel storage for PNG output");
3148 goto cleanup;
3149 }
3150
3151 /* open the output file for writing */
3152 out = fopen(fname, "wb");
3153 if (!out) {
3154 Message(MSG_ERROR, "Can't write to file '%s'", fname);
3155 goto cleanup;
3156 }
3157
3158 /* set up the PNG writing (see libpng.txt) */
3159 png_ptr = png_create_write_struct(
3160 PNG_LIBPNG_VER_STRING, NULL, writepng_error_handler, NULL);
3161 if (!png_ptr) {
3162 Message(MSG_ERROR, "Can't create PNG write structure");
3163 goto cleanup;
3164 }
3165
3166 info_ptr = png_create_info_struct(png_ptr);
3167 if (!info_ptr) {
3168 Message(MSG_ERROR, "Can't create PNG info structure");
3169 goto cleanup;
3170 }
3171
3172 if (setjmp(png_jmpbuf(png_ptr))) {
3173 Message(MSG_ERROR, "PNG write failed");
3174 goto cleanup;
3175 }
3176
3177 png_init_io(png_ptr, out);
3178
3179 /* sets callback that's called by PNG after each written row */
3180 png_set_write_status_fn(png_ptr, write_row_callback);
3181
3182 png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
3183
3184 png_set_IHDR(png_ptr, info_ptr, viewport[2], viewport[3],
3185 8, PNG_COLOR_TYPE_RGB,
3186 doInterlacing ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
3187 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
3188
3189 png_write_info(png_ptr, info_ptr);
3190
3191 /*
3192 Redraw the model into the new off-screen context, then use glReadPixels
3193 to retrieve pixel data. It's much easier to use glReadPixels rather than
3194 trying to read directly from the off-screen buffer, since GL can do all
3195 the potentially tricky work of translating from whatever pixel format
3196 the buffer uses into "regular" RGB byte triples.
3197 */
3198 row_monitor = Nlm_MonitorStrNewEx("PNG Progress", 20, FALSE);
3199 Nlm_MonitorStrValue(row_monitor, "Rendering to off-screen buffer...");
3200 Nlm_Update();
3201 OGL_Data->NeedCameraSetup = TRUE;
3202 #ifdef WIN_MAC
3203 drawingOffscreen = TRUE; /* signal redraw not to use agl buffer rect */
3204 #endif
3205 OGL_DrawViewer3D(OGL_Data);
3206 #ifdef WIN_MAC
3207 drawingOffscreen = FALSE;
3208 #endif
3209 glPixelStorei(GL_PACK_ALIGNMENT, 1);
3210
3211 /*
3212 Write image row by row to avoid having to allocate another full image's
3213 worth of memory. Do multiple passes for interlacing, if necessary. Note
3214 that PNG's rows are stored top down, while GL's are bottom up.
3215 */
3216 nRows = viewport[3];
3217 if (doInterlacing) {
3218 int pass, r;
3219 nRows = -nRows; /* signal to monitor that we're interlacing */
3220 if (png_set_interlace_handling(png_ptr) != 7) {
3221 Message(MSG_ERROR, "confused by unkown PNG interlace scheme");
3222 goto cleanup;
3223 }
3224 for (pass = 1; pass <= 7; pass++) {
3225 for (i = viewport[3] - 1; i >= 0; i--) {
3226 r = viewport[3] - i - 1;
3227 /* when interlacing, only certain rows are actually read
3228 during certain passes - avoid unncessary reads */
3229 if (
3230 ((pass == 1 || pass == 2) && (r % 8 == 0)) ||
3231 ((pass == 3) && ((r - 4) % 8 == 0)) ||
3232 ((pass == 4) && (r % 4 == 0)) ||
3233 ((pass == 5) && ((r - 2) % 4 == 0)) ||
3234 ((pass == 6) && (r % 2 == 0)) ||
3235 ((pass == 7) && ((r - 1) % 2 == 0))
3236 )
3237 glReadPixels(viewport[0], i, viewport[2], 1,
3238 GL_RGB, GL_UNSIGNED_BYTE, row);
3239 /* ... but still have to call this for each row in each pass */
3240 png_write_row(png_ptr, row);
3241 }
3242 }
3243 } else { /* not interlaced */
3244 for (i = viewport[3] - 1; i >= 0; i--) {
3245 glReadPixels(viewport[0], i, viewport[2], 1,
3246 GL_RGB, GL_UNSIGNED_BYTE, row);
3247 png_write_row(png_ptr, row);
3248 }
3249 }
3250 Nlm_MonitorFree(row_monitor);
3251 Nlm_Update();
3252
3253 /* finish up */
3254 png_write_end(png_ptr, info_ptr);
3255
3256
3257 /* restore context and clean up */
3258 cleanup:
3259
3260 if (out) fclose(out);
3261
3262 #if defined(WIN_MOTIF)
3263 gotAnXError = FALSE;
3264 if (glCtx) {
3265 glXMakeCurrent(Nlm_currentXDisplay, currentXdrw, currentCtx);
3266 glXDestroyContext(Nlm_currentXDisplay, glCtx);
3267 }
3268 glXDestroyGLXPixmap(Nlm_currentXDisplay, glxPixmap);
3269 XFreePixmap(Nlm_currentXDisplay, xPixmap);
3270 if (localVI && visinfo) XFree(visinfo);
3271 if (gotAnXError) {
3272 Message(MSG_ERROR, "Got an X error destroying GLXPixmap context");
3273 }
3274 XSetErrorHandler(currentXErrHandler);
3275
3276 #elif defined(WIN_MSWIN)
3277 if (current_hdc && current_hglrc) wglMakeCurrent(current_hdc, current_hglrc);
3278 if (hglrc) wglDeleteContext(hglrc);
3279 /*if (current_hgdiobj) SelectObject(hdc, current_hgdiobj);*/
3280 if (hbm) DeleteObject(hbm);
3281 if (hdc) DeleteDC(hdc);
3282
3283 #elif defined(WIN_MAC)
3284 aglSetCurrentContext(currentCtx);
3285 if (ctx) aglDestroyContext(ctx);
3286 if (fmt) aglDestroyPixelFormat(fmt);
3287 if (base) MemFree(base);
3288
3289 #endif
3290
3291 if (row) MemFree(row);
3292 if (png_ptr) {
3293 if (info_ptr)
3294 png_destroy_write_struct(&png_ptr, &info_ptr);
3295 else
3296 png_destroy_write_struct(&png_ptr, NULL);
3297 }
3298
3299 /* redraw in case progress meter overwrote part of GL area */
3300 OGL_DrawViewer3D(OGL_Data);
3301 }
3302
3303 #endif /* _PNG */
3304
3305
3306 /* create display list with logo */
OGL_DrawLogo(TOGL_Data * OGL_Data)3307 NLM_EXTERN void OGL_DrawLogo(TOGL_Data *OGL_Data)
3308 {
3309 DDV_ColorCell colorCell;
3310 Uint1 logoColor[3] = { 100, 240, 150 };
3311 int i, n, s, g;
3312
3313 #define LOGO_SIDES 36
3314 int segments = 180;
3315 GLdouble bigRad = 12.0, height = 24.0,
3316 minRad = 0.1, maxRad = 2.0,
3317 ringPts[LOGO_SIDES * 3], *pRingPts = ringPts,
3318 prevRing[LOGO_SIDES * 3], *pPrevRing = prevRing, *tmp,
3319 ringNorm[LOGO_SIDES * 3], *pRingNorm = ringNorm,
3320 prevNorm[LOGO_SIDES * 3], *pPrevNorm = prevNorm,
3321 PI = acos(-1), length,
3322 startRad, midRad, phase, currentRad, CR[3], H[3], V[3];
3323
3324 if (!OGL_Data || OGL_Data->IndexMode) return;
3325
3326 /* set up initial camera */
3327 OGL_Data->CameraDistance = 200.0;
3328 OGL_Data->CameraDirection[0] = 0.0;
3329 OGL_Data->CameraDirection[1] = 0.0;
3330 OGL_Data->CameraAngle = acos(-1) / 14;
3331 OGL_Data->NeedCameraSetup = TRUE;
3332 glMatrixMode(GL_MODELVIEW);
3333 glLoadIdentity();
3334 glGetDoublev(GL_MODELVIEW_MATRIX, (GLdouble *) OGL_Data->ModelMatrix);
3335
3336 glNewList(1, GL_COMPILE);
3337
3338 /* create logo */
3339 DDV_SetColorInCell(&colorCell, logoColor);
3340 OGL_SetColor(OGL_Data, &colorCell, GL_DIFFUSE, 1.0);
3341
3342 for (n = 0; n < 2; n++) { /* helix strand */
3343 if (n == 0) {
3344 startRad = maxRad;
3345 midRad = minRad;
3346 phase = 0;
3347 } else {
3348 startRad = minRad;
3349 midRad = maxRad;
3350 phase = PI;
3351 }
3352 for (g = 0; g <= segments; g++) { /* segment (bottom to top) */
3353
3354 if (g < segments/2)
3355 currentRad = startRad + (midRad - startRad) *
3356 (0.5 - 0.5 * cos(PI * g / (segments/2)));
3357 else
3358 currentRad = midRad + (startRad - midRad) *
3359 (0.5 - 0.5 * cos(PI * (g - segments/2) / (segments/2)));
3360
3361 CR[1] = height * g / segments - height/2;
3362 if (g > 0) phase += PI * 2 / segments;
3363 CR[2] = bigRad * cos(phase);
3364 CR[0] = bigRad * sin(phase);
3365
3366 /* make a strip around the strand circumference */
3367 for (s = 0; s < LOGO_SIDES; s++) {
3368 V[0] = CR[0];
3369 V[2] = CR[2];
3370 V[1] = 0;
3371 length = sqrt(V[0]*V[0] + V[1]*V[1] + V[2]*V[2]);
3372 for (i = 0; i < 3; i++) V[i] /= length;
3373 H[0] = H[2] = 0;
3374 H[1] = 1;
3375 for (i = 0; i < 3; i++) {
3376 pRingNorm[3*s + i] = V[i] * cos(PI * 2 * s / LOGO_SIDES) +
3377 H[i] * sin(PI * 2 * s / LOGO_SIDES);
3378 pRingPts[3*s + i] = CR[i] + pRingNorm[3*s + i] * currentRad;
3379 }
3380 }
3381 if (g > 0) {
3382 glBegin(GL_TRIANGLE_STRIP);
3383 for (s = 0; s < LOGO_SIDES; s++) {
3384 glNormal3d(pPrevNorm[3*s], pPrevNorm[3*s + 1], pPrevNorm[3*s + 2]);
3385 glVertex3d(pPrevRing[3*s], pPrevRing[3*s + 1], pPrevRing[3*s + 2]);
3386 glNormal3d(pRingNorm[3*s], pRingNorm[3*s + 1], pRingNorm[3*s + 2]);
3387 glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]);
3388 }
3389 glNormal3d(pPrevNorm[0], pPrevNorm[1], pPrevNorm[2]);
3390 glVertex3d(pPrevRing[0], pPrevRing[1], pPrevRing[2]);
3391 glNormal3d(pRingNorm[0], pRingNorm[1], pRingNorm[2]);
3392 glVertex3d(pRingPts[0], pRingPts[1], pRingPts[2]);
3393 glEnd();
3394 }
3395
3396 /* cap the ends */
3397 glBegin(GL_POLYGON);
3398 if ((g == 0 && n == 0) || (g == segments && n == 1))
3399 glNormal3d(-1, 0, 0);
3400 else
3401 glNormal3d(1, 0, 0);
3402 if (g == 0) {
3403 for (s = 0; s < LOGO_SIDES; s++)
3404 glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]);
3405 } else if (g == segments) {
3406 for (s = LOGO_SIDES - 1; s >= 0; s--)
3407 glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]);
3408 }
3409 glEnd();
3410
3411 /* switch pointers to store previous ring */
3412 tmp = pPrevRing;
3413 pPrevRing = pRingPts;
3414 pRingPts = tmp;
3415 tmp = pPrevNorm;
3416 pPrevNorm = pRingNorm;
3417 pRingNorm = tmp;
3418 }
3419 }
3420
3421 glEndList();
3422
3423 OGL_Data->Layers->SelectedLayer = 1; /* fool DrawViewer3D into thinking there's a single structure */
3424 OGL_DrawViewer3D(OGL_Data);
3425 }
3426
3427 #endif /* _OPENGL */
3428
3429
3430 /* this function "shared" by both vibrant and OpenGL versions */
3431 #ifdef _OPENGL
3432 /* add a thick splined curve from point 1 *halfway* to point 2 */
Nlm_AddHalfWorm3D(TOGL_Data * OGL_Data,DDV_ColorCell * color,Nlm_FloatHi x0,Nlm_FloatHi y0,Nlm_FloatHi z0,Nlm_FloatHi x1,Nlm_FloatHi y1,Nlm_FloatHi z1,Nlm_FloatHi x2,Nlm_FloatHi y2,Nlm_FloatHi z2,Nlm_FloatHi x3,Nlm_FloatHi y3,Nlm_FloatHi z3,Nlm_Boolean cap1,Nlm_Boolean cap2,Nlm_FloatHi radius,Nlm_Int4 segments,Nlm_Int4 sides)3433 void Nlm_AddHalfWorm3D(TOGL_Data * OGL_Data, DDV_ColorCell * color,
3434 Nlm_FloatHi x0, Nlm_FloatHi y0, Nlm_FloatHi z0,
3435 Nlm_FloatHi x1, Nlm_FloatHi y1, Nlm_FloatHi z1,
3436 Nlm_FloatHi x2, Nlm_FloatHi y2, Nlm_FloatHi z2,
3437 Nlm_FloatHi x3, Nlm_FloatHi y3, Nlm_FloatHi z3,
3438 Nlm_Boolean cap1, Nlm_Boolean cap2, Nlm_FloatHi radius,
3439 Nlm_Int4 segments, Nlm_Int4 sides)
3440 #else
3441 typedef Nlm_FloatLo GLfloat;
3442 typedef Nlm_FloatHi GLdouble;
3443 void Nlm_AddHalfWorm3D(Nlm_Picture3D pic,
3444 Nlm_Segment3D segment, BigScalar userData,
3445 Uint1 layer, Uint1 color,
3446 Nlm_FloatHi x0, Nlm_FloatHi y0, Nlm_FloatHi z0,
3447 Nlm_FloatHi x1, Nlm_FloatHi y1, Nlm_FloatHi z1,
3448 Nlm_FloatHi x2, Nlm_FloatHi y2, Nlm_FloatHi z2,
3449 Nlm_FloatHi x3, Nlm_FloatHi y3, Nlm_FloatHi z3,
3450 Nlm_FloatHi radius, Nlm_Int4 segments)
3451 #endif
3452 {
3453 Nlm_Int4 i, j, k, m, offset;
3454 GLdouble len, R1x, R1y, R1z, R2x, R2y, R2z, MG[4][3],
3455 T[4], t, Qtx, Qty, Qtz, px, py, pz,
3456 dQtx, dQty, dQtz, /*ddQtx, ddQty, ddQtz,*/
3457 Hx, Hy, Hz, Vx, Vy, Vz, prevlen,
3458 cosj, sinj, pi = 3.14159265358979323846;
3459 GLdouble *Nx = NULL, *Ny, *Nz, *Cx, *Cy, *Cz,
3460 *pNx, *pNy, *pNz, *pCx, *pCy, *pCz, *tmp, *fblock = NULL;
3461 /*
3462 * The Hermite matrix Mh.
3463 */
3464 static Nlm_FloatHi Mh[4][4] = {
3465 { 2, -2, 1, 1},
3466 {-3, 3, -2, -1},
3467 { 0, 0, 1, 0},
3468 { 1, 0, 0, 0}
3469 };
3470 /*
3471 * Variables that affect the curve shape
3472 * a=b=0 = Catmull-Rom
3473 */
3474 static Nlm_FloatHi a = -0.8, /* tension (adjustable) */
3475 c = 0, /* continuity (should be 0) */
3476 b = 0; /* bias (should be 0) */
3477
3478 #ifdef _OPENGL
3479 if (radius > 0.0) { /* if line, color assigned in OGL_AddLine3D */
3480 if (OGL_Data == NULL || color == NULL)
3481 return;
3482
3483 OGL_SetColor(OGL_Data, color, GL_DIFFUSE, 1.0);
3484
3485 if (sides % 2)
3486 sides++; /* must be an even number! */
3487 }
3488 #endif
3489
3490 /* First, calculate the coordinate points of the center of the worm,
3491 * using the Kochanek-Bartels variant of the Hermite curve.
3492 */
3493 R1x = 0.5 * (1 - a) * (1 + b) * (1 + c) * (x1 - x0) +
3494 0.5 * (1 - a) * (1 - b) * (1 - c) * (x2 - x1);
3495 R1y = 0.5 * (1 - a) * (1 + b) * (1 + c) * (y1 - y0) +
3496 0.5 * (1 - a) * (1 - b) * (1 - c) * (y2 - y1);
3497 R1z = 0.5 * (1 - a) * (1 + b) * (1 + c) * (z1 - z0) +
3498 0.5 * (1 - a) * (1 - b) * (1 - c) * (z2 - z1);
3499 R2x = 0.5 * (1 - a) * (1 + b) * (1 - c) * (x2 - x1) +
3500 0.5 * (1 - a) * (1 - b) * (1 + c) * (x3 - x2);
3501 R2y = 0.5 * (1 - a) * (1 + b) * (1 - c) * (y2 - y1) +
3502 0.5 * (1 - a) * (1 - b) * (1 + c) * (y3 - y2);
3503 R2z = 0.5 * (1 - a) * (1 + b) * (1 - c) * (z2 - z1) +
3504 0.5 * (1 - a) * (1 - b) * (1 + c) * (z3 - z2);
3505 /*
3506 * Multiply MG=Mh.Gh, where Gh = [ P(1) P(2) R(1) R(2) ]. This
3507 * 4x1 matrix of vectors is constant for each segment.
3508 */
3509 for (i = 0; i < 4; i++) { /* calculate Mh.Gh */
3510 MG[i][0] =
3511 Mh[i][0] * x1 + Mh[i][1] * x2 + Mh[i][2] * R1x +
3512 Mh[i][3] * R2x;
3513 MG[i][1] =
3514 Mh[i][0] * y1 + Mh[i][1] * y2 + Mh[i][2] * R1y +
3515 Mh[i][3] * R2y;
3516 MG[i][2] =
3517 Mh[i][0] * z1 + Mh[i][1] * z2 + Mh[i][2] * R1z +
3518 Mh[i][3] * R2z;
3519 }
3520
3521 for (i = 0; i <= segments; i++) {
3522
3523 /* t goes from [0,1] from P(1) to P(2) (and we want to go halfway only),
3524 and the function Q(t) defines the curve of this segment. */
3525 t = (0.5 / segments) * i;
3526 /*
3527 * Q(t)=T.(Mh.Gh), where T = [ t^3 t^2 t 1 ]
3528 */
3529 T[0] = t * t * t;
3530 T[1] = t * t;
3531 T[2] = t;
3532 T[3] = 1;
3533 Qtx = T[0] * MG[0][0] + T[1] * MG[1][0] + T[2] * MG[2][0] + MG[3][0] /* *T[3] */
3534 ;
3535 Qty = T[0] * MG[0][1] + T[1] * MG[1][1] + T[2] * MG[2][1] + MG[3][1] /* *T[3] */
3536 ;
3537 Qtz = T[0] * MG[0][2] + T[1] * MG[1][2] + T[2] * MG[2][2] + MG[3][2] /* *T[3] */
3538 ;
3539
3540 #ifndef _OPENGL
3541 if (i > 0) {
3542 Int4 iX0, iY0, iZ0, iX1, iY1, iZ1;
3543
3544 /* number 1000000.0 must be same as VIEWSCALE in algorend.c! */
3545 iX0 = (Int4) (px * 1000000.0);
3546 iY0 = (Int4) (py * 1000000.0);
3547 iZ0 = (Int4) (pz * 1000000.0);
3548 iX1 = (Int4) (Qtx * 1000000.0);
3549 iY1 = (Int4) (Qty * 1000000.0);
3550 iZ1 = (Int4) (Qtz * 1000000.0);
3551 AddLine3D(pic, segment, userData, layer, color,
3552 iX0, iY0, iZ0, iX1, iY1, iZ1);
3553 }
3554 /* save to use as previous point for connecting points together */
3555 px = Qtx;
3556 py = Qty;
3557 pz = Qtz;
3558
3559 #else
3560 if (radius == 0.0) {
3561 if (i > 0)
3562 OGL_AddLine3D(OGL_Data, color, px, py, pz, Qtx, Qty, Qtz);
3563 /* save to use as previous point for connecting points together */
3564 px = Qtx;
3565 py = Qty;
3566 pz = Qtz;
3567
3568 } else {
3569 /* construct a circle of points centered at and
3570 in a plane normal to the curve at t - these points will
3571 be used to construct the "thick" worm */
3572
3573 /* allocate single block of storage for two circles of points */
3574 if (!Nx) {
3575 fblock = Nx = MemNew(sizeof(Nlm_FloatHi) * 12 * sides);
3576 if (!Nx)
3577 return;
3578 Ny = &Nx[sides];
3579 Nz = &Nx[sides * 2];
3580 Cx = &Nx[sides * 3];
3581 Cy = &Nx[sides * 4];
3582 Cz = &Nx[sides * 5];
3583 pNx = &Nx[sides * 6];
3584 pNy = &Nx[sides * 7];
3585 pNz = &Nx[sides * 8];
3586 pCx = &Nx[sides * 9];
3587 pCy = &Nx[sides * 10];
3588 pCz = &Nx[sides * 11];
3589 }
3590
3591 /*
3592 * The first derivative of Q(t), d(Q(t))/dt, is the slope
3593 * (tangent) at point Q(t); now T = [ 3t^2 2t 1 0 ]
3594 */
3595 T[0] = t * t * 3;
3596 T[1] = t * 2;
3597 T[2] = 1;
3598 T[3] = 0;
3599 dQtx =
3600 T[0] * MG[0][0] + T[1] * MG[1][0] +
3601 MG[2][0] /* *T[2] + T[3]*MG[3][0] */ ;
3602 dQty =
3603 T[0] * MG[0][1] + T[1] * MG[1][1] +
3604 MG[2][1] /* *T[2] + T[3]*MG[3][1] */ ;
3605 dQtz =
3606 T[0] * MG[0][2] + T[1] * MG[1][2] +
3607 MG[2][2] /* *T[2] + T[3]*MG[3][2] */ ;
3608
3609 /* use cross prod't of [1,0,0] x normal as horizontal */
3610 Hx = 0.0;
3611 Hy = -dQtz;
3612 Hz = dQty;
3613 len = sqrt(Hy * Hy + Hz * Hz);
3614 if (len < 0.000001) { /* nearly colinear - use [1,0.1,0] instead */
3615 Hx = 0.1 * dQtz;
3616 Hy = -dQtz;
3617 Hz = dQty - 0.1 * dQtx;
3618 }
3619 Hx /= len;
3620 Hy /= len;
3621 Hz /= len;
3622
3623 /* and a vertical vector = normal x H */
3624 Vx = dQty * Hz - dQtz * Hy;
3625 Vy = dQtz * Hx - dQtx * Hz;
3626 Vz = dQtx * Hy - dQty * Hx;
3627 len = sqrt(Vx * Vx + Vy * Vy + Vz * Vz);
3628 Vx /= len;
3629 Vy /= len;
3630 Vz /= len;
3631
3632 /* finally, the worm circumference points (C) and normals (N) are
3633 simple trigonomic combinations of H and V */
3634 for (j = 0; j < sides; j++) {
3635 cosj = cos(2 * pi * j / sides);
3636 sinj = sin(2 * pi * j / sides);
3637 Nx[j] = Hx * cosj + Vx * sinj;
3638 Ny[j] = Hy * cosj + Vy * sinj;
3639 Nz[j] = Hz * cosj + Vz * sinj;
3640 Cx[j] = Qtx + Nx[j] * radius;
3641 Cy[j] = Qty + Ny[j] * radius;
3642 Cz[j] = Qtz + Nz[j] * radius;
3643 }
3644
3645 /* figure out which points on the previous circle "match" best
3646 with these, to minimize envelope twisting */
3647 for (m = 0; m < sides; m++) {
3648 len = 0.0;
3649 for (j = 0; j < sides; j++) {
3650 k = j + m;
3651 if (k >= sides)
3652 k -= sides;
3653 len += (Cx[k] - pCx[j]) * (Cx[k] - pCx[j]) +
3654 (Cy[k] - pCy[j]) * (Cy[k] - pCy[j]) +
3655 (Cz[k] - pCz[j]) * (Cz[k] - pCz[j]);
3656 }
3657 if (m == 0 || len < prevlen) {
3658 prevlen = len;
3659 offset = m;
3660 }
3661 }
3662
3663 /* create triangles from points along this and previous circle */
3664 if (i > 0) {
3665 glBegin(GL_TRIANGLE_STRIP);
3666 for (j = 0; j < sides; j++) {
3667 k = j + offset;
3668 if (k >= sides) k -= sides;
3669 glNormal3d(Nx[k], Ny[k], Nz[k]);
3670 glVertex3d(Cx[k], Cy[k], Cz[k]);
3671 glNormal3d(pNx[j], pNy[j], pNz[j]);
3672 glVertex3d(pCx[j], pCy[j], pCz[j]);
3673 }
3674 glNormal3d(Nx[offset], Ny[offset], Nz[offset]);
3675 glVertex3d(Cx[offset], Cy[offset], Cz[offset]);
3676 glNormal3d(pNx[0], pNy[0], pNz[0]);
3677 glVertex3d(pCx[0], pCy[0], pCz[0]);
3678 glEnd();
3679 }
3680
3681 /* put caps on the end */
3682 if (cap1 && i == 0) {
3683 glBegin(GL_POLYGON);
3684 len = sqrt(dQtx*dQtx + dQty*dQty + dQtz*dQtz);
3685 dQtx /= len; dQty /= len; dQtz /= len;
3686 glNormal3d(-dQtx, -dQty, -dQtz);
3687 for (j = sides - 1; j >= 0; j--) {
3688 k = j + offset;
3689 if (k >= sides) k -= sides;
3690 glVertex3d(Cx[k], Cy[k], Cz[k]);
3691 }
3692 glEnd();
3693 }
3694 else if (cap2 && i == segments) {
3695 glBegin(GL_POLYGON);
3696 len = sqrt(dQtx*dQtx + dQty*dQty + dQtz*dQtz);
3697 dQtx /= len; dQty /= len; dQtz /= len;
3698 glNormal3d(dQtx, dQty, dQtz);
3699 for (j = 0; j < sides; j++) {
3700 k = j + offset;
3701 if (k >= sides) k -= sides;
3702 glVertex3d(Cx[k], Cy[k], Cz[k]);
3703 }
3704 glEnd();
3705 }
3706
3707 /* store this circle as previous for next round; instead of copying
3708 all values, just swap pointers */
3709 #define SWAPPTR(p1,p2) tmp=(p1); (p1)=(p2); (p2)=tmp
3710 SWAPPTR(Nx, pNx);
3711 SWAPPTR(Ny, pNy);
3712 SWAPPTR(Nz, pNz);
3713 SWAPPTR(Cx, pCx);
3714 SWAPPTR(Cy, pCy);
3715 SWAPPTR(Cz, pCz);
3716 }
3717 #endif
3718
3719 }
3720 if (fblock)
3721 MemFree(fblock);
3722 }
3723
3724