Commit 57642e2b authored by Edward Vigmond's avatar Edward Vigmond
Browse files

Offscreen rendering works!!! There are two methds, one compiled as default...

Offscreen rendering works!!! There are two methds, one compiled as default using GLUT and another version using OSMesa available under mesalyzer is compiled explicity (make mesalyzer)
parent e551a0f7
......@@ -2,8 +2,8 @@ HOSTMACHINE := $(shell uname)
HDF5API_ROOT := ./hdf5api
FLTK_INC := $(shell fltk-config --use-gl --cxxflags)
FLTK_LD_FLAGS := $(shell fltk-config --use-images --use-gl --ldflags)
FLTK_INC := $(shell fltk-config --use-glut --use-gl --cxxflags)
FLTK_LD_FLAGS := $(shell fltk-config --use-images --use-glut --use-gl --ldflags)
COMMON_INC := -I. -O0 -g -DOBJ_CLASS -D_REENTRANT -MMD -DNOMINMAX -fopenmp
#HDF5=1
......@@ -18,7 +18,7 @@ endif
COMMON_LIBS = -lpng -lpthread -lm -lz $(LIB_HDF5)
LIBS = -L$(HDF5API_ROOT)/lib $(FLTK_LD_FLAGS) $(COMMON_LIBS)
LIBS = -L$(HDF5API_ROOT)/lib -lglut $(FLTK_LD_FLAGS) $(COMMON_LIBS)
LDFLAGS = -fopenmp
CXXFLAGS = -I$(HDF5API_ROOT)/src $(FLTK_INC) $(COMMON_INC)
......@@ -33,19 +33,31 @@ OBJS = $(FLTK_SOURCES:.fl=.o)\
$(patsubst %.c,%.o,$(wildcard *.c))\
$(patsubst %.C,%.o,$(wildcard *.C))
#the files in OS_files contain OSMESA dependent clauses
OS_files= main.o TBmeshWin.o
OS_OBJS=$(filter-out $(OS_files),$(OBJS)) $(OS_files:.o=_os.o)
all: meshalyzer
meshalyzer: $(LIB_CH5) $(FLTK_SOURCES:.fl=.cc) $(OBJS) $(LIB_CH5)
$(CXX) $(LDFLAGS) -o meshalyzer $(sort $(OBJS)) $(LIBS)
fltk-config --post meshalyzer
mesalyzer: $(LIB_CH5) $(FLTK_SOURCES:.fl=.cc) $(OS_OBJS) $(LIB_CH5)
$(CXX) $(LDFLAGS) -o mesalyzer $(sort $(OS_OBJS)) -lOSMesa $(LIBS)
fltk-config --post mesalyzer
ifdef HDF5
$(LIB_CH5):
cd hdf5api && make all
cd hdf5api && make all $(LIB_CH5) $(FLTK_SOURCES:.fl=.cc) $(OBJS) $(LIB_CH5)
endif
$(OS_files:.o=_os.o): %_os.o: %.cc
$(CXX) $(CXXFLAGS) $(CPP_FLAGS) -D OSMESA -c -o $@ $<
clean:
rm -rf $(FLTK_SOURCES:.fl=.h) $(FLTK_SOURCES:.fl=.cc) *.o *.d meshalyzer meshalyzer.app
rm -rf $(FLTK_SOURCES:.fl=.h) $(FLTK_SOURCES:.fl=.cc) *.o *.d meshalyzer mesalyzer meshalyzer.app
utils:
cd utils && make all
......
......@@ -15,9 +15,15 @@
#include <ch5/ch5.h>
#endif
//#define OSMESA
#ifdef OSMESA
#include <GL/osmesa.h>
#endif
#define HITBUFSIZE 10000
#define OPAQUE_LIMIT 0.95 //!< consider opaque if alpha level above this
#define MAX_SURFELE_REALTIME 400000 //!< max \#ele's to draw while moving
#define COUT_ERROR(A) if(gle==A)cout<<#A<<endl;
unsigned int TBmeshWin::MAX_MESSAGES_READ = 100;
......@@ -39,9 +45,15 @@ void write_frame( string fname, int w, int h, TBmeshWin *tbwm )
#ifdef ONSCREEN_DUMP
GLubyte* buffer = new GLubyte[4*w*h];
#else
static GLubyte* buffer;
static int oldw=-1, oldh;
static GLubyte* buffer;
static GLuint fb, color_rb, depth_rb;
#ifdef OSMESA
static OSMesaContext ctx;
#else
static GLuint fb, color_rb, depth_rb, textureId;
#endif
#endif
FILE *out = fopen( fname.c_str(), "w" );
......@@ -54,59 +66,77 @@ void write_frame( string fname, int w, int h, TBmeshWin *tbwm )
pngimg->colour_type( PNG_COLOR_TYPE_RGB );
#ifndef ONSCREEN_DUMP
if( oldw==-1 || oldw!=w || oldh!=h ) {
if( oldw != -1 ) {
if( oldw != -1 ) { // not first time, destroy old buffers/contexts
#ifdef OSMESA
OSMesaDestroyContext( ctx );
#else
delete[] buffer;
glDeleteRenderbuffersEXT(1, &color_rb);
glDeleteRenderbuffersEXT(1, &depth_rb);
glDeleteFramebuffersEXT(1, &fb);
#endif
}
oldw = w;
oldh = h;
#ifdef OSMESA
ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
buffer = new GLubyte[w*h*4];
if (!OSMesaMakeCurrent(ctx, buffer, GL_UNSIGNED_BYTE, w, h)) {
cout << "Failed OSMesaMakeCurrent" << endl;
exit(1);
}
#else
buffer = new GLubyte[w*h*4];
glGenFramebuffersEXT(1, &fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
glGenRenderbuffersEXT(1, &color_rb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, color_rb);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h );
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_RENDERBUFFER_EXT, color_rb);
glGenRenderbuffersEXT(1, &depth_rb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, w, h );
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, depth_rb);
GLenum gle=glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
COUT_ERROR(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
COUT_ERROR(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT);
COUT_ERROR(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
COUT_ERROR(GL_FRAMEBUFFER_UNSUPPORTED_EXT);
COUT_ERROR(GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT);
COUT_ERROR(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT);
COUT_ERROR(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT);
COUT_ERROR(GL_FRAMEBUFFER_UNDEFINED);
COUT_ERROR(GL_FRAMEBUFFER_UNSUPPORTED);
COUT_ERROR(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
if( gle!=GL_FRAMEBUFFER_COMPLETE ) {
cout << "aborting:" << gle << endl;
return;
}
#endif //OSMESA
}
#ifdef OSMESA
#else
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
GLenum gle=glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
if( gle==GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT )
cout << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT" << endl;
else if ( gle==GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT )
cout << "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS" << endl;
else if ( gle==GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT )
cout << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT" << endl;
else if( gle==GL_FRAMEBUFFER_UNSUPPORTED_EXT )
cout << "GL_FRAMEBUFFER_UNSUPPORTED" << endl;
else if( gle==GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT )
cout << "FRAMEBUFFER_INCOMPLETE_FORMATS_EXT" << endl;
else if( gle==GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT )
cout << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT" << endl;
else if( gle==GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT )
cout << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT" << endl;
if( gle!=GL_FRAMEBUFFER_COMPLETE ) {
cout << "aborting:" << gle << endl;
return;
}
#endif //OSMESA
tbwm->invalidate();
tbwm->draw();
#endif
#endif //ONSCREEN_DUMP
glReadBuffer(GL_BACK);
if( tbwm->transBgd() )
......@@ -120,9 +150,15 @@ void write_frame( string fname, int w, int h, TBmeshWin *tbwm )
#ifdef ONSCREEN_DUMP
delete[] buffer;
#else
#ifdef OSMESA
#else
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
#endif
#endif //OSMESA
#endif //ONSCREEN_DUMP
}
......@@ -2050,10 +2086,14 @@ TBmeshWin::signal_links( int dir )
* \param a new time index
*
* \pre a is a valid time index
* \return false if not a valid time index
*/
void
bool
TBmeshWin:: set_time(int a)
{
if( a > max_time() )
return false;
tm=a;
if (timeplotter!=NULL)timeplotter->highlight(tm);
contwin->tmslider->value(tm);
......@@ -2066,6 +2106,7 @@ TBmeshWin:: set_time(int a)
}
if( model->pt.num_tm() )
model->pt.time(tm);
return true;
}
......
......@@ -103,7 +103,8 @@ class TBmeshWin:public Fl_Gl_Tb_Window
void revdraworder( bool a ){ revDrawOrder=a; redraw(); }
void animate_delay(float a){ frame_delay = a; }
void animate_skip( int a, void * );
void set_time(int a);
bool set_time(int a);
int time(){return tm;}
void autocolour( bool a ){autocol = a;}
void lights( bool a ){lightson = a;redraw();}
friend void animate_cb( void *v );
......
#include <GLee.h>
//#include <GLee.h>
#include "trimesh.h"
#include "isosurf.h"
#include <string>
......@@ -10,14 +10,22 @@
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#ifdef USE_HDF5
#include <hdf5.h>
#include <ch5/ch5.h>
#endif
#ifndef OSMESA
#include <GL/glut.h>
#endif
static Controls *ctrl_ptr;
static Meshwin *win_ptr;
void write_frame( string fname, int w, int h, TBmeshWin *tbwm );
sem_t *meshProcSem; // global semaphore for temporal linking
sem_t *linkingProcSem; // global semaphore for process linking
......@@ -89,6 +97,64 @@ read_version_info( Fl_Text_Display *txt )
}
/** output a sequence of PNG images offscreen
*
* \param filename file or directory (numf>1) name
* \param f0 first frame number, -1->do not use it
* \param numf number of frames
* \param tbwm rendering window
* \param size image width/height
*/
void
os_png_seq( string filename, int f0, int numf, TBmeshWin *tbwm, int size )
{
#ifndef OSMESA
int argc = 1;
char *argv = strdup("-iconic");
glutInit(&argc, &argv);
glutInitWindowSize(1,1);
glutCreateWindow("Take it eaz");
#endif
tbwm->resize(0,0,size,size);
// determine first and last frame numbers
if( f0<0 )
f0 = tbwm->time();
int f1 = f0 + numf - 1;
// output the sequence into a directory
if( filename.length()>4 && (filename.substr(filename.length()-4)==".png") )
filename.erase(filename.length()-4);
if( numf>1 ) {
if( mkdir( filename.c_str(), 0744 )==-1 && errno!=EEXIST ) {
cerr << "Exiting: Cannot create directory "<<filename<<endl;
exit(1);
}
} else {
filename += ".png";
}
tbwm->transBgd(false);
while( f0<=f1 && tbwm->set_time( f0 ) ){
string fname = filename;
if( numf>1 ) {
char strnum[8];
sprintf( strnum, "/frame%05d.png", f0 );
fname += strnum;
}
write_frame( fname.c_str(), size, size, tbwm );
f0++;
}
if( f0<=f1 )
cerr << "Warning: "<< f1-f0+1 << " frames of " << numf << " requested not written" << endl;
exit(0);
}
/* find out where model is located
*
* \param fn specified file name
......@@ -203,7 +269,9 @@ print_usage(void)
cout << "--help|-h print this message" << endl;
cout << "--thrdRdr|-t force threaded data reading" << endl;
cout << "--groupID=GID|-gGID meshalyzer group" << endl;
cout << "--PNG=file|-pfile output as PNG to file and exit" << endl;
cout << "--PNGfile=file output PNGs and exit" << endl;
cout << "--frame=file first frame for PNG dump (-1=do not set)" << endl;
cout << "--numframe=num number of frames to output (default=1)" << endl;
exit(0);
}
......@@ -213,7 +281,10 @@ static struct option longopts[] = {
{ "no_elem" , no_argument, NULL, 'n' },
{ "help" , no_argument, NULL, 'h' },
{ "gpoupID" , 1 , NULL, 'g' },
{ "PNGdump" , 1 , NULL, 'p' },
{ "PNGfile" , 1 , NULL, 'P' },
{ "frame" , 1 , NULL, 'f' },
{ "numframe" , 1 , NULL, 'N' },
{ "size" , 1 , NULL, 's' },
{ "thrdRdr" , no_argument, NULL, 't' },
{ NULL , 0 , NULL, 0 }
};
......@@ -232,7 +303,10 @@ main( int argc, char *argv[] )
bool no_elems = false;
bool threadedReader = false;
char *PNGfile = NULL;
int pngsize = 512;
const char *grpID = "0";
int frame0 = -1,
numframe = 1;
int ch;
while( (ch=getopt_long(argc, argv, "inhg:", longopts, NULL)) != -1 )
......@@ -249,16 +323,28 @@ main( int argc, char *argv[] )
case 'h':
print_usage();
break;
case 'p':
case 'P':
PNGfile = strdup(optarg);
cerr << "Womp womp wommp : not working yet! " << endl;
break;
case 'N':
numframe = atoi(optarg);
break;
case 'f':
frame0 = atoi(optarg);
break;
case 't':
threadedReader = true;
break;
case 's':
pngsize = atoi(optarg);
break;
case '?':
cerr << "Unrecognized option --- bailing" << endl;
exit(1);
default:
break;
}
Controls control;
ctrl_ptr = &control;
......@@ -302,8 +388,8 @@ main( int argc, char *argv[] )
if( !stat( defstate.c_str(), &buf) )
control.restore_state( defstate.c_str() );
//if( !PNGfile )
win.winny->show();
if( !PNGfile )
win.winny->show();
win.trackballwin->forceThreadData( threadedReader );
// deal with command line files specified
......@@ -385,15 +471,9 @@ main( int argc, char *argv[] )
cerr << "Message Queue inter-process communication not possible"
<< endl;
void write_frame( string fname, int w, int h, TBmeshWin *tbwm );
if( PNGfile ) {
//Fl::wait();
GLeeInit();
GLeeForceLink("GL_EXT_framebuffer_object");
write_frame( PNGfile, 455, 455, win.trackballwin );
//write_frame( PNGfile, 455, 455, win.trackballwin );
exit(0);
}
// just output images, no interaction
if( PNGfile )
os_png_seq( PNGfile, frame0, numframe, win.trackballwin, pngsize );
Fl::run();
......
......@@ -491,11 +491,7 @@ vector data grid could only be read if it had 1 or 100 frames of data.
\section{Invocation}
The program is run by typing
\begin{verbatim}
meshalyzer [pts [vpts] [dat|tdat|igb] [mshz] [tri ...] [pts_t] [dynpt]]
\end{verbatim}
or
\begin{verbatim}
meshalyzer cg_in
meshalyzer [otps] [pts [vpts] [dat|tdat|igb] [mshz] [tri ...] [pts_t] [dynpt]]
\end{verbatim}
where the extensions of the required file types are given.
If no file is specified, a file input box will pop up.
......@@ -508,16 +504,22 @@ This only applies to the vertex file.
\subsection{Options}
\begin{description}
\item[--help$|$-h] Display the usage message
\item[--iconifycontrols$|$-i] iconify the control window on startup
\item[--groupID=GID$|$-gGID] Be part of this semaphore group for \meshal linking. See \S\ref{sec:link}.
\item[--noelem $|$ -n] Do not read in the element file. This will speed up reading in the model at the expense of
\item[--help] Display the usage message
\item[--iconifycontrols] iconify the control window on startup
\item[--groupID=GID] Be part of this semaphore group for \meshal linking. See \S\ref{sec:link}.
\item[--noelem] Do not read in the element file. This will speed up reading in the model at the expense of
not being able to put data on the cutting planes.
\item[--thrdRdr$|$-t] Force threaded data reading. Even if one has enough memory to read in all the data at
\item[--thrdRdr] Force threaded data reading. Even if one has enough memory to read in all the data at
once, it is probably just as fast to read it in on demand. Using this option will reduce start up time
and stop \meshal from using all the RAM..
and stop \meshal from using all the RAM.
\item[--PNGfile] Output file name for PNG files or output directory name for PNG sequences
\item[--frame] first frame for PNG output (-1=do not set)
\item[--numframe] number of frames to output to PNG images (default=1)
\end{description}
Note that only enough characters to uniquely identify the option need be used.
See the Offscreen Rendering section\ref{sec:offscreen} for a complete description of how to use PNG related options.
\subsection{Environment variables}
\meshal reads the following environment variables:
\begin{description}
......@@ -984,4 +986,45 @@ SIGUSR2 & go backwards by the frame increment \\ \hline
If you wish to have different masters controlling different groups of slaves, you need
to specify a groupID on the command line for each group. The default is ``0''.
\section{Offscreen Rendering}
\label{sec:offscreen}
Output PNG files may be written noninteractively. To do so, the \texttt{PNGfile} option must be specified.
If one output frame is specified by setting \texttt{numframes} to 1, then \texttt{PNGfile}
is the output file name with ``.png'' appended
automatically if it is not specified. For more than 1 frame, \texttt{PNGfile} is a directory name, which will be created if
necessary, and the output files will have the names \texttt{frameXXXXX.png} where XXXXX is the frame number padded on the
left with zeros, eg., frame 8 would be ``frame00008.png''. Directory names will have ``.png'' stripped if detected on
the end.
By default, the initial frame is not set, i.e., it will be that of a state file if one is read, or 0 if one is not
specified .
The simplest way to use offscreen rendering is to set up meshalyzer in a suitable state and then save it. The model,
data and state files are specified as normal on the command line and the additional PNG related options added.
A simple example might be something like
\begin{verbatim}
meshalyzer --PNGfile=movie --numfr=10 --frame=5 myopurk.
Vm.igb state.mshz
\end{verbatim}
which would produce 10 PNGs in the movie directory by putting the data in Vm.igb on the myopurk model and use the
setting in state.mshz.
There are two version of \meshal for offscreen rendering. There is no differences in running the code but it is a
question of environment and speed.
\subsection{OSMesa}
OSmesa (http://www.mesa3d.org/osmesa.html) is an offscreen rendering library which performs all of its operations in
software. This has the advantage that it can be used even if a window server is not running. This library must be
available on the system. However, since it does not take advantage of the graphics hardware, rendering is considerably
slower. This executable must be explicitly compiled by
\begin{verbatim}
make mesalyzer
\end{verbatim}
with the resultant executable called \texttt{mesalyzer}. It cannot be used to display a window on the screen.
\subsection{GLUT rendering}
The GLUT library (http://www.opengl.org/resources/libraries/glut/) can be used to create an OpenGL context which then
allows offscreen rendering to use the graphics card. This is compiled into the default version of \meshal. It renders
very quickly but only if a windowing system is available. A small window with no content will be created that is a
byproduct of establishing a connection with the windowing system.
\end{document}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment