2
* drawables.cpp - opengl drawable objects cpp file
3
* Copyright (C) 2011, D Haley
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19
#include "drawables.h"
21
#include "colourmap.h"
23
#include "isoSurface.h"
26
#include "mathfuncs.h"
28
//OpenGL debugging macro
33
GLenum err = glGetError(); \
34
while (err != GL_NO_ERROR) { \
35
fprintf(stderr, "glError: %s caught at %s:%u\n", (char *)gluErrorString(err), __FILE__, __LINE__); \
38
std::cerr << "glErr Clean " << __FILE__ << ":" << __LINE__ << std::endl; \
44
const float DEPTH_SORT_REORDER_EPSILON = 1e-2;
46
//Static class variables
48
const Camera *DrawableObj::curCamera = 0;
54
void drawBox(Point3D pMin, Point3D pMax, float r,float g, float b, float a)
56
//TODO: Could speedup with LINE_STRIP/LOOP. This is
57
//not a bottleneck atm though.
60
//Bottom corner out (three lines from corner)
61
glVertex3f(pMin[0],pMin[1],pMin[2]);
62
glVertex3f(pMax[0],pMin[1],pMin[2]);
64
glVertex3f(pMin[0],pMin[1],pMin[2]);
65
glVertex3f(pMin[0],pMax[1],pMin[2]);
67
glVertex3f(pMin[0],pMin[1],pMin[2]);
68
glVertex3f(pMin[0],pMin[1],pMax[2]);
70
//Top Corner out (three lines from corner)
71
glVertex3f(pMax[0],pMax[1],pMax[2]);
72
glVertex3f(pMin[0],pMax[1],pMax[2]);
74
glVertex3f(pMax[0],pMax[1],pMax[2]);
75
glVertex3f(pMax[0],pMin[1],pMax[2]);
77
glVertex3f(pMax[0],pMax[1],pMax[2]);
78
glVertex3f(pMax[0],pMax[1],pMin[2]);
80
//Missing pieces - in an "across-down-across" shape
81
glVertex3f(pMin[0],pMax[1],pMin[2]);
82
glVertex3f(pMax[0],pMax[1],pMin[2]);
84
glVertex3f(pMax[0],pMax[1],pMin[2]);
85
glVertex3f(pMax[0],pMin[1],pMin[2]);
87
glVertex3f(pMax[0],pMin[1],pMin[2]);
88
glVertex3f(pMax[0],pMin[1],pMax[2]);
90
glVertex3f(pMax[0],pMin[1],pMax[2]);
91
glVertex3f(pMin[0],pMin[1],pMax[2]);
93
glVertex3f(pMin[0],pMin[1],pMax[2]);
94
glVertex3f(pMin[0],pMax[1],pMax[2]);
96
glVertex3f(pMin[0],pMax[1],pMax[2]);
97
glVertex3f(pMin[0],pMax[1],pMin[2]);
104
DrawableObj::DrawableObj() : active(true), haveChanged(true), canSelect(false), wantsLight(false)
108
DrawableObj::~DrawableObj()
114
DrawPoint::DrawPoint() : origin(0.0f,0.0f,0.0f), r(1.0f), g(1.0f), b(1.0f), a(1.0f)
118
DrawPoint::DrawPoint(float x, float y, float z) : origin(x,y,z), r(1.0f), g(1.0f), b(1.0f)
122
DrawPoint::~DrawPoint()
129
void DrawPoint::setColour(float rnew, float gnew, float bnew, float anew)
139
void DrawPoint::setOrigin(const Point3D &pt)
145
void DrawPoint::draw() const
149
glVertex3f(origin[0],origin[1],origin[2]);
153
DrawVector::DrawVector() : origin(0.0f,0.0f,0.0f), vector(0.0f,0.0f,1.0f),arrowSize(1.0f),scaleArrow(true),
154
r(1.0f), g(1.0f), b(1.0f), a(1.0f)
158
DrawVector::~DrawVector()
163
void DrawVector::getBoundingBox(BoundCube &b) const
165
b.setBounds(origin,vector+origin);
168
void DrawVector::setColour(float rnew, float gnew, float bnew, float anew)
176
void DrawVector::setOrigin(const Point3D &pt)
181
void DrawVector::setVector(const Point3D &pt)
186
void DrawVector::draw() const
189
//FIXME: Arrow head calculations?
191
glVertex3f(origin[0],origin[1],origin[2]);
192
glVertex3f(vector[0]+origin[0],vector[1]+origin[1],vector[2]+origin[2]);
196
void DrawVector::recomputeParams(const std::vector<Point3D> &vecs,
197
const std::vector<float> &scalars, unsigned int mode)
201
case DRAW_VECTOR_BIND_ORIENTATION:
202
ASSERT(vecs.size() ==1 && scalars.size() ==0);
205
case DRAW_VECTOR_BIND_ORIGIN:
206
ASSERT(vecs.size() == 1 && scalars.size()==0);
209
case DRAW_VECTOR_BIND_ORIGIN_ONLY:
211
ASSERT(vecs.size() == 1 && scalars.size()==0);
219
case DRAW_VECTOR_BIND_TARGET:
220
ASSERT(vecs.size() == 1 && scalars.size()==0);
221
vector=vecs[0]-origin;
227
DrawTriangle::DrawTriangle() : r(1.0f), g(1.0f),b(1.0f),a(1.0f)
231
DrawTriangle::~DrawTriangle()
235
void DrawTriangle::setVertex(unsigned int ui, const Point3D &pt)
241
void DrawTriangle::setColour(float rnew, float gnew, float bnew, float anew)
249
void DrawTriangle::draw() const
252
glBegin(GL_TRIANGLES);
253
glVertex3f((vertices[0])[0],
254
(vertices[0])[1], (vertices[0])[2]);
255
glVertex3f((vertices[1])[0],
256
(vertices[1])[1], (vertices[1])[2]);
257
glVertex3f((vertices[2])[0],
258
(vertices[2])[1], (vertices[2])[2]);
263
DrawSphere::DrawSphere() : radius(1.0f), latSegments(8),longSegments(8)
268
DrawSphere::~DrawSphere()
276
void DrawSphere::getBoundingBox(BoundCube &b) const
278
for(unsigned int ui=0;ui<3;ui++)
280
b.setBound(ui,0,origin[ui] - radius);
281
b.setBound(ui,1,origin[ui] + radius);
285
void DrawSphere::setOrigin(const Point3D &p)
290
void DrawSphere::setLatSegments(unsigned int ui)
295
void DrawSphere::setLongSegments(unsigned int ui)
300
void DrawSphere::setRadius(float rad)
305
void DrawSphere::setColour(float rnew, float gnew, float bnew, float anew)
313
void DrawSphere::draw() const
319
glTranslatef(origin[0],origin[1],origin[2]);
321
gluSphere(q,radius,latSegments,longSegments);
326
void DrawSphere::recomputeParams(const vector<Point3D> &vecs,
327
const vector<float> &scalars, unsigned int mode)
331
case DRAW_SPHERE_BIND_ORIGIN:
332
ASSERT(vecs.size() ==1 && scalars.size() ==0);
335
case DRAW_SPHERE_BIND_RADIUS:
336
ASSERT(scalars.size() == 1 && vecs.size()==0);
345
DrawCylinder::DrawCylinder() : radius(1.0f),
346
origin(0.0f,0.0f,0.0f), direction(0.0f,0.0f,1.0f), slices(4),stacks(4)
349
qCap[0]= gluNewQuadric();
351
gluQuadricOrientation(qCap[0],GLU_INSIDE);
352
qCap[1]= gluNewQuadric();
354
gluQuadricOrientation(qCap[1],GLU_OUTSIDE);
358
bool DrawCylinder::needsDepthSorting() const
360
return a< 1 && a > std::numeric_limits<float>::epsilon();
363
DrawCylinder::~DrawCylinder()
368
gluDeleteQuadric(qCap[0]);
370
gluDeleteQuadric(qCap[1]);
374
void DrawCylinder::setOrigin(const Point3D& pt)
380
void DrawCylinder::setDirection(const Point3D &p)
386
void DrawCylinder::draw() const
388
if(!q || !qCap[0] || !qCap[1])
391
//Cross product desired drection with default
392
//direction to produce rotation vector
393
Point3D dir(0.0f,0.0f,1.0f);
396
glTranslatef(origin[0],origin[1],origin[2]);
398
Point3D dirNormal(direction);
399
dirNormal.normalise();
401
float length=sqrtf(direction.sqrMag());
402
float angle = dir.angle(dirNormal);
403
if(angle < M_PI - sqrt(std::numeric_limits<float>::epsilon()) &&
404
angle > sqrt(std::numeric_limits<float>::epsilon()))
407
dir = dir.crossProd(dirNormal);
409
glRotatef(angle*180.0f/M_PI,dir[0],dir[1],dir[2]);
412
//OpenGL defined cylinder starting at 0 and going to lenght. I want it starting at 0 and going to+-l/2
413
glTranslatef(0,0,-length/2.0f);
416
//Draw the end cap at z=0
419
gluDisk(qCap[0],0,radius,slices,1);
420
gluCylinder(q,radius,radius, length,slices,stacks);
422
//Draw the start cap at z=l
423
glTranslatef(0,0,length);
424
gluDisk(qCap[1],0,radius,slices,1);
434
void DrawCylinder::setSlices(unsigned int i)
439
void DrawCylinder::setStacks(unsigned int i)
444
void DrawCylinder::setRadius(float rad)
449
void DrawCylinder::recomputeParams(const vector<Point3D> &vecs,
450
const vector<float> &scalars, unsigned int mode)
454
case DRAW_CYLINDER_BIND_ORIGIN:
455
ASSERT(vecs.size() ==1 && scalars.size() ==0);
459
case DRAW_CYLINDER_BIND_DIRECTION:
460
ASSERT(vecs.size() ==1 && scalars.size() ==0);
463
case DRAW_CYLINDER_BIND_RADIUS:
464
ASSERT(scalars.size() == 1 && vecs.size()==0);
473
void DrawCylinder::setLength(float len)
475
ASSERT(direction.sqrMag());
476
direction=direction.normalise()*len;
479
void DrawCylinder::setColour(float rnew, float gnew, float bnew, float anew)
487
void DrawCylinder::getBoundingBox(BoundCube &b) const
492
Point3D normAxis(direction);
493
normAxis.normalise();
495
//Height offset for ending circles.
496
//The joint bounding box of these two is the
497
//overall bounding box
503
tmp=sin(acos(normAxis.dotProd(Point3D(1,0,0))));
504
offset[0] = radius*tmp;
507
tmp=sin(acos(normAxis.dotProd(Point3D(0,1,0))));
508
offset[1] = radius*tmp;
511
tmp=sin(acos(normAxis.dotProd(Point3D(0,0,1))));
512
offset[2] = radius*tmp;
516
p[0]= offset+(direction*0.5+origin);
517
p[1]= -offset+(direction*0.5+origin);
518
p[2]= offset+(-direction*0.5+origin);
519
p[3]= -offset+(-direction*0.5+origin);
527
DrawManyPoints::DrawManyPoints() : r(1.0f),g(1.0f),b(1.0f),a(1.0f), size(1.0f)
532
DrawManyPoints::~DrawManyPoints()
535
haveCachedBounds=false;
538
void DrawManyPoints::getBoundingBox(BoundCube &b) const
541
//Update the cache as needed
542
if(!haveCachedBounds)
544
haveCachedBounds=true;
545
cachedBounds.setBounds(pts);
552
void DrawManyPoints::explode(vector<DrawableObj *> &simpleObjects)
554
simpleObjects.resize(pts.size());
556
for(size_t ui=0;ui<simpleObjects.size();ui++)
561
void DrawManyPoints::clear()
566
void DrawManyPoints::addPoints(const vector<Point3D> &vp)
568
pts.reserve(pts.size()+vp.size());
569
std::copy(vp.begin(),vp.end(),pts.begin());
573
void DrawManyPoints::addPoints(const vector<IonHit> &vp)
575
pts.reserve(pts.size()+vp.size());
576
for(size_t ui=0; ui<vp.size(); ui++)
577
pts.push_back(vp[ui].getPos());
578
haveCachedBounds=false;
581
void DrawManyPoints::shuffle()
583
std::random_shuffle(pts.begin(),pts.end());
587
void DrawManyPoints::addPoint(const Point3D &p)
590
haveCachedBounds=false;
593
void DrawManyPoints::setColour(float rnew, float gnew, float bnew, float anew)
601
void DrawManyPoints::setSize(float f)
606
void DrawManyPoints::draw() const
612
//TODO: Consider Vertex buffer objects. would be faster, but less portable.
613
for(unsigned int ui=0; ui<pts.size(); ui++)
616
glVertex3fv(p->getValueArr());
623
DrawDispList::DrawDispList() : listNum(0),listActive(false)
627
DrawDispList::~DrawDispList()
632
ASSERT(glIsList(listNum));
633
glDeleteLists(listNum,1);
638
bool DrawDispList::startList(bool execute)
640
//Ensure that the user has appropriately closed the list
642
boundBox.setInverseLimits();
644
//If the list is already genned, clear it
646
glDeleteLists(listNum,1);
648
//Create the display list (ask for one)
649
listNum=glGenLists(1);
654
glNewList(listNum,GL_COMPILE_AND_EXECUTE);
656
glNewList(listNum,GL_COMPILE);
662
void DrawDispList::addDrawable(const DrawableObj *d)
666
d->getBoundingBox(b);
671
bool DrawDispList::endList()
675
ASSERT(boundBox.isValid());
677
return (glGetError() ==0);
680
void DrawDispList::draw() const
684
//Cannot select display list objects,
685
//as we cannot modify them without a "do-over".
688
ASSERT(glIsList(listNum));
698
DrawGLText::DrawGLText(std::string fontFile, unsigned int mode) : curFontMode(mode), origin(0.0f,0.0f,0.0f), r(0.0),g(0.0),b(0.0),a(1.0), up(0.0f,1.0f,0.0f), textDir(1.0f,0.0f,0.0f), readDir(0.0f,0.0f,1.0f), isOK(true),ensureReadFromNorm(true)
700
fontString = fontFile;
706
font = new FTGLBitmapFont(fontFile.c_str());
709
font = new FTGLPixmapFont(fontFile.c_str());
712
font = new FTGLOutlineFont(fontFile.c_str());
715
font = new FTGLPolygonFont(fontFile.c_str());
718
font = new FTGLExtrdFont(fontFile.c_str());
721
font = new FTGLTextureFont(fontFile.c_str());
724
//Don't do this. Use valid font numbers
729
//In case of allocation failure or invalid font num
730
if(!font || font->Error())
736
//Try to make it 100 point
741
font->CharMap(ft_encoding_unicode);
743
alignMode = DRAWTEXT_ALIGN_LEFT;
746
void DrawGLText::draw() const
751
//Translate the drawing position to the origin
752
Point3D offsetVec=textDir;
757
box=font->BBox(strText.c_str());
758
advance=box.Upper().X()-box.Lower().X();
760
halfHeight=box.Upper().Y()-box.Lower().Y();
765
case DRAWTEXT_ALIGN_LEFT:
767
case DRAWTEXT_ALIGN_CENTRE:
768
offsetVec=offsetVec*advance/2.0f;
770
case DRAWTEXT_ALIGN_RIGHT:
771
offsetVec=offsetVec*advance;
781
glPushAttrib(GL_CULL_FACE);
783
glDisable(GL_CULL_FACE);
784
if(curFontMode !=FTGL_BITMAP)
786
offsetVec=origin-offsetVec;
787
glTranslatef(offsetVec[0],offsetVec[1],offsetVec[2]);
789
//Rotate such that the new X-Y plane is set to the
790
//desired text orientation. (ie. we want to draw the text in the
791
//specified combination of updir-textdir, rather than in the X-y plane)
794
//Textdir and updir MUST be normal to one another
795
ASSERT(textDir.dotProd(up) < sqrtf(std::numeric_limits<float>::epsilon()));
797
//rotate around textdir cross X, if the two are not the same
800
float angle=textDir.angle(Point3D(1,0,0) );
801
if(angle > sqrtf(std::numeric_limits<float>::epsilon()))
803
rotateAxis = textDir.crossProd(Point3D(-1,0,0));
804
rotateAxis.normalise();
811
axis.fx=rotateAxis[0];
812
axis.fy=rotateAxis[1];
813
axis.fz=rotateAxis[2];
816
glRotatef(angle*180.0f/M_PI,rotateAxis[0],rotateAxis[1],rotateAxis[2]);
817
quat_rot(&tmp,&axis,angle); //angle is in radiians
824
//rotate new up direction into y around x axis
825
angle = newUp.angle(Point3D(0,1,0));
826
if(angle > sqrtf(std::numeric_limits<float>::epsilon()) &&
827
fabs(angle - M_PI) > sqrtf(std::numeric_limits<float>::epsilon()))
829
rotateAxis = newUp.crossProd(Point3D(0,-1,0));
830
rotateAxis.normalise();
831
glRotatef(angle*180.0f/M_PI,rotateAxis[0],rotateAxis[1],rotateAxis[2]);
834
//Ensure that the text is not back-culled (i.e. if the
835
//text normal is pointing away from the camera, it does not
836
//get drawn). Here we have to flip the normal, by spinning the
837
//text by 180 around its up direction (which has been modified
838
//by above code to coincide with the y axis.
841
//This is not *quite* right in perspective mode
842
//but is right in orthogonal
844
Point3D textNormal,camVec;
845
textNormal = up.crossProd(textDir);
846
textNormal.normalise();
848
camVec = origin - curCamera->getOrigin();
850
//ensure the camera is not sitting on top of the text.
851
if(camVec.sqrMag() > std::numeric_limits<float>::epsilon())
856
if(camVec.dotProd(textNormal) < 0)
858
//move halfway along text, noting that
859
//the text direction is now the x-axis
860
glTranslatef(advance/2.0f,halfHeight,0);
861
//spin text around its up direction 180 degrees
862
glRotatef(180,0,1,0);
863
//restore back to original position
864
glTranslatef(-advance/2.0f,-halfHeight,0);
867
camVec=curCamera->getUpDirection();
868
if(camVec.dotProd(up) < 0)
870
//move halfway along text, noting that
871
//the text direction is now the x-axis
872
glTranslatef(advance/2.0f,halfHeight,0);
873
//spin text around its front direction 180 degrees
874
//no need to trnaslate as text sits at its baseline
875
glRotatef(180,0,0,1);
876
//move halfway along text, noting that
877
//the text direction is now the x-axis
878
glTranslatef(-advance/2.0f,-halfHeight,0);
889
//FIXME: The text ends up in a wierd location
890
//2D coordinate storage for bitmap text
891
double xWin,yWin,zWin;
892
//Compute the 2D coordinates
893
double model_view[16];
894
glGetDoublev(GL_MODELVIEW_MATRIX, model_view);
896
double projection[16];
897
glGetDoublev(GL_PROJECTION_MATRIX, projection);
900
glGetIntegerv(GL_VIEWPORT, viewport);
902
//Apply the openGL coordinate transformation pipleine to the
904
gluProject(offsetVec[0],offsetVec[1],offsetVec[2]
905
,model_view,projection,viewport,
908
glRasterPos3f(xWin,yWin,zWin);
917
if(curFontMode == FTGL_TEXTURE)
919
glPushAttrib(GL_ENABLE_BIT);
920
glEnable(GL_TEXTURE_2D);
922
font->Render(strText.c_str());
926
font->Render(strText.c_str());
933
DrawGLText::~DrawGLText()
939
void DrawGLText::setColour(float rnew, float gnew, float bnew, float anew)
947
void DrawGLText::getBoundingBox(BoundCube &b) const
952
float minX,minY,minZ;
953
float maxX,maxY,maxZ;
954
font->BBox(strText.c_str(),minX,minY,minZ,maxX,maxY,maxZ);
955
b.setBounds(minX+origin[0],minY+origin[1],minZ+origin[2],
956
maxX+origin[0],maxY+origin[1],maxZ+origin[2]);
959
b.setInverseLimits();
963
void DrawGLText::setAlignment(unsigned int newMode)
965
ASSERT(newMode < DRAWTEXT_ALIGN_ENUM_END);
969
void DrawGLText::recomputeParams(const vector<Point3D> &vecs,
970
const vector<float> &scalars, unsigned int mode)
974
case DRAW_TEXT_BIND_ORIGIN:
975
ASSERT(vecs.size() ==1 && scalars.size() ==0);
983
DrawRectPrism::DrawRectPrism()
986
drawMode=DRAW_WIREFRAME;
989
DrawRectPrism::~DrawRectPrism()
993
void DrawRectPrism::getBoundingBox(BoundCube &b) const
995
b.setBounds(pMin[0],pMin[1],pMin[2],
996
pMax[0],pMax[1],pMax[2]);
999
void DrawRectPrism::draw() const
1001
ASSERT(r <=1.0f && g<=1.0f && b <=1.0f && a <=1.0f);
1002
ASSERT(r >=0.0f && g>=0.0f && b >=0.0f && a >=0.0f);
1009
case DRAW_WIREFRAME:
1011
glLineWidth(lineWidth);
1012
drawBox(pMin,pMax,r,g,b,a);
1022
glVertex3f(pMin[0],pMin[1],pMin[2]);
1023
glVertex3f(pMin[0],pMax[1],pMin[2]);
1024
glVertex3f(pMax[0],pMax[1],pMin[2]);
1025
glVertex3f(pMax[0],pMin[1],pMin[2]);
1028
glVertex3f(pMax[0],pMax[1],pMax[2]);
1029
glVertex3f(pMax[0],pMin[1],pMax[2]);
1030
glVertex3f(pMax[0],pMin[1],pMin[2]);
1031
glVertex3f(pMax[0],pMax[1],pMin[2]);
1034
glVertex3f(pMax[0],pMin[1],pMax[2]);
1035
glVertex3f(pMax[0],pMax[1],pMax[2]);
1036
glVertex3f(pMin[0],pMax[1],pMax[2]);
1037
glVertex3f(pMin[0],pMin[1],pMax[2]);
1041
glVertex3f(pMin[0],pMax[1],pMin[2]);
1042
glVertex3f(pMin[0],pMin[1],pMin[2]);
1043
glVertex3f(pMin[0],pMin[1],pMax[2]);
1044
glVertex3f(pMin[0],pMax[1],pMax[2]);
1046
//Now the other two sides
1048
glVertex3f(pMax[0],pMin[1],pMax[2]);
1049
glVertex3f(pMin[0],pMin[1],pMax[2]);
1050
glVertex3f(pMin[0],pMin[1],pMin[2]);
1051
glVertex3f(pMax[0],pMin[1],pMin[2]);
1054
glVertex3f(pMax[0],pMax[1],pMax[2]);
1055
glVertex3f(pMax[0],pMax[1],pMin[2]);
1056
glVertex3f(pMin[0],pMax[1],pMin[2]);
1057
glVertex3f(pMin[0],pMax[1],pMax[2]);
1071
void DrawRectPrism::setAxisAligned( const Point3D &p1, const Point3D &p2)
1073
for(unsigned int ui=0; ui<3; ui++)
1075
pMin[ui]=std::min(p1[ui],p2[ui]);
1076
pMax[ui]=std::max(p1[ui],p2[ui]);
1081
void DrawRectPrism::setAxisAligned( const BoundCube &b)
1083
b.getBounds(pMin,pMax);
1086
void DrawRectPrism::setColour(float rnew, float gnew, float bnew, float anew)
1094
void DrawRectPrism::setLineWidth(float newLineWidth)
1096
ASSERT(newLineWidth > 0.0f);
1097
lineWidth=newLineWidth;
1100
void DrawRectPrism::recomputeParams(const vector<Point3D> &vecs,
1101
const vector<float> &scalars, unsigned int mode)
1105
case DRAW_RECT_BIND_TRANSLATE:
1107
ASSERT(vecs.size() ==1);
1109
delta = (pMax - pMin)*0.5;
1110
//Object has been translated
1111
pMin = vecs[0]-delta;
1112
pMax = vecs[0]+delta;
1115
case DRAW_RECT_BIND_CORNER_MOVE:
1117
ASSERT(vecs.size() ==1);
1118
//Delta has changed, but origin shoudl stay the same
1119
Point3D mean, corner;
1120
mean = (pMin + pMax)*0.5;
1122
//Prevent negative offset values, otherwise we can
1123
//get inside out boxes
1125
for(unsigned int ui=0;ui<3;ui++)
1126
corner[ui]= fabs(corner[ui]);
1137
DrawTexturedQuadOverlay::DrawTexturedQuadOverlay()
1142
DrawTexturedQuadOverlay::~DrawTexturedQuadOverlay()
1147
void DrawTexturedQuadOverlay::setSize(float s)
1153
void DrawTexturedQuadOverlay::draw() const
1158
ASSERT(glIsTexture(textureId));
1160
glMatrixMode(GL_PROJECTION);
1163
gluOrtho2D(0, winX, winY, 0);
1165
glMatrixMode(GL_MODELVIEW);
1169
glEnable(GL_TEXTURE_2D);
1170
glBindTexture(GL_TEXTURE_2D,textureId);
1172
// Draw overlay quad
1173
glColor3f(1.0f,1.0f,1.0f);
1175
glTexCoord2f(0.0f,0.0f);
1176
glVertex3f(position[0]-length/2.0,position[1]-length/2.0,0.0);
1177
glTexCoord2f(0.0f,1.0f);
1178
glVertex3f(position[0]-length/2.0,position[1]+length/2.0,0.0);
1179
glTexCoord2f(1.0f,1.0f);
1180
glVertex3f(position[0]+length/2.0,position[1]+length/2.0,0.0);
1181
glTexCoord2f(1.0f,0.0f);
1182
glVertex3f(position[0]+length/2.0,position[1]-length/2.0,0.0);
1185
glDisable(GL_TEXTURE_2D);
1188
glPopMatrix(); //Pop modelview matrix
1190
glMatrixMode(GL_PROJECTION);
1193
glMatrixMode(GL_MODELVIEW);
1197
bool DrawTexturedQuadOverlay::setTexture(const char *textureFile)
1202
textureOK= texPool->openTexture(textureFile,textureId,dummy);
1206
void DrawTexturedQuadOverlay::getBoundingBox(BoundCube &b) const
1212
DrawColourBarOverlay::DrawColourBarOverlay()
1216
f=getDefaultFontFile();
1217
font = new FTGLPolygonFont(f.c_str());
1221
void DrawColourBarOverlay::draw() const
1225
//80% of bar width is for the actual colour bar itself.
1226
float barWidth=0.8*width;
1227
elemHeight=height/(float)rgb.size();
1229
for(unsigned int ui=0;ui<rgb.size();ui++)
1231
//Set the quad colour for bar element
1232
glColor4f(rgb[rgb.size()-(ui+1)].v[0],
1233
rgb[rgb.size()-(ui+1)].v[1],
1234
rgb[rgb.size()-(ui+1)].v[2],1.0);
1236
//draw this quad (bar element)
1237
glVertex3f(tlX,tlY+(float)ui*elemHeight,0);
1238
glVertex3f(tlX,tlY+(float)(ui+1)*elemHeight,0);
1239
glVertex3f(tlX+barWidth,tlY+(float)(ui+1)*elemHeight,0);
1240
glVertex3f(tlX+barWidth,tlY+(float)(ui)*elemHeight,0);
1245
//Draw ticks on colour bar
1247
glColor4f(1.0,1.0,1.0f,1.0f);
1249
glVertex3f(tlX,tlY,0);
1250
glVertex3f(tlX+width,tlY,0);
1252
glVertex3f(tlX,tlY+height,0);
1253
glVertex3f(tlX+width,tlY+height,0);
1259
if(!font || font->Error())
1262
std::cerr << "Ah bugger. No font!" << std::endl;
1269
//FTGL units are a pain; The devs could not decide
1270
//whether to implement them in opengl coords or real coords
1271
//so they did neither, and implemented them in "points".
1272
//here we assume that we can transform 1 ftgl unit
1273
//to 1 opengl unit by inversion
1274
const float FTGL_DEFAULT_UNIT_SCALE=1.0/72.0;
1276
glColor3f(1.0f,1.0f,1.0f);
1278
glDisable(GL_CULL_FACE);
1280
glTranslatef(tlX+width,tlY,0);
1283
//Note negative sign to flip from y-down screen (opengl) to text dir
1285
glScaled(FTGL_DEFAULT_UNIT_SCALE,
1286
-FTGL_DEFAULT_UNIT_SCALE,FTGL_DEFAULT_UNIT_SCALE);
1287
font->Render(s.c_str());
1291
glTranslatef(tlX+width,tlY+height,0);
1293
//Note negative sign to flip from y-down screen (opengl) to text dir
1295
glScaled(FTGL_DEFAULT_UNIT_SCALE,
1296
-FTGL_DEFAULT_UNIT_SCALE,FTGL_DEFAULT_UNIT_SCALE);
1297
font->Render(s.c_str());
1299
glEnable(GL_CULL_FACE);
1305
void DrawColourBarOverlay::setColourVec(const vector<float> &r,
1306
const vector<float> &g,
1307
const vector<float> &b)
1309
ASSERT(r.size() == g.size());
1310
ASSERT(g.size() == b.size());
1311
rgb.resize(r.size());
1312
for(unsigned int ui=0;ui<r.size();ui++)
1322
void DrawColourBarOverlay::getBoundingBox(BoundCube &b) const
1328
DrawField3D::DrawField3D() : alphaVal(0.2f), pointSize(1.0f), drawBoundBox(true),volumeGrid(false), volumeRenderMode(0), field(0)
1330
boxColourR = boxColourG = boxColourB = boxColourA = 1.0f;
1334
DrawField3D::~DrawField3D()
1341
void DrawField3D::getBoundingBox(BoundCube &b) const
1344
b.setBounds(field->getMinBounds(),field->getMaxBounds());
1348
void DrawField3D::setField(const Voxels<float> *newField)
1353
void DrawField3D::setRenderMode(unsigned int mode)
1355
volumeRenderMode=mode;
1358
void DrawField3D::setColourMinMax()
1360
colourMapBound[0]=field->min();
1361
colourMapBound[1]=field->max();
1363
ASSERT(colourMapBound[0] <=colourMapBound[1]);
1367
void DrawField3D::draw() const
1369
if(alphaVal < sqrt(std::numeric_limits<float>::epsilon()))
1374
//Depend upon the render mode
1375
switch(volumeRenderMode)
1379
size_t fieldSizeX,fieldSizeY,fieldSizeZ;
1382
field->getSize(fieldSizeX,fieldSizeY, fieldSizeZ);
1385
delta = field->getPitch();
1390
for(unsigned int uiX=0; uiX<fieldSizeX; uiX++)
1392
for(unsigned int uiY=0; uiY<fieldSizeY; uiY++)
1394
for(unsigned int uiZ=0; uiZ<fieldSizeZ; uiZ++)
1397
v=field->getData(uiX,uiY,uiZ);
1398
if(v > std::numeric_limits<float>::epsilon())
1401
//Set colour and point loc
1402
colourMapWrap(colourMapID,rgb.v,
1403
field->getData(uiX,uiY,uiZ),
1404
colourMapBound[0],colourMapBound[1]);
1406
ptsCache.push_back(make_pair(field->getPoint(uiX,uiY,uiZ)+delta,rgb));
1418
//We need to generate some points, then sort them by distance
1419
//from eye (back to front), otherwise they will not blend properly
1420
std::vector<std::pair<float,unsigned int > > eyeDists;
1422
Point3D camOrigin = curCamera->getOrigin();
1424
eyeDists.resize(ptsCache.size());
1426
//Set up an original index for the eye distances
1427
#pragma omp parallel for
1428
for(unsigned int ui=0;ui<ptsCache.size();ui++)
1430
eyeDists[ui].first=ptsCache[ui].first.sqrDist(camOrigin);
1431
eyeDists[ui].second=ui;
1434
ComparePairFirstReverse cmp;
1435
std::sort(eyeDists.begin(),eyeDists.end(),cmp);
1437
//render each element in the field as a point
1438
//the colour of the point is determined by its scalar value
1439
glDepthMask(GL_FALSE);
1440
glPointSize(pointSize);
1442
for(unsigned int ui=0;ui<ptsCache.size();ui++)
1445
idx=eyeDists[ui].second;
1446
//Tell openGL about it
1447
glColor4f(((float)(ptsCache[idx].second.v[0]))/255.0f,
1448
((float)(ptsCache[idx].second.v[1]))/255.0f,
1449
((float)(ptsCache[idx].second.v[2]))/255.0f,
1451
glVertex3f(ptsCache[idx].first[0],ptsCache[idx].first[1],ptsCache[idx].first[2]);
1454
glDepthMask(GL_TRUE);
1458
for(unsigned int ui=0;ui<ptsCache.size();ui++)
1460
//Tell openGL about it
1461
glColor4f(((float)(ptsCache[ui].second.v[0]))/255.0f,
1462
((float)(ptsCache[ui].second.v[1]))/255.0f,
1463
((float)(ptsCache[ui].second.v[2]))/255.0f,
1465
glVertex3f(ptsCache[ui].first[0],ptsCache[ui].first[1],ptsCache[ui].first[2]);
1476
//Draw the bounding box as required
1479
drawBox(field->getMinBounds(),field->getMaxBounds(),
1480
boxColourR, boxColourG,boxColourB,boxColourA);
1482
//Draw the projections
1485
void DrawField3D::setAlpha(float newAlpha)
1490
void DrawField3D::setPointSize(float size)
1495
void DrawField3D::setMapColours(unsigned int mapID)
1497
ASSERT(mapID < NUM_COLOURMAPS);
1501
void DrawField3D::setBoxColours(float rNew, float gNew, float bNew, float aNew)
1511
DrawIsoSurface::DrawIsoSurface()
1514
drawMode=DRAW_SMOOTH;
1524
DrawIsoSurface::~DrawIsoSurface()
1531
bool DrawIsoSurface::needsDepthSorting() const
1533
return a< 1 && a > std::numeric_limits<float>::epsilon();
1536
void DrawIsoSurface::swapVoxels(Voxels<float> *f)
1538
std::swap(f,voxels);
1544
void DrawIsoSurface::updateMesh() const
1548
marchingCubes(*voxels, threshold,mesh);
1554
void DrawIsoSurface::getBoundingBox(BoundCube &b) const
1558
b.setBounds(voxels->getMinBounds(),
1559
voxels->getMaxBounds());
1562
b.setInverseLimits();
1566
void DrawIsoSurface::draw() const
1568
if(a< sqrt(std::numeric_limits<float>::epsilon()))
1573
//Hmm, we don't have a cached copy of the isosurface mesh.
1574
//we will need to compute one, it would seem.
1579
//This could be optimised by using triangle strips
1580
//rather than direct triangles.
1583
//We need to sort them by distance
1584
//from eye (back to front), otherwise they will not blend properly
1585
std::vector<std::pair<float,unsigned int > > eyeDists;
1587
Point3D camOrigin = curCamera->getOrigin();
1588
eyeDists.resize(mesh.size());
1590
//Set up an original index for the eye distances
1591
#pragma omp parallel for shared(camOrigin)
1592
for(unsigned int ui=0;ui<mesh.size();ui++)
1595
mesh[ui].getCentroid(centroid);
1597
eyeDists[ui].first=centroid.sqrDist(camOrigin);
1598
eyeDists[ui].second=ui;
1601
ComparePairFirstReverse cmp;
1602
std::sort(eyeDists.begin(),eyeDists.end(),cmp);
1605
glDepthMask(GL_FALSE);
1607
glPushAttrib(GL_CULL_FACE);
1608
glDisable(GL_CULL_FACE);
1610
glBegin(GL_TRIANGLES);
1611
for(unsigned int ui=0;ui<mesh.size();ui++)
1614
idx=eyeDists[ui].second;
1615
glNormal3fv(mesh[idx].normal[0].getValueArr());
1616
glVertex3fv(mesh[idx].p[0].getValueArr());
1617
glNormal3fv(mesh[idx].normal[1].getValueArr());
1618
glVertex3fv(mesh[idx].p[1].getValueArr()),
1619
glNormal3fv(mesh[idx].normal[2].getValueArr());
1620
glVertex3fv(mesh[idx].p[2].getValueArr());
1626
glDepthMask(GL_TRUE);
1632
glPushAttrib(GL_CULL_FACE);
1633
glDisable(GL_CULL_FACE);
1634
glBegin(GL_TRIANGLES);
1635
for(unsigned int ui=0;ui<mesh.size();ui++)
1637
glNormal3fv(mesh[ui].normal[0].getValueArr());
1638
glVertex3fv(mesh[ui].p[0].getValueArr());
1639
glNormal3fv(mesh[ui].normal[1].getValueArr());
1640
glVertex3fv(mesh[ui].p[1].getValueArr()),
1641
glNormal3fv(mesh[ui].normal[2].getValueArr());
1642
glVertex3fv(mesh[ui].p[2].getValueArr());
1651
DrawAxis::DrawAxis()
1655
DrawAxis::~DrawAxis()
1659
void DrawAxis::setStyle(unsigned int s)
1664
void DrawAxis::setSize(float s)
1669
void DrawAxis::setPosition(const Point3D &p)
1674
void DrawAxis::draw() const
1677
float halfSize=size/2.0f;
1678
glPushAttrib(GL_LIGHTING_BIT);
1679
glDisable(GL_LIGHTING);
1682
glColor3f(1.0f,0.0f,0.0f);
1683
glVertex3f(position[0]-halfSize,
1684
position[1],position[2]);
1685
glVertex3f(position[0]+halfSize,
1686
position[1],position[2]);
1688
glColor3f(0.0f,1.0f,0.0f);
1689
glVertex3f(position[0],
1690
position[1]-halfSize,position[2]);
1691
glVertex3f(position[0],
1692
position[1]+halfSize,position[2]);
1694
glColor3f(0.0f,0.0f,1.0f);
1695
glVertex3f(position[0],
1696
position[1],position[2]-halfSize);
1697
glVertex3f(position[0],
1698
position[1],position[2]+halfSize);
1704
float numSections=20.0f;
1705
float twoPi = 2.0f *M_PI;
1706
float radius = 0.1*halfSize;
1711
glTranslatef(position[0]+halfSize,position[1],position[2]);
1713
glColor3f(1.0f,0.0f,0.0f);
1714
glBegin(GL_TRIANGLE_FAN);
1715
glVertex3f(radius,0,0);
1717
for (unsigned int i = 0; i<=numSections; i++)
1719
glVertex3f(0,radius * cos(i * twoPi / numSections),
1720
radius* sin(i * twoPi / numSections));
1721
glNormal3f(0,cos(i*twoPi/numSections),sin(i*twoPi/numSections));
1724
glBegin(GL_TRIANGLE_FAN);
1727
for (unsigned int i = 0; i<=numSections; i++)
1729
glVertex3f(0,-radius * cos(i * twoPi / numSections),
1730
radius* sin(i * twoPi / numSections));
1737
glColor3f(0.0f,1.0f,0.0f);
1739
glTranslatef(position[0],position[1]+halfSize,position[2]);
1740
glBegin(GL_TRIANGLE_FAN);
1741
glVertex3f(0,radius,0);
1743
for (unsigned int i = 0; i<=numSections; i++)
1745
glVertex3f(radius * sin(i * twoPi / numSections),0,
1746
radius* cos(i * twoPi / numSections));
1747
glNormal3f(sin(i*twoPi/numSections),0,cos(i*twoPi/numSections));
1751
glBegin(GL_TRIANGLE_FAN);
1754
for (unsigned int i = 0; i<=numSections; i++)
1756
glVertex3f(radius * cos(i * twoPi / numSections),0,
1757
radius* sin(i * twoPi / numSections));
1767
glColor3f(0.0f,0.0f,1.0f);
1769
glTranslatef(position[0],position[1],position[2]+halfSize);
1770
glBegin(GL_TRIANGLE_FAN);
1771
glVertex3f(0,0,radius);
1773
for (unsigned int i = 0; i<=numSections; i++)
1775
glVertex3f(radius * cos(i * twoPi / numSections),
1776
radius* sin(i * twoPi / numSections),0);
1777
glNormal3f(cos(i*twoPi/numSections),sin(i*twoPi/numSections),0);
1781
glBegin(GL_TRIANGLE_FAN);
1784
for (unsigned int i = 0; i<=numSections; i++)
1786
glVertex3f(-radius * cos(i * twoPi / numSections),
1787
radius* sin(i * twoPi / numSections),0);
1794
void DrawAxis::getBoundingBox(BoundCube &b) const
1800
void DrawDepthSorted::draw() const
1803
//Check to see if we need to re-sort the data
1804
needResort=(!haveLastDist ||
1805
lastCamLoc.sqrDist(curCamera->getOrigin()) >DEPTH_SORT_REORDER_EPSILON);
1809
//Rebuild the depthJump key data
1810
std::vector<pair<std::pair<size_t,size_t> , float> > dists;
1814
for(size_t ui=0;ui<depthObjects.size(); ui++)
1818
depthJumpKeys.resize(size);
1820
//Generate the to-camera distances (negative because we want
1821
//further away objects to be first)
1822
#pragma omp parallel for
1823
for(size_t ui=0;ui<depthObjects.size(); ui++)
1826
for(size_t uj=0; uj<depthObjects[ui].second.size(); uj++)
1828
centroid=depthObjects[ui].second[uj]->getCentroid();
1829
dists[ui+uj]=std::make_pair(std::make_pair(ui,uj),-centroid.sqrDist(curCamera->getOrigin()));
1833
//Now we have the distance data, sort it
1834
ComparePairSecond cmp;
1835
std::sort(dists.begin(),dists.end(),cmp);
1837
//Now set the depth Jump Keys using the sorted distances
1838
#pragma omp parallel for
1839
for(size_t ui=0;ui<dists.size();ui++)
1840
depthJumpKeys[ui]=dists[ui].first;
1842
lastCamLoc=curCamera->getOrigin();
1846
//OK, so we have to now draw our objects from back->front order
1847
//as set by depthJumpKeys
1848
for(size_t ui=0;ui<depthObjects.size();ui++)
1850
const DrawableObj *d;
1851
d=(depthObjects[depthJumpKeys[ui].first].second[depthJumpKeys[ui].second]);
1857
void DrawDepthSorted::addObjectsAsNeeded(const DrawableObj *obj)
1859
size_t off=std::numeric_limits<size_t>::max();
1860
for(size_t ui=0;ui<depthObjects.size();ui++)
1862
if(depthObjects[ui].first == obj)
1864
if(depthObjects[ui].first->hasChanged())
1867
off=depthObjects.size();
1874
if(off==depthObjects.size())
1875
return; // Object exists and is up to date.
1876
else if(off==std::numeric_limits<size_t>::max())
1878
//Ok, so we have no object, and we need
1879
//to create a new set of data
1884
ASSERT(off < depthObjects.size());
1885
//we need to update the object