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(¢ers[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(¢ers[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