Main Page Namespace List Class Hierarchy Alphabetical List Compound List File List Namespace Members Compound Members File Members Related Pages

OpenGLRenderer.C

Go to the documentation of this file.
00001 /***************************************************************************
00002 *cr 
00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 
00004 *cr University of Illinois 
00005 *cr All Rights Reserved 
00006 *cr 
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010 * RCS INFORMATION:
00011 *
00012 * $RCSfile: OpenGLRenderer.C,v $
00013 * $Author: johns $ $Locker: $ $State: Exp $
00014 * $Revision: 1.479 $ $Date: 2024年03月01日 01:47:51 $
00015 *
00016 ***************************************************************************/
00033 #include "OpenGLRenderer.h"
00034 #include "DispCmds.h"
00035 #include "Inform.h"
00036 #include "utilities.h"
00037 #include "VMDDisplayList.h"
00038 #include "Hershey.h"
00039 
00040 #include <stdlib.h>
00041 #include <stdio.h>
00042 #include <math.h>
00043 #include "OpenGLStipples.h"
00044 
00045 #if defined(VMDOPTIXRTRT)
00046 #include "OptiXRenderer.h"
00047 #endif
00048 
00049 // enable WireGL support
00050 #define VMDWIREGL 1
00051 
00052 // enable Intel SWR support
00053 #define VMDINTELSWR 1
00054 
00055 #if defined(VMDUSEOPENGLSHADER)
00056 #define VMDUSEGLSLSPHERES 1
00057 #if defined(GL_ARB_point_sprite)
00058 #define VMDUSEGLSLSPHERESPRITES 1
00059 #endif
00060 #endif
00061 
00062 #if 0
00063 #define OGLERR { GLenum err; if ((err = glGetError()) != GL_NO_ERROR) { \
00064 msgErr << __FILE__ << " line " << __LINE__ << " " << \
00065 (const char *) gluErrorString(err) << sendmsg; }}
00066 #else 
00067 #define OGLERR
00068 #endif
00069 
00070 #define MIN_SPHERE_RES 4
00071 #define MAX_SPHERE_RES 30
00072 
00073 #if defined(VMDUSELIBGLU) 
00074 #define vmd_Project gluProject
00075 #define vmd_UnProject gluUnProject
00076 #else
00077 //
00078 // VMD-internal replacements for GLU routines
00079 //
00080 static void vmd_matmult_4x4d(GLdouble *r, const GLdouble *m1, 
00081 const GLdouble *m2) {
00082 r[ 0]=m1[0]*m2[ 0] + m1[4]*m2[ 1] + m1[ 8]*m2[ 2] + m1[12]*m2[ 3];
00083 r[ 4]=m1[0]*m2[ 4] + m1[4]*m2[ 5] + m1[ 8]*m2[ 6] + m1[12]*m2[ 7];
00084 r[ 8]=m1[0]*m2[ 8] + m1[4]*m2[ 9] + m1[ 8]*m2[10] + m1[12]*m2[11];
00085 r[12]=m1[0]*m2[12] + m1[4]*m2[13] + m1[ 8]*m2[14] + m1[12]*m2[15];
00086 
00087 r[ 1]=m1[1]*m2[ 0] + m1[5]*m2[ 1] + m1[ 9]*m2[ 2] + m1[13]*m2[ 3];
00088 r[ 5]=m1[1]*m2[ 4] + m1[5]*m2[ 5] + m1[ 9]*m2[ 6] + m1[13]*m2[ 7];
00089 r[ 9]=m1[1]*m2[ 8] + m1[5]*m2[ 9] + m1[ 9]*m2[10] + m1[13]*m2[11];
00090 r[13]=m1[1]*m2[12] + m1[5]*m2[13] + m1[ 9]*m2[14] + m1[13]*m2[15];
00091 
00092 r[ 2]=m1[2]*m2[ 0] + m1[6]*m2[ 1] + m1[10]*m2[ 2] + m1[14]*m2[ 3];
00093 r[ 6]=m1[2]*m2[ 4] + m1[6]*m2[ 5] + m1[10]*m2[ 6] + m1[14]*m2[ 7];
00094 r[10]=m1[2]*m2[ 8] + m1[6]*m2[ 9] + m1[10]*m2[10] + m1[14]*m2[11];
00095 r[14]=m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
00096 
00097 r[ 3]=m1[3]*m2[ 0] + m1[7]*m2[ 1] + m1[11]*m2[ 2] + m1[15]*m2[ 3];
00098 r[ 7]=m1[3]*m2[ 4] + m1[7]*m2[ 5] + m1[11]*m2[ 6] + m1[15]*m2[ 7];
00099 r[11]=m1[3]*m2[ 8] + m1[7]*m2[ 9] + m1[11]*m2[10] + m1[15]*m2[11];
00100 r[15]=m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
00101 }
00102 
00103 
00104 static void vmd_matmultvec_4x4d(GLdouble *npoint, const GLdouble *opoint, 
00105 const GLdouble *mat) {
00106 npoint[0]=opoint[0]*mat[0]+opoint[1]*mat[4]+opoint[2]*mat[8]+opoint[3]*mat[12];
00107 npoint[1]=opoint[0]*mat[1]+opoint[1]*mat[5]+opoint[2]*mat[9]+opoint[3]*mat[13];
00108 npoint[2]=opoint[0]*mat[2]+opoint[1]*mat[6]+opoint[2]*mat[10]+opoint[3]*mat[14];
00109 npoint[3]=opoint[0]*mat[3]+opoint[1]*mat[7]+opoint[2]*mat[11]+opoint[3]*mat[15];
00110 }
00111 
00112 #define SWAP_ROWS_DOUBLE(a, b) { double *_tmp = a; (a)=(b); (b)=_tmp; }
00113 #define SWAP_ROWS_FLOAT(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; }
00114 #define SWAP_ROWS SWAP_ROWS_DOUBLE
00115 #define MAT(m,r,c) (m)[(c)*4+(r)]
00116 
00117 
00118 static int vmd_invert_mat_4x4d(const GLdouble *m, GLdouble *out) {
00119 double wtmp[4][8];
00120 double m0, m1, m2, m3, s;
00121 double *r0, *r1, *r2, *r3;
00122 
00123 r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
00124 
00125 r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1),
00126 r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3),
00127 r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
00128 r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1),
00129 r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3),
00130 r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
00131 r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1),
00132 r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3),
00133 r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
00134 r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1),
00135 r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3),
00136 r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
00137 
00138 /* choose pivot - or die */
00139 if (fabs(r3[0]) > fabs(r2[0]))
00140 SWAP_ROWS(r3, r2);
00141 if (fabs(r2[0]) > fabs(r1[0]))
00142 SWAP_ROWS(r2, r1);
00143 if (fabs(r1[0]) > fabs(r0[0]))
00144 SWAP_ROWS(r1, r0);
00145 if (0.0 == r0[0])
00146 return 0;
00147 
00148 /* eliminate first variable */
00149 m1 = r1[0] / r0[0];
00150 m2 = r2[0] / r0[0];
00151 m3 = r3[0] / r0[0];
00152 s = r0[1];
00153 r1[1] -= m1 * s;
00154 r2[1] -= m2 * s;
00155 r3[1] -= m3 * s;
00156 s = r0[2];
00157 r1[2] -= m1 * s;
00158 r2[2] -= m2 * s;
00159 r3[2] -= m3 * s;
00160 s = r0[3];
00161 r1[3] -= m1 * s;
00162 r2[3] -= m2 * s;
00163 r3[3] -= m3 * s;
00164 s = r0[4];
00165 if (s != 0.0) {
00166 r1[4] -= m1 * s;
00167 r2[4] -= m2 * s;
00168 r3[4] -= m3 * s;
00169 }
00170 s = r0[5];
00171 if (s != 0.0) {
00172 r1[5] -= m1 * s;
00173 r2[5] -= m2 * s;
00174 r3[5] -= m3 * s;
00175 }
00176 s = r0[6];
00177 if (s != 0.0) {
00178 r1[6] -= m1 * s;
00179 r2[6] -= m2 * s;
00180 r3[6] -= m3 * s;
00181 }
00182 s = r0[7];
00183 if (s != 0.0) {
00184 r1[7] -= m1 * s;
00185 r2[7] -= m2 * s;
00186 r3[7] -= m3 * s;
00187 }
00188 
00189 /* choose pivot - or die */
00190 if (fabs(r3[1]) > fabs(r2[1]))
00191 SWAP_ROWS(r3, r2);
00192 if (fabs(r2[1]) > fabs(r1[1]))
00193 SWAP_ROWS(r2, r1);
00194 if (0.0 == r1[1])
00195 return 0;
00196 
00197 /* eliminate second variable */
00198 m2 = r2[1] / r1[1];
00199 m3 = r3[1] / r1[1];
00200 r2[2] -= m2 * r1[2];
00201 r3[2] -= m3 * r1[2];
00202 r2[3] -= m2 * r1[3];
00203 r3[3] -= m3 * r1[3];
00204 s = r1[4];
00205 if (0.0 != s) {
00206 r2[4] -= m2 * s;
00207 r3[4] -= m3 * s;
00208 }
00209 s = r1[5];
00210 if (0.0 != s) {
00211 r2[5] -= m2 * s;
00212 r3[5] -= m3 * s;
00213 }
00214 s = r1[6];
00215 if (0.0 != s) {
00216 r2[6] -= m2 * s;
00217 r3[6] -= m3 * s;
00218 }
00219 s = r1[7];
00220 if (0.0 != s) {
00221 r2[7] -= m2 * s;
00222 r3[7] -= m3 * s;
00223 }
00224 
00225 /* choose pivot - or die */
00226 if (fabs(r3[2]) > fabs(r2[2]))
00227 SWAP_ROWS(r3, r2);
00228 if (0.0 == r2[2])
00229 return 0;
00230 
00231 /* eliminate third variable */
00232 m3 = r3[2] / r2[2];
00233 r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
00234 r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7];
00235 
00236 /* last check */
00237 if (0.0 == r3[3])
00238 return 0;
00239 
00240 s = 1.0 / r3[3]; /* now back substitute row 3 */
00241 r3[4] *= s;
00242 r3[5] *= s;
00243 r3[6] *= s;
00244 r3[7] *= s;
00245 
00246 m2 = r2[3]; /* now back substitute row 2 */
00247 s = 1.0 / r2[2];
00248 r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
00249 r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
00250 
00251 m1 = r1[3];
00252 r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
00253 r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
00254 
00255 m0 = r0[3];
00256 r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
00257 r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
00258 
00259 m1 = r1[2]; /* now back substitute row 1 */
00260 s = 1.0 / r1[1];
00261 r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
00262 r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
00263 m0 = r0[2];
00264 r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
00265 r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
00266 
00267 m0 = r0[1]; /* now back substitute row 0 */
00268 s = 1.0 / r0[0];
00269 r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
00270 r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
00271 
00272 MAT(out, 0, 0) = r0[4];
00273 MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
00274 MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
00275 MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
00276 MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
00277 MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
00278 MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
00279 MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
00280 MAT(out, 3, 3) = r3[7];
00281 
00282 return 1;
00283 }
00284 
00285 
00286 static GLdouble * vmd_vec_normalize_3d(GLdouble *vect) {
00287 GLdouble len2 = vect[0]*vect[0] + vect[1]*vect[1] + vect[2]*vect[2];
00288 
00289 // prevent division by zero
00290 if (len2 > 0) {
00291 GLdouble rescale = 1.0 / sqrt(len2);
00292 vect[0] *= rescale;
00293 vect[1] *= rescale;
00294 vect[2] *= rescale;
00295 }
00296 
00297 return vect;
00298 }
00299 
00300 
00301 static GLdouble * vmd_cross_3d(GLdouble *x1, const GLdouble *x2, 
00302 const GLdouble *x3) {
00303 x1[0] = x2[1]*x3[2] - x3[1]*x2[2];
00304 x1[1] = -x2[0]*x3[2] + x3[0]*x2[2];
00305 x1[2] = x2[0]*x3[1] - x3[0]*x2[1];
00306 
00307 return x1;
00308 }
00309 
00310 
00311 static void vmd_mattrans_d(GLdouble *m, GLdouble x, GLdouble y, GLdouble z) {
00312 m[12] = m[0]*x + m[4]*y + m[ 8]*z + m[12];
00313 m[13] = m[1]*x + m[5]*y + m[ 9]*z + m[13];
00314 m[14] = m[2]*x + m[6]*y + m[10]*z + m[14];
00315 m[15] = m[3]*x + m[7]*y + m[11]*z + m[15];
00316 }
00317 
00318 
00319 static void vmd_mat_identity_4x4d(GLdouble *m) {
00320 memset((void *)m, 0, 16*sizeof(GLdouble));
00321 m[0]=1.0;
00322 m[5]=1.0;
00323 m[10]=1.0;
00324 m[15]=1.0;
00325 }
00326 
00327 
00328 #define SPHEREMAXRES 30
00329 static void vmd_DrawSphere(float rad, int res, int solid) {
00330 int i, j;
00331 float zLo, zHi, radLo, radHi, stn, ctn;
00332 
00333 float sinLong[SPHEREMAXRES];
00334 float cosLong[SPHEREMAXRES];
00335 float sinLatVert[SPHEREMAXRES];
00336 float cosLatVert[SPHEREMAXRES];
00337 float sinLatNorm[SPHEREMAXRES];
00338 float cosLatNorm[SPHEREMAXRES];
00339 
00340 if (res < 2)
00341 res = 2;
00342 
00343 if (res >= SPHEREMAXRES)
00344 res = SPHEREMAXRES-1;
00345 
00346 // longitudinal "slices"
00347 float ang_twopi_res = VMD_TWOPIF / res;
00348 for (i=0; i<res; i++) {
00349 float angle = i * ang_twopi_res;
00350 sincosf(angle, &sinLong[i], &cosLong[i]);
00351 }
00352 // ensure that longitude end point exactly matches start
00353 sinLong[res] = 0.0f; // sinLong[0]
00354 cosLong[res] = 1.0f; // cosLong[0]
00355 
00356 // latitude "stacks"
00357 float ang_pi_res = VMD_PIF / res;
00358 for (i=0; i<=res; i++) {
00359 float angle = i * ang_pi_res;
00360 sincosf(angle, &sinLatNorm[i], &cosLatNorm[i]);
00361 sinLatVert[i] = rad * sinLatNorm[i];
00362 cosLatVert[i] = rad * cosLatNorm[i];
00363 }
00364 // ensure top and bottom poles come to points
00365 sinLatVert[0] = 0;
00366 sinLatVert[res] = 0;
00367 
00368 // draw sphere caps as triangle fans, lower cap, j==0
00369 if (solid) {
00370 radLo = sinLatVert[1];
00371 zLo = cosLatVert[1];
00372 stn = sinLatNorm[1];
00373 ctn = cosLatNorm[1];
00374 
00375 glNormal3f(sinLong[0] * sinLatNorm[0], 
00376 cosLong[0] * sinLatNorm[0], 
00377 cosLatNorm[0]);
00378 
00379 glBegin(GL_TRIANGLE_FAN);
00380 glVertex3f(0.0, 0.0, rad);
00381 for (i=res; i>=0; i--) {
00382 glNormal3f(sinLong[i] * stn, cosLong[i] * stn, ctn);
00383 glVertex3f(radLo * sinLong[i], radLo * cosLong[i], zLo);
00384 }
00385 glEnd();
00386 }
00387 
00388 // draw sphere caps as triangle fans, high cap, j==(res-1)
00389 radHi = sinLatVert[res-1];
00390 zHi = cosLatVert[res-1];
00391 stn = sinLatNorm[res-1];
00392 ctn = cosLatNorm[res-1];
00393 
00394 if (solid) {
00395 glNormal3f(sinLong[res] * sinLatNorm[res], 
00396 cosLong[res] * sinLatNorm[res], 
00397 cosLatNorm[res]);
00398 
00399 glBegin(GL_TRIANGLE_FAN);
00400 glVertex3f(0.0, 0.0, -rad);
00401 for (i=0; i<=res; i++) {
00402 glNormal3f(sinLong[i] * stn, cosLong[i] * stn, ctn);
00403 glVertex3f(radHi * sinLong[i], radHi * cosLong[i], zHi);
00404 }
00405 glEnd();
00406 } else {
00407 glBegin(GL_POINTS);
00408 glVertex3f(0.0, 0.0, rad); // draw both apex and base points at once
00409 glVertex3f(0.0, 0.0, -rad);
00410 for (i=0; i<=res; i++)
00411 glVertex3f(radHi * sinLong[i], radHi * cosLong[i], zHi);
00412 glEnd();
00413 }
00414 for (j=1; j<res-1; j++) {
00415 zLo = cosLatVert[j];
00416 zHi = cosLatVert[j+1];
00417 
00418 float stv1 = sinLatVert[j];
00419 float stv2 = sinLatVert[j+1];
00420 
00421 float stn1 = sinLatNorm[j];
00422 float ctn1 = cosLatNorm[j];
00423 float stn2 = sinLatNorm[j+1];
00424 float ctn2 = cosLatNorm[j+1];
00425 
00426 if (solid) {
00427 glBegin(GL_QUAD_STRIP);
00428 for (i=0; i<=res; i++) {
00429 glNormal3f(sinLong[i] * stn2, cosLong[i] * stn2, ctn2);
00430 glVertex3f(stv2 * sinLong[i], stv2 * cosLong[i], zHi);
00431 glNormal3f(sinLong[i] * stn1, cosLong[i] * stn1, ctn1);
00432 glVertex3f(stv1 * sinLong[i], stv1 * cosLong[i], zLo);
00433 }
00434 glEnd();
00435 } else {
00436 glBegin(GL_POINTS);
00437 for (i=0; i<=res; i++)
00438 glVertex3f(stv1 * sinLong[i], stv1 * cosLong[i], zLo);
00439 glEnd();
00440 }
00441 }
00442 }
00443 
00444 
00445 // Routine to draw a truncated cone with caps, adapted from the fallback
00446 // triangulated code path in FileRenderer::cone_trunc()
00447 static void vmd_DrawConic(float *base, float *apex, float radius, float radius2, int numsides) {
00448 int h;
00449 float theta, incTheta, cosTheta, sinTheta;
00450 float axis[3], temp[3], perp[3], perp2[3];
00451 float vert0[3], vert1[3], vert2[3], edge0[3], edge1[3], face0[3], face1[3], norm0[3], norm1[3];
00452 
00453 axis[0] = base[0] - apex[0];
00454 axis[1] = base[1] - apex[1];
00455 axis[2] = base[2] - apex[2];
00456 vec_normalize(axis);
00457 
00458 // Find an arbitrary vector that is not the axis and has non-zero length
00459 temp[0] = axis[0] - 1.0f;
00460 temp[1] = 1.0f;
00461 temp[2] = 1.0f;
00462 
00463 // use the cross product to find orthogonal vectors
00464 cross_prod(perp, axis, temp);
00465 vec_normalize(perp);
00466 cross_prod(perp2, axis, perp); // shouldn't need normalization
00467 
00468 // Draw the triangles
00469 incTheta = (float) VMD_TWOPI / numsides;
00470 theta = 0.0;
00471 
00472 // if radius2 is larger than zero, we will draw quadrilateral
00473 // panels rather than triangular panels
00474 if (radius2 > 0) {
00475 float negaxis[3], offsetL[3], offsetT[3], vert3[3];
00476 int filled=1;
00477 vec_negate(negaxis, axis);
00478 memset(vert0, 0, sizeof(vert0));
00479 memset(vert1, 0, sizeof(vert1));
00480 memset(norm0, 0, sizeof(norm0));
00481 
00482 glBegin(GL_TRIANGLES);
00483 for (h=0; h <= numsides+3; h++) {
00484 // project 2-D unit circles onto perp/perp2 3-D basis vectors
00485 // and scale to desired radii
00486 sincosf(theta, &sinTheta, &cosTheta);
00487 float projx = (cosTheta*perp[0] + sinTheta*perp2[0]);
00488 float projy = (cosTheta*perp[1] + sinTheta*perp2[1]);
00489 float projz = (cosTheta*perp[2] + sinTheta*perp2[2]);
00490 
00491 offsetL[0] = radius2 * projx;
00492 offsetL[1] = radius2 * projy;
00493 offsetL[2] = radius2 * projz;
00494 
00495 offsetT[0] = radius * projx;
00496 offsetT[1] = radius * projy;
00497 offsetT[2] = radius * projz;
00498 
00499 // copy old vertices
00500 vec_copy(vert2, vert0);
00501 vec_copy(vert3, vert1);
00502 vec_copy(norm1, norm0);
00503 
00504 // calculate new vertices
00505 vec_add(vert0, base, offsetT);
00506 vec_add(vert1, apex, offsetL);
00507 
00508 // Use the new vertex to find new edges
00509 edge0[0] = vert0[0] - vert1[0];
00510 edge0[1] = vert0[1] - vert1[1];
00511 edge0[2] = vert0[2] - vert1[2];
00512 edge1[0] = vert0[0] - vert2[0];
00513 edge1[1] = vert0[1] - vert2[1];
00514 edge1[2] = vert0[2] - vert2[2];
00515 
00516 // Use the new edge to find a new facet normal
00517 cross_prod(norm0, edge1, edge0);
00518 vec_normalize(norm0);
00519 
00520 if (h > 2) {
00521 // Use the new normal to draw the previous side
00522 glNormal3fv(norm0);
00523 glVertex3fv(vert0);
00524 glNormal3fv(norm1);
00525 glVertex3fv(vert3);
00526 glNormal3fv(norm0);
00527 glVertex3fv(vert1);
00528 
00529 glNormal3fv(norm1);
00530 glVertex3fv(vert3);
00531 glNormal3fv(norm0);
00532 glVertex3fv(vert0);
00533 glNormal3fv(norm1);
00534 glVertex3fv(vert2);
00535 
00536 // Draw cylinder caps
00537 if (filled & CYLINDER_LEADINGCAP) {
00538 glNormal3fv(axis);
00539 glVertex3fv(vert1);
00540 glNormal3fv(axis);
00541 glVertex3fv(vert3);
00542 glNormal3fv(axis);
00543 glVertex3fv(apex);
00544 }
00545 if (filled & CYLINDER_TRAILINGCAP) {
00546 glNormal3fv(negaxis);
00547 glVertex3fv(vert0);
00548 glNormal3fv(negaxis);
00549 glVertex3fv(vert2);
00550 glNormal3fv(negaxis);
00551 glVertex3fv(base);
00552 }
00553 }
00554 
00555 theta += incTheta;
00556 }
00557 glEnd();
00558 } else {
00559 // radius2 is zero, so we draw triangular panels joined at the apex
00560 glBegin(GL_TRIANGLES);
00561 for (h=0; h < numsides+3; h++) {
00562 // project 2-D unit circle onto perp/perp2 3-D basis vectors
00563 // and scale to desired radius
00564 sincosf(theta, &sinTheta, &cosTheta);
00565 float projx = (cosTheta*perp[0] + sinTheta*perp2[0]);
00566 float projy = (cosTheta*perp[1] + sinTheta*perp2[1]);
00567 float projz = (cosTheta*perp[2] + sinTheta*perp2[2]);
00568 
00569 vert0[0] = base[0] + radius * projx;
00570 vert0[1] = base[1] + radius * projy;
00571 vert0[2] = base[2] + radius * projz;
00572 
00573 // Use the new vertex to find a new edge
00574 edge0[0] = vert0[0] - apex[0];
00575 edge0[1] = vert0[1] - apex[1];
00576 edge0[2] = vert0[2] - apex[2];
00577 
00578 if (h > 0) {
00579 // Use the new edge to find a new face
00580 cross_prod(face0, edge0, edge1);
00581 vec_normalize(face0);
00582 
00583 if (h > 1) {
00584 // Use the new face to find the normal of the previous triangle
00585 norm0[0] = (face1[0] + face0[0]) * 0.5f;
00586 norm0[1] = (face1[1] + face0[1]) * 0.5f;
00587 norm0[2] = (face1[2] + face0[2]) * 0.5f;
00588 vec_normalize(norm0);
00589 
00590 if (h > 2) {
00591 // Use the new normal to draw the previous side and base of the cone
00592 glNormal3fv(norm0);
00593 glVertex3fv(vert1);
00594 glNormal3fv(norm1);
00595 glVertex3fv(vert2);
00596 glNormal3fv(face1);
00597 glVertex3fv(apex);
00598 
00599 glNormal3fv(axis);
00600 glVertex3fv(vert2);
00601 glNormal3fv(axis);
00602 glVertex3fv(vert1);
00603 glNormal3fv(axis);
00604 glVertex3fv(base);
00605 }
00606 }
00607 
00608 // Copy the old values
00609 memcpy(norm1, norm0, 3*sizeof(float));
00610 memcpy(vert2, vert1, 3*sizeof(float));
00611 memcpy(face1, face0, 3*sizeof(float));
00612 }
00613 memcpy(vert1, vert0, 3*sizeof(float));
00614 memcpy(edge1, edge0, 3*sizeof(float));
00615 
00616 theta += incTheta;
00617 }
00618 glEnd();
00619 }
00620 }
00621 
00622 
00623 static GLint vmd_Project(GLdouble objX,
00624 GLdouble objY,
00625 GLdouble objZ,
00626 const GLdouble *model,
00627 const GLdouble *proj,
00628 const GLint *view,
00629 GLdouble *winX,
00630 GLdouble *winY,
00631 GLdouble *winZ) {
00632 #if !defined(VMDUSELIBGLU) 
00633 // replaced previous implementation with one that also works correctly
00634 // for orthographic projections
00635 double in[4], tmp[4], out[4];
00636 
00637 in[0]=objX;
00638 in[1]=objY;
00639 in[2]=objZ;
00640 in[3]=1.0;
00641 
00642 vmd_matmultvec_4x4d(tmp, in, model);
00643 vmd_matmultvec_4x4d(out, tmp, proj);
00644 
00645 if (out[3] == 0.0) 
00646 return 0;
00647 
00648 // efficiently map coordinates to range 0-1, and then to the viewport
00649 double tinv = 0.5 / out[3];
00650 *winX = (out[0] * tinv + 0.5) * view[2] + view[0];
00651 *winY = (out[1] * tinv + 0.5) * view[3] + view[1]; 
00652 *winZ = out[2] * tinv + 0.5;
00653 
00654 return 1;
00655 #else
00656 return gluProject(objX, objY, objZ, model, proj, view, winX, winY, winZ);
00657 #endif
00658 }
00659 
00660 
00661 static GLint vmd_UnProject(GLdouble winX,
00662 GLdouble winY,
00663 GLdouble winZ,
00664 const GLdouble *model,
00665 const GLdouble *proj,
00666 const GLint *view,
00667 GLdouble *objX,
00668 GLdouble *objY,
00669 GLdouble *objZ) {
00670 #if !defined(VMDUSELIBGLU) 
00671 // based on opengl.org wiki sample
00672 GLdouble m[16], A[16], in[4], out[4];
00673 memset(m, 0, sizeof(m));
00674 
00675 // invert matrix, compute projection * modelview, store in A
00676 vmd_matmult_4x4d(A, proj, model);
00677 if (vmd_invert_mat_4x4d(A, m) == 0)
00678 return 0;
00679 
00680 in[0]=((winX-(double)view[0])/(double)view[2])*2.0 - 1.0;
00681 in[1]=((winY-(double)view[1])/(double)view[3])*2.0 - 1.0;
00682 in[2]=winZ*2.0 - 1.0;
00683 in[3]=1.0;
00684 
00685 vmd_matmultvec_4x4d(out, in, m);
00686 if (out[3]==0.0)
00687 return 0;
00688 
00689 out[3]=1.0/out[3];
00690 *objX=out[0]*out[3];
00691 *objY=out[1]*out[3];
00692 *objZ=out[2]*out[3];
00693 
00694 return 1; 
00695 #else
00696 return gluUnProject(winX, winY, winZ, model, proj, view, objX, objY, objZ);
00697 #endif
00698 }
00699 #endif
00700 
00701 
00702 static void vmd_LookAt(GLdouble eyeX,
00703 GLdouble eyeY,
00704 GLdouble eyeZ,
00705 GLdouble centerX,
00706 GLdouble centerY,
00707 GLdouble centerZ,
00708 GLdouble upX,
00709 GLdouble upY,
00710 GLdouble upZ) {
00711 #if !defined(VMDUSELIBGLU) 
00712 // initialize to identity matrix
00713 GLdouble matrix[16];
00714 vmd_mat_identity_4x4d(matrix);
00715 
00716 // now compute transform for look at point
00717 GLdouble f[3], s[3], u[3];
00718 GLdouble matrix2[16], resmat[16];
00719 
00720 f[0] = centerX - eyeX;
00721 f[1] = centerY - eyeY;
00722 f[2] = centerZ - eyeZ;
00723 vmd_vec_normalize_3d(f);
00724 
00725 // side = forward x up
00726 u[0] = upX; u[1] = upY; u[2] = upZ;
00727 vmd_cross_3d(s, f, u);
00728 vmd_vec_normalize_3d(s);
00729 
00730 // recompute orthogonal up dir: up = side x forward
00731 vmd_cross_3d(u, s, f);
00732 
00733 matrix2[ 0] = s[0];
00734 matrix2[ 4] = s[1];
00735 matrix2[ 8] = s[2];
00736 matrix2[12] = 0.0;
00737 
00738 matrix2[ 1] = u[0];
00739 matrix2[ 5] = u[1];
00740 matrix2[ 9] = u[2];
00741 matrix2[13] = 0.0;
00742 
00743 matrix2[ 2] = -f[0];
00744 matrix2[ 6] = -f[1];
00745 matrix2[10] = -f[2];
00746 matrix2[14] = 0.0;
00747 
00748 matrix2[3] = matrix2[7] = matrix2[11] = 0.0;
00749 matrix2[15] = 1.0;
00750 
00751 vmd_matmult_4x4d(resmat, matrix, matrix2);
00752 vmd_mattrans_d(resmat, -eyeX, -eyeY, -eyeZ);
00753 
00754 GLfloat tmpmat[16];
00755 for (int i=0; i<16; i++) 
00756 tmpmat[i]= (GLfloat)(resmat[i]);
00757 
00758 glLoadIdentity();
00759 glMultMatrixf(tmpmat);
00760 #else
00761 glLoadIdentity();
00762 gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
00763 #endif
00764 }
00765 
00766 
00767 #if defined(VMD_NANOHUB)
00768 bool OpenGLRenderer::init_offscreen_framebuffer(int winWidth, int winHeight) {
00769 if (_finalColorTex != 0) {
00770 glDeleteTextures(1, &_finalColorTex);
00771 }
00772 if (_finalDepthRb != 0) {
00773 glDeleteRenderbuffersEXT(1, &_finalDepthRb);
00774 }
00775 if (_finalFbo != 0) {
00776 glDeleteFramebuffersEXT(1, &_finalFbo);
00777 }
00778 
00779 // Initialize a fbo for final display.
00780 glGenFramebuffersEXT(1, &_finalFbo);
00781 
00782 glGenTextures(1, &_finalColorTex);
00783 glBindTexture(GL_TEXTURE_2D, _finalColorTex);
00784 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00785 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00786 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, winWidth, winHeight, 0,
00787 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
00788 
00789 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _finalFbo);
00790 glGenRenderbuffersEXT(1, &_finalDepthRb);
00791 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
00792 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 
00793 winWidth, winHeight);
00794 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
00795 GL_TEXTURE_2D, _finalColorTex, 0);
00796 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
00797 GL_RENDERBUFFER_EXT, _finalDepthRb);
00798 
00799 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
00800 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
00801 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00802 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
00803 msgWarn << "FBO Setup failed" << sendmsg;
00804 return false;
00805 }
00806 
00807 return true;
00808 }
00809 #endif
00810 
00811 
00812 void OpenGLRenderer::setup_initial_opengl_state(void) {
00813 int i; 
00814 
00815 if (getenv("VMDSIMPLEGRAPHICS") == NULL) {
00816 simplegraphics = 0; // use all available OpenGL features and extensions
00817 } else {
00818 simplegraphics = 1; // limit VMD to OpenGL ~1.0 with no extensions
00819 msgWarn << "Simple graphics mode: OpenGL 1.0, no extensions" << sendmsg;
00820 }
00821 
00822 // Create quadric objects for spheres, cylinders, and disks
00823 // Default to drawing filled objects, may be changed by the detail level
00824 #if defined(VMDUSELIBGLU)
00825 objQuadric = gluNewQuadric();
00826 pointsQuadric = gluNewQuadric();
00827 gluQuadricDrawStyle(objQuadric, (GLenum)GLU_FILL);
00828 gluQuadricDrawStyle(pointsQuadric, (GLenum)GLU_POINT);
00829 #endif
00830 
00831 // display list caching
00832 ogl_cachelistbase = 2000;
00833 ogl_cacheenabled = 0;
00834 ogl_cachedebug = 0;
00835 if (getenv("VMDCACHEDLDEBUG") != NULL) {
00836 ogl_cachedebug = 1; // enable verbose output for display list caching
00837 }
00838 
00839 wiregl = 0; // wiregl not detected yet
00840 intelswr = 0; // Intel SWR not detected yet
00841 immersadeskflip = 0; // Immersadesk right-eye X-axis mode off by default
00842 shearstereo = 0; // use stereo based on eye rotation by default
00843 
00844 // initialize state caching variables so they get overwritten on 
00845 // first reference in the call to render()
00846 oglmaterialindex = -1;
00847 oglopacity = -1.0f;
00848 oglambient = -1.0f;
00849 ogldiffuse = -1.0f;
00850 oglspecular = -1.0f;
00851 oglshininess = -1.0f;
00852 ogloutline = -1.0f;
00853 ogloutlinewidth = -1.0f;
00854 ogltransmode = -1;
00855 
00856 ogl_useblendedtrans = 0;
00857 ogl_transpass = 0; 
00858 ogl_useglslshader = 0;
00859 ogl_acrobat3dcapture = 0;
00860 ogl_lightingenabled = 0;
00861 ogl_rendstateserial = 1; // force GLSL update on 1st pass
00862 ogl_glslserial = 0; // force GLSL update on 1st pass
00863 ogl_glsltoggle = 1; // force GLSL update on 1st pass
00864 ogl_glslmaterialindex = -1; // force GLSL update on 1st pass
00865 ogl_glslprojectionmode = DisplayDevice::PERSPECTIVE; 
00866 ogl_glsltexturemode = 0; // initialize GLSL projection to off
00867 
00868 // identify the rendering hardware we're using
00869 ext->find_renderer();
00870 
00871 // find all available OpenGL extensions, unless the user doesn't want us to.
00872 if (!simplegraphics) {
00873 ext->find_extensions(); 
00874 }
00875 
00876 
00877 #if 0
00878 // XXX the performance workaround aspect of this must still be tested
00879 // on Linux to verify that the existing code path is actually a benefit.
00880 
00881 // not tested on other platforms yet
00882 #if defined(__APPLE__)
00883 // Detect NVidia graphics cards, which have a semi-broken stereo 
00884 // implementation that favors rendering in stereo mode all the time, 
00885 // as the alternative is 20-50x performance hit on Linux.
00886 // XXX on MacOS X, the behavior is much more serious than just a performance
00887 // hit, they actually fail to draw/clear the back right color buffer 
00888 // when drawing to GL_BACK.
00889 if (ext->hasstereo && ext->oglrenderer == OpenGLExtensions::NVIDIA) {
00890 msgInfo << "nVidia card detected, enabling mono drawing performance workaround" << sendmsg;
00891 
00892 // force drawing in stereo even when VMD is set for mono mode
00893 ext->stereodrawforced = 1;
00894 }
00895 #endif
00896 #endif
00897 
00898 // XXX recent ATI/AMD graphics drivers are greatly improved, so this safety
00899 // check is disabled for the time being...
00900 #if 0 && defined(__linux)
00901 // Detect ATI Linux driver and disable unsafe extensions
00902 if (ext->oglrenderer == OpenGLExtensions::ATI) {
00903 if (getenv("VMDDISABLEATILINUXWORKAROUND") == NULL) {
00904 msgInfo << "ATI Linux driver detected, limiting features to avoid driver bugs." << sendmsg;
00905 msgInfo << " Set the environment variable VMDDISABLEATILINUXWORKAROUND" << sendmsg;
00906 msgInfo << " to enable full functionality on a known-safe driver version." << sendmsg;
00907 
00908 simplegraphics = 1; 
00909 }
00910 }
00911 #endif
00912 
00913 #if defined(VMDWIREGL)
00914 // Detect WireGL and shut off unsupported rendering features if so.
00915 if (ext->oglrenderer == OpenGLExtensions::WIREGL ||
00916 (getenv("VMDWIREGL") != NULL)) {
00917 msgInfo << "WireGL renderer detected, disabling unsupported OpenGL features." << sendmsg;
00918 wiregl=1;
00919 
00920 // Shut off unsupported rendering features if so.
00921 ext->hastex2d = 0;
00922 ext->hastex3d = 0;
00923 }
00924 #endif
00925 
00926 #if defined(VMDINTELSWR)
00927 // Detect Intel OpenSWR and shut off unsupported rendering features if so.
00928 if (ext->oglrenderer == OpenGLExtensions::INTELSWR) {
00929 msgInfo << "Intel OpenSWR renderer detected, disabling unsupported OpenGL features." << sendmsg;
00930 intelswr=1;
00931 
00932 // the current alpha version of SWR has lots of missing functionality
00933 simplegraphics = 1; 
00934 
00935 // Shut off unsupported rendering features if so.
00936 ext->hastex2d = 0;
00937 ext->hastex3d = 0;
00938 }
00939 #endif
00940 
00941 glDepthFunc(GL_LEQUAL);
00942 glEnable(GL_DEPTH_TEST); // use zbuffer for hidden-surface removal
00943 glClearDepth(1.0);
00944 
00945 #if 1
00946 // VMD now renormalizes all the time since non-uniform scaling 
00947 // operations must be applied for drawing ellipsoids and other 
00948 // warped geometry, and this is a final cure for people remote
00949 // displaying on machines with broken rescale normal extensions
00950 glEnable(GL_NORMALIZE); // automatically normalize normals
00951 #else
00952 // Rescale normals, assumes they are initially normalized to begin with, 
00953 // and that only uniform scaling is applied, and non-warping modelview
00954 // matrices are used. (i.e. no shear in the modelview matrix...)
00955 // Gets rid of a square root on every normal, but still tracks
00956 // uniform scaling operations. If not available, enable full
00957 // normalization.
00958 if (simplegraphics || wiregl || ogl_acrobat3dcapture) {
00959 // Renormalize normals if we're in 'simplegraphics' mode.
00960 // WireGL doesn't work correctly with the various normal rescaling
00961 // features and extensions, so we have to make it use GL_NORMALIZE.
00962 glEnable(GL_NORMALIZE); // automatically normalize normals
00963 } else {
00964 #if defined(_MSC_VER) || defined(__irix) || defined(__APPLE__)
00965 // XXX The Microsoft "GDI Generic", MacOS X, and IRIX OpenGL renderers
00966 // malfunction when we use GL_RESCALE_NORMAL, so we disable it here
00967 glEnable(GL_NORMALIZE); // automatically normalize normals
00968 #else
00969 #if defined(GL_VERSION_1_2)
00970 ext->hasrescalenormalext = 1;
00971 glEnable(GL_RESCALE_NORMAL); // automatically rescale normals
00972 #elif defined(GL_RESCALE_NORMAL_EXT)
00973 if (ext->vmdQueryExtension("GL_RESCALE_NORMAL_EXT")) {
00974 ext->hasrescalenormalext = 1;
00975 glEnable(GL_RESCALE_NORMAL_EXT); // automatically rescale normals
00976 } else {
00977 glEnable(GL_NORMALIZE); // automatically normalize normals
00978 }
00979 #else
00980 glEnable(GL_NORMALIZE); // automatically normalize normals
00981 #endif
00982 #endif
00983 } 
00984 #endif
00985 
00986 // configure for dashed lines ... but initially show solid lines
00987 glLineStipple(1, 0x3333);
00988 glDisable(GL_LINE_STIPPLE);
00989 
00990 // configure the fogging characteristics ... color and position of fog
00991 // are set during the clear routine
00992 glFogi(GL_FOG_MODE, GL_EXP2);
00993 glFogf(GL_FOG_DENSITY, 0.40f);
00994 
00995 // configure the light model
00996 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00997 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
00998 
00999 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
01000 glEnable(GL_COLOR_MATERIAL); // have materials set by curr color
01001 glDisable(GL_POLYGON_SMOOTH); // make sure not to antialias polygons
01002 
01003 // disable all lights by default
01004 for (i=0; i < DISP_LIGHTS; i++) {
01005 ogl_lightstate[i] = 0; // off by default
01006 }
01007 
01008 // disable all clipping planes by default
01009 for (i=0; i < VMD_MAX_CLIP_PLANE; i++) {
01010 ogl_clipmode[i] = 0; // off by default
01011 glDisable((GLenum) (GL_CLIP_PLANE0 + i));
01012 }
01013 
01014 // load transformation matrices on stack, initially with identity transforms
01015 glMatrixMode(GL_PROJECTION);
01016 glLoadIdentity();
01017 glMatrixMode(GL_MODELVIEW);
01018 glLoadIdentity();
01019 
01020 // generate sphere display lists
01021 glMatrixMode(GL_MODELVIEW);
01022 for (i=MIN_SPHERE_RES; i<=MAX_SPHERE_RES; i++) {
01023 GLuint solidlist = glGenLists(1);
01024 glNewList(solidlist, GL_COMPILE);
01025 #if defined(VMDUSELIBGLU)
01026 gluSphere(objQuadric, 1.0, i, i);
01027 #else
01028 vmd_DrawSphere(1.0, i, 1);
01029 #endif
01030 glEndList(); 
01031 solidSphereLists.append(solidlist);
01032 
01033 GLuint pointlist = glGenLists(1);
01034 glNewList(pointlist, GL_COMPILE);
01035 #if defined(VMDUSELIBGLU)
01036 gluSphere(pointsQuadric, 1.0, i, i);
01037 #else
01038 vmd_DrawSphere(1.0, i, 0);
01039 #endif
01040 glEndList(); 
01041 pointSphereLists.append(pointlist);
01042 }
01043 
01044 // create font display lists for use in displaying text
01045 ogl_textMat.identity();
01046 
01047 // display list for 1-pixel wide non-antialiased font rendering,
01048 // which doesn't have points at each font stroke vector endpoint
01049 font1pxListBase = glGenLists(256);
01050 glListBase(font1pxListBase);
01051 for (i=0 ; i<256 ; i++) {
01052 glNewList(font1pxListBase+i, GL_COMPILE);
01053 hersheyDrawLetterOpenGL(i, 0); // draw vector lines only
01054 glEndList();
01055 }
01056 
01057 // display list for N-pixel wide antialiased font rendering,
01058 // which has added points at each font stroke vector endpoint
01059 // to prevent "cracks" from showing up with large font sizes
01060 fontNpxListBase = glGenLists(256);
01061 glListBase(fontNpxListBase);
01062 for (i=0 ; i<256 ; i++) {
01063 glNewList(fontNpxListBase+i, GL_COMPILE);
01064 hersheyDrawLetterOpenGL(i, 1); // draw with lines+points
01065 glEndList();
01066 }
01067 
01068 // display lists are now initialized, so they must be freed when this
01069 // OpenGL context is destroyed
01070 dpl_initialized = 1;
01071 
01072 #if defined(GL_VERSION_1_1)
01073 if (!(simplegraphics || ogl_acrobat3dcapture)) {
01074 // enable vertex arrays.
01075 glEnableClientState(GL_VERTEX_ARRAY);
01076 glEnableClientState(GL_NORMAL_ARRAY);
01077 glEnableClientState(GL_COLOR_ARRAY);
01078 }
01079 #endif
01080 
01081 
01082 #if defined(GL_VERSION_1_1)
01083 if (ext->hastex2d) {
01084 int i, sz;
01085 GLint x, y;
01086 
01087 // test actual maximums for desired format
01088 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max2DtexSize);
01089 
01090 for (i=0; (sz = 1 << i) <= max2DtexSize; i++) {
01091 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGB8,
01092 sz, sz, 0, 
01093 GL_RGB, GL_UNSIGNED_BYTE, NULL);
01094 
01095 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &x);
01096 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &y);
01097 
01098 if (x > 0 && y > 0) { 
01099 max2DtexX = x;
01100 max2DtexY = y;
01101 }
01102 }
01103 
01104 if (max2DtexX > max2DtexSize)
01105 max2DtexX = max2DtexSize;
01106 
01107 if (max2DtexY > max2DtexSize)
01108 max2DtexY = max2DtexSize;
01109 } 
01110 #endif
01111 
01112 #if defined(GL_VERSION_1_2)
01113 if (ext->hastex3d) {
01114 int i, sz;
01115 GLint x, y, z;
01116 
01117 // test actual maximums for desired format
01118 max3DtexSize = 0; // until successfully queried from OpenGL
01119 max3DtexX = 0;
01120 max3DtexY = 0;
01121 max3DtexZ = 0;
01122 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DtexSize);
01123 
01124 for (i=0; (sz = 1 << i) <= max3DtexSize; i++) {
01125 GLTEXIMAGE3D(GL_PROXY_TEXTURE_3D, 0, GL_RGB8, 
01126 sz, sz, sz, 0, 
01127 GL_RGB, GL_UNSIGNED_BYTE, NULL);
01128 
01129 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &x);
01130 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &y);
01131 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &z);
01132 
01133 if (x > 0 && y > 0 && z > 0) {
01134 max3DtexX = x; 
01135 max3DtexY = y; 
01136 max3DtexZ = z; 
01137 } 
01138 }
01139 
01140 if (max3DtexX > max3DtexSize)
01141 max3DtexX = max3DtexSize;
01142 
01143 if (max3DtexY > max3DtexSize)
01144 max3DtexY = max3DtexSize;
01145 
01146 if (max3DtexZ > max3DtexSize)
01147 max3DtexZ = max3DtexSize;
01148 
01149 // disable 3-D texturing on cards that return unusable max texture sizes
01150 if (max3DtexX < 1 || max3DtexY < 1 || max3DtexZ < 1) {
01151 ext->hastex3d = 0;
01152 }
01153 
01154 } 
01155 #endif
01156 
01157 
01158 
01159 // MacOS X has had a broken implementation of GL_SEPARATE_SPECULAR_COLOR
01160 // for some time.
01161 #if defined(GL_VERSION_1_2) && !defined(__APPLE__)
01162 if (((ext->oglmajor == 1) && (ext->oglminor >= 2)) || (ext->oglmajor >= 2)) {
01163 if (ext->hastex2d || ext->hastex3d) {
01164 // Make specular color calculations follow texture mapping operations
01165 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
01166 } else {
01167 // Do the specular color calculations at the same time as the rest 
01168 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
01169 }
01170 }
01171 #endif
01172 
01173 ext->PrintExtensions(); 
01174 
01175 #if defined(VMDUSEOPENGLSHADER)
01176 int glslextensionsavailable=0;
01177 
01178 // Enable OpenGL programmable shading if it is available
01179 if (!(simplegraphics || ogl_acrobat3dcapture) &&
01180 ext->hasglshadinglangarb &&
01181 ext->hasglfragmentshaderarb && 
01182 ext->hasglvertexshaderarb &&
01183 ext->hasglshaderobjectsarb &&
01184 (getenv("VMDNOGLSL") == NULL)) {
01185 glslextensionsavailable=1; // GLSL is available
01186 }
01187 
01188 if (glslextensionsavailable) {
01189 mainshader = new OpenGLShader(ext);
01190 
01191 if (mainshader) {
01192 char *shaderpath = NULL;
01193 
01194 if (getenv("VMDOGLSHADER") != NULL) {
01195 shaderpath = (char *) calloc(1, strlen(getenv("VMDOGLSHADER")) + 512);
01196 strcpy(shaderpath, getenv("VMDOGLSHADER"));
01197 } else if (getenv("VMDDIR") != NULL) {
01198 shaderpath = (char *) calloc(1, strlen(getenv("VMDDIR")) + 512);
01199 strcpy(shaderpath, getenv("VMDDIR"));
01200 strcat(shaderpath, "/shaders/vmd");
01201 } else {
01202 msgErr << "Unable to locate VMD vertex and fragment shader path, " 
01203 << "VMDDIR environment variable not set" << sendmsg;
01204 delete mainshader;
01205 mainshader = NULL;
01206 } 
01207 
01208 if (mainshader) {
01209 #if defined(_MSC_VER)
01210 // convert '/' to '\' for Windows...
01211 int i, len;
01212 len=strlen(shaderpath);
01213 for (i=0; i<len; i++) {
01214 if (shaderpath[i] == '\\') {
01215 shaderpath[i] = '/';
01216 }
01217 }
01218 #endif
01219 
01220 if (mainshader->LoadShader(shaderpath)) {
01221 mainshader->UseShader(0); // if glsl is available, turn off initially
01222 // OpenGL rendering state gets propagated on-demand at render time 
01223 // whenever ogl_renderstateserial != ogl_glslserial, thus no need to
01224 // enable the shader immediately at startup anymore.
01225 } else {
01226 msgWarn << "GPU driver failed to compile shader: " << sendmsg;
01227 msgWarn << " " << shaderpath << sendmsg;
01228 delete mainshader;
01229 mainshader = NULL;
01230 }
01231 }
01232 
01233 if (shaderpath)
01234 free(shaderpath);
01235 }
01236 OGLERR // enable OpenGL debugging code
01237 }
01238 
01239 #if defined(VMDUSEGLSLSPHERES)
01240 // if the main shader compiled successfully, try loading up the 
01241 // sphere shader also
01242 if (mainshader) {
01243 sphereshader = new OpenGLShader(ext);
01244 char *shaderpath = NULL;
01245 
01246 if (getenv("VMDOGLSPHERESHADER") != NULL) {
01247 shaderpath = (char *) calloc(1, strlen(getenv("VMDOGLSPHERESHADER")) + 512);
01248 strcpy(shaderpath, getenv("VMDOGLSPHERESHADER"));
01249 } else if (getenv("VMDDIR") != NULL) {
01250 shaderpath = (char *) calloc(1, strlen(getenv("VMDDIR")) + 512);
01251 strcpy(shaderpath, getenv("VMDDIR"));
01252 strcat(shaderpath, "/shaders/vmdsphere");
01253 } else {
01254 msgWarn << "Unable to locate VMD sphere vertex and fragment shaders, " 
01255 << "VMDDIR environment variable not set" << sendmsg;
01256 delete sphereshader;
01257 sphereshader = NULL;
01258 } 
01259 
01260 if (sphereshader) {
01261 #if defined(_MSC_VER)
01262 // convert '/' to '\' for Windows...
01263 int i, len;
01264 len=strlen(shaderpath);
01265 for (i=0; i<len; i++) {
01266 if (shaderpath[i] == '\\') {
01267 shaderpath[i] = '/';
01268 }
01269 }
01270 #endif
01271 
01272 if (sphereshader->LoadShader(shaderpath)) {
01273 sphereshader->UseShader(0); // if glsl is available, turn off initially
01274 // OpenGL rendering state gets propagated on-demand at render time 
01275 // whenever ogl_renderstateserial != ogl_glslserial, thus no need to
01276 // enable the shader immediately at startup anymore.
01277 } else {
01278 msgWarn << "GPU driver failed to compile shader: " << sendmsg;
01279 msgWarn << " " << shaderpath << sendmsg;
01280 delete sphereshader;
01281 sphereshader = NULL;
01282 }
01283 }
01284 
01285 if (shaderpath)
01286 free(shaderpath);
01287 
01288 OGLERR // enable OpenGL debugging code
01289 }
01290 #endif
01291 
01292 
01293 #if defined(VMDUSEGLSLSPHERESPRITES)
01294 // if the main shader compiled successfully, try loading up the 
01295 // sphere shader also
01296 if (mainshader 
01297 #if 0
01298 && getenv("VMDUSESPHERESPRITES")
01299 #endif
01300 ) {
01301 spherespriteshader = new OpenGLShader(ext);
01302 char *shaderpath = NULL;
01303 
01304 if (getenv("VMDOGLSPHERESPRITESHADER") != NULL) {
01305 shaderpath = (char *) calloc(1, strlen(getenv("VMDOGLSPHERESPRITESHADER")) + 512);
01306 strcpy(shaderpath, getenv("VMDOGLSPHERESPRITESHADER"));
01307 } else if (getenv("VMDDIR") != NULL) {
01308 shaderpath = (char *) calloc(1, strlen(getenv("VMDDIR")) + 512);
01309 strcpy(shaderpath, getenv("VMDDIR"));
01310 strcat(shaderpath, "/shaders/vmdspheresprite");
01311 } else {
01312 msgWarn << "Unable to locate VMD sphere sprite vertex and fragment shaders, " 
01313 << "VMDDIR environment variable not set" << sendmsg;
01314 delete spherespriteshader;
01315 spherespriteshader = NULL;
01316 } 
01317 
01318 if (spherespriteshader) {
01319 #if defined(_MSC_VER)
01320 // convert '/' to '\' for Windows...
01321 int i, len;
01322 len=strlen(shaderpath);
01323 for (i=0; i<len; i++) {
01324 if (shaderpath[i] == '\\') {
01325 shaderpath[i] = '/';
01326 }
01327 }
01328 #endif
01329 
01330 if (spherespriteshader->LoadShader(shaderpath)) {
01331 spherespriteshader->UseShader(0); // if glsl is available, turn off initially
01332 // OpenGL rendering state gets propagated on-demand at render time 
01333 // whenever ogl_renderstateserial != ogl_glslserial, thus no need to
01334 // enable the shader immediately at startup anymore.
01335 } else {
01336 msgWarn << "GPU driver failed to compile shader: " << sendmsg;
01337 msgWarn << " " << shaderpath << sendmsg;
01338 delete spherespriteshader;
01339 spherespriteshader = NULL;
01340 }
01341 }
01342 
01343 if (shaderpath)
01344 free(shaderpath);
01345 
01346 OGLERR // enable OpenGL debugging code
01347 }
01348 #endif
01349 
01350 if (mainshader && sphereshader 
01351 #if defined(VMDUSEGLSLSPHERESPRITES)
01352 && ((spherespriteshader != 0) 
01353 #if 0
01354 == (getenv("VMDUSESPHERESPRITES") != NULL)
01355 #endif
01356 )
01357 #endif
01358 ) {
01359 msgInfo << " Full GLSL rendering mode is available." << sendmsg;
01360 } else if (mainshader) {
01361 if (glslextensionsavailable) {
01362 msgWarn << "This GPU/driver is buggy, or doesn't fully implement GLSL." << sendmsg;
01363 msgWarn << "Set environment variable VMDGLSLVERBOSE for more info." << sendmsg;
01364 }
01365 msgInfo << " Basic GLSL rendering mode is available." << sendmsg;
01366 } else {
01367 if (glslextensionsavailable) {
01368 msgWarn << "This GPU/driver is buggy, or doesn't fully implement GLSL." << sendmsg;
01369 msgWarn << "Set environment variable VMDGLSLVERBOSE for more info." << sendmsg;
01370 }
01371 msgInfo << " GLSL rendering mode is NOT available." << sendmsg;
01372 }
01373 #endif
01374 
01375 // print information on OpenGL texturing hardware
01376 if (ext->hastex2d || ext->hastex3d) {
01377 msgInfo << " Textures: ";
01378 
01379 if (ext->hastex2d) 
01380 msgInfo << "2-D (" << max2DtexX << "x" << max2DtexY << ")"; 
01381 
01382 if (ext->hastex2d && ext->hastex3d)
01383 msgInfo << ", ";
01384 
01385 if (ext->hastex3d) 
01386 msgInfo << "3-D (" << max3DtexX << "x" << max3DtexY << "x" << max3DtexZ << ")";
01387 
01388 if ((ext->hastex2d || ext->hastex3d) && ext->multitextureunits > 0)
01389 msgInfo << ", ";
01390 
01391 if (ext->multitextureunits > 0)
01392 msgInfo << "Multitexture (" << ext->multitextureunits << ")";
01393 
01394 msgInfo << sendmsg;
01395 }
01396 
01397 // print information about special stereo configuration
01398 if (getenv("VMDIMMERSADESKFLIP") != NULL) {
01399 immersadeskflip = 1;
01400 msgInfo << " Enabled Immersadesk right-eye reflection stereo mode" << sendmsg;
01401 }
01402 
01403 // print information about special stereo configuration
01404 if (getenv("VMDSHEARSTEREO") != NULL) {
01405 shearstereo = 1;
01406 msgInfo << " Enabled shear matrix stereo projection mode" << sendmsg;
01407 }
01408 
01409 OGLERR // enable OpenGL debugging code
01410 }
01411 
01412 
01413 void OpenGLRenderer::update_lists(void) {
01414 // point SphereList to the proper list
01415 ResizeArray<GLuint> *lists = (sphereMode == 
01416 ::SOLIDSPHERE) ? &solidSphereLists : &pointSphereLists;
01417 int ind = sphereRes - MIN_SPHERE_RES;
01418 if (ind < 0) 
01419 ind = 0;
01420 else if (ind >= lists->num())
01421 ind = lists->num()-1;
01422 SphereList = (*lists)[ind];
01423 }
01424 
01426 // constructor ... initialize some variables
01427 OpenGLRenderer::OpenGLRenderer(const char *nm) : DisplayDevice(nm) {
01428 #if defined(VMD_NANOHUB)
01429 _finalFbo = _finalColorTex = _finalDepthRb = 0;
01430 #endif
01431 
01432 // initialize data
01433 #if defined(VMDUSELIBGLU)
01434 objQuadric = NULL;
01435 pointsQuadric = NULL;
01436 #endif
01437 
01438 #if defined(VMDUSEOPENGLSHADER)
01439 mainshader = NULL; // init shaders to NULL until they're loaded
01440 sphereshader = NULL; // init shaders to NULL until they're loaded
01441 spherespriteshader = NULL; // init shaders to NULL until they're loaded
01442 #endif
01443 ext = new OpenGLExtensions;
01444 
01445 dpl_initialized = 0; // display lists need to be initialized still
01446 }
01447 
01448 
01449 // destructor
01450 OpenGLRenderer::~OpenGLRenderer(void) {
01451 #if defined(VMDUSELIBGLU)
01452 if (objQuadric != NULL)
01453 gluDeleteQuadric(objQuadric); // delete the quadrics
01454 
01455 if (pointsQuadric != NULL)
01456 gluDeleteQuadric(pointsQuadric); // delete the quadrics
01457 #endif
01458 
01459 delete ext; // delete OpenGL extensions
01460 
01461 #if defined(VMDUSEOPENGLSHADER)
01462 delete mainshader; // delete programmable shaders
01463 delete sphereshader; // delete programmable shaders
01464 delete spherespriteshader; // delete programmable shaders
01465 #endif
01466 }
01467 
01468 // prepare to free OpenGL context (should be called from subclass destructor)
01469 void OpenGLRenderer::free_opengl_ctx() {
01470 int i;
01471 GLuint tag;
01472 
01473 // delete all cached display lists
01474 displaylistcache.markUnused();
01475 while ((tag = displaylistcache.deleteUnused()) != GLCACHE_FAIL) {
01476 glDeleteLists(tag, 1);
01477 }
01478 
01479 // delete all cached textures
01480 texturecache.markUnused();
01481 while ((tag = texturecache.deleteUnused()) != GLCACHE_FAIL) {
01482 glDeleteTextures(1, &tag);
01483 }
01484 
01485 if (dpl_initialized) { 
01486 // free sphere display lists
01487 for (i=MIN_SPHERE_RES; i<=MAX_SPHERE_RES; i++) {
01488 glDeleteLists(solidSphereLists[i-MIN_SPHERE_RES], 1);
01489 glDeleteLists(pointSphereLists[i-MIN_SPHERE_RES], 1);
01490 } 
01491 
01492 // free the display lists used for the 3-D label/text font
01493 glDeleteLists(font1pxListBase, 256);
01494 glDeleteLists(fontNpxListBase, 256);
01495 }
01496 }
01497 
01498 
01500 
01501 // change current line width
01502 void OpenGLRenderer::set_line_width(int w) {
01503 if(w > 0) {
01504 glLineWidth((GLfloat)w);
01505 lineWidth = w;
01506 }
01507 }
01508 
01509 // change current line style
01510 void OpenGLRenderer::set_line_style(int s) {
01511 if(s == ::DASHEDLINE) {
01512 lineStyle = s;
01513 glEnable(GL_LINE_STIPPLE);
01514 } else {
01515 lineStyle = ::SOLIDLINE;
01516 glDisable(GL_LINE_STIPPLE);
01517 }
01518 }
01519 
01520 
01521 // change current sphere resolution
01522 void OpenGLRenderer::set_sphere_res(int r) {
01523 // avoid unnecessary display list state changes, helps avoid some serious
01524 // OpenGL performance problems on MacOS X.
01525 if (sphereRes == r)
01526 return; 
01527 
01528 if (r > 2)
01529 sphereRes = r;
01530 else
01531 sphereRes = 2;
01532 
01533 update_lists();
01534 }
01535 
01536 
01537 // change current sphere type
01538 void OpenGLRenderer::set_sphere_mode(int m) {
01539 // avoid unnecessary display list state changes, helps avoid some serious
01540 // OpenGL performance problems on MacOS X.
01541 if (sphereMode == m)
01542 return; 
01543 
01544 sphereMode = m;
01545 update_lists();
01546 }
01547 
01548 
01549 // this routine draws a cylinder from start to end, using rod_res panels,
01550 // of radius rod_radius
01551 void OpenGLRenderer::cylinder(float *end, float *start, int rod_res,
01552 float rod_radius, float rod_top_radius) {
01553 #if !defined(VMDUSELIBGLU)
01554 vmd_DrawConic(start, end, rod_radius, rod_top_radius, rod_res);
01555 #else
01556 float R, RXY, phi, theta, lenaxis[3];
01557 
01558 // need to do some preprocessing ... find length of vector
01559 lenaxis[0] = end[0] - start[0];
01560 lenaxis[1] = end[1] - start[1];
01561 lenaxis[2] = end[2] - start[2];
01562 
01563 R = lenaxis[0]*lenaxis[0]+lenaxis[1]*lenaxis[1]+lenaxis[2]*lenaxis[2];
01564 
01565 if (R <= 0.0)
01566 return; // early exit if cylinder is of length 0;
01567 
01568 R = sqrtf(R); // evaluation of sqrt() _after_ early exit 
01569 
01570 // determine phi rotation angle, amount to rotate about y
01571 phi = acosf(lenaxis[2] / R);
01572 
01573 // determine theta rotation, amount to rotate about z
01574 RXY = sqrtf(lenaxis[0]*lenaxis[0]+lenaxis[1]*lenaxis[1]);
01575 if (RXY <= 0.0f) {
01576 theta = 0.0f;
01577 } else {
01578 theta = acosf(lenaxis[0] / RXY);
01579 if (lenaxis[1] < 0.0f)
01580 theta = (float) (2.0f * VMD_PI) - theta;
01581 }
01582 
01583 glPushMatrix(); // setup transform moving cylinder from Z-axis to position
01584 glTranslatef((GLfloat)(start[0]), (GLfloat)(start[1]), (GLfloat)(start[2]));
01585 if (theta != 0.0f)
01586 glRotatef((GLfloat) ((theta / VMD_PI) * 180.0f), 0.0f, 0.0f, 1.0f);
01587 if (phi != 0.0f)
01588 glRotatef((GLfloat) ((phi / VMD_PI) * 180.0f), 0.0f, 1.0f, 0.0f);
01589 
01590 // call utility routine to draw cylinders
01591 gluCylinder(objQuadric, (GLdouble)rod_radius, (GLdouble)rod_top_radius,
01592 (GLdouble)R, (GLint)rod_res, 1);
01593 
01594 // if this is a cone, we also draw a disk at the bottom
01595 gluQuadricOrientation(objQuadric, (GLenum)GLU_INSIDE);
01596 gluDisk(objQuadric, (GLdouble)0, (GLdouble)rod_radius, (GLint)rod_res, 1);
01597 gluQuadricOrientation(objQuadric, (GLenum)GLU_OUTSIDE);
01598 
01599 glPopMatrix(); // restore the previous transformation matrix
01600 #endif
01601 }
01602 
01603 
01604 // this routine also draws a cylinder. However, it assumes that
01605 // the cylinder drawing command has precomputed the data. This
01606 // uses more memory, but is faster
01607 // the data are: num == number of edges
01608 // edges = a normal, start, and end 
01609 static void cylinder_full(int num, float *edges, int filled) {
01610 int n = num;
01611 float *start = edges;
01612 
01613 if (num < 2)
01614 return;
01615 
01616 glBegin(GL_QUAD_STRIP);
01617 while (n-- > 0) {
01618 glNormal3fv(edges);
01619 glVertex3fv(edges+6);
01620 glVertex3fv(edges+3);
01621 edges += 9;
01622 }
01623 glNormal3fv(start); // loop back to the beginning
01624 glVertex3fv(start+6);
01625 glVertex3fv(start+3);
01626 glEnd();
01627 
01628 // and fill in the top and bottom, if needed
01629 if (filled) {
01630 float axis[3];
01631 axis[0] = start[6] - start[3];
01632 axis[1] = start[7] - start[4];
01633 axis[2] = start[8] - start[5];
01634 vec_normalize(axis);
01635 
01636 if (filled & CYLINDER_LEADINGCAP) { // do the first side
01637 n = num; // get one side
01638 edges = start + 3;
01639 glBegin(GL_POLYGON);
01640 glNormal3fv(axis);
01641 while (--n >= 0) {
01642 glVertex3fv(edges);
01643 edges += 9;
01644 }
01645 glEnd();
01646 }
01647 if (filled & CYLINDER_TRAILINGCAP) { // do the other side
01648 n = num; // and the other
01649 edges = start + 6;
01650 glBegin(GL_POLYGON);
01651 glNormal3fv(axis); // I'm going the other direction, so
01652 while (--n >= 0) {
01653 glVertex3fv(edges);
01654 edges += 9;
01655 }
01656 glEnd();
01657 }
01658 }
01659 }
01660 
01661 
01663 
01664 // define a new light source ... return success of operation
01665 int OpenGLRenderer::do_define_light(int n, float *color, float *position) {
01666 int i;
01667 
01668 for(i=0; i < 3; i++) {
01669 ogl_lightcolor[n][i] = color[i];
01670 ogl_lightpos[n][i] = position[i];
01671 }
01672 ogl_lightpos[n][3] = 0.0; // directional lights require w=0.0 otherwise
01673 // OpenGL assumes they are positional lights.
01674 ogl_lightcolor[n][3] = 1.0;
01675 
01676 // normalize the light direction vector
01677 vec_normalize(&ogl_lightpos[n][0]); // 4th element is left alone
01678 
01679 glLightfv((GLenum)(GL_LIGHT0 + n), GL_POSITION, &ogl_lightpos[n][0]);
01680 glLightfv((GLenum)(GL_LIGHT0 + n), GL_SPECULAR, &ogl_lightcolor[n][0]);
01681 
01682 ogl_rendstateserial++; // cause GLSL cached state to update when necessary
01683 _needRedraw = 1;
01684 return TRUE;
01685 }
01686 
01687 // activate a given light source ... return success of operation
01688 int OpenGLRenderer::do_activate_light(int n, int turnon) {
01689 if (turnon) {
01690 glEnable((GLenum)(GL_LIGHT0 + n));
01691 ogl_lightstate[n] = 1;
01692 } else {
01693 glDisable((GLenum)(GL_LIGHT0 + n));
01694 ogl_lightstate[n] = 0;
01695 }
01696 
01697 ogl_rendstateserial++; // cause GLSL cached state to update when necessary
01698 _needRedraw = 1;
01699 return TRUE;
01700 }
01701 
01702 void OpenGLRenderer::loadmatrix(const Matrix4 &m) {
01703 GLfloat tmpmat[16];
01704 for (int i=0; i<16; i++) tmpmat[i]=(GLfloat)(m.mat[i]);
01705 glLoadMatrixf(tmpmat);
01706 }
01707 
01708 void OpenGLRenderer::multmatrix(const Matrix4 &m) {
01709 GLfloat tmpmat[16];
01710 for (int i=0; i<16; i++) tmpmat[i]=(GLfloat)(m.mat[i]);
01711 glMultMatrixf(tmpmat);
01712 }
01713 
01714 // virtual routines to return 2D screen coordinates, given 2D or 3D world
01715 // coordinates. These assume the proper GL window has focus, etc.
01716 // The xy coordinates returned are absolute screen coords, relative to 
01717 // the lower left corner of the display monitor. The returned Z coordinate
01718 // has been normalized according to its position within the view frustum
01719 // between the front and back clipping planes. The normalized Z coordinate
01720 // is used to avoid picking points that are outside of the visible portion
01721 // of the view frustum.
01722 void OpenGLRenderer::abs_screen_loc_3D(float *loc, float *spos) {
01723 GLdouble modelMatrix[16], projMatrix[16];
01724 GLdouble pos[3];
01725 int i;
01726 
01727 // get current matrices and viewport for project call
01728 for (i=0; i<16; i++) {
01729 modelMatrix[i] = ogl_mvmatrix[i];
01730 projMatrix[i] = ogl_pmatrix[i];
01731 }
01732 
01733 // call the GLU routine to project the object coord to world coords
01734 if(!vmd_Project((GLdouble)(loc[0]), (GLdouble)(loc[1]), (GLdouble)(loc[2]),
01735 modelMatrix, projMatrix, ogl_viewport, pos, pos + 1, pos + 2)) {
01736 msgErr << "Cannot determine window position of world coordinate.";
01737 msgErr << sendmsg;
01738 } else {
01739 spos[0] = (float) (pos[0] + (float)xOrig);
01740 spos[1] = (float) (pos[1] + (float)yOrig);
01741 spos[2] = (float) (pos[2]);
01742 }
01743 }
01744 
01745 void OpenGLRenderer::abs_screen_loc_2D(float *loc, float *spos) {
01746 float newloc[3];
01747 newloc[0] = loc[0];
01748 newloc[1] = loc[1];
01749 newloc[2] = 0.0f;
01750 abs_screen_loc_3D(newloc, spos);
01751 }
01752 
01753 // Given a 3D point (pos A),
01754 // and a 2D rel screen pos point (for pos B), computes the 3D point
01755 // which goes with the second 2D point at pos B. Result returned in B3D.
01756 // NOTE: currently, this algorithm only supports the simple case where the
01757 // eye look direction is along the Z-axis. A more sophisticated version
01758 // requires finding the plane to which the look direction is normal, which is
01759 // assumed here to be the Z-axis (for simplicity in coding).
01760 void OpenGLRenderer::find_3D_from_2D(const float *A3D, const float *B2D,
01761 float *B3D) {
01762 GLdouble modelMatrix[16], projMatrix[16], w1[3], w2[3];
01763 int i;
01764 float lsx, lsy; // used to convert rel screen -> abs
01765 
01766 // get current matrices and viewport for unproject call
01767 for (i=0; i<16; i++) {
01768 modelMatrix[i] = ogl_mvmatrix[i];
01769 projMatrix[i] = ogl_pmatrix[i];
01770 }
01771 
01772 // get window coordinates of 2D point
01773 lsx = B2D[0];
01774 lsy = B2D[1];
01775 lsx = lsx * (float)xSize;
01776 lsy = lsy * (float)ySize;
01777 
01778 // call the GLU routine to unproject the window coords to world coords
01779 if (!vmd_UnProject((GLdouble)lsx, (GLdouble)lsy, 0,
01780 modelMatrix, projMatrix, ogl_viewport, w1, w1 + 1, w1 + 2)) {
01781 msgErr << "Can't determine world coords of window position 1." << sendmsg;
01782 return;
01783 }
01784 if (!vmd_UnProject((GLdouble)lsx, (GLdouble)lsy, 1.0,
01785 modelMatrix, projMatrix, ogl_viewport, w2, w2 + 1, w2 + 2)) {
01786 msgErr << "Can't determine world coords of window position2." << sendmsg;
01787 return;
01788 }
01789 
01790 // finally, find the point where line returned as w1..w2 intersects the 
01791 // given 3D point's plane (this plane is assumed to be parallel to the X-Y
01792 // plane, i.e., with a normal along the Z-axis. A more general algorithm
01793 // would need to find the plane which is normal to the eye look direction,
01794 // and which contains the given 3D point.)
01795 
01796 // special case: w1z = w2z ==> just return given 3D point, since there
01797 // is either no solution, or the line is in the given plane
01798 if(w1[2] == w2[2]) {
01799 memcpy(B3D, A3D, 3*sizeof(float));
01800 } else {
01801 float relchange = (float) ((A3D[2] - w1[2]) / (w2[2] - w1[2]));
01802 B3D[0] = (float) ((w2[0] - w1[0]) * relchange + w1[0]);
01803 B3D[1] = (float) ((w2[1] - w1[1]) * relchange + w1[1]);
01804 B3D[2] = A3D[2];
01805 }
01806 }
01807 
01808 
01809 //
01810 // antialiasing and depth-cueing
01811 //
01812 
01813 // turn on antialiasing effect
01814 void OpenGLRenderer::aa_on(void) {
01815 if (inStereo == OPENGL_STEREO_STENCIL_CHECKERBOARD ||
01816 inStereo == OPENGL_STEREO_STENCIL_COLUMNS ||
01817 inStereo == OPENGL_STEREO_STENCIL_ROWS) {
01818 msgInfo << "Antialiasing must be disabled for stencil-based stereo modes."
01819 << sendmsg;
01820 msgInfo << "You may re-enable antialiasing when stereo is turned off." << sendmsg;
01821 aa_off();
01822 return;
01823 }
01824 
01825 if (aaAvailable && !aaEnabled) {
01826 #if defined(GL_ARB_multisample)
01827 if (ext->hasmultisample) {
01828 glEnable(GL_MULTISAMPLE_ARB);
01829 aaEnabled = TRUE;
01830 _needRedraw = 1;
01831 return;
01832 } 
01833 #endif
01834 // could implement accumulation buffer antialiasing here someday
01835 aaEnabled = TRUE;
01836 }
01837 }
01838 
01839 // turn off antialiasing effect
01840 void OpenGLRenderer::aa_off(void) {
01841 if(aaAvailable && aaEnabled) {
01842 #if defined(GL_ARB_multisample)
01843 if (ext->hasmultisample) {
01844 glDisable(GL_MULTISAMPLE_ARB);
01845 aaEnabled = FALSE;
01846 _needRedraw = 1;
01847 return;
01848 } 
01849 #else
01850 #endif
01851 // could implement accumulation buffer antialiasing here someday
01852 aaEnabled = FALSE;
01853 }
01854 }
01855 
01856 // turn on hardware depth-cueing
01857 void OpenGLRenderer::cueing_on(void) {
01858 if (cueingAvailable && !cueingEnabled) {
01859 glEnable(GL_FOG);
01860 cueingEnabled = TRUE;
01861 _needRedraw = 1;
01862 }
01863 }
01864 
01865 // turn off hardware depth-cueing
01866 void OpenGLRenderer::cueing_off(void) {
01867 if (cueingAvailable && cueingEnabled) {
01868 glDisable(GL_FOG);
01869 cueingEnabled = FALSE;
01870 _needRedraw = 1;
01871 }
01872 }
01873 
01874 
01875 void OpenGLRenderer::culling_on(void) {
01876 if (cullingAvailable && !cullingEnabled) {
01877 glFrontFace(GL_CCW); // set CCW as fron face direction
01878 glPolygonMode(GL_FRONT, GL_FILL); // set front face fill mode
01879 glPolygonMode(GL_BACK, GL_LINE); // set back face fill mode
01880 glCullFace(GL_BACK); // set for culling back faces
01881 glEnable(GL_CULL_FACE); // enable face culling
01882 cullingEnabled = TRUE; 
01883 _needRedraw = 1;
01884 }
01885 }
01886 
01887 void OpenGLRenderer::culling_off(void) {
01888 if (cullingAvailable && cullingEnabled) {
01889 glPolygonMode(GL_FRONT, GL_FILL); // set front face fill mode
01890 glPolygonMode(GL_BACK, GL_FILL); // set back face fill mode
01891 glCullFace(GL_BACK); // set for culling back faces
01892 glDisable(GL_CULL_FACE); // disable face culling
01893 cullingEnabled = FALSE; 
01894 _needRedraw = 1;
01895 }
01896 }
01897 
01898 void OpenGLRenderer::set_background(const float *newback) {
01899 // make softcopy of background color for RTRT mode etc
01900 ogl_backcolor[0] = (GLfloat) newback[0];
01901 ogl_backcolor[1] = (GLfloat) newback[1];
01902 ogl_backcolor[2] = (GLfloat) newback[2];
01903 ogl_backcolor[3] = (GLfloat) 1.0f;
01904 
01905 // set fog color used for depth cueing
01906 glFogfv(GL_FOG_COLOR, ogl_backcolor);
01907 
01908 // set clear color
01909 glClearColor((GLclampf) ogl_backcolor[0],
01910 (GLclampf) ogl_backcolor[1],
01911 (GLclampf) ogl_backcolor[2], 1.0);
01912 }
01913 
01914 void OpenGLRenderer::set_backgradient(const float *topcol, 
01915 const float *botcol) {
01916 int i;
01917 for (i=0; i<3; i++) {
01918 ogl_backgradient[0][i] = topcol[i]; 
01919 ogl_backgradient[1][i] = botcol[i]; 
01920 }
01921 ogl_backgradient[0][3] = 1.0;
01922 ogl_backgradient[1][3] = 1.0;
01923 }
01924 
01925 // change to a different stereo mode
01926 void OpenGLRenderer::set_stereo_mode(int newMode) {
01927 if (inStereo == newMode)
01928 return; // do nothing if current mode is same as specified mode
01929 
01930 if (inStereo == OPENGL_STEREO_STENCIL_CHECKERBOARD ||
01931 inStereo == OPENGL_STEREO_STENCIL_COLUMNS ||
01932 inStereo == OPENGL_STEREO_STENCIL_ROWS)
01933 disable_stencil_stereo(); 
01934 
01935 if (newMode == OPENGL_STEREO_STENCIL_CHECKERBOARD ||
01936 newMode == OPENGL_STEREO_STENCIL_COLUMNS ||
01937 newMode == OPENGL_STEREO_STENCIL_ROWS)
01938 enable_stencil_stereo(newMode); 
01939 
01940 inStereo = newMode; // set new mode
01941 reshape(); // adjust the viewport width/height
01942 normal(); // adjust the viewport size/projection matrix
01943 // this is reset again when left/right are called.
01944 clear(); // clear the screen
01945 update(); // redraw
01946 
01947 _needRedraw = 1;
01948 }
01949 
01950 // change to a different caching mode
01951 void OpenGLRenderer::set_cache_mode(int newMode) {
01952 cacheMode = newMode; // set new mode;
01953 ogl_cacheenabled = newMode;
01954 }
01955 
01956 // change to a different rendering mode
01957 void OpenGLRenderer::set_render_mode(int newMode) {
01958 if (renderMode == newMode)
01959 return; // do nothing if current mode is same as specified mode
01960 
01961 char wtitle[1024];
01962 strcpy(wtitle, name);
01963 
01964 renderMode = newMode; // set new mode
01965 switch (renderMode) {
01966 case OPENGL_RENDER_NORMAL:
01967 ogl_useblendedtrans = 0;
01968 ogl_useglslshader = 0;
01969 ogl_acrobat3dcapture = 0;
01970 #if defined(VMDOPTIXRTRT)
01971 ogl_optix_rtrt_passthrough = 0;
01972 #endif
01973 strcat(wtitle, " (OpenGL)");
01974 break;
01975 
01976 case OPENGL_RENDER_GLSL:
01977 #if defined(VMDUSEOPENGLSHADER)
01978 // GLSL shader state variables must now be updated to match the 
01979 // active fixed-pipeline state before/during the next rendering pass. 
01980 if (mainshader) {
01981 ogl_useblendedtrans = 1;
01982 ogl_useglslshader = 1;
01983 } else
01984 #endif
01985 {
01986 ogl_useblendedtrans = 0;
01987 ogl_useglslshader = 0;
01988 msgWarn << "OpenGL Programmable Shading not available." << sendmsg;
01989 }
01990 ogl_acrobat3dcapture = 0;
01991 #if defined(VMDOPTIXRTRT)
01992 ogl_optix_rtrt_passthrough = 0;
01993 #endif
01994 strcat(wtitle, " (OpenGL - GLSL)");
01995 break;
01996 
01997 case OPENGL_RENDER_ACROBAT3D:
01998 ogl_useblendedtrans = 0;
01999 ogl_useglslshader = 0;
02000 ogl_acrobat3dcapture = 1;
02001 #if defined(VMDOPTIXRTRT)
02002 ogl_optix_rtrt_passthrough = 0;
02003 #endif
02004 strcat(wtitle, " (OpenGL - Acrobat3D)");
02005 break;
02006 
02007 
02008 #if defined(VMDOPTIXRTRT)
02009 case OPENGL_RENDER_RTXRTRT:
02010 #if defined(VMDUSEOPENGLSHADER)
02011 if (mainshader && ogl_useglslshader) {
02012 mainshader->UseShader(0); // use fixed-func pipeline
02013 }
02014 #endif
02015 ogl_useblendedtrans = 0;
02016 ogl_useglslshader = 0;
02017 ogl_acrobat3dcapture = 0;
02018 ogl_optix_rtrt_passthrough = 1;
02019 strcat(wtitle, " (Tachyon - OptiX RTX)");
02020 break;
02021 #endif
02022 
02023 }
02024 
02025 set_window_title(wtitle);
02026 
02027 reshape(); // adjust the viewport width/height
02028 normal(); // adjust the viewport size/projection matrix
02029 // this is reset again when left/right are called.
02030 clear(); // clear the screen
02031 update(); // redraw
02032 
02033 _needRedraw = 1;
02034 }
02035 
02036 
02037 // set up for normal (non-stereo) drawing. Sets the viewport and perspective.
02038 void OpenGLRenderer::normal(void) {
02039 glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize);
02040 set_persp();
02041 
02042 // draw the background gradient if necessary
02043 draw_background_gradient();
02044 }
02045 
02046 
02047 void OpenGLRenderer::enable_stencil_stereo(int newMode) {
02048 int i;
02049 
02050 if (!ext->hasstencilbuffer) {
02051 set_stereo_mode(OPENGL_STEREO_OFF); 
02052 msgInfo << "Stencil Buffer Stereo is NOT available." << sendmsg;
02053 return;
02054 } 
02055 
02056 if (aaEnabled) {
02057 msgInfo << "Antialiasing must be disabled for stencil-based stereo modes." << sendmsg;
02058 msgInfo << "Antialiasing will be re-enabled when stereo is turned off." << sendmsg;
02059 aaPrevious = aaEnabled;
02060 aa_off();
02061 }
02062 
02063 glPushMatrix();
02064 glDisable(GL_DEPTH_TEST);
02065 
02066 glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize);
02067 glMatrixMode(GL_MODELVIEW);
02068 glLoadIdentity();
02069 glMatrixMode (GL_PROJECTION);
02070 glLoadIdentity();
02071 
02072 glOrtho(0.0, xSize, 0.0, ySize, -1.0, 1.0); // 2-D orthographic projection
02073 
02074 glMatrixMode(GL_MODELVIEW);
02075 glLoadIdentity();
02076 
02077 // clearing and configuring stencil drawing
02078 glDrawBuffer(GL_BACK);
02079 
02080 glEnable(GL_STENCIL_TEST);
02081 glClearStencil(0);
02082 glClear(GL_STENCIL_BUFFER_BIT);
02083 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); 
02084 glStencilFunc(GL_ALWAYS, 1, 1); 
02085 
02086 glColor4f(1,1,1,0); // set draw color to all 1s
02087 
02088 // According to Appendix G. of the OpenGL 1.2 Programming Guide
02089 // correct 2-D line rasterization requires placing vertices at half
02090 // pixel offsets. This is mentioned specifically on page 677.
02091 glDisable(GL_LINE_STIPPLE); // ensure stippling is off
02092 glLineWidth(1);
02093 glBegin(GL_LINES);
02094 if (newMode == OPENGL_STEREO_STENCIL_CHECKERBOARD) {
02095 // Draw the stencil pattern on every other pixel of the window
02096 // in a checkerboard pattern, by drawing diagonal lines.
02097 for (i = -ySize; i < xSize+ySize; i += 2) {
02098 glVertex2f((GLfloat) i + 0.5f, (GLfloat) 0.5f);
02099 glVertex2f((GLfloat) i + ySize + 0.5f, (GLfloat) ySize + 0.5f);
02100 }
02101 } else if (newMode == OPENGL_STEREO_STENCIL_COLUMNS) {
02102 // Draw the stencil pattern on every other column of the window.
02103 for (i=0; i<xSize; i+=2) {
02104 glVertex2f((GLfloat) i + 0.5f, 0.0f);
02105 glVertex2f((GLfloat) i + 0.5f, (GLfloat) ySize);
02106 }
02107 } else if (newMode == OPENGL_STEREO_STENCIL_ROWS) {
02108 // draw the stencil pattern on every other row of the window.
02109 for (i=0; i<ySize; i+=2) {
02110 glVertex2f( 0.0f, (GLfloat) i + 0.5f);
02111 glVertex2f((GLfloat) xSize, (GLfloat) i + 0.5f);
02112 }
02113 }
02114 glEnd();
02115 
02116 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // disable changes to stencil buffer
02117 
02118 glEnable(GL_DEPTH_TEST);
02119 
02120 glPopMatrix();
02121 }
02122 
02123 void OpenGLRenderer::disable_stencil_stereo(void) {
02124 glDisable(GL_STENCIL_TEST);
02125 if (aaPrevious) {
02126 // XXX hack to please aa_on() so it'll reenable stereo even though
02127 // inStereo isn't quite back to normal yet.
02128 int foo = inStereo; 
02129 inStereo = OPENGL_STEREO_OFF;
02130 aa_on(); // re-enable antialiasing if we're leaving stenciling mode
02131 inStereo = foo;
02132 msgInfo << "Antialiasing re-enabled." << sendmsg;
02133 }
02134 }
02135 
02136 
02137 // set up for drawing the left eye image. Assume always the left eye is
02138 // drawn first (so no zclear is needed before it)
02139 void OpenGLRenderer::left(void) {
02140 DisplayEye cureye = LEFTEYE;
02141 if (stereoSwap) {
02142 switch (inStereo) {
02143 case OPENGL_STEREO_HDTVSIDE:
02144 case OPENGL_STEREO_SIDE:
02145 case OPENGL_STEREO_ABOVEBELOW:
02146 case OPENGL_STEREO_QUADBUFFER:
02147 case OPENGL_STEREO_STENCIL_CHECKERBOARD:
02148 case OPENGL_STEREO_STENCIL_COLUMNS:
02149 case OPENGL_STEREO_STENCIL_ROWS:
02150 case OPENGL_STEREO_ANAGLYPH:
02151 cureye = RIGHTEYE;
02152 break;
02153 }
02154 }
02155 
02156 switch (inStereo) {
02157 case OPENGL_STEREO_HDTVSIDE:
02158 glViewport(0, 0, (GLsizei)xSize / 2, (GLsizei)ySize);
02159 set_persp(cureye);
02160 break;
02161 
02162 case OPENGL_STEREO_SIDE:
02163 glViewport(0, 0, (GLsizei)xSize / 2, (GLsizei)ySize);
02164 set_persp(cureye);
02165 break;
02166 
02167 case OPENGL_STEREO_ABOVEBELOW:
02168 glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize / 2);
02169 set_persp(cureye);
02170 break;
02171 
02172 case OPENGL_STEREO_LEFT:
02173 set_persp(LEFTEYE);
02174 break;
02175 
02176 case OPENGL_STEREO_RIGHT:
02177 set_persp(RIGHTEYE);
02178 break;
02179 
02180 case OPENGL_STEREO_QUADBUFFER:
02181 if (ext->hasstereo) {
02182 glDrawBuffer(GL_BACK_LEFT); // Z-buffer must be cleared already
02183 } else {
02184 // XXX do something since we don't support non-quad buffered modes
02185 glViewport(0, (GLint)ySize / 2, (GLsizei)xSize, (GLsizei)ySize / 2);
02186 }
02187 set_persp(cureye);
02188 break;
02189 
02190 case OPENGL_STEREO_STENCIL_CHECKERBOARD:
02191 case OPENGL_STEREO_STENCIL_COLUMNS:
02192 case OPENGL_STEREO_STENCIL_ROWS:
02193 glStencilFunc(GL_NOTEQUAL,1,1); // draws if stencil <> 1
02194 set_persp(cureye);
02195 break;
02196 
02197 case OPENGL_STEREO_ANAGLYPH:
02198 if(ext->hasstereo) {
02199 glDrawBuffer(GL_BACK_LEFT); // Z-buffer must be cleared already
02200 }
02201 // Prevailing default anaglyph format is left-eye-red
02202 glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE); 
02203 set_persp(cureye);
02204 break;
02205 
02206 default:
02207 normal(); // left called even though we're non-stereo
02208 // not tested on other platforms yet
02209 #if defined(__APPLE__)
02210 if (ext->hasstereo && ext->stereodrawforced)
02211 glDrawBuffer(GL_BACK_LEFT); // draw to back-left
02212 #endif
02213 break;
02214 }
02215 
02216 // draw the background gradient if necessary
02217 draw_background_gradient();
02218 }
02219 
02220 
02221 // set up for drawing the right eye image. Assume always the right eye is
02222 // drawn last (so a zclear IS needed before it)
02223 void OpenGLRenderer::right(void) {
02224 DisplayEye cureye = RIGHTEYE;
02225 if (stereoSwap) {
02226 switch (inStereo) {
02227 case OPENGL_STEREO_HDTVSIDE:
02228 case OPENGL_STEREO_SIDE:
02229 case OPENGL_STEREO_ABOVEBELOW:
02230 case OPENGL_STEREO_QUADBUFFER:
02231 case OPENGL_STEREO_STENCIL_CHECKERBOARD:
02232 case OPENGL_STEREO_STENCIL_COLUMNS:
02233 case OPENGL_STEREO_STENCIL_ROWS:
02234 case OPENGL_STEREO_ANAGLYPH:
02235 cureye = LEFTEYE;
02236 break;
02237 }
02238 }
02239 
02240 switch (inStereo) {
02241 case OPENGL_STEREO_HDTVSIDE:
02242 glViewport((GLsizei)xSize / 2, 0, (GLsizei)xSize / 2, (GLsizei)ySize);
02243 set_persp(cureye);
02244 break;
02245 
02246 case OPENGL_STEREO_SIDE:
02247 glViewport((GLsizei)xSize / 2, 0, (GLsizei)xSize / 2, (GLsizei)ySize);
02248 set_persp(cureye);
02249 break;
02250 
02251 case OPENGL_STEREO_ABOVEBELOW:
02252 glViewport(0, (GLsizei)ySize / 2, (GLsizei)xSize, (GLsizei)ySize / 2);
02253 set_persp(cureye);
02254 break;
02255 
02256 case OPENGL_STEREO_LEFT:
02257 case OPENGL_STEREO_RIGHT:
02258 // no need to do anything, already done in call to left
02259 break;
02260 
02261 case OPENGL_STEREO_QUADBUFFER:
02262 if (ext->hasstereo) {
02263 glDepthMask(GL_TRUE); // make Z-buffer writable
02264 #if defined(__APPLE__)
02265 // XXX This hack is required by MacOS X because their 
02266 // Quadro 4500 stereo drivers are broken such that the 
02267 // clear on both right/left buffers doesn't actually work.
02268 // This explicitly forces a second clear on the back right buffer.
02269 glDrawBuffer(GL_BACK_RIGHT);
02270 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
02271 #else
02272 // all other platforms work fine
02273 glClear(GL_DEPTH_BUFFER_BIT);
02274 #endif
02275 glDrawBuffer(GL_BACK_RIGHT);
02276 } else {
02277 // XXX do something since we don't support non-quad buffered modes
02278 glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize / 2);
02279 }
02280 set_persp(cureye);
02281 break;
02282 
02283 case OPENGL_STEREO_STENCIL_CHECKERBOARD:
02284 case OPENGL_STEREO_STENCIL_COLUMNS:
02285 case OPENGL_STEREO_STENCIL_ROWS:
02286 glDepthMask(GL_TRUE); // make Z-buffer writable
02287 glClear(GL_DEPTH_BUFFER_BIT);
02288 glStencilFunc(GL_EQUAL,1,1); // draws if stencil <> 0
02289 set_persp(cureye);
02290 break;
02291 
02292 case OPENGL_STEREO_ANAGLYPH:
02293 if(ext->hasstereo) {
02294 glDrawBuffer(GL_BACK_RIGHT);
02295 }
02296 
02297 // Prevailing default anaglyph format is left-eye-red
02298 #if 1
02299 // Use both green and blue components on right-eye, to yield
02300 // a more "full color" effect for red-blue and red-cyan glasses
02301 glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); 
02302 #else
02303 // Use blue channel only for reduced ghosting with cheap filters
02304 glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE); 
02305 #endif
02306 glDepthMask(GL_TRUE); // make Z-buffer writable
02307 glClear(GL_DEPTH_BUFFER_BIT);
02308 set_persp(cureye);
02309 break;
02310 
02311 default:
02312 normal(); // right called even though we're non-stereo
02313 // not tested on other platforms yet
02314 #if defined(__APPLE__)
02315 if (ext->hasstereo && ext->stereodrawforced)
02316 glDrawBuffer(GL_BACK_RIGHT); // draw to back-right
02317 #endif
02318 break;
02319 }
02320 
02321 // draw the background gradient if necessary
02322 draw_background_gradient();
02323 }
02324 
02325 
02326 // set the current perspective, based on the eye position and where we
02327 // are looking.
02328 void OpenGLRenderer::set_persp(DisplayEye my_eye) {
02329 // define eye and look at some point. Assumes up vector = (0,1,0)
02330 GLdouble ep[3];
02331 switch (my_eye) {
02332 case LEFTEYE:
02333 ep[0] = eyePos[0] - eyeSepDir[0];
02334 ep[1] = eyePos[1] - eyeSepDir[1];
02335 ep[2] = eyePos[2] - eyeSepDir[2];
02336 DisplayDevice::left();
02337 break;
02338 case RIGHTEYE: 
02339 ep[0] = eyePos[0] + eyeSepDir[0];
02340 ep[1] = eyePos[1] + eyeSepDir[1];
02341 ep[2] = eyePos[2] + eyeSepDir[2];
02342 DisplayDevice::right();
02343 break;
02344 
02345 case NOSTEREO:
02346 default:
02347 ep[0] = eyePos[0];
02348 ep[1] = eyePos[1];
02349 ep[2] = eyePos[2];
02350 DisplayDevice::normal();
02351 break;
02352 }
02353 
02354 // setup camera system and projection transformations
02355 if (projection() == PERSPECTIVE) {
02356 ogl_glslprojectionmode = DisplayDevice::PERSPECTIVE; 
02357 
02358 if (shearstereo) {
02359 // XXX almost ready for prime time, when testing is done we may
02360 // make shear stereo the default and eye rotation a backwards 
02361 // compatibility option.
02362 // Use the "frustum shearing" method for creating a stereo view. 
02363 // The frustum shearing method is preferable to eye rotation in general.
02364 
02365 // Calculate the eye shift (half eye separation distance)
02366 // XXX hack, needs to be more general
02367 float eyeshift = float(ep[0] - eyePos[0]);
02368 
02369 glMatrixMode(GL_PROJECTION);
02370 glLoadIdentity();
02371 // Shifts viewing frustum horizontally in the image plane
02372 // according to the stereo eye separation if rendering in stereo.
02373 // XXX hack, the parameterization of this projection still 
02374 // needs work, but the fact that it incorporates eyeDist is nice.
02375 glFrustum((GLdouble)cpLeft + (eyeshift * nearClip / eyeDist),
02376 (GLdouble)cpRight + (eyeshift * nearClip / eyeDist),
02377 (GLdouble)cpDown, 
02378 (GLdouble)cpUp,
02379 (GLdouble)nearClip, 
02380 (GLdouble)farClip);
02381 
02382 // Shift the eye position horizontally by half the eye separation
02383 // distance if rendering in stereo.
02384 glTranslatef(-eyeshift, 0.0, 0.0); 
02385 
02386 glMatrixMode(GL_MODELVIEW);
02387 // set modelview identity and then applies transform
02388 vmd_LookAt(eyePos[0], eyePos[1], eyePos[2],
02389 (GLdouble)(eyePos[0] + eyeDir[0]),
02390 (GLdouble)(eyePos[1] + eyeDir[1]),
02391 (GLdouble)(eyePos[2] + eyeDir[2]),
02392 (GLdouble)(upDir[0]),
02393 (GLdouble)(upDir[1]),
02394 (GLdouble)(upDir[2]));
02395 } else {
02396 // Use the "eye rotation" method for creating a stereo view. 
02397 // The frustum shearing method would be preferable.
02398 // XXX this implementation is not currently using the eyeDist
02399 // parameter, though it probably should.
02400 glMatrixMode(GL_PROJECTION);
02401 glLoadIdentity();
02402 glFrustum((GLdouble)cpLeft, (GLdouble)cpRight, (GLdouble)cpDown,
02403 (GLdouble)cpUp, (GLdouble)nearClip, (GLdouble)farClip);
02404 
02405 // Reflect the X axis of the right eye for the new LCD panel immersadesks
02406 // XXX experimental hack that needs more work to get lighting
02407 // completely correct for the Axes, Title Screen, etc.
02408 if (immersadeskflip && my_eye == RIGHTEYE) {
02409 // Scale the X axis by -1 in the GL_PROJECTION matrix
02410 glScalef(-1, 1, 1);
02411 }
02412 
02413 glMatrixMode(GL_MODELVIEW);
02414 // set modelview identity and then applies transform
02415 vmd_LookAt(ep[0], ep[1], ep[2],
02416 (GLdouble)(eyePos[0] + eyeDir[0]),
02417 (GLdouble)(eyePos[1] + eyeDir[1]),
02418 (GLdouble)(eyePos[2] + eyeDir[2]),
02419 (GLdouble)(upDir[0]),
02420 (GLdouble)(upDir[1]),
02421 (GLdouble)(upDir[2]));
02422 }
02423 } else { // ORTHOGRAPHIC
02424 ogl_glslprojectionmode = DisplayDevice::ORTHOGRAPHIC; 
02425 glMatrixMode(GL_PROJECTION);
02426 glLoadIdentity();
02427 
02428 glOrtho(-0.25 * vSize * Aspect, 0.25 * vSize * Aspect,
02429 -0.25 * vSize, 0.25 * vSize,
02430 nearClip, farClip);
02431 
02432 // Use the "eye rotation" method for creating a stereo view. 
02433 // The frustum shearing method won't work with orthographic 
02434 // views since the eye rays are parallel, so the rotation method 
02435 // is ok in this case.
02436 glMatrixMode(GL_MODELVIEW);
02437 // set modelview identity and then applies transform
02438 vmd_LookAt(ep[0], ep[1], ep[2],
02439 (GLdouble)(eyePos[0] + eyeDir[0]),
02440 (GLdouble)(eyePos[1] + eyeDir[1]),
02441 (GLdouble)(eyePos[2] + eyeDir[2]),
02442 (GLdouble)(upDir[0]),
02443 (GLdouble)(upDir[1]),
02444 (GLdouble)(upDir[2]));
02445 }
02446 
02447 // update the cached transformation matrices for use in text display, etc.
02448 glGetFloatv(GL_PROJECTION_MATRIX, ogl_pmatrix);
02449 glGetFloatv(GL_MODELVIEW_MATRIX, ogl_mvmatrix);
02450 glGetIntegerv(GL_VIEWPORT, ogl_viewport);
02451 ogl_textMat.identity();
02452 ogl_textMat.multmatrix(ogl_pmatrix);
02453 ogl_textMat.multmatrix(ogl_mvmatrix);
02454 }
02455 
02456 
02457 // prepare to draw a 3D image
02458 int OpenGLRenderer::prepare3D(int do_clear) {
02459 if (do_clear) {
02460 clear();
02461 } else {
02462 glDepthMask(GL_TRUE); // make Z-buffer writable
02463 glClear(GL_DEPTH_BUFFER_BIT);
02464 }
02465 
02466 // invalidate the OpenGL material index cache since a new frame is
02467 // being drawn and the material state for the previous index may 
02468 // have changed. 
02469 oglmaterialindex = -1;
02470 
02471 // start a new frame, marking all cached IDs as "unused"
02472 displaylistcache.markUnused();
02473 texturecache.markUnused();
02474 
02475 #if defined(VMDOPTIXRTRT)
02476 if (ogl_optix_rtrt_passthrough) {
02477 #if 0
02478 printf("OpenGLRenderer::prepare3D(%ld x %ld) --> RTX RTRT Passthrough\n",
02479 xSize, ySize);
02480 #endif
02481 ort->destroy_scene();
02482 ort->framebuffer_config(xSize, ySize, 0);
02483 // ort->framebuffer_resize(xSize, ySize);
02484 
02485 ort->shadows_on(shadows_enabled()); // shadowing mode required 
02486 ort->set_ao_samples(ao_enabled() * 8);
02487 ort->set_ao_ambient(get_ao_ambient());
02488 ort->set_ao_direct(get_ao_direct());
02489 ort->dof_on(dof_enabled());
02490 ort->set_camera_dof_fnumber(get_dof_fnumber());
02491 ort->set_camera_dof_focal_dist(get_dof_focal_dist());
02492 
02493 // set depth cueing parameters
02494 float start = get_cue_start();
02495 float end = get_cue_end();
02496 float density = get_cue_density();
02497 if (cueingEnabled) {
02498 switch (cueMode) {
02499 case CUE_LINEAR:
02500 ort->set_cue_mode(OptiXRenderer::RT_FOG_LINEAR, start, end, density);
02501 break;
02502 
02503 case CUE_EXP:
02504 ort->set_cue_mode(OptiXRenderer::RT_FOG_EXP, start, end, density);
02505 break;
02506 
02507 case CUE_EXP2:
02508 ort->set_cue_mode(OptiXRenderer::RT_FOG_EXP2, start, end, density);
02509 break;
02510 
02511 case NUM_CUE_MODES:
02512 // this should never happen
02513 break;
02514 }
02515 } else {
02516 ort->set_cue_mode(OptiXRenderer::RT_FOG_NONE, start, end, density);
02517 }
02518 
02519 // clear all existing lights before (re)appending the current lights,
02520 // otherwise if the OptiX context is reused, we will crash and burn.
02521 ort->clear_all_lights();
02522 
02523 // directional lights
02524 int i;
02525 for (i=0; i<DISP_LIGHTS; i++) {
02526 if (ogl_lightstate[i]) {
02527 ort->add_directional_light(ogl_lightpos[i], ogl_lightcolor[i]);
02528 }
02529 }
02530 
02531 // set stereoscopic display parameters
02532 ort->set_camera_stereo_eyesep(eyeSep);
02533 ort->set_camera_stereo_convergence_dist(eyeDist);
02534 
02535 // set camera projection mode and associated background mode
02536 switch (projection()) {
02537 case DisplayDevice::ORTHOGRAPHIC:
02538 ort->set_camera_projection(OptiXRenderer::RT_ORTHOGRAPHIC);
02539 ort->set_camera_zoom(0.5f / (1.0 / (vSize / 2.0)));
02540 break;
02541 
02542 case DisplayDevice::PERSPECTIVE:
02543 default:
02544 ort->set_camera_projection(OptiXRenderer::RT_PERSPECTIVE);
02545 ort->set_camera_zoom(0.5f / ((eyePos[2] - zDist) / vSize));
02546 break;
02547 }
02548 
02549 ort->set_bg_color(ogl_backcolor);
02550 
02551 // Specify Tachyon/OptiX background sky sphere/plane if gradient mode is on
02552 if (backgroundmode == 1) {
02553 float bspheremag = 0.5f;
02554 
02555 // compute positive/negative magnitude of sphere gradient
02556 switch (projection()) {
02557 case DisplayDevice::ORTHOGRAPHIC:
02558 ort->set_bg_mode(OptiXRenderer::RT_BACKGROUND_TEXTURE_SKY_ORTHO_PLANE);
02559 
02560 // For orthographic views, Tachyon uses the dot product between
02561 // the incident ray origin and the sky plane gradient "up" vector,
02562 // since all camera rays have the same direction and differ only
02563 // in their origin.
02564 bspheremag = vSize / 4.0f;
02565 break;
02566 
02567 case DisplayDevice::PERSPECTIVE:
02568 default:
02569 ort->set_bg_mode(OptiXRenderer::RT_BACKGROUND_TEXTURE_SKY_SPHERE);
02570 
02571 // For perspective views, Tachyon uses the dot product between
02572 // the incident ray and the sky sphere gradient "up" vector,
02573 // so for larger values of vSize, we have to clamp the maximum
02574 // magnitude to 1.0.
02575 bspheremag = (vSize / 2.0f) / (eyePos[2] - zDist);
02576 if (bspheremag > 1.0f)
02577 bspheremag = 1.0f;
02578 break;
02579 }
02580 
02581 // set background color, fog color, and background gradient colors
02582 ort->set_bg_color_grad_top(ogl_backgradient[0]);
02583 ort->set_bg_color_grad_bot(ogl_backgradient[1]);
02584 
02585 float updir[3] = { 0.0f, 1.0f, 0.0f };
02586 ort->set_bg_gradient(updir);
02587 
02588 ort->set_bg_gradient_topval(bspheremag);
02589 ort->set_bg_gradient_botval(-bspheremag);
02590 } else {
02591 ort->set_bg_mode(OptiXRenderer::RT_BACKGROUND_TEXTURE_SOLID);
02592 }
02593 
02594 }
02595 #endif
02596 
02597 return TRUE; // must return true for normal (non file-based) renderers
02598 }
02599 
02600 
02601 // prepare to draw opaque objects
02602 int OpenGLRenderer::prepareOpaque(void) {
02603 if (ogl_useblendedtrans) {
02604 glDepthMask(GL_TRUE); // make Z-buffer writable
02605 ogl_transpass = 0;
02606 }
02607 
02608 return 1;
02609 }
02610 
02611 // prepare to draw transparent objects
02612 int OpenGLRenderer::prepareTrans(void) {
02613 if (ogl_useblendedtrans) {
02614 glDepthMask(GL_FALSE); // make Z-buffer read-only while drawing trans objs
02615 ogl_transpass = 1;
02616 return 1;
02617 }
02618 
02619 return 0;
02620 }
02621 
02622 // clear the display
02623 void OpenGLRenderer::clear(void) {
02624 // clear the whole viewport, not just one side 
02625 switch (inStereo) {
02626 case OPENGL_STEREO_HDTVSIDE:
02627 case OPENGL_STEREO_SIDE:
02628 case OPENGL_STEREO_ABOVEBELOW:
02629 case OPENGL_STEREO_QUADBUFFER:
02630 case OPENGL_STEREO_ANAGLYPH:
02631 glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize);
02632 break;
02633 }
02634 
02635 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // reset color mask 
02636 glDepthMask(GL_TRUE); // make Z-buffer writable
02637 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color/depth bufs
02638 
02639 // not tested on other platforms yet
02640 #if defined(__APPLE__)
02641 if (ext->hasstereo && ext->stereodrawforced) {
02642 glDrawBuffer(GL_BACK_RIGHT);
02643 glClear(GL_COLOR_BUFFER_BIT); // force separate clear of right buffer
02644 glDrawBuffer(GL_BACK);
02645 }
02646 #endif
02647 }
02648 
02649 
02650 // draw the background gradient
02651 void OpenGLRenderer::draw_background_gradient(void) {
02652 // if the background mode is set for gradient, then draw the gradient
02653 // note: this must be done immediately after clearing the viewport
02654 if (backgroundmode != 0) {
02655 int i;
02656 
02657 // disable all clipping planes by default
02658 for (i=0; i < VMD_MAX_CLIP_PLANE; i++) {
02659 ogl_clipmode[i] = 0; // off by default
02660 glDisable((GLenum) (GL_CLIP_PLANE0 + i));
02661 }
02662 
02663 glDisable(GL_LIGHTING); // disable lighting
02664 ogl_lightingenabled=0; // update state var
02665 #if defined(VMDUSEOPENGLSHADER)
02666 if (mainshader && ogl_useglslshader) {
02667 mainshader->UseShader(0); // use fixed-func pipeline
02668 }
02669 #endif
02670 glDisable(GL_DEPTH_TEST); // disable depth test
02671 glDepthMask(GL_FALSE); // make Z-buffer read-only
02672 
02673 // turn off any transparent rendering state
02674 glDisable(GL_POLYGON_STIPPLE); // make sure stippling is disabled
02675 glDisable(GL_BLEND); // disable blending
02676 
02677 glMatrixMode(GL_MODELVIEW); // save existing transformation state
02678 glPushMatrix();
02679 glLoadIdentity(); // prepare for 2-D orthographic drawing
02680 
02681 glMatrixMode (GL_PROJECTION); // save existing transformation state
02682 glPushMatrix();
02683 glLoadIdentity();
02684 glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); // 2-D orthographic projection
02685 
02686 glMatrixMode(GL_MODELVIEW);
02687 glPushMatrix();
02688 glLoadIdentity(); // add one more modelview
02689 
02690 // draw the background polygon
02691 glBegin(GL_QUADS);
02692 glColor3fv(&ogl_backgradient[1][0]);
02693 glVertex2f(0.0f, 0.0f);
02694 glColor3fv(&ogl_backgradient[1][0]);
02695 glVertex2f(1.0f, 0.0f);
02696 glColor3fv(&ogl_backgradient[0][0]);
02697 glVertex2f(1.0f, 1.0f);
02698 glColor3fv(&ogl_backgradient[0][0]);
02699 glVertex2f(0.0f, 1.0f);
02700 glEnd();
02701 
02702 glPopMatrix(); // pop off top modelview
02703 
02704 glMatrixMode (GL_PROJECTION);
02705 glPopMatrix(); // restore projection transform state
02706 
02707 glMatrixMode(GL_MODELVIEW);
02708 glPopMatrix(); // restore modelview transform state
02709 
02710 glEnable(GL_DEPTH_TEST); // restore depth testing
02711 glDepthMask(GL_TRUE); // make Z-buffer writeable
02712 glEnable(GL_LIGHTING); // restore lighting
02713 ogl_lightingenabled=1; // update state var
02714 #if defined(VMDUSEOPENGLSHADER)
02715 if (mainshader && ogl_useglslshader) {
02716 mainshader->UseShader(1); // re-enable glsl mainshader
02717 }
02718 #endif
02719 }
02720 }
02721 
02722 
02723 //********************** the rendering routine ***********************
02724 //* This scans the given command list until the end, doing the commands
02725 //* in the order they appear
02726 //**********************************************************************
02727 void OpenGLRenderer::render(const VMDDisplayList *cmdList) {
02728 char *cmdptr = NULL; // ptr to current display command data
02729 int tok; // what display command was encountered
02730 _needRedraw = 0; // reset the flag now that we are drawing
02731 
02732 // early exit if any of these conditions are true. 
02733 if (!cmdList) 
02734 return;
02735 
02736 #if defined(VMDOPTIXRTRT)
02740 if (ogl_optix_rtrt_passthrough) {
02741 ort->scene_aggregate_cmdlist(cmdList, colorData);
02742 return;
02743 }
02744 #endif
02745 
02746 if (ogl_useblendedtrans) {
02747 if (ogl_transpass) {
02748 // skip rendering mostly Opaque objects on transparent pass
02749 if (cmdList->opacity > 0.50) 
02750 return;
02751 } else {
02752 // skip rendering mostly transparent objects on opaque pass
02753 if (cmdList->opacity <= 0.50)
02754 return;
02755 }
02756 } else {
02757 if (cmdList->opacity < 0.0625)
02758 return;
02759 }
02760 
02761 // if we're rendering for Acrobat3D capture, emit materials and other
02762 // state changes at every opportunity, caching next to nothing by 
02763 // invalidating materials on every object we draw
02764 if (ogl_acrobat3dcapture) {
02765 oglmaterialindex = -1;
02766 oglambient = -1;
02767 ogldiffuse = -1;
02768 oglspecular = -1;
02769 oglshininess = -1;
02770 ogloutline = -1;
02771 ogloutlinewidth = -1;
02772 ogltransmode = -1;
02773 } 
02774 
02775 //
02776 // set the material - only changing those items that have been updated.
02777 //
02778 if (oglmaterialindex != cmdList->materialtag) {
02779 float matbuf[4];
02780 matbuf[3] = 1.0f; 
02781 int recalcambientlights = 0;
02782 int recalcdiffuselights = 0;
02783 
02784 oglmaterialindex = cmdList->materialtag;
02785 if (oglopacity != cmdList->opacity) {
02786 oglopacity = cmdList->opacity; // update for next time through
02787 
02788 if (ogl_useblendedtrans) {
02789 glDisable(GL_POLYGON_STIPPLE); 
02790 if (oglopacity > 0.999) {
02791 // disable alpha-blended transparency
02792 glDisable(GL_BLEND);
02793 } else {
02794 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02795 glEnable(GL_BLEND);
02796 }
02797 } else {
02798 // disable alpha-blended transparency
02799 glDisable(GL_BLEND);
02800 
02801 // use stipple-based transparency
02802 if (oglopacity > 0.9375) { 
02803 glDisable(GL_POLYGON_STIPPLE); 
02804 } else {
02805 // here's our transparency: opacity < 0.9375 -> transparent
02806 if (oglopacity > 0.875) 
02807 glPolygonStipple(ninesixteentone); 
02808 else if (oglopacity > 0.75) 
02809 glPolygonStipple(seveneighthtone); 
02810 else if (oglopacity > 0.5) 
02811 glPolygonStipple(threequartertone); 
02812 else if (oglopacity > 0.25)
02813 glPolygonStipple(halftone); 
02814 else if (oglopacity > 0.125)
02815 glPolygonStipple(quartertone); 
02816 else if (oglopacity > 0.0625)
02817 glPolygonStipple(eighthtone); 
02818 else 
02819 return; // skip rendering the geometry if entirely transparent
02820 
02821 glEnable(GL_POLYGON_STIPPLE); 
02822 }
02823 }
02824 }
02825 
02826 if (ogloutline != cmdList->outline) { 
02827 ogloutline = cmdList->outline;
02828 }
02829 
02830 if (ogloutlinewidth != cmdList->outlinewidth) { 
02831 ogloutlinewidth = cmdList->outlinewidth;
02832 }
02833 
02834 if (ogltransmode != (int) cmdList->transmode) { 
02835 ogltransmode = (int) cmdList->transmode;
02836 }
02837 
02838 if (oglambient != cmdList->ambient) { 
02839 oglambient = cmdList->ambient;
02840 recalcambientlights = 1; // force recalculation of ambient lighting
02841 matbuf[0] = matbuf[1] = matbuf[2] = oglambient; 
02842 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matbuf);
02843 }
02844 
02845 if (ogldiffuse != cmdList->diffuse) { 
02846 ogldiffuse = cmdList->diffuse;
02847 recalcdiffuselights = 1; // force recalculation of diffuse lighting
02848 matbuf[0] = matbuf[1] = matbuf[2] = ogldiffuse; 
02849 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matbuf);
02850 }
02851 
02852 if (oglspecular != cmdList->specular) { 
02853 oglspecular = cmdList->specular;
02854 matbuf[0] = matbuf[1] = matbuf[2] = oglspecular; 
02855 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matbuf);
02856 }
02857 
02858 if (oglshininess != cmdList->shininess) {
02859 oglshininess = cmdList->shininess;
02860 
02861 // clamp shininess parameter to what OpenGL 1.x can deal with
02862 // XXX there are new OpenGL extensions that allow a broader range
02863 // of Phong exponents.
02864 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 
02865 (GLfloat) (oglshininess < 128.0f) ? oglshininess : 128.0f);
02866 }
02867 
02868 // change lighting to match new diffuse/ambient factors
02869 if (recalcambientlights) { 
02870 for (int z=0; z<DISP_LIGHTS; z++) {
02871 GLfloat d[4];
02872 d[0] = ogl_lightcolor[z][0] * oglambient;
02873 d[1] = ogl_lightcolor[z][1] * oglambient;
02874 d[2] = ogl_lightcolor[z][2] * oglambient;
02875 d[3] = 1.0;
02876 glLightfv((GLenum)(GL_LIGHT0 + z), GL_AMBIENT, d);
02877 }
02878 }
02879 
02880 if (recalcdiffuselights) { 
02881 for (int z=0; z<DISP_LIGHTS; z++) {
02882 GLfloat d[4];
02883 d[0] = ogl_lightcolor[z][0] * ogldiffuse;
02884 d[1] = ogl_lightcolor[z][1] * ogldiffuse;
02885 d[2] = ogl_lightcolor[z][2] * ogldiffuse;
02886 d[3] = 1.0;
02887 glLightfv((GLenum)(GL_LIGHT0 + z), GL_DIFFUSE, d);
02888 }
02889 }
02890 }
02891 // 
02892 // end material processing code for fixed-function OpenGL pipeline
02893 //
02894 
02895 // XXX shouldn't be testing this every rep, but for now this works ok 
02896 ogl_fogmode = 0; // fogmode for shaders
02897 
02898 if (cueingEnabled) {
02899 switch (cueMode) {
02900 case CUE_LINEAR: 
02901 glFogi(GL_FOG_MODE, GL_LINEAR);
02902 ogl_fogmode = 1;
02903 break;
02904 
02905 case CUE_EXP:
02906 glFogi(GL_FOG_MODE, GL_EXP);
02907 ogl_fogmode = 2;
02908 break;
02909 
02910 case CUE_EXP2:
02911 glFogi(GL_FOG_MODE, GL_EXP2);
02912 ogl_fogmode = 3;
02913 break;
02914 
02915 case NUM_CUE_MODES:
02916 // this should never happen
02917 break;
02918 }
02919 
02920 glFogf(GL_FOG_DENSITY, (GLfloat) get_cue_density());
02921 glFogf(GL_FOG_START, (GLfloat) get_cue_start());
02922 glFogf(GL_FOG_END, (GLfloat) get_cue_end());
02923 }
02924 
02925 #if defined(VMDUSEOPENGLSHADER)
02926 // setup programmable shader for this object
02927 if (mainshader) {
02928 if (ogl_useglslshader) {
02929 mainshader->UseShader(1); // if glsl is available and enabled, use it
02930 
02931 if ((ogl_glslmaterialindex != cmdList->materialtag) || ogl_glsltoggle) {
02932 ogl_glslmaterialindex = cmdList->materialtag;
02933 ogl_glsltoggle = 0;
02934 update_shader_uniforms(mainshader, 1);
02935 }
02936 } else {
02937 mainshader->UseShader(0); // if glsl is available but disabled, turn it off
02938 }
02939 }
02940 #endif
02941 
02942 // save transformation matrix
02943 glMatrixMode(GL_MODELVIEW);
02944 glPushMatrix();
02945 multmatrix(cmdList->mat);
02946 
02947 // set up text matrices
02948 Matrix4 textMat(ogl_textMat);
02949 textMat.multmatrix(cmdList->mat);
02950 
02951 // XXX Display list caching begins here
02952 GLuint ogl_cachedid = 0; // reset OpenGL display list ID for cached list
02953 int ogl_cachecreated = 0; // reset display list creation flag
02954 int ogl_cacheskip;
02955 
02956 // Disable display list caching if GLSL is enabled or we encounter
02957 // a non-cacheable representation (such as an animating structure).
02958 ogl_cacheskip = (cmdList->cacheskip || ogl_useglslshader);
02959 
02960 // enable/disable clipping planes
02961 for (int cp=0; cp<VMD_MAX_CLIP_PLANE; cp++) {
02962 // don't cache 'on' state since the parameters will likely differ,
02963 // just setup the clip plane from the new state
02964 if (cmdList->clipplanes[cp].mode) {
02965 GLdouble cpeq[4];
02966 cpeq[0] = cmdList->clipplanes[cp].normal[0];
02967 cpeq[1] = cmdList->clipplanes[cp].normal[1];
02968 cpeq[2] = cmdList->clipplanes[cp].normal[2];
02969 
02970 // Convert specification to OpenGL plane equation
02971 cpeq[3] = 
02972 -(cmdList->clipplanes[cp].normal[0] * cmdList->clipplanes[cp].center[0] +
02973 cmdList->clipplanes[cp].normal[1] * cmdList->clipplanes[cp].center[1] +
02974 cmdList->clipplanes[cp].normal[2] * cmdList->clipplanes[cp].center[2]);
02975 glClipPlane((GLenum) (GL_CLIP_PLANE0 + cp), cpeq);
02976 glEnable((GLenum) (GL_CLIP_PLANE0 + cp)); 
02977 
02978 // XXX if the clipping plane mode is set for rendering
02979 // capped clipped solids, we will have to perform several
02980 // rendering passes using the stencil buffer and Z-buffer 
02981 // in order to get the desired results.
02982 // http://www.nigels.com/research/wscg2002.pdf 
02983 // http://citeseer.ist.psu.edu/stewart02lineartime.html
02984 // http://citeseer.ist.psu.edu/stewart98improved.html
02985 // http://www.sgi.com/software/opengl/advanced97/notes/node10.html
02986 // http://www.opengl.org/resources/tutorials/sig99/advanced99/notes/node21.html
02987 // http://www.ati.com/developer/sdk/rage128sdk/OpenGL/Samples/Rage128StencilCap.html
02988 // The most common algorithm goes something like what is described here:
02989 // 0) clear stencil/color/depth buffers
02990 // 1) disable color buffer writes
02991 // 2) render clipping plane polygon writing to depth buffer
02992 // 3) disable depth buffer writes
02993 // 4) set stencil op to increment when depth test passes
02994 // 5) draw molecule with glCullFace(GL_BACK)
02995 // 6) set stencil op to decrement when depth test passes
02996 // 7) draw molecule with glCullFace(GL_FRONT)
02997 // 8) clear depth buffer
02998 // 9) enable color buffer writes 
02999 // 10) set stencil function to GL_EQUAL of 1
03000 // 11) draw clipping plane polygon with appropriate materials
03001 // 12) disable stencil buffer
03002 // 13) enable OpenGL clipping plane
03003 // 14) draw molecule
03004 } else {
03005 // if its already off, no need to disable it again.
03006 if (ogl_clipmode[cp] != cmdList->clipplanes[cp].mode) {
03007 glDisable((GLenum) (GL_CLIP_PLANE0 + cp)); 
03008 }
03009 }
03010 
03011 // update clip mode cache
03012 ogl_clipmode[cp] = cmdList->clipplanes[cp].mode;
03013 }
03014 
03015 // Compute periodic image transformation matrices
03016 ResizeArray<Matrix4> pbcImages;
03017 find_pbc_images(cmdList, pbcImages);
03018 int npbcimages = pbcImages.num();
03019 
03020 // Retreive instance image transformation matrices
03021 ResizeArray<Matrix4> instanceImages;
03022 find_instance_images(cmdList, instanceImages);
03023 int ninstances = instanceImages.num();
03024 
03025 for (int pbcimage = 0; pbcimage < npbcimages; pbcimage++) {
03026 glPushMatrix();
03027 multmatrix(pbcImages[pbcimage]);
03028 
03029 for (int instanceimage = 0; instanceimage < ninstances; instanceimage++) {
03030 glPushMatrix();
03031 multmatrix(instanceImages[instanceimage]);
03032 
03033 if (ogl_cachedebug) {
03034 msgInfo << "Rendering scene: cache enable=" << ogl_cacheenabled 
03035 << ", created=" << ogl_cachecreated << ", serial=" << (int)cmdList->serial
03036 << ", id=" << (int)ogl_cachedid << ", skip=" << ogl_cacheskip << sendmsg;
03037 }
03038 
03039 // find previously cached display list for this object
03040 if (ogl_cacheenabled && !ogl_cacheskip) {
03041 ogl_cachedid = displaylistcache.markUsed(cmdList->serial);
03042 
03043 // add to the cache and regenerate if we didn't find it
03044 if (ogl_cachedid == GLCACHE_FAIL) {
03045 ogl_cachedid = glGenLists(1); 
03046 displaylistcache.encache(cmdList->serial, ogl_cachedid);
03047 
03048 // create the display list, and execute it.
03049 glNewList(ogl_cachedid, GL_COMPILE_AND_EXECUTE);
03050 ogl_cachecreated = 1; // a new display list was created 
03051 } 
03052 }
03053 
03054 // XXX Draw OpenGL geometry only when caching is disabled or when
03055 // we have new geometry to cache
03056 if ((!ogl_cacheenabled) || ogl_cacheskip || (ogl_cacheenabled && ogl_cachecreated)) {
03057 
03058 // scan through the list, getting each command and executing it, until
03059 // the end of commands token is found
03060 VMDDisplayList::VMDLinkIter cmditer;
03061 cmdList->first(&cmditer);
03062 while((tok = cmdList->next(&cmditer, cmdptr)) != DLASTCOMMAND) {
03063 OGLERR // enable OpenGL debugging code
03064 
03065 switch (tok) {
03066 case DPOINT:
03067 // plot a point at the given position
03068 glBegin(GL_POINTS);
03069 glVertex3fv(((DispCmdPoint *)cmdptr)->pos);
03070 glEnd();
03071 break;
03072 
03073 case DPOINTARRAY: 
03074 {
03075 DispCmdPointArray *pa = (DispCmdPointArray *)cmdptr;
03076 float *centers;
03077 float *colors;
03078 pa->getpointers(centers, colors);
03079 #if defined(GL_VERSION_1_1)
03080 if (!(simplegraphics || ogl_acrobat3dcapture)) {
03081 // Vertex array implementation 
03082 glDisable(GL_LIGHTING); 
03083 ogl_lightingenabled=0;
03084 glEnableClientState(GL_VERTEX_ARRAY);
03085 glEnableClientState(GL_COLOR_ARRAY);
03086 glDisableClientState(GL_NORMAL_ARRAY);
03087 glVertexPointer(3, GL_FLOAT, 12, (void *) centers);
03088 glColorPointer(3, GL_FLOAT, 12, (void *) colors);
03089 
03090 #if defined(GL_EXT_compiled_vertex_array) 
03091 if (ext->hascompiledvertexarrayext) {
03092 GLLOCKARRAYSEXT(0, pa->numpoints);
03093 }
03094 #endif
03095 
03096 // set point size, enable blending and point antialiasing
03097 glPointSize(pa->size); 
03098 glEnable(GL_POINT_SMOOTH);
03099 glEnable(GL_BLEND);
03100 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
03101 
03102 #if defined(VMDUSEGLSLSPHERESPRITES) && defined(GL_ARB_point_sprite)
03103 // XXX enable point sprites
03104 if (ext->hasglpointspritearb &&
03105 spherespriteshader && ogl_useglslshader) {
03106 glEnable(GL_POINT_SPRITE_ARB);
03107 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
03108 mainshader->UseShader(0); // switch to sphere shader
03109 spherespriteshader->UseShader(1); // switch to sphere sprite shader
03110 update_shader_uniforms(spherespriteshader, 1); // force update of shader
03111 
03112 // define sprite size in pixels
03113 GLint loc;
03114 loc = GLGETUNIFORMLOCATIONARB(spherespriteshader->ProgramObject,
03115 "vmdspritesize");
03116 GLfloat sz = pa->size;
03117 GLUNIFORM1FVARB(loc, 1, &sz);
03118 
03119 // Specify point sprite texture coordinate replacement mode
03120 glPushAttrib(GL_TEXTURE_BIT);
03121 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
03122 OGLERR;
03123 }
03124 #endif
03125 
03126 #if defined(GL_ARB_point_parameters) 
03127 int dodepthscaling = 0;
03128 
03129 // enable distance based point attenuation
03130 if (ext->hasglpointparametersext && (projection() == PERSPECTIVE)) {
03131 dodepthscaling = 1;
03132 
03133 GLfloat abc[4] = {0.0, 0.0, 1.0};
03134 GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
03135 }
03136 #endif
03137 
03138 glDrawArrays(GL_POINTS, 0, pa->numpoints);
03139 
03140 #if defined(GL_ARB_point_parameters) 
03141 // disable distance based point attenuation
03142 if (dodepthscaling) {
03143 GLfloat abc[4] = {1.0, 0.0, 0.0};
03144 GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
03145 }
03146 #endif
03147 
03148 // disable blending and point antialiasing
03149 glDisable(GL_BLEND);
03150 glDisable(GL_POINT_SMOOTH);
03151 
03152 #if defined(GL_EXT_compiled_vertex_array) 
03153 if (ext->hascompiledvertexarrayext) {
03154 GLUNLOCKARRAYSEXT();
03155 }
03156 #endif
03157 
03158 #if defined(VMDUSEGLSLSPHERESPRITES) && defined(GL_ARB_point_sprite)
03159 // XXX enable point sprites
03160 if (ext->hasglpointspritearb &&
03161 spherespriteshader && ogl_useglslshader) {
03162 glPopAttrib(); // return previous texturing state
03163 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
03164 glDisable(GL_POINT_SPRITE_ARB);
03165 spherespriteshader->UseShader(0); // switch back to the main shader
03166 mainshader->UseShader(1); // switch back to the main shader
03167 OGLERR;
03168 }
03169 #endif
03170 
03171 glEnableClientState(GL_NORMAL_ARRAY);
03172 glPointSize(1.0); // reset point size to default
03173 } else {
03174 #endif
03175 // Immediate mode implementation
03176 int i; 
03177 ptrdiff_t ind;
03178 glBegin(GL_POINTS);
03179 ind = 0;
03180 for (i=0; i<pa->numpoints; i++) {
03181 glColor3fv(&colors[ind]);
03182 glVertex3fv(&centers[ind]); 
03183 ind+=3;
03184 }
03185 glEnd();
03186 #if defined(GL_VERSION_1_1)
03187 }
03188 #endif
03189 }
03190 break;
03191 
03192 case DLITPOINTARRAY: 
03193 {
03194 DispCmdLitPointArray *pa = (DispCmdLitPointArray *)cmdptr;
03195 float *centers;
03196 float *normals;
03197 float *colors;
03198 pa->getpointers(centers, normals, colors);
03199 #if defined(GL_VERSION_1_1)
03200 if (!(simplegraphics || ogl_acrobat3dcapture)) {
03201 // Vertex array implementation 
03202 glEnableClientState(GL_VERTEX_ARRAY);
03203 glEnableClientState(GL_COLOR_ARRAY);
03204 glEnableClientState(GL_NORMAL_ARRAY);
03205 glVertexPointer(3, GL_FLOAT, 12, (void *) centers);
03206 glNormalPointer(GL_FLOAT, 12, (void *) normals);
03207 glColorPointer(3, GL_FLOAT, 12, (void *) colors);
03208 
03209 #if defined(GL_EXT_compiled_vertex_array) 
03210 if (ext->hascompiledvertexarrayext) {
03211 GLLOCKARRAYSEXT(0, pa->numpoints);
03212 }
03213 #endif
03214 
03215 // set point size, enable blending and point antialiasing
03216 glPointSize(pa->size); 
03217 glEnable(GL_POINT_SMOOTH);
03218 
03219 #if defined(GL_ARB_point_parameters) 
03220 int dodepthscaling = 0;
03221 // enable distance based point attenuation
03222 if (ext->hasglpointparametersext && (projection() == PERSPECTIVE)) {
03223 dodepthscaling = 1;
03224 GLfloat abc[4] = {0.0, 0.0, 1.0};
03225 GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
03226 }
03227 #endif
03228 
03229 glDrawArrays(GL_POINTS, 0, pa->numpoints);
03230 
03231 #if defined(GL_ARB_point_parameters) 
03232 // disable distance based point attenuation
03233 if (dodepthscaling) {
03234 GLfloat abc[4] = {1.0, 0.0, 0.0};
03235 GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
03236 }
03237 #endif
03238 
03239 // disable blending and point antialiasing
03240 glDisable(GL_BLEND);
03241 glDisable(GL_POINT_SMOOTH);
03242 
03243 #if defined(GL_EXT_compiled_vertex_array) 
03244 if (ext->hascompiledvertexarrayext) {
03245 GLUNLOCKARRAYSEXT();
03246 }
03247 #endif
03248 
03249 glPointSize(1.0); // reset point size to default
03250 } else {
03251 #endif
03252 // Immediate mode implementation 
03253 int i; 
03254 ptrdiff_t ind;
03255 glBegin(GL_POINTS);
03256 ind = 0;
03257 for (i=0; i<pa->numpoints; i++) {
03258 glColor3fv(&colors[ind]);
03259 glNormal3fv(&normals[ind]); 
03260 glVertex3fv(&centers[ind]); 
03261 ind+=3;
03262 }
03263 glEnd();
03264 #if defined(GL_VERSION_1_1)
03265 }
03266 #endif
03267 }
03268 break;
03269 
03270 case DLINE:
03271 // plot a line
03272 glBegin(GL_LINES);
03273 glVertex3fv(((DispCmdLine *)cmdptr)->pos1);
03274 glVertex3fv(((DispCmdLine *)cmdptr)->pos2);
03275 glEnd();
03276 break;
03277 
03278 case DLINEARRAY:
03279 {
03280 float *v = (float *)(cmdptr);
03281 int nlines = (int)v[0];
03282 v++; // move pointer forward before traversing vertex data
03283 
03284 #if defined(GL_VERSION_1_1)
03285 if (!(simplegraphics || ogl_acrobat3dcapture)) {
03286 // Vertex array implementation
03287 glInterleavedArrays(GL_V3F, 0, v);
03288 
03289 #if defined(GL_EXT_compiled_vertex_array) 
03290 if (ext->hascompiledvertexarrayext) {
03291 GLLOCKARRAYSEXT(0, 2*nlines);
03292 }
03293 #endif
03294 
03295 glDrawArrays(GL_LINES, 0, 2*nlines); 
03296 
03297 #if defined(GL_EXT_compiled_vertex_array) 
03298 if (ext->hascompiledvertexarrayext) {
03299 GLUNLOCKARRAYSEXT();
03300 }
03301 #endif
03302 } else {
03303 #endif
03304 // Immediate mode implementation
03305 glBegin(GL_LINES);
03306 for (int i=0; i<nlines; i++) {
03307 glVertex3fv(v);
03308 glVertex3fv(v+3);
03309 v += 6;
03310 }
03311 glEnd();
03312 #if defined(GL_VERSION_1_1)
03313 }
03314 #endif
03315 }
03316 break; 
03317 
03318 case DPOLYLINEARRAY:
03319 {
03320 float *v = (float *)(cmdptr);
03321 int nverts = (int)v[0];
03322 v++; // move pointer forward before traversing vertex data
03323 
03324 #if defined(GL_VERSION_1_1)
03325 if (!(simplegraphics || ogl_acrobat3dcapture)) {
03326 // Vertex array implementation
03327 glInterleavedArrays(GL_V3F, 0, v);
03328 
03329 #if defined(GL_EXT_compiled_vertex_array) 
03330 if (ext->hascompiledvertexarrayext) {
03331 GLLOCKARRAYSEXT(0, nverts);
03332 }
03333 #endif
03334 
03335 glDrawArrays(GL_LINE_STRIP, 0, nverts); 
03336 
03337 #if defined(GL_EXT_compiled_vertex_array) 
03338 if (ext->hascompiledvertexarrayext) {
03339 GLUNLOCKARRAYSEXT();
03340 }
03341 #endif
03342 } else {
03343 #endif
03344 // Immediate mode implementation
03345 glBegin(GL_LINE_STRIP);
03346 for (int i=0; i<nverts; i++) {
03347 glVertex3fv(v);
03348 v += 3;
03349 }
03350 glEnd();
03351 #if defined(GL_VERSION_1_1)
03352 }
03353 #endif
03354 }
03355 break; 
03356 
03357 case DSPHERE: 
03358 {
03359 float *p = (float *)cmdptr;
03360 glPushMatrix();
03361 glTranslatef(p[0], p[1], p[2]); 
03362 glScalef(p[3], p[3], p[3]);
03363 glCallList(SphereList);
03364 glPopMatrix();
03365 }
03366 break;
03367 
03368 case DSPHEREARRAY: 
03369 {
03370 DispCmdSphereArray *sa = (DispCmdSphereArray *)cmdptr;
03371 int i;
03372 ptrdiff_t ind;
03373 float * centers;
03374 float * radii;
03375 float * colors;
03376 sa->getpointers(centers, radii, colors);
03377 
03378 #if defined(VMDUSEGLSLSPHERES) 
03379 // Render the sphere using programmable shading via ray-casting
03380 if (sphereshader && ogl_useglslshader) {
03381 // coordinates of unit bounding box
03382 GLfloat v0[] = {-1.0, -1.0, -1.0}; 
03383 GLfloat v1[] = { 1.0, -1.0, -1.0}; 
03384 GLfloat v2[] = {-1.0, 1.0, -1.0}; 
03385 GLfloat v3[] = { 1.0, 1.0, -1.0}; 
03386 GLfloat v4[] = {-1.0, -1.0, 1.0}; 
03387 GLfloat v5[] = { 1.0, -1.0, 1.0}; 
03388 GLfloat v6[] = {-1.0, 1.0, 1.0}; 
03389 GLfloat v7[] = { 1.0, 1.0, 1.0}; 
03390 
03391 mainshader->UseShader(0); // switch to sphere shader
03392 sphereshader->UseShader(1); // switch to sphere shader
03393 update_shader_uniforms(sphereshader, 1); // force update of shader
03394 
03395 // Update projection parameters for OpenGL shader
03396 GLfloat projparms[4];
03397 projparms[0] = nearClip;
03398 projparms[1] = farClip; 
03399 projparms[2] = 0.5f * (farClip + nearClip);
03400 projparms[3] = 1.0f / (farClip - nearClip);
03401 GLint projloc = GLGETUNIFORMLOCATIONARB(sphereshader->ProgramObject, "vmdprojparms");
03402 GLUNIFORM4FVARB(projloc, 1, projparms);
03403 OGLERR;
03404 
03405 ind = 0;
03406 for (i=0; i<sa->numspheres; i++) {
03407 glPushMatrix();
03408 glTranslatef(centers[ind], centers[ind + 1], centers[ind + 2]); 
03409 glScalef(radii[i], radii[i], radii[i]);
03410 glColor3fv(&colors[ind]);
03411 
03412 // Draw the bounding box containing the sphere, gauranteeing 
03413 // that it will be correctly rendered regardless of the 
03414 // perspective projection used, viewing direction, etc.
03415 // If enough is known about the projection being used, this
03416 // could be done with simple billboard polygons, or perhaps even
03417 // a large OpenGL point primitive instead of a whole cube
03418 glBegin(GL_QUADS);
03419 glVertex3fv((GLfloat *) v0); /* -Z face */
03420 glVertex3fv((GLfloat *) v1);
03421 glVertex3fv((GLfloat *) v3);
03422 glVertex3fv((GLfloat *) v2);
03423 
03424 glVertex3fv((GLfloat *) v4); /* +Z face */
03425 glVertex3fv((GLfloat *) v5);
03426 glVertex3fv((GLfloat *) v7);
03427 glVertex3fv((GLfloat *) v6);
03428 
03429 glVertex3fv((GLfloat *) v0); /* -Y face */
03430 glVertex3fv((GLfloat *) v1);
03431 glVertex3fv((GLfloat *) v5);
03432 glVertex3fv((GLfloat *) v4);
03433 
03434 glVertex3fv((GLfloat *) v2); /* +Y face */
03435 glVertex3fv((GLfloat *) v3);
03436 glVertex3fv((GLfloat *) v7);
03437 glVertex3fv((GLfloat *) v6);
03438 
03439 glVertex3fv((GLfloat *) v0); /* -X face */
03440 glVertex3fv((GLfloat *) v2);
03441 glVertex3fv((GLfloat *) v6);
03442 glVertex3fv((GLfloat *) v4);
03443 
03444 glVertex3fv((GLfloat *) v1); /* +X face */
03445 glVertex3fv((GLfloat *) v3);
03446 glVertex3fv((GLfloat *) v7);
03447 glVertex3fv((GLfloat *) v5);
03448 glEnd();
03449 glPopMatrix();
03450 ind+=3; // next sphere
03451 }
03452 
03453 sphereshader->UseShader(0); // switch back to the main shader
03454 mainshader->UseShader(1); // switch back to the main shader
03455 OGLERR;
03456 } else {
03457 #endif
03458 // OpenGL display listed sphere rendering implementation
03459 set_sphere_res(sa->sphereres); // set the current sphere resolution
03460 
03461 // use single-sided lighting when drawing spheres for 
03462 // peak rendering speed.
03463 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
03464 ind = 0;
03465 for (i=0; i<sa->numspheres; i++) {
03466 glPushMatrix();
03467 glTranslatef(centers[ind], centers[ind + 1], centers[ind + 2]); 
03468 glScalef(radii[i], radii[i], radii[i]);
03469 glColor3fv(&colors[ind]);
03470 glCallList(SphereList);
03471 glPopMatrix();
03472 ind+=3; // next sphere
03473 }
03474 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
03475 #if defined(VMDUSEGLSLSPHERES)
03476 }
03477 #endif
03478 
03479 }
03480 break;
03481 
03482 case DCUBEARRAY: 
03483 {
03484 DispCmdLatticeCubeArray *ca = (DispCmdLatticeCubeArray *)cmdptr;
03485 int i; 
03486 ptrdiff_t ind;
03487 float * centers;
03488 float * radii;
03489 float * colors;
03490 ca->getpointers(centers, radii, colors);
03491 
03492 // Render the cube 
03493 // coordinates of unit cube
03494 GLfloat v0[] = {-1.0, -1.0, -1.0}; 
03495 GLfloat v1[] = { 1.0, -1.0, -1.0}; 
03496 GLfloat v2[] = {-1.0, 1.0, -1.0}; 
03497 GLfloat v3[] = { 1.0, 1.0, -1.0}; 
03498 GLfloat v4[] = {-1.0, -1.0, 1.0}; 
03499 GLfloat v5[] = { 1.0, -1.0, 1.0}; 
03500 GLfloat v6[] = {-1.0, 1.0, 1.0}; 
03501 GLfloat v7[] = { 1.0, 1.0, 1.0}; 
03502 
03503 ind = 0;
03504 for (i=0; i<ca->numcubes; i++) {
03505 glPushMatrix();
03506 glTranslatef(centers[ind], centers[ind + 1], centers[ind + 2]); 
03507 glScalef(radii[i], radii[i], radii[i]);
03508 glColor3fv(&colors[ind]);
03509 
03510 // Draw the unit cube
03511 glBegin(GL_QUADS);
03512 glNormal3f(0.0f, 0.0f, 1.0f);
03513 glVertex3fv((GLfloat *) v0); /* -Z face */
03514 glVertex3fv((GLfloat *) v1);
03515 glVertex3fv((GLfloat *) v3);
03516 glVertex3fv((GLfloat *) v2);
03517 
03518 glNormal3f(0.0f, 0.0f, 1.0f);
03519 glVertex3fv((GLfloat *) v4); /* +Z face */
03520 glVertex3fv((GLfloat *) v5);
03521 glVertex3fv((GLfloat *) v7);
03522 glVertex3fv((GLfloat *) v6);
03523 
03524 glNormal3f(0.0f, -1.0f, 0.0f);
03525 glVertex3fv((GLfloat *) v0); /* -Y face */
03526 glVertex3fv((GLfloat *) v1);
03527 glVertex3fv((GLfloat *) v5);
03528 glVertex3fv((GLfloat *) v4);
03529 
03530 glNormal3f(0.0f, -1.0f, 0.0f);
03531 glVertex3fv((GLfloat *) v2); /* +Y face */
03532 glVertex3fv((GLfloat *) v3);
03533 glVertex3fv((GLfloat *) v7);
03534 glVertex3fv((GLfloat *) v6);
03535 
03536 glNormal3f(1.0f, 0.0f, 0.0f);
03537 glVertex3fv((GLfloat *) v0); /* -X face */
03538 glVertex3fv((GLfloat *) v2);
03539 glVertex3fv((GLfloat *) v6);
03540 glVertex3fv((GLfloat *) v4);
03541 
03542 glNormal3f(1.0f, 0.0f, 0.0f);
03543 glVertex3fv((GLfloat *) v1); /* +X face */
03544 glVertex3fv((GLfloat *) v3);
03545 glVertex3fv((GLfloat *) v7);
03546 glVertex3fv((GLfloat *) v5);
03547 glEnd();
03548 glPopMatrix();
03549 ind+=3; // next cube
03550 }
03551 OGLERR;
03552 }
03553 break;
03554 
03555 case DTRIANGLE: 
03556 {
03557 DispCmdTriangle *cmd = (DispCmdTriangle *)cmdptr;
03558 glBegin(GL_TRIANGLES);
03559 glNormal3fv(cmd->norm1);
03560 glVertex3fv(cmd->pos1);
03561 glNormal3fv(cmd->norm2);
03562 glVertex3fv(cmd->pos2);
03563 glNormal3fv(cmd->norm3);
03564 glVertex3fv(cmd->pos3);
03565 glEnd();
03566 }
03567 break;
03568 
03569 case DSQUARE:
03570 // draw a square, given the four points
03571 {
03572 DispCmdSquare *cmd = (DispCmdSquare *)cmdptr;
03573 glBegin(GL_QUADS);
03574 glNormal3fv((GLfloat *) cmd->norml);
03575 glVertex3fv((GLfloat *) cmd->pos1);
03576 glVertex3fv((GLfloat *) cmd->pos2);
03577 glVertex3fv((GLfloat *) cmd->pos3);
03578 glVertex3fv((GLfloat *) cmd->pos4);
03579 glEnd();
03580 }
03581 break;
03582 
03583 #if 0
03584 case DSTRIPETEX:
03585 if (ext->hastex3d) {
03586 #if defined(GL_VERSION_1_2)
03587 #define STRIPEWIDTH 32
03588 GLubyte stripeImage[4 * STRIPEWIDTH];
03589 GLuint texName = 0;
03590 // glGenTextures(1, &texName);
03591 int i;
03592 for (i=0; i<STRIPEWIDTH; i++) {
03593 stripeImage[4*i ] = (GLubyte) ((i>4) ? 255 : 0); // R
03594 stripeImage[4*i + 1] = (GLubyte) ((i>4) ? 255 : 0); // G
03595 stripeImage[4*i + 2] = (GLubyte) ((i>4) ? 255 : 0); // B
03596 stripeImage[4*i + 3] = (GLubyte) 255; // W
03597 }
03598 
03599 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
03600 glBindTexture(GL_TEXTURE_1D, texName);
03601 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
03602 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT);
03603 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_R, GL_REPEAT);
03604 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
03605 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
03606 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, STRIPEWIDTH, 
03607 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage);
03608 
03609 // XXX should use GL_MODULATE, but requires all polygons to be
03610 // drawn "white", in order for shading to make it through the
03611 // texturing process. GL_REPLACE works well for situations
03612 // where we want coloring to come entirely from texture.
03613 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03614 GLfloat xplaneeq[4] = {0.5, 0.0, 0.0, 0.0};
03615 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
03616 glTexGenfv(GL_S, GL_EYE_PLANE, xplaneeq);
03617 glEnable(GL_TEXTURE_GEN_S);
03618 glEnable(GL_TEXTURE_1D);
03619 #endif
03620 }
03621 break;
03622 
03623 case DSTRIPETEXOFF:
03624 if (ext->hastex3d) {
03625 #if defined(GL_VERSION_1_2)
03626 glDisable(GL_TEXTURE_GEN_S);
03627 glDisable(GL_TEXTURE_1D);
03628 #endif
03629 }
03630 break;
03631 #endif
03632 
03633 case DVOLUMETEXTURE:
03634 if (ext->hastex3d)
03635 #if defined(GL_VERSION_1_2)
03636 {
03637 
03638 #if defined(GL_GENERATE_MIPMAP_HINT)
03639 // set MIP map generation hint for high quality
03640 glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
03641 #endif
03642 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
03643 
03644 DispCmdVolumeTexture *cmd = (DispCmdVolumeTexture *)cmdptr;
03645 require_volume_texture(cmd->ID, 
03646 cmd->xsize, cmd->ysize, cmd->zsize, 
03647 cmd->texmap);
03648 
03649 GLfloat xplaneeq[4]; 
03650 GLfloat yplaneeq[4]; 
03651 GLfloat zplaneeq[4]; 
03652 int i;
03653 
03654 glEnable(GL_TEXTURE_3D);
03655 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03656 
03657 #if defined(VMDUSEOPENGLSHADER)
03658 // Update active GLSL texturing mode
03659 if (mainshader && ogl_useglslshader) {
03660 if (!ogl_lightingenabled)
03661 mainshader->UseShader(1); // enable shader so state updates 
03662 ogl_glsltexturemode = 1;
03663 GLint vmdtexturemode = 1; // enable 3-D texturing->MODULATE
03664 GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03665 GLUNIFORM1IARB(loc, vmdtexturemode);
03666 
03667 // Set active texture map index
03668 loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtex0");
03669 GLUNIFORM1IARB(loc, 0); // using texture unit 0
03670 if (!ogl_lightingenabled)
03671 mainshader->UseShader(0); // disable shader after state updates
03672 }
03673 #endif
03674 
03675 // automatically generate texture coordinates by translating from
03676 // model coordinate space to volume coordinates. These aren't
03677 // going to be used by volume slices, but the performance hit
03678 // is expected to be insignificant.
03679 for (i=0; i<3; i++) {
03680 xplaneeq[i] = cmd->v1[i];
03681 yplaneeq[i] = cmd->v2[i];
03682 zplaneeq[i] = cmd->v3[i];
03683 }
03684 xplaneeq[3] = cmd->v0[0];
03685 yplaneeq[3] = cmd->v0[1];
03686 zplaneeq[3] = cmd->v0[2];
03687 
03688 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
03689 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
03690 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
03691 glTexGenfv(GL_S, GL_EYE_PLANE, xplaneeq);
03692 glTexGenfv(GL_T, GL_EYE_PLANE, yplaneeq);
03693 glTexGenfv(GL_R, GL_EYE_PLANE, zplaneeq);
03694 glEnable(GL_TEXTURE_GEN_S);
03695 glEnable(GL_TEXTURE_GEN_T);
03696 glEnable(GL_TEXTURE_GEN_R);
03697 #endif
03698 }
03699 break;
03700 
03701 case DVOLTEXON:
03702 if (ext->hastex3d) {
03703 #if defined(GL_VERSION_1_2)
03704 glEnable(GL_TEXTURE_3D); // enable volume texturing
03705 #if defined(VMDUSEOPENGLSHADER)
03706 // Update active GLSL texturing mode
03707 if (mainshader && ogl_useglslshader) {
03708 if (!ogl_lightingenabled)
03709 mainshader->UseShader(1); // enable shader so state updates 
03710 ogl_glsltexturemode = 1;
03711 GLint vmdtexturemode = 1; // enable 3-D texturing->MODULATE
03712 GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03713 GLUNIFORM1IARB(loc, vmdtexturemode);
03714 if (!ogl_lightingenabled)
03715 mainshader->UseShader(0); // disable shader after state updates
03716 }
03717 #endif
03718 glEnable(GL_TEXTURE_GEN_S); // enable automatic texture 
03719 glEnable(GL_TEXTURE_GEN_T); // coordinate generation
03720 glEnable(GL_TEXTURE_GEN_R);
03721 #endif
03722 }
03723 break;
03724 
03725 case DVOLTEXOFF:
03726 if (ext->hastex3d) {
03727 #if defined(GL_VERSION_1_2)
03728 glDisable(GL_TEXTURE_3D); // disable volume texturing
03729 #if defined(VMDUSEOPENGLSHADER)
03730 // Update active GLSL texturing mode
03731 if (mainshader && ogl_useglslshader) {
03732 if (!ogl_lightingenabled)
03733 mainshader->UseShader(1); // enable shader so state updates 
03734 ogl_glsltexturemode = 0;
03735 GLint vmdtexturemode = 0; // disable 3-D texturing
03736 GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03737 GLUNIFORM1IARB(loc, vmdtexturemode);
03738 if (!ogl_lightingenabled)
03739 mainshader->UseShader(0); // disable shader after state updates
03740 }
03741 #endif
03742 
03743 glDisable(GL_TEXTURE_GEN_S); // disable automatic texture 
03744 glDisable(GL_TEXTURE_GEN_T); // coordinate generation
03745 glDisable(GL_TEXTURE_GEN_R);
03746 #endif
03747 }
03748 break;
03749 
03750 
03751 case DVOLSLICE:
03752 if (ext->hastex3d) {
03753 DispCmdVolSlice *cmd = (DispCmdVolSlice *)cmdptr;
03754 #if defined(GL_VERSION_1_2)
03755 
03756 // DVOLUMETEXTURE does most of the work for us, but we override
03757 // a few of the texenv settings
03758 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
03759 
03760 // enable or disable texture interpolation and filtering
03761 switch (cmd->texmode) {
03762 case 2:
03763 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
03764 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
03765 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
03766 break;
03767 
03768 case 1:
03769 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
03770 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
03771 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
03772 break;
03773 
03774 case 0: 
03775 default:
03776 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
03777 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
03778 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
03779 break;
03780 }
03781 
03782 // use the texture edge colors rather border color when wrapping
03783 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
03784 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
03785 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
03786 
03787 #if defined(VMDUSEOPENGLSHADER)
03788 // Update active GLSL texturing mode
03789 if (mainshader && ogl_useglslshader) {
03790 ogl_glsltexturemode = 2;
03791 GLint vmdtexturemode = 2; // enable 3-D texturing->REPLACE
03792 GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03793 GLUNIFORM1IARB(loc, vmdtexturemode);
03794 }
03795 #endif
03796 glBegin(GL_QUADS); 
03797 for (int i=0; i<4; i++) {
03798 glNormal3fv(cmd->normal);
03799 glVertex3fv(cmd->v + 3*i);
03800 }
03801 glEnd(); 
03802 #endif // GL_VERSION_1_2
03803 } 
03804 break;
03805 
03806 case DTRIMESH_C3F_N3F_V3F: 
03807 { 
03808 // draw a triangle mesh
03809 DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03810 float *colors=NULL, *normals=NULL, *vertices=NULL;
03811 
03812 if (cmd->pervertexcolors)
03813 cmd->getpointers(colors, normals, vertices);
03814 else
03815 cmd->getpointers(normals, vertices);
03816 
03817 #if 1
03818 #if defined(GL_VERSION_1_1)
03819 if (!(simplegraphics || ogl_acrobat3dcapture)) {
03820 // Vertex array implementation
03821 if (cmd->pervertexcolors)
03822 glEnableClientState(GL_COLOR_ARRAY);
03823 else
03824 glDisableClientState(GL_COLOR_ARRAY);
03825 glEnableClientState(GL_NORMAL_ARRAY);
03826 glEnableClientState(GL_VERTEX_ARRAY);
03827 
03828 if (cmd->pervertexcolors)
03829 glColorPointer(3, GL_FLOAT, 0, (void *) colors);
03830 glNormalPointer(GL_FLOAT, 0, (void *) normals);
03831 glVertexPointer(3, GL_FLOAT, 0, (void *) vertices);
03832 
03833 #if defined(GL_EXT_compiled_vertex_array)
03834 if (ext->hascompiledvertexarrayext) {
03835 GLLOCKARRAYSEXT(0, cmd->numverts);
03836 }
03837 #endif
03838 
03839 glDrawArrays(GL_TRIANGLES, 0, cmd->numverts);
03840 
03841 #if defined(GL_EXT_compiled_vertex_array)
03842 if (ext->hascompiledvertexarrayext) {
03843 GLUNLOCKARRAYSEXT();
03844 }
03845 #endif
03846 } else {
03847 #endif
03848 // Immediate mode implementation
03849 int i; 
03850 ptrdiff_t ind;
03851 glBegin(GL_TRIANGLES);
03852 ind = 0;
03853 if (cmd->pervertexcolors) {
03854 for (i=0; i<cmd->numverts; i++) {
03855 glColor3fv(&colors[ind]);
03856 glNormal3fv(&normals[ind]);
03857 glVertex3fv(&vertices[ind]);
03858 ind+=3;
03859 }
03860 } else {
03861 for (i=0; i<cmd->numverts; i++) {
03862 glNormal3fv(&normals[ind]);
03863 glVertex3fv(&vertices[ind]);
03864 ind+=3;
03865 }
03866 }
03867 
03868 glEnd();
03869 #if defined(GL_VERSION_1_1)
03870 }
03871 #endif
03872 
03873 #endif
03874 }
03875 break;
03876 
03877 case DTRIMESH_C4F_N3F_V3F: 
03878 {
03879 // draw a triangle mesh
03880 DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03881 int ind = cmd->numfacets * 3;
03882 float *cnv;
03883 int *f;
03884 cmd->getpointers(cnv, f);
03885 
03886 #if defined(GL_VERSION_1_1)
03887 // Vertex array implementation
03888 if (!(simplegraphics || ogl_acrobat3dcapture)) {
03889 // If OpenGL 1.1, then use vertex arrays 
03890 glInterleavedArrays(GL_C4F_N3F_V3F, 0, cnv);
03891 
03892 #if defined(GL_EXT_compiled_vertex_array) 
03893 if (ext->hascompiledvertexarrayext) {
03894 GLLOCKARRAYSEXT(0, cmd->numverts);
03895 }
03896 #endif
03897 
03898 glDrawElements(GL_TRIANGLES, ind, GL_UNSIGNED_INT, f);
03899 
03900 #if defined(GL_EXT_compiled_vertex_array) 
03901 if (ext->hascompiledvertexarrayext) {
03902 GLUNLOCKARRAYSEXT();
03903 }
03904 #endif
03905 } else {
03906 #endif
03907 
03908 // simple graphics mode, but not Acrobat3D capture mode
03909 if (!ogl_acrobat3dcapture) {
03910 int i, ind2;
03911 glBegin(GL_TRIANGLES);
03912 for (i=0; i<ind; i++) {
03913 ind2 = f[i] * 10;
03914 glColor3fv(cnv + ind2 );
03915 glNormal3fv(cnv + ind2 + 4);
03916 glVertex3fv(cnv + ind2 + 7);
03917 }
03918 glEnd();
03919 } else { 
03920 // Version 7.0.9 of Acrobat3D can't capture multicolor
03921 // triangles, so we revert to averaged-single-color
03922 // triangles until they fix this capture bug.
03923 int i;
03924 for (i=0; i<cmd->numfacets; i++) {
03925 int ind = i * 3;
03926 float tmp[3], tmp2[3];
03927 
03928 int v0 = f[ind ] * 10;
03929 int v1 = f[ind + 1] * 10;
03930 int v2 = f[ind + 2] * 10;
03931 
03932 vec_add(tmp, cnv + v0, cnv + v1);
03933 vec_add(tmp2, tmp, cnv + v2);
03934 vec_scale(tmp, 0.3333333f, tmp2);
03935 glBegin(GL_TRIANGLES);
03936 glColor3fv(tmp);
03937 glNormal3fv(cnv + v0 + 4);
03938 glVertex3fv(cnv + v0 + 7);
03939 glNormal3fv(cnv + v1 + 4);
03940 glVertex3fv(cnv + v1 + 7);
03941 glNormal3fv(cnv + v2 + 4);
03942 glVertex3fv(cnv + v2 + 7);
03943 glEnd();
03944 }
03945 }
03946 
03947 #if defined(GL_VERSION_1_1)
03948 }
03949 #endif
03950 }
03951 break;
03952 
03953 
03954 case DTRIMESH_C4U_N3F_V3F: 
03955 { 
03956 // draw a triangle mesh
03957 DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03958 unsigned char *colors=NULL;
03959 float *normals=NULL, *vertices=NULL;
03960 
03961 if (cmd->pervertexcolors)
03962 cmd->getpointers(colors, normals, vertices);
03963 else
03964 cmd->getpointers(normals, vertices);
03965 
03966 #if 1
03967 #if defined(GL_VERSION_1_1)
03968 if (!(simplegraphics || ogl_acrobat3dcapture)) {
03969 // Vertex array implementation
03970 if (cmd->pervertexcolors)
03971 glEnableClientState(GL_COLOR_ARRAY);
03972 else
03973 glDisableClientState(GL_COLOR_ARRAY);
03974 glEnableClientState(GL_NORMAL_ARRAY);
03975 glEnableClientState(GL_VERTEX_ARRAY);
03976 
03977 if (cmd->pervertexcolors)
03978 glColorPointer(4, GL_UNSIGNED_BYTE, 0, (void *) colors);
03979 glNormalPointer(GL_FLOAT, 0, (void *) normals);
03980 glVertexPointer(3, GL_FLOAT, 0, (void *) vertices);
03981 
03982 #if defined(GL_EXT_compiled_vertex_array)
03983 if (ext->hascompiledvertexarrayext) {
03984 GLLOCKARRAYSEXT(0, cmd->numverts);
03985 }
03986 #endif
03987 
03988 glDrawArrays(GL_TRIANGLES, 0, cmd->numverts);
03989 
03990 #if defined(GL_EXT_compiled_vertex_array)
03991 if (ext->hascompiledvertexarrayext) {
03992 GLUNLOCKARRAYSEXT();
03993 }
03994 #endif
03995 } else {
03996 #endif
03997 // Immediate mode implementation
03998 int i; 
03999 ptrdiff_t ind;
04000 glBegin(GL_TRIANGLES);
04001 ind = 0;
04002 if (cmd->pervertexcolors) {
04003 for (i=0; i<cmd->numverts; i++) {
04004 glColor3ubv(&colors[ind]);
04005 glNormal3fv(&normals[ind]);
04006 glVertex3fv(&vertices[ind]);
04007 ind+=3;
04008 }
04009 } else {
04010 for (i=0; i<cmd->numverts; i++) {
04011 glNormal3fv(&normals[ind]);
04012 glVertex3fv(&vertices[ind]);
04013 ind+=3;
04014 }
04015 }
04016 
04017 glEnd();
04018 #if defined(GL_VERSION_1_1)
04019 }
04020 #endif
04021 
04022 #endif
04023 }
04024 break;
04025 
04026 
04027 case DTRIMESH_C4U_N3B_V3F: 
04028 { 
04029 // draw a triangle mesh
04030 DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
04031 unsigned char *colors=NULL;
04032 signed char *normals=NULL;
04033 float *vertices=NULL;
04034 
04035 if (cmd->pervertexcolors)
04036 cmd->getpointers(colors, normals, vertices);
04037 else
04038 cmd->getpointers(normals, vertices);
04039 
04040 #if 1
04041 #if defined(GL_VERSION_1_1)
04042 if (!(simplegraphics || ogl_acrobat3dcapture)) {
04043 // Vertex array implementation
04044 if (cmd->pervertexcolors)
04045 glEnableClientState(GL_COLOR_ARRAY);
04046 else
04047 glDisableClientState(GL_COLOR_ARRAY);
04048 glEnableClientState(GL_NORMAL_ARRAY);
04049 glEnableClientState(GL_VERTEX_ARRAY);
04050 
04051 if (cmd->pervertexcolors)
04052 glColorPointer(4, GL_UNSIGNED_BYTE, 0, (void *) colors);
04053 glNormalPointer(GL_BYTE, 0, (void *) normals);
04054 glVertexPointer(3, GL_FLOAT, 0, (void *) vertices);
04055 
04056 #if defined(GL_EXT_compiled_vertex_array)
04057 if (ext->hascompiledvertexarrayext) {
04058 GLLOCKARRAYSEXT(0, cmd->numverts);
04059 }
04060 #endif
04061 
04062 glDrawArrays(GL_TRIANGLES, 0, cmd->numverts);
04063 
04064 #if defined(GL_EXT_compiled_vertex_array)
04065 if (ext->hascompiledvertexarrayext) {
04066 GLUNLOCKARRAYSEXT();
04067 }
04068 #endif
04069 } else {
04070 #endif
04071 // Immediate mode implementation
04072 int i; 
04073 ptrdiff_t ind;
04074 glBegin(GL_TRIANGLES);
04075 ind = 0;
04076 if (cmd->pervertexcolors) {
04077 for (i=0; i<cmd->numverts; i++) {
04078 glColor3ubv(&colors[ind]);
04079 glNormal3bv((GLbyte *) &normals[ind]);
04080 glVertex3fv(&vertices[ind]);
04081 ind+=3;
04082 }
04083 } else {
04084 for (i=0; i<cmd->numverts; i++) {
04085 glNormal3bv((GLbyte *) &normals[ind]);
04086 glVertex3fv(&vertices[ind]);
04087 ind+=3;
04088 }
04089 }
04090 
04091 glEnd();
04092 #if defined(GL_VERSION_1_1)
04093 }
04094 #endif
04095 
04096 #endif
04097 }
04098 break;
04099 
04100 
04101 case DTRISTRIP: 
04102 {
04103 // draw triangle strips
04104 DispCmdTriStrips *cmd = (DispCmdTriStrips *) cmdptr;
04105 int numstrips = cmd->numstrips;
04106 int strip;
04107 
04108 float *cnv;
04109 int *f;
04110 int *vertsperstrip;
04111 
04112 cmd->getpointers(cnv, f, vertsperstrip);
04113 
04114 // use single-sided lighting when drawing possible, for
04115 // peak rendering speed.
04116 if (!cmd->doublesided) {
04117 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
04118 }
04119 
04120 #if defined(GL_VERSION_1_1)
04121 if (!(simplegraphics || ogl_acrobat3dcapture)) {
04122 // If OpenGL 1.1, then use vertex arrays
04123 glInterleavedArrays(GL_C4F_N3F_V3F, 0, cnv);
04124 
04125 #if defined(GL_EXT_compiled_vertex_array) 
04126 if (ext->hascompiledvertexarrayext) {
04127 GLLOCKARRAYSEXT(0, cmd->numverts);
04128 }
04129 #endif
04130 
04131 #if defined(GL_EXT_multi_draw_arrays)
04132 // Try the Sun/ARB MultiDrawElements() extensions first.
04133 if (ext->hasmultidrawext) {
04134 int **indices = new int *[cmd->numstrips];
04135 
04136 // build array of facet list pointers to allow the renderer to
04137 // send everything in a single command/DMA when possible
04138 int qv=0;
04139 for (int i=0; i<numstrips; i++) {
04140 indices[i] = (int *) ((char *)f + qv * sizeof(int));
04141 qv += vertsperstrip[i]; // incr vertex index, next strip
04142 }
04143 
04144 GLMULTIDRAWELEMENTSEXT(GL_TRIANGLE_STRIP, 
04145 (GLsizei *) vertsperstrip, 
04146 GL_UNSIGNED_INT, 
04147 (const GLvoid **) indices, 
04148 numstrips);
04149 
04150 delete [] indices;
04151 }
04152 else // if not MDE, then fall back to other techniques
04153 #endif
04154 // Use the regular OpenGL 1.1 vertex array APIs, loop over all strips
04155 {
04156 int qv=0;
04157 for (strip=0; strip < numstrips; strip++) {
04158 glDrawElements(GL_TRIANGLE_STRIP, vertsperstrip[strip],
04159 GL_UNSIGNED_INT, (int *) ((char *) f + qv * sizeof(int)));
04160 qv += vertsperstrip[strip];
04161 }
04162 }
04163 
04164 #if defined(GL_EXT_compiled_vertex_array) 
04165 if (ext->hascompiledvertexarrayext) {
04166 GLUNLOCKARRAYSEXT();
04167 }
04168 #endif
04169 } else {
04170 #endif
04171 // simple graphics mode, but not Acrobat3D capture mode
04172 if (!ogl_acrobat3dcapture) {
04173 // No OpenGL 1.1? ouch, then we have to do this the slow way
04174 int t, ind;
04175 int v = 0; // current vertex index, initially 0
04176 // loop over all of the triangle strips
04177 for (strip=0; strip < numstrips; strip++) { 
04178 glBegin(GL_TRIANGLE_STRIP);
04179 // render all of the triangles in this strip
04180 for (t = 0; t < vertsperstrip[strip]; t++) {
04181 ind = f[v] * 10;
04182 glColor3fv(cnv + ind );
04183 glNormal3fv(cnv + ind + 4);
04184 glVertex3fv(cnv + ind + 7);
04185 v++; // increment vertex index, for the next triangle
04186 }
04187 glEnd();
04188 }
04189 } else {
04190 // Acrobat3D capture mode works around several bugs in the
04191 // capture utility provided with version 7.x. Their capture
04192 // feature can't catch triangle strips, so we have to render
04193 // each of the triangles individually.
04194 
04195 // render triangle strips one triangle at a time
04196 // triangle winding order is:
04197 // v0, v1, v2, then v2, v1, v3, then v2, v3, v4, etc.
04198 int strip, t, v = 0;
04199 int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
04200 
04201 // loop over all of the triangle strips
04202 for (strip=0; strip < numstrips; strip++) {
04203 // loop over all triangles in this triangle strip
04204 glBegin(GL_TRIANGLES);
04205 
04206 for (t = 0; t < (vertsperstrip[strip] - 2); t++) {
04207 // render one triangle, using lookup table to fix winding order
04208 int v0 = f[v + (stripaddr[t & 0x01][0])] * 10;
04209 int v1 = f[v + (stripaddr[t & 0x01][1])] * 10;
04210 int v2 = f[v + (stripaddr[t & 0x01][2])] * 10;
04211 
04212 #if 1
04213 // Version 7.0.9 of Acrobat3D can't capture multicolor
04214 // triangles, so we revert to averaged-single-color
04215 // triangles until they fix this capture bug.
04216 float tmp[3], tmp2[3];
04217 vec_add(tmp, cnv + v0, cnv + v1); 
04218 vec_add(tmp2, tmp, cnv + v2); 
04219 vec_scale(tmp, 0.3333333f, tmp2);
04220 glColor3fv(tmp);
04221 glNormal3fv(cnv + v0 + 4);
04222 glVertex3fv(cnv + v0 + 7);
04223 glNormal3fv(cnv + v1 + 4);
04224 glVertex3fv(cnv + v1 + 7);
04225 glNormal3fv(cnv + v2 + 4);
04226 glVertex3fv(cnv + v2 + 7);
04227 #else
04228 glColor3fv(cnv + v0 );
04229 glNormal3fv(cnv + v0 + 4);
04230 glVertex3fv(cnv + v0 + 7);
04231 glColor3fv(cnv + v1 );
04232 glNormal3fv(cnv + v1 + 4);
04233 glVertex3fv(cnv + v1 + 7);
04234 glColor3fv(cnv + v2 );
04235 glNormal3fv(cnv + v2 + 4);
04236 glVertex3fv(cnv + v2 + 7);
04237 #endif
04238 
04239 v++; // move on to next vertex
04240 }
04241 glEnd();
04242 v+=2; // last two vertices are already used by last triangle
04243 }
04244 }
04245 
04246 #if defined(GL_VERSION_1_1)
04247 }
04248 #endif
04249 
04250 // return to double-sided lighting mode if we switched
04251 if (!cmd->doublesided) {
04252 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
04253 }
04254 }
04255 break;
04256 
04257 case DWIREMESH: 
04258 {
04259 // draw a wire mesh
04260 DispCmdWireMesh *cmd = (DispCmdWireMesh *) cmdptr;
04261 int ind = cmd->numlines * 2;
04262 float *cnv;
04263 int *l;
04264 cmd->getpointers(cnv, l);
04265 #if defined(GL_VERSION_1_1)
04266 if (!simplegraphics) {
04267 glInterleavedArrays(GL_C4F_N3F_V3F, 0, cnv);
04268 
04269 #if defined(GL_EXT_compiled_vertex_array) 
04270 if (ext->hascompiledvertexarrayext) {
04271 GLLOCKARRAYSEXT(0, cmd->numverts);
04272 }
04273 #endif
04274 
04275 glDrawElements(GL_LINES, ind, GL_UNSIGNED_INT, l);
04276 
04277 #if defined(GL_EXT_compiled_vertex_array) 
04278 if (ext->hascompiledvertexarrayext) {
04279 GLUNLOCKARRAYSEXT();
04280 }
04281 #endif
04282 } else {
04283 #endif
04284 int i, ind2;
04285 glBegin(GL_LINES);
04286 for (i=0; i<ind; i++) {
04287 ind2 = l[i] * 10;
04288 glColor3fv(cnv + ind2 );
04289 glNormal3fv(cnv + ind2 + 4);
04290 glVertex3fv(cnv + ind2 + 7);
04291 }
04292 glEnd();
04293 #if defined(GL_VERSION_1_1)
04294 }
04295 #endif
04296 }
04297 break;
04298 
04299 case DCYLINDER:
04300 {
04301 // draw a cylinder of given radius and resolution
04302 float *cmd = (float *)cmdptr; 
04303 cylinder_full((int)(cmd[7]), cmd+9, (int)(cmd[8]));
04304 } 
04305 break;
04306 
04307 #if defined(VMDOPTIXRTRT)
04308 case DCYLINDERARRAY:
04309 {
04310 DispCmdCylinderArray *ca = (DispCmdCylinderArray *)cmdptr;
04311 float *points, *radii, *colors;
04312 ca->getpointers(points, radii, colors);
04313 int i;
04314 ptrdiff_t ind3, ind6;
04315 for (i=0,ind3=0,ind6=0; i<ca->numcylinders; i++,ind3+=3,ind6+=6) {
04316 glColor3fv(&colors[ind3]);
04317 // cylinder_full(ca->cylinderres, points+ind6, radii[i], ca->cylindercaps);
04318 cylinder(points + ind6, points + ind6+3, ca->cylinderres,
04319 radii[i], radii[i]);
04320 //, ca->cylindercaps);
04321 }
04322 }
04323 break;
04324 #endif
04325 
04326 case DCONE:
04327 {
04328 DispCmdCone *cmd = (DispCmdCone *)cmdptr;
04329 // draw a cone of given radius and resolution
04330 cylinder(cmd->pos2, cmd->pos1, cmd->res, cmd->radius, cmd->radius2);
04331 }
04332 break;
04333 
04334 case DTEXT:
04335 {
04336 float *pos = (float *)cmdptr; 
04337 float thickness = pos[3]; // thickness is stored in 4th element
04338 GLfloat textsize = pos[4];
04339 float textoffset_x = pos[5];
04340 float textoffset_y = pos[6];
04341 char *txt = (char *)(pos+7);
04342 float wp[4];
04343 float mp[4] = { 0, 0, 0, 1};
04344 
04345 #ifdef VMDWIREGL
04346 // WireGL doesn't suppor the glPushAttrib() function, so these are
04347 // variables used to save current OpenGL state prior to 
04348 // clobbering it with new state, so we can return properly.
04349 GLfloat tmppointSize;
04350 GLfloat tmplineWidth;
04351 GLboolean tmplineStipple;
04352 GLint tmplineSRepeat;
04353 GLint tmplineSPattern;
04354 #endif
04355 
04356 mp[0] = pos[0]; mp[1] = pos[1]; mp[2] = pos[2];
04357 textMat.multpoint4d(mp,wp);
04358 
04359 glPushMatrix();
04360 glLoadIdentity();
04361 glMatrixMode(GL_PROJECTION);
04362 glPushMatrix();
04363 glLoadIdentity();
04364 glTranslatef((wp[0]+textoffset_x)/wp[3], 
04365 (wp[1]+textoffset_y)/wp[3], 
04366 wp[2]/wp[3]);
04367 
04368 glScalef(textsize/Aspect,textsize,textsize);
04369 
04370 #ifdef VMDWIREGL
04371 glGetFloatv(GL_POINT_SIZE, &tmppointSize );
04372 glGetFloatv(GL_LINE_WIDTH, &tmplineWidth );
04373 glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmplineSRepeat );
04374 glGetIntegerv(GL_LINE_STIPPLE_PATTERN,&tmplineSPattern);
04375 tmplineStipple = glIsEnabled(GL_LINE_STIPPLE);
04376 #else
04377 glPushAttrib(GL_LINE_BIT | GL_POINT_BIT);
04378 #endif
04379 
04380 // enable line antialiasing, looks much nicer, may run slower
04381 glEnable(GL_BLEND);
04382 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
04383 glEnable(GL_LINE_SMOOTH);
04384 
04385 // #define VMDMSAAFONTTOGGLE 1
04386 
04387 // MSAA lines with widths > 1.0 can look bad at low sample counts
04388 // so we either toggle MSAA off/on, or we have to stick to lines
04389 // of 1.0 pixels in width.
04390 #if defined(VMDMSAAFONTTOGGLE)
04391 #if defined(GL_ARB_multisample)
04392 // Toggle MSAA off/on on-the-fly
04393 if (aaEnabled) {
04394 glDisable(GL_MULTISAMPLE_ARB);
04395 }
04396 glLineWidth(thickness);
04397 glPointSize(thickness * 0.95f); // scale down point size by a hair
04398 #endif 
04399 #else 
04400 glLineWidth(thickness);
04401 glPointSize(thickness * 0.95f); // scale down point size by a hair
04402 #endif
04403 
04404 glDisable(GL_LINE_STIPPLE);
04405 if (thickness > 2.0f)
04406 glListBase(fontNpxListBase); // font stroke vectors only
04407 else
04408 glListBase(font1pxListBase); // font stroke vectors+points
04409 
04410 glCallLists(GLsizei(strlen(txt)), GL_UNSIGNED_BYTE, (GLubyte *)txt);
04411 
04412 #if defined(VMDMSAAFONTTOGGLE)
04413 #if defined(GL_ARB_multisample)
04414 // Toggle MSAA off/on on-the-fly
04415 if (aaEnabled) {
04416 glEnable(GL_MULTISAMPLE_ARB);
04417 }
04418 #endif 
04419 #endif
04420 
04421 // disable line antialiasing, return to normal mode 
04422 glDisable(GL_BLEND);
04423 glDisable(GL_LINE_SMOOTH);
04424 
04425 #ifdef VMDWIREGL
04426 glLineWidth(tmplineWidth);
04427 glPointSize(tmppointSize);
04428 glLineStipple(tmplineSRepeat, (GLushort) tmplineSPattern);
04429 if (tmplineStipple == GL_TRUE)
04430 glEnable(GL_LINE_STIPPLE);
04431 else
04432 glDisable(GL_LINE_STIPPLE);
04433 #else
04434 glPopAttrib();
04435 #endif
04436 
04437 
04438 glPopMatrix();
04439 glMatrixMode(GL_MODELVIEW);
04440 glPopMatrix();
04441 }
04442 break;
04443 
04444 case DCOLORINDEX:
04445 // set the current color to the given color index ... assumes the
04446 // color has already been defined
04447 glColor3fv((GLfloat *)(colorData+3*(((DispCmdColorIndex *)cmdptr)->color)));
04448 break;
04449 
04450 case DMATERIALON:
04451 glEnable(GL_LIGHTING);
04452 ogl_lightingenabled=1;
04453 #if defined(VMDUSEOPENGLSHADER)
04454 if (mainshader && ogl_useglslshader) {
04455 mainshader->UseShader(1); // use glsl mainshader when shading is on
04456 }
04457 #endif
04458 break;
04459 
04460 case DMATERIALOFF:
04461 glDisable(GL_LIGHTING);
04462 ogl_lightingenabled=0;
04463 #if defined(VMDUSEOPENGLSHADER)
04464 if (mainshader && ogl_useglslshader) {
04465 mainshader->UseShader(0); // use fixed-func pipeline when shading is off
04466 }
04467 #endif
04468 break;
04469 
04470 case DSPHERERES:
04471 // set the current sphere resolution
04472 set_sphere_res(((DispCmdSphereRes *)cmdptr)->res);
04473 break;
04474 
04475 case DSPHERETYPE:
04476 // set the current sphere type
04477 set_sphere_mode(((DispCmdSphereType *)cmdptr)->type);
04478 break;
04479 
04480 case DLINESTYLE: 
04481 // set the current line style
04482 set_line_style(((DispCmdLineType *)cmdptr)->type);
04483 break;
04484 
04485 case DLINEWIDTH: 
04486 // set the current line width
04487 set_line_width(((DispCmdLineWidth *)cmdptr)->width);
04488 break;
04489 
04490 case DPICKPOINT_ARRAY:
04491 default:
04492 // msgErr << "OpenGLRenderer: Unknown drawing token " << tok
04493 // << " encountered ... Skipping this command." << sendmsg;
04494 break;
04495 
04496 } 
04497 }
04498 
04499 } // XXX code to run render loop or not
04500 
04501 // Tail end of display list caching code
04502 if (ogl_cacheenabled && (!ogl_cacheskip)) { 
04503 if (ogl_cachecreated) {
04504 glEndList(); // finish off display list we're creating
04505 } else {
04506 if (ogl_cachedebug) {
04507 msgInfo << "Calling cached geometry: id=" << (int)ogl_cachedid << sendmsg;
04508 }
04509 glCallList(ogl_cachedid); // call the display list we previously cached
04510 }
04511 }
04512 
04513 
04514 glPopMatrix();
04515 } // end loop over instance images
04516 
04517 glPopMatrix();
04518 } // end loop over periodic images
04519 
04520 // restore transformation matrix
04521 glPopMatrix();
04522 }
04523 
04524 void OpenGLRenderer::render_done() {
04525 #if defined(VMDOPTIXRTRT)
04526 if (ogl_optix_rtrt_passthrough) {
04527 //printf("OpenGLRenderer::render_done()\n");
04528 
04529 ort->scene_aggregation_complete(); // if 1st time, complete rendering setup
04530 
04531 ort->render_current_scene();
04532 
04533 unsigned char *imgrgb4u=NULL;
04534 ort->framebuffer_map_rgb4u(&imgrgb4u);
04535 
04536 if (imgrgb4u != NULL) {
04537 int xs=xSize;
04538 int ys=ySize;
04539 
04540 glPushMatrix();
04541 glDisable(GL_LIGHTING); // disable lighting
04542 glDisable(GL_DEPTH_TEST); // disable depth test
04543 glDepthMask(GL_FALSE); // make Z-buffer read-only
04544 
04545 glViewport(0, 0, xs, ys);
04546 
04547 // glShadeModel(GL_FLAT);
04548 glMatrixMode(GL_PROJECTION);
04549 glLoadIdentity();
04550 glOrtho(0.0, xs, 0.0, ys, -1.0, 1.0);
04551 glMatrixMode(GL_MODELVIEW);
04552 
04553 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
04554 
04555 #if 0
04556 GLuint texName = 0;
04557 GLfloat texborder[4] = {0.0, 0.0, 0.0, 1.0};
04558 glBindTexture(GL_TEXTURE_2D, texName);
04559 
04560 /* black borders if we go rendering anything beyond texture coordinates */
04561 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, texborder);
04562 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
04563 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
04564 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
04565 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
04566 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
04567 
04568 glLoadIdentity();
04569 glColor3f(1.0, 1.0, 1.0);
04570 
04571 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0,
04572 GL_RGBA, GL_UNSIGNED_BYTE, imgrgb4u);
04573 glEnable(GL_TEXTURE_2D);
04574 
04575 glBegin(GL_QUADS);
04576 glTexCoord2f(0.0f, 0.0f);
04577 glVertex2f(0, 0);
04578 glTexCoord2f(0.0f, 1.0f);
04579 glVertex2f(0, GLfloat(ys));
04580 glTexCoord2f(1.0f, 1.0f);
04581 glVertex2f(GLfloat(xs), GLfloat(ys));
04582 glTexCoord2f(1.0f, 0.0f);
04583 glVertex2f(GLfloat(xs), 0.0f);
04584 glEnd();
04585 
04586 glDisable(GL_TEXTURE_2D);
04587 #else
04588 glPixelZoom(1.0, 1.0);
04589 glLoadIdentity();
04590 glRasterPos2i(0, 0);
04591 glDrawPixels(xs, ys, GL_RGBA, GL_UNSIGNED_BYTE, imgrgb4u);
04592 #endif
04593 
04594 // glShadeModel(GL_SMOOTH);
04595 glDepthMask(GL_TRUE); // make Z-buffer writeable
04596 glEnable(GL_DEPTH_TEST); // enable Z-buffer test
04597 glEnable(GL_LIGHTING); // restore lighting
04598 glPopMatrix();
04599 }
04600 
04601 ort->framebuffer_unmap();
04602 }
04603 #endif
04604 
04605 ogl_glsltoggle = 1; // force GLSL update next time through
04606 
04607 GLuint tag;
04608 // delete all unused display lists
04609 while ((tag = displaylistcache.deleteUnused()) != GLCACHE_FAIL) {
04610 glDeleteLists(tag, 1);
04611 }
04612 
04613 // delete all unused textures
04614 while ((tag = texturecache.deleteUnused()) != GLCACHE_FAIL) {
04615 glDeleteTextures(1, &tag);
04616 }
04617 }
04618 
04619 void OpenGLRenderer::require_volume_texture(unsigned long ID,
04620 unsigned xsize, unsigned ysize, unsigned zsize,
04621 unsigned char *texmap) {
04622 
04623 if (!ext->hastex3d) return;
04624 GLuint texName;
04625 if ((texName = texturecache.markUsed(ID)) == 0) {
04626 glGenTextures(1, &texName);
04627 texturecache.encache(ID, texName); // cache this texture ID
04628 glBindTexture(GL_TEXTURE_3D, texName);
04629 
04630 // set texture border color to black
04631 GLfloat texborder[4] = {0.0, 0.0, 0.0, 1.0};
04632 glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, texborder);
04633 
04634 // use the border color when wrapping at the edge
04635 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
04636 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
04637 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
04638 
04639 // enable texture interpolation and filtering
04640 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
04641 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
04642 
04643 if (build3Dmipmaps(xsize, ysize, zsize, texmap)) {
04644 msgErr << "OpenGLRenderer failed to download 3-D texture map!" 
04645 << sendmsg; 
04646 }
04647 } else { // already cached, so just enable.
04648 glBindTexture(GL_TEXTURE_3D, texName);
04649 }
04650 }
04651 
04652 
04653 int OpenGLRenderer::build3Dmipmaps(int width, int height, int depth, unsigned char *tx) {
04654 #if defined(GL_VERSION_1_2)
04655 if (ext->hastex3d) {
04656 int xsize=width;
04657 int ysize=height;
04658 int zsize=depth;
04659 int xstep=1;
04660 int ystep=1;
04661 int zstep=1;
04662 int x,y,z;
04663 
04664 if (tx == NULL) {
04665 msgErr << "Skipping MIP map generation for NULL 3-D texture map" 
04666 << sendmsg;
04667 return 1;
04668 } 
04669 
04670 // build Mipmaps if the card can't handle the full resolution texture map
04671 if (xsize > max3DtexX || ysize > max3DtexY || zsize > max3DtexZ) { 
04672 unsigned char *texmap;
04673 
04674 while (xsize > max3DtexX) {
04675 xsize >>= 1;
04676 xstep <<= 1;
04677 }
04678 
04679 while (ysize > max3DtexY) {
04680 ysize >>= 1;
04681 ystep <<= 1;
04682 }
04683 
04684 while (zsize > max3DtexZ) {
04685 zsize >>= 1; 
04686 zstep <<= 1;
04687 }
04688 
04689 if (xsize == 0 || ysize == 0 || zsize == 0)
04690 return 1; // error, can't subsample the image down to required res
04691 
04692 texmap = (unsigned char *) malloc(xsize*ysize*zsize*3);
04693 if (texmap == NULL) {
04694 msgErr << "Failed to allocate MIP map for downsampled texture" 
04695 << sendmsg;
04696 return 1; // failed allocation
04697 }
04698 
04699 #if 0
04700 // XXX draw a checkerboard texture until the MIPmap code is finished
04701 msgError << "3-D texture map can't fit into accelerator memory, aborted."
04702 << sendmsg;
04703 
04704 for (z=0; z<zsize; z++) {
04705 for (y=0; y<ysize; y++) {
04706 int addr = z*xsize*ysize + y*xsize;
04707 for (x=0; x<xsize; x++) {
04708 if ((x + y + z) % 2) {
04709 texmap[(addr + x)*3 ] = 0;
04710 texmap[(addr + x)*3 + 1] = 0;
04711 texmap[(addr + x)*3 + 2] = 0;
04712 } else {
04713 texmap[(addr + x)*3 ] = 255;
04714 texmap[(addr + x)*3 + 1] = 255;
04715 texmap[(addr + x)*3 + 2] = 255;
04716 }
04717 }
04718 }
04719 }
04720 
04721 #else
04722 msgInfo << "Downsampling 3-D texture map from " 
04723 << width << "x" << height << "x" << depth << " to " 
04724 << xsize << "x" << ysize << "x" << zsize << sendmsg;
04725 
04726 for (z=0; z<zsize; z++) {
04727 for (y=0; y<ysize; y++) {
04728 int addr = z*xsize*ysize + y*xsize;
04729 for (x=0; x<xsize; x++) {
04730 int sumR=0, sumG=0, sumB=0;
04731 int texelcount = 0;
04732 int ox, oxs, oxe;
04733 int oy, oys, oye;
04734 int oz, ozs, oze;
04735 
04736 oxs = x * xstep;
04737 oys = y * ystep;
04738 ozs = z * zstep;
04739 
04740 oxe = oxs + xstep;
04741 oye = oys + ystep;
04742 oze = ozs + zstep;
04743 if (oxe > width) oxe=width;
04744 if (oye > height) oye=height;
04745 if (oze > depth) oze=depth;
04746 
04747 for (oz=ozs; oz<oze; oz++) {
04748 for (oy=oys; oy<oye; oy++) {
04749 int oaddr = oz*width*height + oy*width;
04750 for (ox=oxs; ox<oxe; ox++) {
04751 int oadx = (oaddr + ox)*3;
04752 sumR += tx[oadx ];
04753 sumG += tx[oadx + 1];
04754 sumB += tx[oadx + 2];
04755 texelcount++;
04756 }
04757 }
04758 }
04759 
04760 int adx = (addr + x)*3;
04761 texmap[adx ] = (unsigned char) (sumR / ((float) texelcount));
04762 texmap[adx + 1] = (unsigned char) (sumG / ((float) texelcount));
04763 texmap[adx + 2] = (unsigned char) (sumB / ((float) texelcount));
04764 }
04765 }
04766 }
04767 #endif
04768 
04769 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
04770 GLTEXIMAGE3D(GL_TEXTURE_3D, 0, GL_RGB8, xsize, ysize, zsize,
04771 0, GL_RGB, GL_UNSIGNED_BYTE, texmap);
04772 
04773 free(texmap); // free the generated texture map for now
04774 } else {
04775 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
04776 GLTEXIMAGE3D(GL_TEXTURE_3D, 0, GL_RGB8, width, height, depth,
04777 0, GL_RGB, GL_UNSIGNED_BYTE, tx);
04778 }
04779 
04780 return 0;
04781 }
04782 #endif
04783 
04784 return 1; // failed to render 3-D texture map
04785 }
04786 
04787 void OpenGLRenderer::update_shader_uniforms(void * voidshader, int forceupdate) {
04788 #if defined(VMDUSEOPENGLSHADER)
04789 OpenGLShader *sh = (OpenGLShader *) voidshader; 
04790 GLint loc;
04791 
04792 // Update GLSL projection mode (used to control normal flipping code)
04793 GLint vmdprojectionmode = (ogl_glslprojectionmode == DisplayDevice::PERSPECTIVE) ? 1 : 0;
04794 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdprojectionmode");
04795 GLUNIFORM1IARB(loc, vmdprojectionmode);
04796 
04797 // Update active GLSL texturing mode from cached state just in case
04798 GLint vmdtexturemode = ogl_glsltexturemode;
04799 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdtexturemode");
04800 GLUNIFORM1IARB(loc, vmdtexturemode);
04801 
04802 // Update material parameters for OpenGL shader.
04803 // XXX unnecessary once references to gl_FrontMaterial.xxx work
04804 GLfloat matparms[4];
04805 matparms[0] = oglambient;
04806 matparms[1] = ogldiffuse;
04807 matparms[2] = oglspecular;
04808 matparms[3] = oglshininess;
04809 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdmaterial");
04810 GLUNIFORM4FVARB(loc, 1, matparms);
04811 
04812 // Set vmdopacity uniform used for alpha-blended transparency in GLSL 
04813 GLfloat vmdopacity[1];
04814 vmdopacity[0] = oglopacity;
04815 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdopacity");
04816 GLUNIFORM1FVARB(loc, 1, vmdopacity);
04817 
04818 // Set GLSL outline magnitude and width
04819 GLfloat vmdoutline[1];
04820 vmdoutline[0] = ogloutline;
04821 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdoutline");
04822 GLUNIFORM1FVARB(loc, 1, vmdoutline);
04823 
04824 GLfloat vmdoutlinewidth[1];
04825 vmdoutlinewidth[0] = ogloutlinewidth;
04826 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdoutlinewidth");
04827 GLUNIFORM1FVARB(loc, 1, vmdoutlinewidth);
04828 
04829 // Set GLSL transparency rendering mode for active material
04830 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdtransmode");
04831 GLUNIFORM1IARB(loc, ogltransmode);
04832 
04833 // Set fog mode for shader using vmdfogmode uniform
04834 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdfogmode");
04835 GLUNIFORM1IARB(loc, ogl_fogmode);
04836 
04837 // Set active texture map index
04838 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdtex0");
04839 GLUNIFORM1IARB(loc, 0); // using texture unit 0
04840 
04841 // Update the main lighting state used by GLSL if it isn't the same
04842 // as what is currently set in the fixed-function pipeline.
04843 // XXX this code will not be necessary once vendors correctly implement
04844 // references to gl_LightSource[n].position in GLSL shader
04845 if (forceupdate || (ogl_glslserial != ogl_rendstateserial)) {
04846 int i;
04847 
04848 if (!forceupdate) {
04849 // Once updated, no need to do it again
04850 ogl_glslserial = ogl_rendstateserial;
04851 }
04852 
04853 // Set light positions and pre-calculating Blinn halfway
04854 // vectors for use by the shaders
04855 for (i=0; i<DISP_LIGHTS; i++) {
04856 char varbuf[32];
04857 sprintf(varbuf, "vmdlight%d", i);
04858 GLint loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, varbuf);
04859 GLUNIFORM3FVARB(loc, 1, &ogl_lightpos[i][0]);
04860 
04861 // calculate Blinn's halfway vector 
04862 // L = direction to light
04863 // V = direction to camera
04864 // H=normalize(L + V)
04865 float L[3], V[3];
04866 GLfloat Hvec[3];
04867 (transMat.top()).multpoint3d(&ogl_lightpos[i][0], L);
04868 vec_scale(V, -1.0, eyeDir);
04869 vec_normalize(V);
04870 Hvec[0] = L[0] + V[0];
04871 Hvec[1] = L[1] + V[1];
04872 Hvec[2] = L[2] + V[2];
04873 vec_normalize(Hvec);
04874 sprintf(varbuf, "vmdlight%dH", i);
04875 loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, varbuf);
04876 GLUNIFORM3FVARB(loc, 1, Hvec);
04877 } 
04878 
04879 // Set light on/off state for shader as well, using pre-known uniforms
04880 // XXX this code assumes a max of 4 lights, due to the use of a 
04881 // vec4 for storing the values, despite DISP_LIGHTS sizing 
04882 // the array of light scales.
04883 loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdlightscale");
04884 GLfloat vmdlightscale[DISP_LIGHTS];
04885 for (i=0; i<DISP_LIGHTS; i++) {
04886 vmdlightscale[i] = (float) ogl_lightstate[i];
04887 }
04888 GLUNIFORM4FVARB(loc, 1, vmdlightscale);
04889 }
04890 #endif
04891 }
04892 
04893 

Generated on Tue Nov 18 02:47:32 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

AltStyle によって変換されたページ (->オリジナル) /