#include #ifdef NEEDGLEE #include "GLee.h" #endif #include "openglcanvas.h" #include #include // for fstat, getpwuid, getuid #include // for fstat #ifdef _WIN32 #include // for getenv (TODO: use getenv_s) #else #include // for getpwuid #endif #include // for getc #include #include "files.h" #define VERT_SHADER_FILE "vertex_shader.vert" #define FRAG_SHADER_FILE "fragment_shader.frag" #define CONST_PI 3.141592653589793115997963468544185161590576171875 #define CONST_PI_2 1.5707963267948965579989817342720925807952880859375 #define CONST_PI_F 3.1415927410125732421875f #define CONST_PI_2_F 1.57079637050628662109375f //#define CONST_PI (0x1.921fb54442d18p+1) //#define CONST_PI_2 (0x1.921fb54442d18p+0) //#define CONST_PI_F (0x1.921fb6p+1f) //#define CONST_PI_2_F (0x1.921fb6p+0f) OpenGLCanvas::OpenGLCanvas(QWidget *parent) : QGLWidget(parent) { setFormat(QGL::DoubleBuffer | QGL::DepthBuffer); fov = 60.f; fov_max = 60.f; // TODO: I only use floats here because Leo did... check scale = 1.0f; center_lambda = 0.f; center_phi = 0.f; fov_scale_relation = "Naive"; visualization = "Moebius"; auto_fov_max=false; zblambda=.1f; // Zorin-Barr transformation lambda zbR=1.f; // Zorin-Barr transformation R time_frames = 0; time_timer.setInterval(0); connect(&time_timer, SIGNAL(timeout()), this, SLOT(slotTimer())); time_start = time_time.time(); } void OpenGLCanvas::slotTimer(void) { updateGL(); } void OpenGLCanvas::change_fov(double f){ if (fov!=f && f>=1.f && f<=360.f) fov=f; if (fov<=fov_max) scale=1.f; //else if (fov>295.f) // scale = 0.02f; // TODO: check this value wrt fov_max else { if (fov_scale_relation == "Naive") scale=fov_max/fov; else if (fov_scale_relation == "Square Root") scale=sqrt((360.f-fov_max-fov)/(360.-2*fov_max)); else if (fov_scale_relation == "Linear") scale=(360.f-fov_max-fov)/(360.-2*fov_max); else if (fov_scale_relation == "Square Power") scale=powf((360.f-fov_max-fov)/(360.-2*fov_max),2); else if (fov_scale_relation == "Cubic Power") scale=powf((360.f-fov_max-fov)/(360.-2*fov_max),3); else if (fov_scale_relation == "Logarithm") scale=log(exp(1.f)+(1.f-exp(1.f))*(fov-fov_max)/(360.-2*fov_max)); } // scale = 0.3f; fprintf(stderr,"change fov, fov=%f, fov_max=%f, scale=%f\n",fov,fov_max,scale); emit fov_changed((int)fov); updateGL(); } void OpenGLCanvas::automaxbutton(bool autovalue){ auto_fov_max=autovalue; change_fov_max(compute_auto_fov_max(fov)); } void OpenGLCanvas::change_fov(int new_fov){ if(new_fov<=360&&new_fov>=1){ change_fov((double)new_fov); if(auto_fov_max) change_fov_max(compute_auto_fov_max(new_fov)); } } void OpenGLCanvas::change_fov_max(int new_fov_max){ if(new_fov_max<=360&&new_fov_max>=1) fov_max=(double)new_fov_max; if (fov<=fov_max) scale=1.f; //else if (fov>295.f) // scale = 0.02f; // TODO: check this value wrt fov_max else { if (fov_scale_relation == "Naive") scale=fov_max/fov; else if (fov_scale_relation == "Square Root") scale=sqrt((360.f-fov_max-fov)/(360.-2*fov_max)); else if (fov_scale_relation == "Linear") scale=(360.f-fov_max-fov)/(360.-2*fov_max); else if (fov_scale_relation == "Square Power") scale=powf((360.f-fov_max-fov)/(360.-2*fov_max),2); else if (fov_scale_relation == "Cubic Power") scale=powf((360.f-fov_max-fov)/(360.-2*fov_max),3); else if (fov_scale_relation == "Logarithm") scale=log(exp(1.f)+(1.f-exp(1.f))*(fov-fov_max)/(360.-2*fov_max)); } fprintf(stderr,"change fov_max, fov=%f, fov_max=%f, new scale=%f\n",fov,fov_max,scale); emit max_fov_changed((int)fov_max); updateGL(); } //void OpenGLCanvas::change_scale(double s){ // if (scale!=s && s>=0.0 && s<=1.0) scale = s; // updateGL(); //} void OpenGLCanvas::change_center_lambda(double lambda){ if (center_lambda!=lambda && lambda>=-CONST_PI && lambda<=CONST_PI) { center_lambda = lambda; updateGL(); } } void OpenGLCanvas::change_center_phi(double phi){ if (center_phi!=phi && phi>=-CONST_PI_2 && phi<=CONST_PI_2) { center_phi = phi; updateGL(); } } void OpenGLCanvas::re_center(){ center_phi=.0f; center_lambda=.0f; updateGL(); } void OpenGLCanvas::change_fov_scale_relation(QString name){ fov_scale_relation = name; if (fov295.f) scale = 0.01f; else{ if (fov_scale_relation == "Naive") scale=fov_max/fov; else if (fov_scale_relation == "Square Root") scale=sqrt((360.f-fov_max-fov)/(360.-2*fov_max)); else if (fov_scale_relation == "Linear") scale=(360.f-fov_max-fov)/(360.-2*fov_max); else if (fov_scale_relation == "Square Power") scale=powf((360.f-fov_max-fov)/(360.-2*fov_max),2); else if (fov_scale_relation == "Cubic Power") scale=powf((360.f-fov_max-fov)/(360.-2*fov_max),3); else if (fov_scale_relation == "Logarithm") scale=log(exp(1.f)+(1.f-exp(1.f))*(fov-fov_max)/(360.-2*fov_max)); } fprintf(stderr,"changed scale relation, scale=%f, fov_max=%f\n",scale,fov_max); updateGL(); } void OpenGLCanvas::change_visualization(QString name){ visualization = name; updateGL(); } // This function reads the contents of the ~/.panorc file and stores the // options in private variables. void OpenGLCanvas::read_config_file(){ #ifdef _WIN32 char* envvar=(char*)malloc(12*sizeof(char)); strcpy(envvar,"USERPROFILE\0"); char *filepath=(char*)malloc(512*sizeof(char)); strcpy(filepath,getenv(envvar)); free(envvar); strcat(filepath,"\\.panorc"); #else struct passwd *pw=getpwuid(getuid()); char *filepath=pw->pw_dir; strcat(filepath,"/.panorc"); #endif shader_dir=(char*)malloc(512*sizeof(char)); shader_dir[0]='\0'; input_image_file=(char*)malloc(512*sizeof(char)); input_image_file[0]='\0'; input_image_dir=(char*)malloc(512*sizeof(char)); input_image_dir[0]='\0'; char *read_line=(char*)malloc(64*sizeof(char)); struct stat testbuf; if(stat(filepath,&testbuf)){ fprintf(stderr,"%s does not exist\n",filepath); }else{ FILE *rcfile; FOPEN_RO(rcfile,filepath); char c; char *line=(char*)malloc(512*sizeof(char)); while((c=getc(rcfile))!=EOF){ while(c=='\n') // discard empty lines c=getc(rcfile); if(c==EOF) break; line[0]=c; // first char on the line was already read if(!fgets(line+1,511,rcfile)){ fprintf(stderr,"error reading rcfile\n"); exit(-1); } // check for 'shader_dir' option if(!strncmp(line,"shader_dir=",11)){ strcpy(shader_dir,line+11); shader_dir[strlen(line)-12]='\0'; fprintf(stderr,"shader_dir=%s\n",shader_dir); } // check for 'image_file' option if(!strncmp(line,"image_file=",11)){ strcpy(input_image_file,line+11); input_image_file[strlen(line)-12]='\0'; fprintf(stderr,"input_image_file=%s\n",input_image_file); } // check for 'image_dir' option if(!strncmp(line,"image_dir=",10)){ strcpy(input_image_dir,line+10); input_image_dir[strlen(line)-11]='\0'; fprintf(stderr,"input_image_dir=%s\n",input_image_dir); } // check for 'max_fov' option if(!strncmp(line,"max_fov=",8)){ strcpy(read_line,line+8); read_line[strlen(line)-9]='\0'; fov_max=atof(read_line); fprintf(stderr,"max_fov=%f\n",fov_max); } // check for 'fov' option if(!strncmp(line,"fov=",4)){ strcpy(read_line,line+4); read_line[strlen(line)-5]='\0'; fov=atof(read_line); fprintf(stderr,"fov=%f\n",fov); } // check for 'auto_max_fov' option if(!strncmp(line,"auto_max_fov=",13)){ strcpy(read_line,line+13); read_line[strlen(line)-14]='\0'; auto_fov_max=atof(read_line); fprintf(stderr,"auto_max_fov=%d\n",auto_fov_max); } // check for the Zorin-Barr transformation parameters, lambda and R if(!strncmp(line,"zblambda=",9)){ strcpy(read_line,line+9); read_line[strlen(line)-10]='\0'; zblambda=atof(read_line); fprintf(stderr,"zblambda=%f\n",zblambda); } if(!strncmp(line,"zbR=",4)){ strcpy(read_line,line+4); read_line[strlen(line)-5]='\0'; zbR=atof(read_line); fprintf(stderr,"zbR=%f\n",zbR); } } fclose(rcfile); } #ifdef _WIN32 free(filepath); #endif emit fov_changed((int)fov); emit max_fov_changed((int)fov_max); } void OpenGLCanvas::load_image(const char *new_image){ unsigned char *textureBytes=read_image(new_image,&image_size_x,&image_size_y); glPixelStorei(GL_UNPACK_ALIGNMENT,1); GLuint tex; glGenTextures(1,&tex); glBindTexture(GL_TEXTURE_2D,tex); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image_size_x, image_size_y, 0, GL_RGB, GL_UNSIGNED_BYTE, textureBytes); } void OpenGLCanvas::change_input_image(){ const char *fname=QFileDialog::getOpenFileName(this,tr("Choose Panorama File"),input_image_dir,FileRead::image_types).toStdString().c_str(); if(strlen(fname)>0){ load_image(fname); updateGL(); } } void OpenGLCanvas::initializeGL(){ glShadeModel(GL_SMOOTH); glClearColor(1.0f,1.0f,1.0f,0.0f); glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); #ifndef _MSC_VER #ifdef __APPLE__ const char * const progname = "PROJ_ROOT_DIR"; #else // progname is a file name or a path??? const char * const progname = (char*)(PROGNAME); #endif fprintf(stderr,"progname=%s\n",progname); #endif // MSC_VER read_config_file(); // If the input file does not exist or was not specified. struct stat testbuf; if(stat(input_image_file,&testbuf)||!strcmp(input_image_file,"")){ load_image(QFileDialog::getOpenFileName(this,tr("Choose Panorama File"),input_image_dir,FileRead::image_types).toStdString().c_str()); }else{ load_image(input_image_file); } free(input_image_file); // mesh resolution int m,n; m = n = 100; //defining texture coordinates int meshNumTexCoord = m*n; float *texCoord = (float *)malloc(2*meshNumTexCoord*sizeof(float)); if (texCoord == NULL){ printf("problem allocating memory for texture coordinates \n"); } define_texture_coordinates(texCoord, m, n, -CONST_PI_2_F, CONST_PI_2_F, -CONST_PI_F, CONST_PI_F); //defining positions of the sphere vertices int meshNumVertices = m*n; float* positions = (float *)malloc(3*meshNumVertices*sizeof(float)); if (positions == NULL){ printf("problem allocating memory for positions \n"); } // vertex_transformation(positions, m, n, center_lambda, center_phi, fov_rads, scale); //passar pelo vertex shader load_sphere_mesh(positions, m, n); //colocar essa e funcoes para textura e triangulos no initializeGL //defining triagle indices unsigned int meshNumFaces = 2*(m-1)*(n-1); unsigned int meshNumIndices = 3*meshNumFaces; unsigned int * indices = (unsigned int *)malloc(meshNumIndices*sizeof(unsigned int)); define_triangle_indices(indices, m, n); // draw setup verticesPositions = positions; textureCoordinates = texCoord; numberOfIndices = meshNumIndices; triangleIndices = indices; setShaders(); } void OpenGLCanvas::define_texture_coordinates(float *texCoord, int m, int n, float min_phi, float max_phi, float min_lambda, float max_lambda){ float delta_lambda = (max_lambda-min_lambda)/(1.0*(n-1)); float delta_phi = (max_phi-min_phi)/(1.0*(m-1)); for (int i = 0; i179) return 1; //if(new_fov>60) return (90-new_fov/2); } void OpenGLCanvas::resizeGL(int w, int h){ if(w>h) glViewport(0,(h-w)/2,w,w); else glViewport((w-h)/2,0,h,h); } char * OpenGLCanvas::textFileRead(char *fn) { FILE *fp; char *content = NULL; int f, count; f = OPEN_FILE(fn, O_RDONLY); count = LSEEK_FD(f, 0, SEEK_END); // close(f); if (fn != NULL) { FOPEN_RO(fp,fn); if (fp != NULL) { if (count > 0) { content = (char *)malloc(sizeof(char) * (count+1)); count = fread(content,sizeof(char),count,fp); content[count] = '\0'; } fclose(fp); // maybe this line must be outside the {} } } return content; } void OpenGLCanvas::setShaders() { char *vs,*fs; #ifndef __APPLE__ #ifdef GLEW_VERSION_1_5 GLenum err=glewInit(); if(err!=GLEW_OK){ fprintf(stderr,"error in GLEW initialization: %s\n",glewGetString(err)); exit(-1); } #endif #endif GLuint v = glCreateShader(GL_VERTEX_SHADER); GLuint f = glCreateShader(GL_FRAGMENT_SHADER); // Configure vertex and fragment shader files. char *vs_file=(char*)malloc(512*sizeof(char*)); char *fs_file=(char*)malloc(512*sizeof(char*)); if(!strcmp(shader_dir,"")){ // if shader_dir was not configured if(!GET_WORKDIR(vs_file,512)||!GET_WORKDIR(fs_file,512)){ fprintf(stderr,"error reading shader files\n"); exit(-1); } strcat(vs_file,"/shaders/"); strcat(fs_file,"/shaders/"); }else{; strcpy(vs_file,shader_dir); strcat(vs_file,"/"); strcpy(fs_file,shader_dir); strcat(fs_file,"/"); } strcat(vs_file,VERT_SHADER_FILE); strcat(fs_file,FRAG_SHADER_FILE); fprintf(stderr,"vs_file=%s\nfs_file=%s\n",vs_file,fs_file); struct stat vs_testbuf,fs_testbuf; if(stat(vs_file,&vs_testbuf)||stat(fs_file,&fs_testbuf)){ fprintf(stderr,"a shader file does not exist!\n"); free(vs_file); free(fs_file); exit(-1); } vs=textFileRead(vs_file); fs=textFileRead(fs_file); const char * vv = vs; const char * ff = fs; glShaderSource(v, 1, &vv,NULL); glShaderSource(f, 1, &ff,NULL); free(vs);free(fs); free(vs_file);free(fs_file); glCompileShader(v); glCompileShader(f); GLuint p = glCreateProgram(); // Bind attributes zblambda and zbR to the vertex shader. Nvidia hardware // only leaves attributes 1 and 7 unreserved; attributes 8 to 15 are // reserved for textures. // TODO: we use attributes 14 and 15, which work for Nvidia; we need to // test with other hardware. #define ZBL_ATTR 14 #define ZBR_ATTR 15 glVertexAttrib1f(ZBL_ATTR,zblambda); glBindAttribLocation(p,ZBL_ATTR,"zblambda"); glVertexAttrib1f(ZBR_ATTR,zbR); glBindAttribLocation(p,ZBR_ATTR,"zbR"); glAttachShader(p,v); glAttachShader(p,f); glLinkProgram(p); glUseProgram(p); } void OpenGLCanvas::mousePressEvent(QMouseEvent *event){ lastPos=event->pos(); //fprintf(stderr,"mouse click\n"); } void OpenGLCanvas::mouseMoveEvent(QMouseEvent *event){ // scroll with the left button if(event->buttons()==Qt::LeftButton){ // compute the delta and move the image center_lambda+=(event->x()-lastPos.x())*CONST_PI_F/image_size_x; center_phi+=(event->y()-lastPos.y())*CONST_PI_F/image_size_y; lastPos=event->pos(); updateGL(); } } void OpenGLCanvas::wheelEvent(QWheelEvent *event){ if(event->orientation()==Qt::Vertical){ if(event->modifiers()==Qt::ShiftModifier){ change_fov_max(fov_max+((double)event->delta())/30); }else{ int new_fov=fov+event->delta()/30; change_fov((double)new_fov); if(auto_fov_max) change_fov_max(compute_auto_fov_max(new_fov)); } } } void OpenGLCanvas::paintGL(){ float fov_rads = (fov/360.)*CONST_PI; // // changing scale to generate the figures for the paper (remove it after) // scale = 0.8; // defining transformation parameters (that will be passed to the vertex shader) float extent = calculate_extent(fov_rads); float vis_mode=.0; if (visualization=="Moebius") vis_mode=1.0; else if (visualization=="3D Sphere") vis_mode=2.0; else if (visualization=="Equi-Rectangular") vis_mode=3.0; else if (visualization=="Stereographic") vis_mode=4.0; else if (visualization=="Mercator") vis_mode=5.0; else if (visualization=="Zorin-Barr") vis_mode=6.0; else if (visualization=="Orthographic") vis_mode=7.0; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 2.0/extent, 0.0, 2.0/scale, 0.0, -2.0/vis_mode); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glOrtho(0.0, 2.0/center_lambda, 0.0, 2.0/center_phi, -1.0, 1.0); // drawing the mesh glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor3f(1, 0, 0); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, verticesPositions); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, textureCoordinates); glDrawElements(GL_TRIANGLES, numberOfIndices, GL_UNSIGNED_INT, triangleIndices); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); time_frames++; // if (time_frames > 0) { double dt = time_time.elapsed(); // if (dt > 0.5) { time_fps = time_frames/dt; time_frames = 0; time_time.reset(); emit fps(QString("%1 fps").arg((int)(time_fps+0.5))); //printf("fps = %d ", (int)(time_fps+0.5)); // } // } }