summaryrefslogtreecommitdiff
path: root/graphics/asymptote/glrender.cc
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/asymptote/glrender.cc')
-rw-r--r--graphics/asymptote/glrender.cc281
1 files changed, 172 insertions, 109 deletions
diff --git a/graphics/asymptote/glrender.cc b/graphics/asymptote/glrender.cc
index e86df78c55..9e9fb70629 100644
--- a/graphics/asymptote/glrender.cc
+++ b/graphics/asymptote/glrender.cc
@@ -24,6 +24,7 @@
#include "bbox3.h"
#include "drawimage.h"
#include "interact.h"
+#include "fpu.h"
namespace gl {
#ifdef HAVE_PTHREAD
@@ -79,9 +80,6 @@ vertexBuffer triangleData;
const size_t Nbuffer=10000;
const size_t nbuffer=1000;
-
-GLuint attributeBuffer;
-GLuint indicesBuffer;
}
#endif /* HAVE_GL */
@@ -103,12 +101,15 @@ size_t Nmaterials=1;
size_t nmaterials=48;
}
+extern void exitHandler(int);
+
namespace gl {
bool outlinemode=false;
bool glthread=false;
+bool glupdate=false;
+bool glexit=false;
bool initialize=true;
-bool exporting=false;
using camp::picture;
using camp::drawRawImage;
@@ -123,7 +124,8 @@ using settings::Setting;
bool Iconify=false;
bool ignorezoom;
-int Fitscreen;
+int Fitscreen=1;
+bool firstFit;
bool queueExport=false;
bool readyAfterExport=false;
@@ -141,8 +143,6 @@ int fullWidth,fullHeight;
int Width,Height;
double oWidth,oHeight;
int screenWidth,screenHeight;
-int maxWidth;
-int maxHeight;
int maxTileWidth;
int maxTileHeight;
@@ -206,8 +206,6 @@ const double *dprojView;
const double *dView;
double BBT[9];
-GLuint ubo;
-
unsigned int framecount;
template<class T>
@@ -313,6 +311,7 @@ bool Animate;
bool Step;
#ifdef HAVE_GL
+
void idle()
{
glutIdleFunc(NULL);
@@ -325,10 +324,12 @@ void home(bool webgl=false)
X=Y=cx=cy=0.0;
#ifdef HAVE_GL
#ifdef HAVE_LIBGLUT
- if(!webgl && !getSetting<bool>("offscreen"))
+#ifndef HAVE_LIBOSMESA
+ if(!webgl)
idle();
#endif
#endif
+#endif
dviewMat=dmat4(1.0);
dView=value_ptr(dviewMat);
viewMat=mat4(dviewMat);
@@ -392,7 +393,7 @@ GLuint initHDR() {
return tex;
}
-#endif
+#endif
GLint shaderProg,shaderProgColor;
void *glrenderWrapper(void *a);
@@ -479,10 +480,6 @@ void deleteShaders()
void setBuffers()
{
- glGenBuffers(1,&camp::attributeBuffer);
- glGenBuffers(1,&camp::indicesBuffer);
- glGenBuffers(1,&ubo);
-
GLuint vao;
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
@@ -498,7 +495,7 @@ void drawscene(int Width, int Height)
{
#ifdef HAVE_PTHREAD
static bool first=true;
- if(glthread && first && !getSetting<bool>("offscreen")) {
+ if(glthread && first) {
wait(initSignal,initLock);
endwait(initSignal,initLock);
first=false;
@@ -561,17 +558,15 @@ void Export()
(orthographic ? trOrtho : trFrustum)(tr,xmin,xmax,ymin,ymax,-zmax,-zmin);
size_t count=0;
- exporting=true;
do {
trBeginTile(tr);
+ fpu_trap(false); // Work around FE_INVALID in OSMesa.
drawscene(fullWidth,fullHeight);
+ fpu_trap(settings::trap());
++count;
} while (trEndTile(tr));
- exporting=false;
-
if(settings::verbose > 1)
- cout << count << " tile" << (count != 1 ? "s" : "") << " drawn"
- << endl;
+ cout << count << " tile" << (count != 1 ? "s" : "") << " drawn" << endl;
trDelete(tr);
picture pic;
@@ -594,18 +589,19 @@ void Export()
outOfMemory();
}
setProjection();
- bool offscreen=getSetting<bool>("offscreen");
+
+#ifndef HAVE_LIBOSMESA
#ifdef HAVE_LIBGLUT
- if(!offscreen)
glutPostRedisplay();
#endif
#ifdef HAVE_PTHREAD
- if(glthread && readyAfterExport && !offscreen) {
+ if(glthread && readyAfterExport) {
readyAfterExport=false;
endwait(readySignal,readyLock);
}
#endif
+#endif
}
void nodisplay()
@@ -631,11 +627,9 @@ inline unsigned int floorpow2(unsigned int n)
void quit()
{
#ifdef HAVE_LIBOSMESA
- if(getSetting<bool>("offscreen")) {
if(osmesa_buffer) delete[] osmesa_buffer;
if(ctx) OSMesaDestroyContext(ctx);
exit(0);
- }
#endif
#ifdef HAVE_LIBGLUT
if(glthread) {
@@ -650,7 +644,7 @@ void quit()
glutDisplayFunc(nodisplay);
endwait(readySignal,readyLock);
}
-#endif
+#endif
if(interact::interactive)
glutHideWindow();
} else {
@@ -683,9 +677,10 @@ void mode()
break;
}
#ifdef HAVE_LIBGLUT
- if(!getSetting<bool>("offscreen"))
+#ifndef HAVE_LIBOSMESA
glutPostRedisplay();
#endif
+#endif
}
// GUI-related functions
@@ -693,12 +688,12 @@ void mode()
bool capsize(int& width, int& height)
{
bool resize=false;
- if(width > maxWidth) {
- width=maxWidth;
+ if(width > screenWidth) {
+ width=screenWidth;
resize=true;
}
- if(height > maxHeight) {
- height=maxHeight;
+ if(height > screenHeight) {
+ height=screenHeight;
resize=true;
}
return resize;
@@ -745,10 +740,30 @@ void setsize(int w, int h, bool reposition=true)
glutPostRedisplay();
}
+void capzoom()
+{
+ static double maxzoom=sqrt(DBL_MAX);
+ static double minzoom=1.0/maxzoom;
+ if(Zoom <= minzoom) Zoom=minzoom;
+ if(Zoom >= maxzoom) Zoom=maxzoom;
+
+ if(Zoom != lastzoom) remesh=true;
+ lastzoom=Zoom;
+}
+
void fullscreen(bool reposition=true)
{
Width=screenWidth;
Height=screenHeight;
+ if(firstFit) {
+ if(Width < Height*Aspect)
+ Zoom *= Width/(Height*Aspect);
+ capzoom();
+ setProjection();
+ firstFit=false;
+ }
+ Xfactor=((double) screenHeight)/Height;
+ Yfactor=((double) screenWidth)/Width;
reshape0(Width,Height);
if(reposition)
glutPositionWindow(0,0);
@@ -772,15 +787,15 @@ void fitscreen(bool reposition=true)
oldHeight=Height;
int w=screenWidth;
int h=screenHeight;
- if(w >= h*Aspect) w=(int) (h*Aspect+0.5);
- else h=(int) (w/Aspect+0.5);
+ if(w > h*Aspect)
+ w=min((int) ceil(h*Aspect),w);
+ else
+ h=min((int) ceil(w/Aspect),h);
setsize(w,h,reposition);
break;
}
case 2: // Full screen
{
- Xfactor=((double) screenHeight)/Height;
- Yfactor=((double) screenWidth)/Width;
fullscreen(reposition);
break;
}
@@ -816,7 +831,7 @@ void nextframe(int)
{
#ifdef HAVE_PTHREAD
endwait(readySignal,readyLock);
-#endif
+#endif
double framedelay=getSetting<double>("framedelay");
if(framedelay > 0)
usleep((unsigned int) (1000.0*framedelay+0.5));
@@ -901,12 +916,26 @@ void update()
void updateHandler(int)
{
queueScreen=true;
+ remesh=true;
update();
if(interact::interactive || !Animate) {
glutShowWindow();
}
}
+void poll(int)
+{
+ if(glupdate) {
+ updateHandler(0);
+ glupdate=false;
+ }
+ if(glexit) {
+ exitHandler(0);
+ glexit=false;
+ }
+ glutTimerFunc(100.0,poll,0);
+}
+
void animate()
{
Animate=!Animate;
@@ -959,17 +988,6 @@ void pan(int x, int y)
update();
}
-void capzoom()
-{
- static double maxzoom=sqrt(DBL_MAX);
- static double minzoom=1.0/maxzoom;
- if(Zoom <= minzoom) Zoom=minzoom;
- if(Zoom >= maxzoom) Zoom=maxzoom;
-
- if(Zoom != lastzoom) remesh=true;
- lastzoom=Zoom;
-}
-
void zoom(int x, int y)
{
if(ignorezoom) {ignorezoom=false; y0=y; return;}
@@ -1380,17 +1398,21 @@ void setosize()
void exportHandler(int=0)
{
#ifdef HAVE_LIBGLUT
- bool offscreen=getSetting<bool>("offscreen");
- if(!Iconify && !offscreen)
+#ifndef HAVE_LIBOSMESA
+ if(!Iconify)
glutShowWindow();
-#endif
+#endif
+#endif
readyAfterExport=true;
Export();
+
#ifdef HAVE_LIBGLUT
- if(!Iconify && !offscreen)
+#ifndef HAVE_LIBOSMESA
+ if(!Iconify)
glutHideWindow();
-#endif
glutDisplayFunc(nodisplay);
+#endif
+#endif
}
static bool glinitialize=true;
@@ -1456,7 +1478,7 @@ void init()
#ifndef __APPLE__
glutInitContextProfile(GLUT_CORE_PROFILE);
-#endif
+#endif
glutInit(&argc,argv);
screenWidth=glutGet(GLUT_SCREEN_WIDTH);
@@ -1563,25 +1585,28 @@ void glrender(const string& prefix, const picture *pic, const string& format,
#ifdef HAVE_GL
#ifdef HAVE_PTHREAD
static bool initializedView=false;
-#endif
+#endif
- bool offscreen=getSetting<bool>("offscreen");
- if(offscreen && !webgl) {
+#ifdef HAVE_LIBOSMESA
+ if(!webgl) {
screenWidth=maxTileWidth;
screenHeight=maxTileHeight;
static bool osmesa_initialized=false;
if(!osmesa_initialized) {
osmesa_initialized=true;
+ fpu_trap(false); // Work around FE_INVALID.
init_osmesa();
+ fpu_trap(settings::trap());
}
}
-
+#else
if(glinitialize) {
if(!webgl) init();
Fitscreen=1;
}
#endif
+#endif
static bool initialized=false;
@@ -1606,23 +1631,25 @@ void glrender(const string& prefix, const picture *pic, const string& format,
// Alternatively, one can use -glOptions=-indirect (with a performance
// penalty).
pair maxViewport=getSetting<pair>("maxviewport");
- maxWidth=(int) ceil(maxViewport.getx());
- maxHeight=(int) ceil(maxViewport.gety());
+ int maxWidth=maxViewport.getx() > 0 ? (int) ceil(maxViewport.getx()) :
+ screenWidth;
+ int maxHeight=maxViewport.gety() > 0 ? (int) ceil(maxViewport.gety()) :
+ screenHeight;
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);
+
fullWidth=(int) ceil(expand*width);
fullHeight=(int) ceil(expand*height);
-
+
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);
@@ -1642,7 +1669,6 @@ void glrender(const string& prefix, const picture *pic, const string& format,
for(int i=0; i < 16; ++i)
T[i]=t[i];
- remesh=true;
Aspect=((double) Width)/Height;
if(maxTileWidth <= 0) maxTileWidth=screenWidth;
@@ -1654,33 +1680,40 @@ 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
+#endif
}
#ifdef HAVE_GL
- bool havewindow=initialized && glthread && !offscreen;
+ bool havewindow=initialized && glthread;
+#ifndef HAVE_LIBOSMESA
#ifdef HAVE_LIBGLUT
unsigned int displaymode=GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH;
-#endif
+#endif
#ifdef __APPLE__
displaymode |= GLUT_3_2_CORE_PROFILE;
-#endif
+#endif
+#endif
camp::clearMaterialBuffer();
+#ifndef HAVE_LIBOSMESA
+
#ifdef HAVE_PTHREAD
- if(glthread && initializedView && !offscreen) {
- if(!View)
- readyAfterExport=queueExport=true;
+ if(glthread && initializedView) {
+ if(View) {
+#ifdef __MSDOS__ // Signals are unreliable in MSWindows
+ glupdate=true;
+#else
pthread_kill(mainthread,SIGUSR1);
+#endif
+ } else readyAfterExport=queueExport=true;
return;
}
-#endif
+#endif
#ifdef HAVE_LIBGLUT
- if(!offscreen) {
if(View) {
int x,y;
if(havewindow)
@@ -1702,8 +1735,8 @@ void glrender(const string& prefix, const picture *pic, const string& format,
while(true) {
if(multisample > 0)
glutSetOption(GLUT_MULTISAMPLE,multisample);
-#endif
-#endif
+#endif
+#endif
string title=string(settings::PROGRAM)+": "+prefix;
window=glutCreateWindow(title.c_str());
@@ -1724,8 +1757,8 @@ void glrender(const string& prefix, const picture *pic, const string& format,
}
break;
}
-#endif
-#endif
+#endif
+#endif
if(settings::verbose > 1 && samples > 1)
cout << "Multisampling enabled with sample width " << samples
<< endl;
@@ -1734,11 +1767,14 @@ void glrender(const string& prefix, const picture *pic, const string& format,
} else if(!havewindow) {
glutInitWindowSize(maxTileWidth,maxTileHeight);
glutInitDisplayMode(displaymode);
+ fpu_trap(false); // Work around FE_INVALID in Gallium
window=glutCreateWindow("");
+ fpu_trap(settings::trap());
glutHideWindow();
}
- }
#endif // HAVE_LIBGLUT
+#endif // HAVE_LIBOSMESA
+
initialized=true;
GLint val;
@@ -1762,17 +1798,18 @@ void glrender(const string& prefix, const picture *pic, const string& format,
glClearColor(Background[0],Background[1],Background[2],Background[3]);
#ifdef HAVE_LIBGLUT
- if(!offscreen) {
- Animate=getSetting<bool>("autoplay") && glthread;
-
- if(View) {
- if(!getSetting<bool>("fitscreen"))
- Fitscreen=0;
- fitscreen();
- setosize();
- }
+#ifndef HAVE_LIBOSMESA
+ Animate=getSetting<bool>("autoplay") && glthread;
+
+ if(View) {
+ if(!getSetting<bool>("fitscreen"))
+ Fitscreen=0;
+ firstFit=true;
+ fitscreen();
+ setosize();
}
#endif
+#endif
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
@@ -1781,25 +1818,34 @@ void glrender(const string& prefix, const picture *pic, const string& format,
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
mode();
- if(View && !offscreen) {
+#ifdef HAVE_LIBOSMESA
+ View=false;
+#endif
+
+ if(View) {
#ifdef HAVE_LIBGLUT
#ifdef HAVE_PTHREAD
initializedView=true;
-#endif
+#endif
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutDisplayFunc(display);
+#ifdef __MSDOS__
+ if(glthread && interact::interactive)
+ poll(0);
+#endif
+
glutMainLoop();
#endif // HAVE_LIBGLUT
} else {
- if(glthread && !offscreen) {
+ if(glthread) {
if(havewindow) {
readyAfterExport=true;
#ifdef HAVE_PTHREAD
pthread_kill(mainthread,SIGUSR1);
-#endif
+#endif
} else {
initialized=true;
readyAfterExport=true;
@@ -1836,16 +1882,21 @@ string getCenterIndex(size_t const& index) {
}
template<class T>
-void registerBuffer(const std::vector<T>& buffervector, GLuint bufferIndex,
- GLint type=GL_ARRAY_BUFFER) {
+void registerBuffer(const std::vector<T>& buffervector, GLuint& bufferIndex,
+ bool copy, GLenum type=GL_ARRAY_BUFFER) {
if(!buffervector.empty()) {
+ if(bufferIndex == 0) {
+ glGenBuffers(1,&bufferIndex);
+ copy=true;
+ }
glBindBuffer(type,bufferIndex);
- glBufferData(type,buffervector.size()*sizeof(T),
- buffervector.data(),GL_STATIC_DRAW);
+ if(copy)
+ glBufferData(type,buffervector.size()*sizeof(T),
+ buffervector.data(),GL_STATIC_DRAW);
}
}
-void setUniforms(const vertexBuffer& data, GLint shader)
+void setUniforms(vertexBuffer& data, GLint shader)
{
bool normal=shader != pixelShader;
@@ -1883,8 +1934,9 @@ void setUniforms(const vertexBuffer& data, GLint shader)
GLuint binding=0;
GLint blockindex=glGetUniformBlockIndex(shader,"MaterialBuffer");
glUniformBlockBinding(shader,blockindex,binding);
- registerBuffer(data.materials,gl::ubo,GL_UNIFORM_BUFFER);
- glBindBufferBase(GL_UNIFORM_BUFFER,binding,gl::ubo);
+ bool copy=gl::remesh || data.partial || !data.rendered;
+ registerBuffer(data.materials,data.materialsBuffer,copy,GL_UNIFORM_BUFFER);
+ glBindBufferBase(GL_UNIFORM_BUFFER,binding,data.materialsBuffer);
glUniformMatrix4fv(glGetUniformLocation(shader,"projViewMat"),1,GL_FALSE,
value_ptr(gl::projViewMat));
@@ -1908,17 +1960,17 @@ void drawBuffer(vertexBuffer& data, GLint shader)
const size_t bytestride=color ? sizeof(VertexData) :
(normal ? sizeof(vertexData) : sizeof(vertexData0));
- if(color) registerBuffer(data.Vertices,attributeBuffer);
- else if(normal) registerBuffer(data.vertices,attributeBuffer);
- else registerBuffer(data.vertices0,attributeBuffer);
+ bool copy=gl::remesh || data.partial || !data.rendered;
+ if(color) registerBuffer(data.Vertices,data.VerticesBuffer,copy);
+ else if(normal) registerBuffer(data.vertices,data.verticesBuffer,copy);
+ else registerBuffer(data.vertices0,data.vertices0Buffer,copy);
- registerBuffer(data.indices,indicesBuffer,GL_ELEMENT_ARRAY_BUFFER);
+ registerBuffer(data.indices,data.indicesBuffer,copy,GL_ELEMENT_ARRAY_BUFFER);
- glBindBuffer(GL_ARRAY_BUFFER,attributeBuffer);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,indicesBuffer);
-
camp::setUniforms(data,shader);
+ data.rendered=true;
+
glVertexAttribPointer(positionAttrib,3,GL_FLOAT,GL_FALSE,bytestride,
(void *) 0);
glEnableVertexAttribArray(positionAttrib);
@@ -1987,6 +2039,7 @@ void drawColor()
void drawTriangle()
{
drawBuffer(triangleData,transparentShader);
+ triangleData.rendered=false; // Force copying of sorted triangles to GPU.
triangleData.clear();
}
@@ -1995,6 +2048,7 @@ void drawTransparent()
sortTriangles();
glDepthMask(GL_FALSE); // Enable transparency
drawBuffer(transparentData,transparentShader);
+ transparentData.rendered=false; // Force copying of sorted triangles to GPU.
glDepthMask(GL_TRUE); // Disable transparency
transparentData.clear();
}
@@ -2015,14 +2069,23 @@ void clearMaterialBuffer()
material.reserve(nmaterials);
materialMap.clear();
materialIndex=0;
+
+ material0Data.partial=false;
+ material1Data.partial=false;
+ materialData.partial=false;
+ colorData.partial=false;
+ triangleData.partial=false;
+ transparentData.partial=false;
}
void setMaterial(vertexBuffer& data, draw_t *draw)
{
if(materialIndex >= data.materialTable.size() ||
data.materialTable[materialIndex] == -1) {
- if(data.materials.size() >= Maxmaterials)
+ if(data.materials.size() >= Maxmaterials) {
+ data.partial=true;
(*draw)();
+ }
size_t size0=data.materialTable.size();
data.materialTable.resize(materialIndex+1);
for(size_t i=size0; i < materialIndex; ++i)