diff options
author | Karl Berry <karl@freefriends.org> | 2019-10-06 17:17:34 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2019-10-06 17:17:34 +0000 |
commit | 7f9f7dad00ea5f025578c491005835740f9ffd90 (patch) | |
tree | 011a87a78042a82ea3a18f5c08e60f6a3930bf0b /Build/source/utils/asymptote/glrender.cc | |
parent | 37d8fb68e502daabe6aa5f5ae9fb78191f275742 (diff) |
asy 2.56 sources
git-svn-id: svn://tug.org/texlive/trunk@52300 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/glrender.cc')
-rw-r--r-- | Build/source/utils/asymptote/glrender.cc | 959 |
1 files changed, 595 insertions, 364 deletions
diff --git a/Build/source/utils/asymptote/glrender.cc b/Build/source/utils/asymptote/glrender.cc index 7ec0370ad62..28bfdb8a472 100644 --- a/Build/source/utils/asymptote/glrender.cc +++ b/Build/source/utils/asymptote/glrender.cc @@ -1,6 +1,6 @@ /***** * glrender.cc - * John Bowman and Orest Shardt + * John Bowman, Orest Shardt, and Supakorn "Jamie" Rassameemasmuang * Render 3D Bezier paths and surfaces. *****/ @@ -13,7 +13,6 @@ #include <cstring> #include <sys/time.h> - #include "common.h" #include "locate.h" #include "seconds.h" @@ -21,7 +20,13 @@ #include "bezierpatch.h" #include "beziercurve.h" +#include "picture.h" +#include "bbox3.h" +#include "drawimage.h" +#include "interact.h" + #ifdef HAVE_GL +#include "tr.h" #ifdef HAVE_LIBGLUT #ifdef __MSDOS__ @@ -36,48 +41,60 @@ #define GLUT_BUILDING_LIB #endif // HAVE_LIBGLUT -#include "picture.h" -#include "arcball.h" -#include "bbox3.h" -#include "drawimage.h" -#include "interact.h" -#include "tr.h" - #ifdef HAVE_LIBGLUT #ifdef FREEGLUT #include <GL/freeglut_ext.h> #endif #endif -#include <glm/glm.hpp> -#include <glm/gtc/matrix_transform.hpp> -#include <glm/gtc/type_ptr.hpp> - #include "shaders.h" -#include "material.h" #ifdef HAVE_LIBOPENIMAGEIO #include <OpenImageIO/imageio.h> #endif using settings::locateFile; +using utils::seconds; + +namespace camp { +Billboard BB; + +GLint pixelShader; +GLint noNormalShader; +GLint materialShader; +GLint colorShader; +GLint transparentShader; + +vertexBuffer material0Data; +vertexBuffer material1Data; +vertexBuffer materialData; +vertexBuffer colorData; +vertexBuffer transparentData; +vertexBuffer triangleData; + +const size_t Nbuffer=10000; +const size_t nbuffer=1000; +} + +#endif /* HAVE_GL */ + +#ifdef HAVE_LIBGLM using camp::Material; using camp::Maxmaterials; using camp::Nmaterials; using camp::nmaterials; -using utils::seconds; +using camp::MaterialMap; namespace camp { -billboard BB; -GLint materialShader; -GLint colorShader; -GLint noNormalShader; -GLint pixelShader; +mem::vector<Material> material; +MaterialMap materialMap; +size_t materialIndex; size_t Maxmaterials; size_t Nmaterials=1; size_t nmaterials=48; } + namespace gl { bool outlinemode=false; @@ -85,7 +102,7 @@ bool glthread=false; bool initialize=true; GLint Maxvertices; -Int maxvertices; +size_t maxvertices; using camp::picture; using camp::drawRawImage; @@ -104,27 +121,9 @@ int Fitscreen; bool queueExport=false; bool readyAfterExport=false; - -#ifdef HAVE_LIBGLUT -timeval lasttime; -timeval lastframetime; -int oldWidth,oldHeight; - -bool Xspin,Yspin,Zspin; -bool Animate; -bool Step; bool remesh; -bool forceRemesh=false; - -bool queueScreen=false; -int x0,y0; -string Action; - -double lastangle; -Arcball arcball; -int window; -#endif +int Mode; double Aspect; bool View; @@ -132,8 +131,8 @@ int Oldpid; string Prefix; const picture* Picture; string Format; -int Width,Height; int fullWidth,fullHeight; +int Width,Height; double oWidth,oHeight; int screenWidth,screenHeight; int maxWidth; @@ -141,10 +140,6 @@ int maxHeight; int maxTileWidth; int maxTileHeight; -double T[16]; - -int Mode; - double Angle; bool orthographic; double H; @@ -156,15 +151,18 @@ double Xmin,Xmax; double Ymin,Ymax; pair Shift; +pair Margin; double X,Y; +int x0,y0; double cx,cy; double Xfactor,Yfactor; +double ArcballFactor; static const double pi=acos(-1.0); static const double degrees=180.0/pi; static const double radians=1.0/degrees; -double Background[4]; +double *Background; size_t Nlights=1; // Maximum number of lights compiled in shader size_t nlights; // Actual number of lights size_t nlights0; @@ -177,106 +175,33 @@ double Zoom; double Zoom0; double lastzoom; +GLint lastshader=-1; + using glm::dvec3; +using glm::dmat3; +using glm::mat3; using glm::mat4; using glm::dmat4; using glm::value_ptr; using glm::translate; +mat3 normMat; +dmat3 dnormMat; + mat4 projViewMat; mat4 viewMat; -mat4 normMat; dmat4 dprojMat; +dmat4 dprojViewMat; dmat4 dviewMat; dmat4 drotateMat; -using utils::statistics; -statistics S; - -ModelView modelView; - -#ifdef HAVE_LIBOPENIMAGEIO -GLuint envMapBuf; - -GLuint initHDR() { - GLuint tex; - glGenTextures(1, &tex); - - auto imagein = OIIO::ImageInput::open(locateFile("res/studio006.hdr").c_str()); - OIIO::ImageSpec const& imspec = imagein->spec(); - - // uses GL_TEXTURE1 for now. - glActiveTexture(GL_TEXTURE1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +const double *dprojView; +double BBT[9]; - glBindTexture(GL_TEXTURE_2D, tex); - std::vector<float> pixels(imspec.width*imspec.height*3); - imagein->read_image(pixels.data()); +GLuint ubo; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imspec.width, imspec.height, 0, - GL_RGB, GL_FLOAT, pixels.data()); - - glGenerateMipmap(GL_TEXTURE_2D); - imagein->close(); - - glActiveTexture(GL_TEXTURE0); - return tex; -} - -#endif -void updateModelViewData() -{ - // Like Fortran, OpenGL uses transposed (column-major) format! - dmat4 MV=glm::transpose(dviewMat); - dmat4 MVinv=glm::inverse(MV); - - normMat=mat4(MVinv); - - double* T=value_ptr(MV); - double* Tinv=value_ptr(MVinv); - - for(int j=0; j < 16; ++j) { - modelView.T[j]=T[j]; - modelView.Tinv[j]=Tinv[j]; - } -} - - -GLint shaderProg,shaderProgColor; - -double *Rotate; -void *glrenderWrapper(void *a); - -#ifdef HAVE_LIBOSMESA -OSMesaContext ctx; -unsigned char *osmesa_buffer; -#endif - -#ifdef HAVE_PTHREAD -pthread_t mainthread; - -pthread_cond_t initSignal=PTHREAD_COND_INITIALIZER; -pthread_mutex_t initLock=PTHREAD_MUTEX_INITIALIZER; - -pthread_cond_t readySignal=PTHREAD_COND_INITIALIZER; -pthread_mutex_t readyLock=PTHREAD_MUTEX_INITIALIZER; - -void endwait(pthread_cond_t& signal, pthread_mutex_t& lock) -{ - pthread_mutex_lock(&lock); - pthread_cond_signal(&signal); - pthread_mutex_unlock(&lock); -} -void wait(pthread_cond_t& signal, pthread_mutex_t& lock) -{ - pthread_mutex_lock(&lock); - pthread_cond_signal(&signal); - pthread_cond_wait(&signal,&lock); - pthread_mutex_unlock(&lock); -} -#endif +unsigned int framecount; template<class T> inline T min(T a, T b) @@ -338,18 +263,25 @@ void setDimensions(int Width, int Height, double X, double Y) } } +void updateProjection() +{ + dprojViewMat=dprojMat*dviewMat; + projViewMat=mat4(dprojViewMat); + dprojView=value_ptr(dprojViewMat); +} + void frustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble nearVal, GLdouble farVal) { dprojMat=glm::frustum(left,right,bottom,top,nearVal,farVal); - projViewMat=mat4(dprojMat*dviewMat); + updateProjection(); } void ortho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble nearVal, GLdouble farVal) { dprojMat=glm::ortho(left,right,bottom,top,nearVal,farVal); - projViewMat=mat4(dprojMat*dviewMat); + updateProjection(); } void setProjection() @@ -357,12 +289,136 @@ void setProjection() setDimensions(Width,Height,X,Y); if(orthographic) ortho(xmin,xmax,ymin,ymax,-zmax,-zmin); else frustum(xmin,xmax,ymin,ymax,-zmax,-zmin); +} + +void updateModelViewData() +{ + // Like Fortran, OpenGL uses transposed (column-major) format! + dnormMat=dmat3(glm::inverse(dviewMat)); + double *T=value_ptr(dnormMat); + for(size_t i=0; i < 9; ++i) + BBT[i]=T[i]; + normMat=mat3(dnormMat); +} + +bool Xspin,Yspin,Zspin; +bool Animate; +bool Step; + +#ifdef HAVE_GL +void idle() +{ + glutIdleFunc(NULL); + Xspin=Yspin=Zspin=Animate=Step=false; +} +#endif + +void home(bool webgl=false) +{ + X=Y=cx=cy=0.0; +#ifdef HAVE_GL +#ifdef HAVE_LIBGLUT + if(!webgl && !getSetting<bool>("offscreen")) + idle(); +#endif +#endif + dviewMat=dmat4(1.0); + viewMat=mat4(dviewMat); + + drotateMat=dmat4(1.0); + updateModelViewData(); + + remesh=true; + lastzoom=Zoom=Zoom0; + setDimensions(Width,Height,0,0); + framecount=0; +} + +#ifdef HAVE_GL + +double T[16]; + #ifdef HAVE_LIBGLUT - double arcballRadius=getSetting<double>("arcballradius"); - arcball.set_params(vec2(0.5*Width,0.5*Height),arcballRadius*Zoom); +timeval lasttime; +timeval lastframetime; +int oldWidth,oldHeight; + +bool forceRemesh=false; + +bool queueScreen=false; + +string Action; + +double lastangle; +int window; #endif + +using utils::statistics; +statistics S; + +#ifdef HAVE_LIBOPENIMAGEIO +GLuint envMapBuf; + +GLuint initHDR() { + GLuint tex; + glGenTextures(1, &tex); + + auto imagein = OIIO::ImageInput::open(locateFile("res/studio006.hdr").c_str()); + OIIO::ImageSpec const& imspec = imagein->spec(); + + // uses GL_TEXTURE1 for now. + glActiveTexture(GL_TEXTURE1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, tex); + std::vector<float> pixels(imspec.width*imspec.height*3); + imagein->read_image(pixels.data()); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imspec.width, imspec.height, 0, + GL_RGB, GL_FLOAT, pixels.data()); + + glGenerateMipmap(GL_TEXTURE_2D); + imagein->close(); + + glActiveTexture(GL_TEXTURE0); + return tex; +} + +#endif +GLint shaderProg,shaderProgColor; + +void *glrenderWrapper(void *a); + +#ifdef HAVE_LIBOSMESA +OSMesaContext ctx; +unsigned char *osmesa_buffer; +#endif + +#ifdef HAVE_PTHREAD +pthread_t mainthread; + +pthread_cond_t initSignal=PTHREAD_COND_INITIALIZER; +pthread_mutex_t initLock=PTHREAD_MUTEX_INITIALIZER; + +pthread_cond_t readySignal=PTHREAD_COND_INITIALIZER; +pthread_mutex_t readyLock=PTHREAD_MUTEX_INITIALIZER; + +void endwait(pthread_cond_t& signal, pthread_mutex_t& lock) +{ + pthread_mutex_lock(&lock); + pthread_cond_signal(&signal); + pthread_mutex_unlock(&lock); +} +void wait(pthread_cond_t& signal, pthread_mutex_t& lock) +{ + pthread_mutex_lock(&lock); + pthread_cond_signal(&signal); + pthread_cond_wait(&signal,&lock); + pthread_mutex_unlock(&lock); } +#endif void drawscene(int Width, int Height) { @@ -383,23 +439,20 @@ void drawscene(int Width, int Height) double size2=hypot(Width,Height); - if(remesh) { - camp::BezierPatch::clear(); - camp::BezierPatch::Clear(); - camp::BezierPatch::tClear(); - camp::BezierCurve::clear(); - camp::Pixel::clear(); + if(forceRemesh) { + remesh=true; + forceRemesh=false; } - // Render opaque objects - Picture->render(size2,m,M,perspective,false,remesh); + camp::clearBuffers(); + + if(remesh) + camp::drawElement::center.clear(); - // Enable transparency - glDepthMask(GL_FALSE); + Picture->render(size2,m,M,perspective,remesh); - // Render transparent objects - Picture->render(size2,m,M,perspective,true,remesh); - glDepthMask(GL_TRUE); + if(!forceRemesh) + remesh=false; } // Return x divided by y rounded up to the nearest integer. @@ -415,6 +468,7 @@ void Export() glFinish(); try { size_t ndata=3*fullWidth*fullHeight; + unsigned border=1; unsigned char *data=new unsigned char[ndata]; if(data) { TRcontext *tr=trNew(); @@ -426,7 +480,7 @@ void Export() << fullHeight << " image" << " using tiles of size " << width << "x" << height << endl; - trTileSize(tr,width,height,0); + trTileSize(tr,width,height,border); trImageSize(tr,fullWidth,fullHeight); trImageBuffer(tr,GL_RGB,GL_UNSIGNED_BYTE,data); @@ -477,38 +531,6 @@ void Export() #endif } -#ifdef HAVE_LIBGLUT -void idle() -{ - glutIdleFunc(NULL); - Xspin=Yspin=Zspin=Animate=Step=false; -} -#endif - -void home() -{ - X=Y=cx=cy=0.0; -#ifdef HAVE_LIBGLUT - if(!getSetting<bool>("offscreen")) { - idle(); - arcball.init(); - } -#endif - viewMat=mat4(1.0f); - normMat=mat4(1.0f); - - dviewMat=dmat4(1.0); - drotateMat=dmat4(1.0); - - Rotate=value_ptr(drotateMat); - updateModelViewData(); - - remesh=true; - lastzoom=Zoom=Zoom0; - setDimensions(Width,Height,0,0); - glClearColor(Background[0],Background[1],Background[2],Background[3]); -} - void nodisplay() { } @@ -565,19 +587,20 @@ void mode() { remesh=true; switch(Mode) { - case 0: // wireframe -> regular + case 0: // regular outlinemode=false; nlights=nlights0; + lastshader=-1; glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); ++Mode; break; - case 1: // regular -> outline + case 1: // outline outlinemode=true; nlights=0; glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); ++Mode; break; - case 2: // outline -> wireframe + case 2: // wireframe outlinemode=false; Mode=0; break; @@ -734,16 +757,20 @@ void display() if(maxvertices == 0) maxvertices=Maxvertices; bool fps=settings::verbose > 2; - if(fps) seconds(); drawscene(Width,Height); if(fps) { - glFinish(); - double s=seconds(); - if(s > 0.0) { - double rate=1.0/s; - S.add(rate); - cout << "FPS=" << rate << "\t" << S.mean() << " +/- " << S.stdev() << endl; + if(framecount < 10) // Measure steady-state framerate + seconds(); + else { + double s=seconds(); + if(s > 0.0) { + double rate=1.0/s; + S.add(rate); + cout << "FPS=" << rate << "\t" << S.mean() << " +/- " << S.stdev() + << endl; + } } + ++framecount; } glutSwapBuffers(); @@ -782,12 +809,14 @@ void update() Animate=getSetting<bool>("autoplay"); glutShowWindow(); if(Zoom != lastzoom) remesh=true; + lastzoom=Zoom; double cz=0.5*(zmin+zmax); dviewMat=translate(translate(dmat4(1.0),dvec3(cx,cy,cz))*drotateMat, dvec3(0,0,-cz)); viewMat=mat4(dviewMat); + setProjection(); updateModelViewData(); @@ -834,35 +863,31 @@ void reshape(int width, int height) void shift(int x, int y) { - if(x > 0 && y > 0) { - double Zoominv=1.0/Zoom; - X += (x-x0)*Zoominv; - Y += (y0-y)*Zoominv; - x0=x; y0=y; - update(); - } + double Zoominv=1.0/Zoom; + X += (x-x0)*Zoominv; + Y += (y0-y)*Zoominv; + x0=x; y0=y; + update(); } void pan(int x, int y) { - if(x > 0 && y > 0) { - if(orthographic) { - double Zoominv=1.0/Zoom; - X += (x-x0)*Zoominv; - Y += (y0-y)*Zoominv; - } else { - cx += (x-x0)*(xmax-xmin)/Width; - cy += (y0-y)*(ymax-ymin)/Height; - } - x0=x; y0=y; - update(); + if(orthographic) { + double Zoominv=1.0/Zoom; + X += (x-x0)*Zoominv; + Y += (y0-y)*Zoominv; + } else { + cx += (x-x0)*(xmax-xmin)/Width; + cy += (y0-y)*(ymax-ymin)/Height; } + x0=x; y0=y; + update(); } void capzoom() { static double maxzoom=sqrt(DBL_MAX); - static double minzoom=1/maxzoom; + static double minzoom=1.0/maxzoom; if(Zoom <= minzoom) Zoom=minzoom; if(Zoom >= maxzoom) Zoom=maxzoom; @@ -873,19 +898,17 @@ void capzoom() void zoom(int x, int y) { if(ignorezoom) {ignorezoom=false; y0=y; return;} - if(x > 0 && y > 0) { - double zoomFactor=getSetting<double>("zoomfactor"); - if(zoomFactor > 0.0) { - double zoomStep=getSetting<double>("zoomstep"); - const double limit=log(0.1*DBL_MAX)/log(zoomFactor); - double s=zoomStep*(y0-y); - if(fabs(s) < limit) { - Zoom *= pow(zoomFactor,s); - capzoom(); - y0=y; - setProjection(); - glutPostRedisplay(); - } + double zoomFactor=getSetting<double>("zoomfactor"); + if(zoomFactor > 0.0) { + double zoomStep=getSetting<double>("zoomstep"); + const double limit=log(0.1*DBL_MAX)/log(zoomFactor); + double stepPower=zoomStep*(y0-y); + if(fabs(stepPower) < limit) { + Zoom *= pow(zoomFactor,stepPower); + capzoom(); + y0=y; + setProjection(); + glutPostRedisplay(); } } } @@ -904,20 +927,48 @@ void mousewheel(int wheel, int direction, int x, int y) } } +struct arcball { + double angle; + triple axis; + + arcball(double x0, double y0, double x, double y) { + triple v0=norm(x0,y0); + triple v1=norm(x,y); + double Dot=dot(v0,v1); + if(Dot > 1.0) Dot=1.0; + else if(Dot < -1.0) Dot=-1.0; + angle=acos(Dot); + axis=unit(cross(v0,v1)); + } + + triple norm(double x, double y) { + double norm=hypot(x,y); + if(norm > 1.0) { + double denom=1.0/norm; + x *= denom; + y *= denom; + } + return triple(x,y,sqrt(max(1.0-x*x-y*y,0.0))); + } +}; + +inline double glx(int x) { + return 2.0*x/Width-1.0; +} + +inline double gly(int y) { + return 1.0-2.0*y/Height; +} + void rotate(int x, int y) { - if(x > 0 && y > 0) { - arcball.mouse_motion(x,Height-y,0, - Action == "rotateX", // X rotation only - Action == "rotateY"); // Y rotation only - - for(int i=0; i < 4; ++i) { - const ::vec4& roti=arcball.rot[i]; - int i4=4*i; - for(int j=0; j < 4; ++j) - value_ptr(drotateMat)[i4+j]=roti[j]; - } - + if(x != x0 || y != y0) { + arcball A(glx(x0),gly(y0),glx(x),gly(y)); + triple v=A.axis; + drotateMat=glm::rotate<double>(2*A.angle/lastzoom*ArcballFactor, + glm::dvec3(v.getx(),v.gety(),v.getz()))* + drotateMat; + x0=x; y0=y; update(); } } @@ -927,24 +978,12 @@ double Degrees(int x, int y) return atan2(0.5*Height-y-Y,x-0.5*Width-X)*degrees; } -void updateArcball() -{ - Rotate=value_ptr(drotateMat); - for(int i=0; i < 4; ++i) { - int i4=4*i; - ::vec4& roti=arcball.rot[i]; - for(int j=0; j < 4; ++j) - roti[j]=Rotate[i4+j]; - } - update(); -} - void rotateX(double step) { dmat4 tmpRot(1.0); tmpRot=glm::rotate(tmpRot,glm::radians(step),dvec3(1,0,0)); drotateMat=tmpRot*drotateMat; - updateArcball(); + update(); } void rotateY(double step) @@ -952,7 +991,7 @@ void rotateY(double step) dmat4 tmpRot(1.0); tmpRot=glm::rotate(tmpRot,glm::radians(step),dvec3(0,1,0)); drotateMat=tmpRot*drotateMat; - updateArcball(); + update(); } void rotateZ(double step) @@ -960,16 +999,28 @@ void rotateZ(double step) dmat4 tmpRot(1.0); tmpRot=glm::rotate(tmpRot,glm::radians(step),dvec3(0,0,1)); drotateMat=tmpRot*drotateMat; - updateArcball(); + update(); +} + +void rotateX(int x, int y) +{ + double angle=Degrees(x,y); + rotateX(angle-lastangle); + lastangle=angle; +} + +void rotateY(int x, int y) +{ + double angle=Degrees(x,y); + rotateY(angle-lastangle); + lastangle=angle; } void rotateZ(int x, int y) { - if(x > 0 && y > 0) { - double angle=Degrees(x,y); - rotateZ(angle-lastangle); - lastangle=angle; - } + double angle=Degrees(x,y); + rotateZ(angle-lastangle); + lastangle=angle; } #ifndef GLUT_WHEEL_UP @@ -1059,8 +1110,8 @@ void mouse(int button, int state, int x, int y) } if(state == GLUT_DOWN) { - if(Action == "rotate" || Action == "rotateX" || Action == "rotateY") { - arcball.mouse_down(x,Height-y); + if(Action == "rotate") { + x0=x; y0=y; glutMotionFunc(rotate); } else if(Action == "shift") { x0=x; y0=y; @@ -1071,13 +1122,18 @@ void mouse(int button, int state, int x, int y) } else if(Action == "zoom" || Action == "zoom/menu") { y0=y; glutMotionFunc(zoom); + } else if(Action == "rotateX") { + lastangle=Degrees(x,y); + glutMotionFunc(rotateX); + } else if(Action == "rotateY") { + lastangle=Degrees(x,y); + glutMotionFunc(rotateY); } else if(Action == "rotateZ") { lastangle=Degrees(x,y); glutMotionFunc(rotateZ); } } else { - arcball.mouse_up(); - glutMotionFunc(NULL); + glutMotionFunc(NULL); } } @@ -1155,11 +1211,6 @@ void spinz() } } -void write(const char *text, const double *v) -{ - cout << text << "=(" << v[0] << "," << v[1] << "," << v[2] << ")"; -} - void showCamera() { projection P=camera(); @@ -1277,6 +1328,8 @@ projection camera(bool user) double cz=0.5*(zmin+zmax); + double *Rotate=value_ptr(drotateMat); + if(user) { for(int i=0; i < 3; ++i) { double sumCamera=0.0, sumTarget=0.0, sumUp=0.0; @@ -1311,8 +1364,8 @@ projection camera(bool user) return projection(orthographic,vCamera,vUp,vTarget,Zoom, 2.0*atan(tan(0.5*Angle)/Zoom)/radians, - pair(X/Width*lastzoom+Shift.getx(), - Y/Height*lastzoom+Shift.gety())); + pair(X/Width+Shift.getx(), + Y/Height+Shift.gety())); } void init() @@ -1333,7 +1386,6 @@ void init() glutInit(&argc,argv); screenWidth=glutGet(GLUT_SCREEN_WIDTH); screenHeight=glutGet(GLUT_SCREEN_HEIGHT); - #endif } @@ -1376,10 +1428,6 @@ void init_osmesa() } #endif // HAVE_LIBOSMESA } - -GLuint vertShader,fragShader; -GLuint vertShaderCol,fragShaderCol; - void initshader() { Nlights=max(Nlights,nlights); @@ -1404,45 +1452,47 @@ void initshader() std::vector<ShaderfileModePair> shaders; shaders.push_back(ShaderfileModePair(vs.c_str(),GL_VERTEX_SHADER)); shaders.push_back(ShaderfileModePair(fs.c_str(),GL_FRAGMENT_SHADER)); + if(orthographic) + shaderParams.push_back("ORTHOGRAPHIC"); - camp::noNormalShader=compileAndLinkShader(shaders,Nlights,Nmaterials, - shaderParams); - shaderParams.push_back("WIDTH"); camp::pixelShader=compileAndLinkShader(shaders,Nlights,Nmaterials, shaderParams); shaderParams.pop_back(); - + camp::noNormalShader=compileAndLinkShader(shaders,Nlights,Nmaterials, + shaderParams); shaderParams.push_back("NORMAL"); camp::materialShader=compileAndLinkShader(shaders,Nlights,Nmaterials, shaderParams); - - shaderParams.push_back("EXPLICIT_COLOR"); + shaderParams.push_back("COLOR"); camp::colorShader=compileAndLinkShader(shaders,Nlights,Nmaterials, shaderParams); + shaderParams.push_back("TRANSPARENT"); + camp::transparentShader=compileAndLinkShader(shaders,Nlights,Nmaterials, + shaderParams); } void deleteshader() { - glDeleteProgram(camp::materialShader); + glDeleteProgram(camp::transparentShader); glDeleteProgram(camp::colorShader); + glDeleteProgram(camp::materialShader); + glDeleteProgram(camp::pixelShader); glDeleteProgram(camp::noNormalShader); } - + +#endif /* HAVE_GL */ + // angle=0 means orthographic. void glrender(const string& prefix, const picture *pic, const string& format, double width, double height, double angle, double zoom, - const triple& m, const triple& M, const pair& shift, double *t, + const triple& m, const triple& M, const pair& shift, + const pair& margin, double *t, double *background, size_t nlightsin, triple *lights, double *diffuse, double *specular, bool view, int oldpid) { - remesh=true; - bool offscreen=getSetting<bool>("offscreen"); Iconify=getSetting<bool>("iconify"); -#ifdef HAVE_PTHREAD - static bool initializedView=false; -#endif width=max(width,1.0); height=max(height,1.0); @@ -1451,10 +1501,6 @@ void glrender(const string& prefix, const picture *pic, const string& format, Prefix=prefix; Picture=pic; Format=format; - for(int i=0; i < 16; ++i) - T[i]=t[i]; - for(int i=0; i < 4; ++i) - Background[i]=background[i]; nlights0=nlights=nlightsin; @@ -1466,6 +1512,8 @@ void glrender(const string& prefix, const picture *pic, const string& format, Zoom0=zoom; Oldpid=oldpid; Shift=shift; + Margin=margin; + Background=background; Xmin=m.getx(); Xmax=M.getx(); @@ -1476,7 +1524,7 @@ void glrender(const string& prefix, const picture *pic, const string& format, orthographic=Angle == 0.0; H=orthographic ? 0.0 : -tan(0.5*Angle)*zmax; - + ignorezoom=false; Mode=0; Xfactor=Yfactor=1.0; @@ -1487,7 +1535,15 @@ void glrender(const string& prefix, const picture *pic, const string& format, if(maxTileWidth <= 0) maxTileWidth=1024; if(maxTileHeight <= 0) maxTileHeight=768; - if(offscreen) { + bool webgl=Format == "html"; + +#ifdef HAVE_GL +#ifdef HAVE_PTHREAD + static bool initializedView=false; +#endif + + bool offscreen=getSetting<bool>("offscreen"); + if(offscreen && !webgl) { screenWidth=maxTileWidth; screenHeight=maxTileHeight; @@ -1499,19 +1555,27 @@ void glrender(const string& prefix, const picture *pic, const string& format, } if(glinitialize) { - glinitialize=false; - init(); + if(!webgl) init(); Fitscreen=1; } +#endif static bool initialized=false; if(!initialized || !interact::interactive) { antialias=getSetting<Int>("antialias") > 1; - double expand=getSetting<double>("render"); - if(expand < 0) - expand *= (Format.empty() || Format == "eps" || Format == "pdf") - ? -2.0 : -1.0; - if(antialias) expand *= 2.0; + double expand; + if(webgl) + expand=1.0; + else { + expand=getSetting<double>("render"); + if(expand < 0) + expand *= (Format.empty() || Format == "eps" || Format == "pdf") ? -2.0 : -1.0; + if(antialias) expand *= 2.0; + } + + oWidth=width; + oHeight=height; + Aspect=width/height; // Force a hard viewport limit to work around direct rendering bugs. // Alternatively, one can use -glOptions=-indirect (with a performance @@ -1521,26 +1585,40 @@ void glrender(const string& prefix, const picture *pic, const string& format, maxHeight=(int) ceil(maxViewport.gety()); if(maxWidth <= 0) maxWidth=max(maxHeight,2); if(maxHeight <= 0) maxHeight=max(maxWidth,2); - if(screenWidth <= 0) screenWidth=maxWidth; - else screenWidth=min(screenWidth,maxWidth); - if(screenHeight <= 0) screenHeight=maxHeight; - else screenHeight=min(screenHeight,maxHeight); - - oWidth=width; - oHeight=height; - Aspect=width/height; - + fullWidth=(int) ceil(expand*width); fullHeight=(int) ceil(expand*height); - Width=min(fullWidth,screenWidth); - Height=min(fullHeight,screenHeight); + if(webgl) { + Width=fullWidth; + Height=fullHeight; + } else { + if(screenWidth <= 0) screenWidth=maxWidth; + else screenWidth=min(screenWidth,maxWidth); + if(screenHeight <= 0) screenHeight=maxHeight; + else screenHeight=min(screenHeight,maxHeight); + + Width=min(fullWidth,screenWidth); + Height=min(fullHeight,screenHeight); + + if(Width > Height*Aspect) + Width=min((int) (ceil(Height*Aspect)),screenWidth); + else + Height=min((int) (ceil(Width/Aspect)),screenHeight); + } - if(Width > Height*Aspect) - Width=min((int) (ceil(Height*Aspect)),screenWidth); - else - Height=min((int) (ceil(Width/Aspect)),screenHeight); + home(webgl); + setProjection(); + + if(webgl) return; + + ArcballFactor=1+8.0*hypot(Margin.getx(),Margin.gety())/hypot(Width,Height); + +#ifdef HAVE_GL + for(int i=0; i < 16; ++i) + T[i]=t[i]; + remesh=true; Aspect=((double) Width)/Height; if(maxTileWidth <= 0) maxTileWidth=screenWidth; @@ -1552,8 +1630,10 @@ void glrender(const string& prefix, const picture *pic, const string& format, if(View && settings::verbose > 1) cout << "Rendering " << stripDir(prefix) << " as " << Width << "x" << Height << " image" << endl; +#endif } +#ifdef HAVE_GL bool havewindow=initialized && glthread && !offscreen; #ifdef HAVE_LIBGLUT @@ -1637,13 +1717,6 @@ void glrender(const string& prefix, const picture *pic, const string& format, #endif // HAVE_LIBGLUT initialized=true; - int result = glewInit(); - - if (result != GLEW_OK) { - cerr << "GLEW initialization error." << endl; - exit(-1); - } - GLint val; glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,&val); Maxmaterials=val/sizeof(Material); @@ -1651,7 +1724,19 @@ void glrender(const string& prefix, const picture *pic, const string& format, glGetIntegerv(GL_MAX_ELEMENTS_VERTICES,&Maxvertices); - home(); + if(glinitialize) { + glinitialize=false; + int result = glewInit(); + + if (result != GLEW_OK) { + cerr << "GLEW initialization error." << endl; + exit(-1); + } + + initshader(); + } + + glClearColor(Background[0],Background[1],Background[2],Background[3]); #ifdef HAVE_LIBGLUT if(!offscreen) { @@ -1666,8 +1751,6 @@ void glrender(const string& prefix, const picture *pic, const string& format, } #endif - initshader(); - glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); @@ -1684,7 +1767,7 @@ void glrender(const string& prefix, const picture *pic, const string& format, glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutDisplayFunc(display); - + glutMainLoop(); #endif // HAVE_LIBGLUT } else { @@ -1705,10 +1788,16 @@ void glrender(const string& prefix, const picture *pic, const string& format, quit(); } } + +#endif /* HAVE_GL */ } } // namespace gl +#endif + +#ifdef HAVE_GL + namespace camp { string getLightIndex(size_t const& index, string const& fieldName) { @@ -1717,63 +1806,205 @@ string getLightIndex(size_t const& index, string const& fieldName) { return Strdup(buf.str()); } +string getCenterIndex(size_t const& index) { + ostringstream buf; + buf << "Centers[" << index << "]"; + return Strdup(buf.str()); +} + void setUniforms(GLint shader) { if(gl::nlights > gl::Nlights || nmaterials > Nmaterials) { gl::deleteshader(); gl::initshader(); + gl::lastshader=-1; } - glUseProgram(shader); + bool normal=shader != pixelShader && shader != noNormalShader; + + if(shader != gl::lastshader) { + glUseProgram(shader); + gl::lastshader=shader; - glUniformMatrix4fv(glGetUniformLocation(shader,"projViewMat"),1,GL_FALSE, value_ptr(gl::projViewMat)); - glUniformMatrix4fv(glGetUniformLocation(shader,"viewMat"),1,GL_FALSE, value_ptr(gl::viewMat)); - glUniformMatrix4fv(glGetUniformLocation(shader,"normMat"),1,GL_FALSE, value_ptr(gl::normMat)); + glUniform1i(glGetUniformLocation(shader,"nlights"),gl::nlights); + + for(size_t i=0; i < gl::nlights; ++i) { + triple Lighti=gl::Lights[i]; + size_t i4=4*i; + glUniform3f(glGetUniformLocation(shader, + getLightIndex(i,"direction").c_str()), + (GLfloat) Lighti.getx(),(GLfloat) Lighti.gety(), + (GLfloat) Lighti.getz()); + + glUniform3f(glGetUniformLocation(shader, + getLightIndex(i,"color").c_str()), + (GLfloat) gl::Diffuse[i4],(GLfloat) gl::Diffuse[i4+1], + (GLfloat) gl::Diffuse[i4+2]); + } +#if HAVE_LIBOPENIMAGEIO + // textures + if (settings::getSetting<bool>("envmap")) { + glActiveTexture(GL_TEXTURE1); + glBindBuffer(GL_TEXTURE_2D, gl::envMapBuf); + glUniform1i(glGetUniformLocation(shader, "environmentMap"), 1); + glActiveTexture(GL_TEXTURE0); + } +#endif + } + GLuint binding=0; GLint blockindex=glGetUniformBlockIndex(shader,"MaterialBuffer"); glUniformBlockBinding(shader,blockindex,binding); - GLuint ubo; - glGenBuffers(1,&ubo); - glBindBuffer(GL_UNIFORM_BUFFER,ubo); + glGenBuffers(1,&gl::ubo); + glBindBuffer(GL_UNIFORM_BUFFER,gl::ubo); - glBufferData(GL_UNIFORM_BUFFER,drawElement::material.size()*sizeof(Material), - drawElement::material.data(),GL_STATIC_DRAW); - glBindBufferBase(GL_UNIFORM_BUFFER,binding,ubo); - - glUniform1i(glGetUniformLocation(shader,"nlights"),gl::nlights); - - for(size_t i=0; i < gl::nlights; ++i) { - triple Lighti=gl::Lights[i]; - size_t i4=4*i; - glUniform4f(glGetUniformLocation(shader, - getLightIndex(i,"direction").c_str()), - (GLfloat) Lighti.getx(),(GLfloat) Lighti.gety(), - (GLfloat) Lighti.getz(),0.0); - - glUniform4f(glGetUniformLocation(shader, - getLightIndex(i,"diffuse").c_str()), - (GLfloat) gl::Diffuse[i4],(GLfloat) gl::Diffuse[i4+1], - (GLfloat) gl::Diffuse[i4+2],(GLfloat) gl::Diffuse[i4+3]); - - glUniform4f(glGetUniformLocation(shader, - getLightIndex(i,"specular").c_str()), - (GLfloat) gl::Specular[i4],(GLfloat) gl::Specular[i4+1], - (GLfloat) gl::Specular[i4+2],(GLfloat) gl::Specular[i4+3]); - } + glBufferData(GL_UNIFORM_BUFFER,material.size()*sizeof(Material), + material.data(),GL_STATIC_DRAW); + glBindBufferBase(GL_UNIFORM_BUFFER,binding,gl::ubo); + + glUniformMatrix4fv(glGetUniformLocation(shader,"projViewMat"),1,GL_FALSE, value_ptr(gl::projViewMat)); + + glUniformMatrix4fv(glGetUniformLocation(shader,"viewMat"),1,GL_FALSE, value_ptr(gl::viewMat)); + + if(normal) + glUniformMatrix3fv(glGetUniformLocation(shader,"normMat"),1,GL_FALSE, value_ptr(gl::normMat)); +} -#if HAVE_LIBOPENIMAGEIO - // textures - if (settings::getSetting<bool>("envmap")) { - glActiveTexture(GL_TEXTURE1); - glBindBuffer(GL_TEXTURE_2D, gl::envMapBuf); - glUniform1i(glGetUniformLocation(shader, "environmentMap"), 1); - glActiveTexture(GL_TEXTURE0); +void deleteUniforms() +{ + glBindBuffer(GL_UNIFORM_BUFFER,0); + glDeleteBuffers(1,&gl::ubo); +} + +void drawBuffer(vertexBuffer& data, GLint shader) +{ + if(data.indices.empty()) return; + + bool pixel=shader == pixelShader; + bool normal=!pixel && (shader != noNormalShader); + bool color=shader == colorShader || shader == transparentShader; + + const size_t size=sizeof(GLfloat); + const size_t intsize=sizeof(GLint); + const size_t bytestride=color ? sizeof(VertexData) : + (normal ? sizeof(vertexData) : + (pixel ? sizeof(vertexData0) : sizeof(vertexData1))); + + GLuint vertsBufferIndex; + GLuint elemBufferIndex; + + GLuint vao; + + glGenVertexArrays(1,&vao); + glBindVertexArray(vao); + + glGenBuffers(1,&vertsBufferIndex); + glGenBuffers(1,&elemBufferIndex); + + if(color) registerBuffer(data.Vertices,vertsBufferIndex); + else if(normal) registerBuffer(data.vertices,vertsBufferIndex); + else if(pixel) registerBuffer(data.vertices0,vertsBufferIndex); + else registerBuffer(data.vertices1,vertsBufferIndex); + + registerBuffer(data.indices,elemBufferIndex); + + glBindBuffer(GL_ARRAY_BUFFER,vertsBufferIndex); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,elemBufferIndex); + + camp::setUniforms(shader); + + const GLint posAttrib=glGetAttribLocation(shader,"position"); + const GLint materialAttrib=glGetAttribLocation(shader,"material"); + GLint normalAttrib,colorAttrib,widthAttrib=0; + + glVertexAttribPointer(posAttrib,3,GL_FLOAT,GL_FALSE,bytestride,(void *) 0); + glEnableVertexAttribArray(posAttrib); + + if(normal) { + normalAttrib=glGetAttribLocation(shader,"normal"); + glVertexAttribPointer(normalAttrib,3,GL_FLOAT,GL_FALSE,bytestride, + (void *) (3*size)); + glEnableVertexAttribArray(normalAttrib); + } else if(pixel) { + widthAttrib=glGetAttribLocation(shader,"width"); + glVertexAttribPointer(widthAttrib,1,GL_FLOAT,GL_FALSE,bytestride, + (void *) (3*size)); + glEnableVertexAttribArray(widthAttrib); } -#endif + + glVertexAttribIPointer(materialAttrib,1,GL_INT,bytestride, + (void *) ((normal ? 6 : (pixel ? 4 : 3))*size)); + glEnableVertexAttribArray(materialAttrib); + + if(color) { + colorAttrib=glGetAttribLocation(shader,"color"); + glVertexAttribPointer(colorAttrib,4,GL_UNSIGNED_BYTE,GL_TRUE,bytestride, + (void *) (6*size+intsize)); + glEnableVertexAttribArray(colorAttrib); + } + + glFlush(); // Workaround broken MSWindows drivers for Intel GPU + glDrawElements(normal ? GL_TRIANGLES : (pixel ? GL_POINTS : GL_LINES), + data.indices.size(),GL_UNSIGNED_INT,(void *) 0); + + glDisableVertexAttribArray(posAttrib); + if(normal) + glDisableVertexAttribArray(normalAttrib); + if(pixel) + glDisableVertexAttribArray(widthAttrib); + glDisableVertexAttribArray(materialAttrib); + if(color) + glDisableVertexAttribArray(colorAttrib); + + deleteUniforms(); + + glBindBuffer(GL_ARRAY_BUFFER,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + + glBindVertexArray(0); + glDeleteVertexArrays(1,&vao); + + glDeleteBuffers(1,&vertsBufferIndex); + glDeleteBuffers(1,&elemBufferIndex); } +void drawBuffers() +{ + drawBuffer(material0Data,pixelShader); + drawBuffer(material1Data,noNormalShader); + drawBuffer(materialData,materialShader); + drawBuffer(colorData,colorShader); + drawBuffer(triangleData,transparentShader); + sortTriangles(); + + glDepthMask(GL_FALSE); // Enable transparency + drawBuffer(transparentData,transparentShader); + glDepthMask(GL_TRUE); // Disable transparency } -#endif +void clearBuffers() +{ + material0Data.clear(); + material1Data.clear(); + materialData.clear(); + colorData.clear(); + triangleData.clear(); + transparentData.clear(); +} + +void clearMaterialBuffer(bool draw) +{ + if(draw) + drawBuffers(); + material.clear(); + material.reserve(nmaterials); + materialMap.clear(); + materialIndex=0; +} + + +} + +#endif /* HAVE_GL */ |