source: trunk/src/testing/app/volvis/vRenderer.cpp @ 4

Revision 4, 17.2 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1/********************************************************************************
2 * Volatile - Volume Visualization Software for SAGE
3 * Copyright (C) 2004 Electronic Visualization Laboratory,
4 * University of Illinois at Chicago
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 *  * Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *  * Redistributions in binary form must reproduce the above
14 *    copyright notice, this list of conditions and the following disclaimer
15 *    in the documentation and/or other materials provided with the distribution.
16 *  * Neither the name of the University of Illinois at Chicago nor
17 *    the names of its contributors may be used to endorse or promote
18 *    products derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
33 *********************************************************************************/
34
35#ifdef WIN32
36#include <windows.h>
37#endif
38
39#include "vRenderer.h"
40#include "VectorMath.h"
41#include "MatrixMath.h"
42#include "glUE.h"
43#include "vVolume.h"
44#include "vCG.h"
45#include "vARB.h"
46#include <math.h>
47
48
49#if defined(linux)
50extern "C"
51{
52extern void glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
53}
54#endif
55
56float vo[8][3] = {{0,0,0},{1.0f,0,0},{0,1.0f,0},{1.0f,1.0f,0},{0,0,1.0f},{1.0f,0,1.0f},{0,1.0f,1.0f},{1.0f,1.0f,1.0f}};
57float tx[8][3] = {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}};
58float axis[3]  = {0,0,1};
59double mv[16];
60vRenderer::vRenderer() {
61        myVolume = NULL;
62        cutEnabled = true;//enable cutplane by default
63        showOverview = false;
64}
65
66vRenderer::~vRenderer() {
67}
68
69
70int vRenderer::select() {
71        if (withinBounds3D(mv,vo,global.pointerPos)) {
72                selected = 1;
73        }
74        else
75                selected = 0;
76        return selected;
77}
78
79
80void vRenderer::init()
81{
82        if (myVolume) {
83                glGenTextures(1, &myVolume->texName);
84                loadTexture3D(myVolume->getVoxelData(), myVolume->dimX,myVolume->dimY,myVolume->dimZ);
85                GlErr("vRenderer", "init");
86        }
87
88}
89
90//load 1 byte volume
91void vRenderer::loadTexture3D(unsigned char *tex, int sx, int sy, int sz)
92{
93        glEnable(GL_TEXTURE_3D);
94        glBindTexture(GL_TEXTURE_3D, myVolume->texName);
95        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
96        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
97        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
98        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
99        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
100        glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
101
102#ifdef _WIN32
103        glTexImage3DEXT(GL_TEXTURE_3D, 0, GL_ALPHA8, sx, sy, sz, 0, GL_ALPHA, GL_UNSIGNED_BYTE, tex);
104#else
105        glTexImage3D(GL_TEXTURE_3D, 0, GL_ALPHA8, sx, sy, sz, 0, GL_ALPHA, GL_UNSIGNED_BYTE, tex);
106#endif
107
108        GlErr("vRenderer", "loadTexture3D");
109        glDisable(GL_TEXTURE_3D);
110}
111
112void vRenderer::drawBoundBox() {
113        glDisable(GL_LIGHTING);
114        glPushMatrix();
115        glTranslatef(-0.5f,-0.5f,-0.5f);
116        glBegin(GL_LINES);
117                glVertex3f(1.0f,1.0f,1.0f);
118                glVertex3f(1.0f,1.0f,0.0f);
119                glVertex3f(1.0f,0.0f,1.0f);
120                glVertex3f(1.0f,0.0f,0.0f);
121                glVertex3f(0.0f,1.0f,1.0f);
122                glVertex3f(0.0f,1.0f,0.0f);
123                glVertex3f(0.0f,0.0f,1.0f);
124                glVertex3f(0.0f,0.0f,0.0f);
125                glVertex3f(1.0f,1.0f,1.0f);
126                glVertex3f(1.0f,0.0f,1.0f);
127                glVertex3f(1.0f,1.0f,0.0f);
128                glVertex3f(1.0f,0.0f,0.0f);
129                glVertex3f(0.0f,1.0f,1.0f);
130                glVertex3f(0.0f,0.0f,1.0f);
131                glVertex3f(0.0f,1.0f,0.0f);
132                glVertex3f(0.0f,0.0f,0.0f);
133                glVertex3f(1.0f,1.0f,1.0f);
134                glVertex3f(0.0f,1.0f,1.0f);
135                glVertex3f(1.0f,1.0f,0.0f);
136                glVertex3f(0.0f,1.0f,0.0f);
137                glVertex3f(1.0f,0.0f,1.0f);
138                glVertex3f(0.0f,0.0f,1.0f);
139                glVertex3f(1.0f,0.0f,0.0f);
140                glVertex3f(0.0f,0.0f,0.0f);
141        glEnd();
142        glPopMatrix();
143        glEnable(GL_LIGHTING);
144}
145
146void vRenderer::next() {
147        myVolume->next();
148        global.volren.loadVolume = true;
149}
150
151void vRenderer::prev() {
152        myVolume->prev();
153        global.volren.loadVolume = true;
154}
155
156
157void vRenderer::drawSubvolBoundBox() {
158        float scaleX, scaleY, scaleZ;
159        float offsetX, offsetY, offsetZ;
160        global.volume->getNormOffset(offsetX, offsetY, offsetZ);
161        global.volume->getNormDim(scaleX, scaleY, scaleZ);
162
163        glPushMatrix();
164        glTranslatef(offsetX, offsetY, offsetZ);
165        glTranslatef(-0.5f, -0.5f, -0.5f);
166        glScalef(scaleX,scaleY,scaleZ);
167
168        glBegin(GL_LINES);
169                glColor3f(1.0f,0.0f,0.0f);
170                glVertex3f(1.0f,1.0f,1.0f);
171                glVertex3f(1.0f,1.0f,0.0f);
172                glVertex3f(1.0f,0.0f,1.0f);
173                glVertex3f(1.0f,0.0f,0.0f);
174                glVertex3f(0.0f,1.0f,1.0f);
175                glVertex3f(0.0f,1.0f,0.0f);
176                glVertex3f(0.0f,0.0f,1.0f);
177                glVertex3f(0.0f,0.0f,0.0f);
178                glVertex3f(1.0f,1.0f,1.0f);
179                glVertex3f(1.0f,0.0f,1.0f);
180                glVertex3f(1.0f,1.0f,0.0f);
181                glVertex3f(1.0f,0.0f,0.0f);
182                glVertex3f(0.0f,1.0f,1.0f);
183                glVertex3f(0.0f,0.0f,1.0f);
184                glVertex3f(0.0f,1.0f,0.0f);
185                glVertex3f(0.0f,0.0f,0.0f);
186                glVertex3f(1.0f,1.0f,1.0f);
187                glVertex3f(0.0f,1.0f,1.0f);
188                glVertex3f(1.0f,1.0f,0.0f);
189                glVertex3f(0.0f,1.0f,0.0f);
190                glVertex3f(1.0f,0.0f,1.0f);
191                glVertex3f(0.0f,0.0f,1.0f);
192                glVertex3f(1.0f,0.0f,0.0f);
193                glVertex3f(0.0f,0.0f,0.0f);
194        glEnd();
195        glPopMatrix();
196
197}
198//update any variables here- must be called from draw
199void vRenderer::update() {
200        //check if we need to reload volume, typically set by the roamer
201        if (global.volren.loadVolume) {
202                loadTexture3D(myVolume->getVoxelData(),myVolume->dimX,myVolume->dimY,myVolume->dimZ);
203                global.volren.loadVolume = false;
204        }
205        myVolume->getNormProbe(xptr,yptr,zptr);//between 0..1
206}
207
208//called by the main
209void vRenderer::draw()
210{
211        //update any variables before doing the draw
212        update();
213        //finally render
214        renderAll();
215}
216
217//
218//     (010)        (110)
219//       6 +---------+ 7   Where 1's are the size of the brick
220//        /|        /|      allong that axis
221//       / |       / |
222// (011)/  |(111) /  |
223//   4 +---------+ 5 |
224//     |   |     |   |(100) y axis
225//     | 2 +-----+---+ 3    ^
226//     |  /(000) |  /       |
227//     | /       | /        |
228//     |/        |/         |
229//   0 +---------+ 1        +-------> x axis
230//  (001)      (101)       /
231//                        /z axis
232
233void vRenderer::renderAll()
234{
235        //now start the render
236        glPushMatrix();
237        { //move to the volume location
238                glTranslatef(xform.trans[0], xform.trans[1], xform.trans[2]);
239                /*if (rot) {
240                        glRotatef(rotAngle,0.0f,1.0f,0.0f);
241                        rotAngle ++;
242                }*/
243                glMultMatrixf(xform.rotn);  //rotate
244                glScalef(myVolume->spacingX*xform.scale, myVolume->spacingY*xform.scale, myVolume->spacingZ*xform.scale);
245                glGetDoublev(GL_MODELVIEW_MATRIX, mv);  //save modelview matrix
246                //translate the volume and render it
247                if (global.cut.update && cutEnabled) {
248                        cut.setTransform(xform.rotn);
249                        global.cut.update = false;
250                }
251                if (cutEnabled)
252                        cut.draw();
253                //draw the box framing everything
254                if (global.ui.bboxEnabled) {
255                        glColor3f(0.0f,0.25f,0.25f);
256                        drawBoundBox();
257                }
258                if (selected) {
259                        glColor3f(0.5f,0.5f,0.0f);
260                        drawBoundBox();
261                }
262                if (showOverview)
263                        drawSubvolBoundBox();
264
265                //draw just the 3d textures
266                enableTex3D(myVolume->texName);
267                if (cutEnabled)
268                        cut.enable();
269
270                glPushMatrix();
271                        glTranslatef(-0.5, -0.5,-0.5);
272                        disableTex3D();
273                        volProbe.setTranslation(xptr,yptr,zptr);
274                        volProbe.draw();
275
276                        glGetDoublev(GL_MODELVIEW_MATRIX, mv);  //save modelview matrix
277#if defined(ADDCGGL)
278                        setCurTextureCG(global.volren.scaledDeptexName);
279#endif
280#if defined(ADDARBGL)
281                        setCurTextureARB(global.volren.scaledDeptexName);
282#endif
283
284
285                        enableTex3D(myVolume->texName);
286                        renderTexture3D(global.volren.sampleRate,mv,vo,tx,axis);
287
288
289                glPopMatrix();
290
291                if (cutEnabled)
292                        cut.disable();
293        }glPopMatrix();
294
295        disableTex3D();
296
297}
298void enableTex3D(unsigned int texName)
299{
300        glDisable(GL_LIGHTING); //light makes it look bad!
301        glPolygonMode(GL_FRONT, GL_FILL);
302        glPolygonMode(GL_BACK, GL_FILL);
303        glEnable(GL_TEXTURE_3D);
304        glEnable(GL_ALPHA_TEST);
305        glEnable(GL_BLEND);
306        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
307
308#if defined(ADDCGGL)
309        enableCG(texName);
310#endif
311#if defined(ADDARBGL)
312        enableARB(texName);
313#endif
314}
315
316void disableTex3D() {
317        glDisable(GL_BLEND);
318        glDisable(GL_TEXTURE_3D);
319        glDisable(GL_ALPHA_TEST);
320        glEnable(GL_LIGHTING);
321        glDepthMask(GL_TRUE);
322
323#if defined(ADDCGGL)
324        disableCG();
325#endif
326#if defined(ADDARBGL)
327        disableARB();
328#endif
329}
330
331//understand the edge vertex computation from JMK@cs.utah.edu
332//ASSUMPTION: eye is along z-axis
333//vo: volume vertex coords model-space coords
334//tx: texture vertex coords tex-space coords
335//axis: axis to slice along world-space coords
336void vRenderer::renderTexture3D(float sampleFrequency,GLdouble mv[16],float vo[8][3],float tx[8][3],float axis[3])
337{
338    float rv[8][3];     //the rotated volume (may include a scale)
339    float maxval = -10; //(tmp)
340    float minval = 10;
341    int minvert = 0, maxvert = 0;
342    GLdouble mvinv[16];
343    int i, j, k;
344    inverseMatrix(mvinv, mv); //invert model view matrix
345
346    for(i=0; i<8; ++i){
347        translateV3(rv[i], mv, vo[i]); //get the rotated vol coords
348        //now get the max and min z in view space
349        if(maxval < MAX(maxval, rv[i][2])){
350            maxval = MAX(maxval, rv[i][2]);
351            maxvert = i;
352        }
353        if(minval > MIN(minval, rv[i][2])){
354            minval = MIN(minval, rv[i][2]);
355            minvert = i;  //determine the starting corner for slicing
356        }
357    }
358
359    //find the slice plane point 'sp' (initial) and the slice plane normal 'sn'
360    //sp is the slice starting point, simply the vertex farthest from the eye
361    float sp[3] = {vo[minvert][0], vo[minvert][1], vo[minvert][2]};
362//    float sp[3] = {vo[maxvert][0], vo[maxvert][1], vo[maxvert][2]};
363    float vpn[3];
364    vpn[0] = axis[0]; vpn[1] = axis[1]; vpn[2] = axis[2];
365
366    //now calculate sn which is the normalized vpn in the model space
367    //ie where the orginal slices are stored
368    float sn[3];
369    translateV3(sn, mvinv, vpn); //move vpn to sn (model space);
370    //now normalize this
371    float normsn = (float)sqrt(sn[0]*sn[0] + sn[1]*sn[1] + sn[2]*sn[2]); //normalize
372    sn[0]/=normsn;
373    sn[1]/=normsn;
374    sn[2]/=normsn;
375
376    //now find the distance we need to slice (|max_vertex - min_vertex|)
377    float maxd[3] = {0, 0, maxval}; //(tmp) only use z-coord (view space)
378    float mind[3] = {0, 0, minval}; //(tmp) ditto           (view space)
379    float maxv[3], minv[3];        //(tmp)
380    translateV3(maxv, mvinv, maxd); //translate back to model space
381    translateV3(minv, mvinv, mind); //ditto
382    maxv[0] -= minv[0]; //subtract
383    maxv[1] -= minv[1];
384    maxv[2] -= minv[2];
385
386    //now take the norm of this vector... we have the distance to be sampled
387    //this distance is in the world space
388    float dist = (float)sqrt(maxv[0]*maxv[0] + maxv[1]*maxv[1] + maxv[2]*maxv[2]);
389
390#if defined(ADDCGGL) || defined(ADDARBGL)
391    glColor4f(1.0f,1.0f,1.0f,0.01);
392#else
393    glColor4f(1.0f,1.0f,1.0f,0.1);
394#endif
395
396    GlErr("vRenderer","drawVA");
397
398    //distance between samples
399    float sampleSpacing = 1.0 / (myVolume->maxDim* sampleFrequency);
400    float del[3] = {sn[0]*sampleSpacing, sn[1]*sampleSpacing, sn[2]*sampleSpacing};
401
402    int samples = (int)((dist) / sampleSpacing);//(total distance to be sam     //highly un-optimized!!!!!!!!!
403    float poly[6][3];   // for edge intersections
404    float tcoord[6][3]; // for texture intersections
405    float tpoly[6][3];  // for transformed edge intersections
406    int edges;         // total number of edge intersections
407
408    //the dep texture should be scaled
409    glBindTexture(GL_TEXTURE_3D, myVolume->texName);
410    //sp:slice plane point
411    //sn:the slice dirn to cut thru the volume
412    //the above 2 are in world coord space
413
414    for(i = 0 ; i < samples; ++i){ //for each slice
415        //increment the slice plane point by the slice distance
416//      sp[0] -= del[0];
417//      sp[1] -= del[1];
418//      sp[2] -= del[2];
419
420        sp[0] += del[0];
421        sp[1] += del[1];
422        sp[2] += del[2];
423
424        edges = 0;
425        //now check each edge of the volume for intersection with..
426        //the plane defined by sp & sn
427        //front bottom edge
428        edges += intersect(vo[0], vo[1], tx[0], tx[1], rv[0], rv[1], sp, sn,
429                           poly[edges], tcoord[edges], tpoly[edges]);
430        //front left edge
431        edges += intersect(vo[0], vo[2], tx[0], tx[2], rv[0], rv[2], sp, sn,
432                           poly[edges], tcoord[edges], tpoly[edges]);
433        //front right edge
434        edges += intersect(vo[1], vo[3], tx[1], tx[3], rv[1], rv[3], sp, sn,
435                           poly[edges], tcoord[edges], tpoly[edges]);
436        //left bottom edge
437        edges += intersect(vo[4], vo[0], tx[4], tx[0], rv[4], rv[0], sp, sn,
438                           poly[edges], tcoord[edges], tpoly[edges]);
439        //right bottom edge
440        edges += intersect(vo[1], vo[5], tx[1], tx[5], rv[1], rv[5], sp, sn,
441                           poly[edges], tcoord[edges], tpoly[edges]);
442        //front top edge
443        edges += intersect(vo[2], vo[3], tx[2], tx[3], rv[2], rv[3], sp, sn,
444                           poly[edges], tcoord[edges], tpoly[edges]);
445        //back bottom edge
446        edges += intersect(vo[4], vo[5], tx[4], tx[5], rv[4], rv[5], sp, sn,
447                           poly[edges], tcoord[edges], tpoly[edges]);
448        //back left edge
449        edges += intersect(vo[4], vo[6], tx[4], tx[6], rv[4], rv[6], sp, sn,
450                           poly[edges], tcoord[edges], tpoly[edges]);
451        //back right edge
452        edges += intersect(vo[5], vo[7], tx[5], tx[7], rv[5], rv[7], sp, sn,
453                           poly[edges], tcoord[edges], tpoly[edges]);
454        //back top edge
455        edges += intersect(vo[6], vo[7], tx[6], tx[7], rv[6], rv[7], sp, sn,
456                           poly[edges], tcoord[edges], tpoly[edges]);
457        //left top edge
458        edges += intersect(vo[2], vo[6], tx[2], tx[6], rv[2], rv[6], sp, sn,
459                           poly[edges], tcoord[edges], tpoly[edges]);
460        //right top edge
461        edges += intersect(vo[3], vo[7], tx[3], tx[7], rv[3], rv[7], sp, sn,
462                           poly[edges], tcoord[edges], tpoly[edges]);
463
464        // B.M.E. Moret & H.D. Shapiro "P to NP" pp. 453
465
466        float dx, dy, tt ,theta, cen[2];  //tt= TempTheta
467        cen[0] = cen[1] = 0.0;
468        int next;
469        //rather than swap 3 arrays, only one?
470        int order[6] ={0,1,2,3,4,5};
471
472        // order[6] could be an extreemly inefficient way to do this
473        for(j=0; j<edges; ++j){ //find the center of the points
474            cen[0] += tpoly[j][0];
475            cen[1] += tpoly[j][1];
476        } //by averaging
477        cen[0]/= edges;
478        cen[1]/= edges;
479
480        for(j=0; j<edges; ++j){ //for each vertex
481            theta = -10;               //find one with largest angle from center..
482            next = j;
483            for (k= j; k<edges; ++k){
484                //... and check angle made between other edges
485                dx = tpoly[order[k]][0] - cen[0];
486                dy = tpoly[order[k]][1] - cen[1];
487                if( (dx == 0) && (dy == 0)){ //same as center?
488                    next = k;
489                    cout << "what teh " << endl;
490                    break; //out of this for-loop
491                }
492                tt = dy/(ABS(dx) + ABS(dy)); //else compute theta [0-4]
493                if( dx < 0.0 ) tt = (float)(2.0 - tt); //check quadrants 2&3
494                else if( dy < 0.0 ) tt = (float)(4.0 + tt); //quadrant 4
495                if( theta <= tt ){  //grab the max theta
496                    next = k;
497                    theta = tt;
498                }
499            } //end for(k) angle checking
500            // i am using 'tt' as a temp
501            // swap polygon vertex ( is this better than another branch?)
502            // I am not sure wich is worse: swapping 3 vectors for every edge
503            // or: using an array to index into another array??? hmmm....
504            //   should have payed more attention in class
505            int tmp = order[j];
506            order[j] = order[next];
507            order[next] = tmp;
508
509        } //end for(j) edge /angle sort
510        renderSlice(edges, tcoord, poly, order);
511        //}//end else compute convex hull
512    }// end for(i) each slice
513    //now draw each slice view
514
515 }
516
517
518inline void vRenderer::renderSlice(int edges,float tc[6][3], float pc[6][3],int   order[6])
519{
520    glBegin(GL_POLYGON);  {//draw slice and texture map it
521        for(int j=0; j< edges; ++j)
522        {
523            glTexCoord3fv(tc[order[j]]);
524            glVertex3fv(pc[order[j]]);
525        }
526    } glEnd();
527}
528
529inline int vRenderer::intersect(const float p0[3], const float p1[3], //line end points
530                                const float t0[3], const float t1[3], //texture points
531                                const float v0[3], const float v1[3], //view coord points
532                                const float sp[3], const float sn[3], //plane point & norm
533                                float pnew[3], float tnew[3], float vnew[3]) //new values
534{
535    //t = (sn.(sp - p0))/(sn.(p1 - p0))
536    float t = ((sn[0]*(sp[0] - p0[0]) + sn[1]*(sp[1] - p0[1])
537                + sn[2]*(sp[2] - p0[2])) /
538               (sn[0]*(p1[0] - p0[0]) + sn[1]*(p1[1] - p0[1])
539                + sn[2]*(p1[2] - p0[2])));
540    //note if the denominator is zero t is a NAN so we should have no problems?
541
542    if( (t>=0) && (t<=1) ){
543        //compute line intersection
544        pnew[0] = p0[0] + t*(p1[0] - p0[0]);
545        pnew[1] = p0[1] + t*(p1[1] - p0[1]);
546        pnew[2] = p0[2] + t*(p1[2] - p0[2]);
547        //compute texture interseciton
548        tnew[0] = t0[0] + t*(t1[0] - t0[0]);
549        tnew[1] = t0[1] + t*(t1[1] - t0[1]);
550        tnew[2] = t0[2] + t*(t1[2] - t0[2]);
551        //compute view coordinate intersections
552        vnew[0] = v0[0] + t*(v1[0] - v0[0]);
553        vnew[1] = v0[1] + t*(v1[1] - v0[1]);
554        vnew[2] = v0[2] + t*(v1[2] - v0[2]);
555        return 1;
556    }
557    return 0;
558}
559
560
Note: See TracBrowser for help on using the repository browser.