#include #ifdef NEEDGLEE #include "GLee.h" #endif #include "openglcanvas.h" #include #include // for getcwd, getpwuid, getuid #include // for fstat, getpwuid, getuid #include // for fstat #include // for getpwuid (TODO: windows?) #include // for fopen, fclose, getc #include #ifdef WINDOWS #include #define GET_WORKDIR _getcwd #else // unistd was included above #define GET_WORKDIR getcwd #endif #define PROGNAME "pano_interface" #define VERT_SHADER_FILE "test_vertex_shader.vert" #define FRAG_SHADER_FILE "fragment_shader.frag" OpenGLCanvas::OpenGLCanvas(QWidget *parent) : QGLWidget(parent) { setFormat(QGL::DoubleBuffer | QGL::DepthBuffer); fov = 60.f; scale = 1.0f; center_lambda = 0.f; center_phi = 0.f; fov_scale_relation = "Square Root"; visualization = "Perspective"; 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<60.f) scale = 1.f; else if (fov>295.f) scale = 0.02f; else { if (fov_scale_relation == "Square Root") scale = sqrt((300.f-fov)/240.f); else if (fov_scale_relation == "Linear") scale = (300.f-fov)/240.f; else if (fov_scale_relation == "Square Power") scale = powf((300.f-fov)/240.f,2); else if (fov_scale_relation == "Cubic Power") scale = powf((300.f-fov)/240.f,3); else if (fov_scale_relation == "Logarithm") scale = log(exp(1.f) + (1.f-exp(1.f))*(fov-60.f)/240.f); } // scale = 0.3f; 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>=-3.14f && lambda<=3.14f) { center_lambda = lambda; updateGL(); } } void OpenGLCanvas::change_center_phi(double phi){ if (center_phi!=phi && phi>=-1.57f && phi<=1.57f) { center_phi = phi; updateGL(); } } void OpenGLCanvas::change_fov_scale_relation(QString name){ fov_scale_relation = name; if (fov<60.f) scale = 1.f; else if (fov>295.f) scale = 0.01f; else{ if (fov_scale_relation == "Square Root") scale = sqrt((300.f-fov)/240.f); else if (fov_scale_relation == "Linear") scale = (300.f-fov)/240.f; else if (fov_scale_relation == "Square Power") scale = powf((300.f-fov)/240.f,2); else if (fov_scale_relation == "Cubic Power") scale = powf((300.f-fov)/240.f,3); else if (fov_scale_relation == "Logarithm") scale = log(exp(1.f) + (1.f-exp(1.f))*(fov-60.f)/240.f); } 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. // TODO: windows void OpenGLCanvas::read_config_file(){ struct passwd *pw=getpwuid(getuid()); char *filepath=pw->pw_dir; strcat(filepath,"/.panorc"); shader_dir=(char*)malloc(512*sizeof(char)); shader_dir[0]='\0'; input_image_file=(char*)malloc(512*sizeof(char)); input_image_file[0]='\0'; struct stat testbuf; if(stat(filepath,&testbuf)){ fprintf(stderr,"~/.panorc does not exist\n"); }else{ FILE *rcfile=fopen(filepath,"r"); 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); } } fclose(rcfile); } } void OpenGLCanvas::load_image(const char *new_image){ const char * const progname=(char*)(PROGNAME); int textureSize=getTextureSize(progname,new_image); unsigned char * textureBytes=(unsigned char*)malloc(textureSize); int width,height; readTextureBytes(progname,new_image,textureBytes,&width,&height); 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, width,height,0,GL_RGB,GL_UNSIGNED_BYTE,textureBytes); } void OpenGLCanvas::change_input_image(){ load_image(QFileDialog::getOpenFileName(this,tr("Choose Panorama File")).toStdString().c_str()); 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); #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); 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")).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, -1.57f, 1.57f, -3.14f, 3.14f); //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; ih) 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(fn, O_RDONLY); count = lseek(f, 0, SEEK_END); // close(f); if (fn != NULL) { fp = fopen(fn,"rt"); 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); } } return content; } void OpenGLCanvas::setShaders() { char *vs,*fs; #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 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(); glAttachShader(p,v); glAttachShader(p,f); glLinkProgram(p); glUseProgram(p); } void OpenGLCanvas::paintGL(){ float fov_rads = (fov/180.f)*1.5708f; // // 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=="Perspective") vis_mode=1.0; else if (visualization=="3D Sphere") vis_mode=2.0; else if (visualization=="Equi-Rectangular") vis_mode=3.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)); // } // } }