Jump to content
  • Advertisement
Sign in to follow this  
Cakemeister

Confused with shader + multitexture + offscreen rendering

This topic is 3977 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I've got a working program which does the multitexturing + shader program part. I'm having trouble with the offscreen rendering part. Here is the working program. I used Glee, Glut, and Glaux. I know glaux is deprecated. :)

#include <stdio.h>
#include <stdlib.h>
#include "glee.h"
#include <GL/glut.h>
#include <GL/glaux.h>

#define ESC 27

GLuint bg_texture;
GLuint object_texture;
GLuint mask_texture;
GLint bg_texture_loc;
GLint obj_texture_loc;
GLint mask_texture_loc;
GLhandleARB shader_program=0;

void compile_shader(void);
int LoadGLTextures(void);

struct vertex
{
   float tx, ty;
   float x,y,z;
};

struct vertex vertex_array[]=
{
   { 0,0,    -1,-1,0 },
   { 1,0,     1,-1,0 },
   { 1,1,     1, 1,0 },
   { 0,1,    -1, 1,0 }
};

void compile_shader(void)
{
   GLhandleARB g_vertexShader;
   GLhandleARB g_fragmentShader;
   GLint bVertCompiled;
   GLint bFragCompiled;
   GLint bLinked;
   char str[4096];

   const char *vertexShaderAssembly[]=
   {
      "void main(void)\n",
      "{\n",
      "   gl_Position=ftransform();\n",
      "   gl_TexCoord[0]=gl_MultiTexCoord0;\n",
      "   gl_TexCoord[1]=gl_MultiTexCoord1;\n",
      "   gl_TexCoord[2]=gl_MultiTexCoord2;\n",
      "}\n"
   };

   const char *fragmentShaderAssembly[]=
   {
      "uniform sampler2D bgTexture;\n",
      "uniform sampler2D objTexture;\n",
      "uniform sampler2D maskTexture;\n",
      "void main(void)\n",
      "{\n",
      "   vec3 bg_value=texture2D(bgTexture, gl_TexCoord[0].xy).rgb;\n",
      "   vec3 obj_value=texture2D(objTexture, gl_TexCoord[0].xy).rgb;\n",
      "   vec3 mask_value=texture2D(maskTexture, gl_TexCoord[0].xy).rgb;\n",
      "   gl_FragColor.r=((bg_value.r-obj_value.r)*mask_value.r)+obj_value.r;\n",
      "   gl_FragColor.g=((bg_value.g-obj_value.g)*mask_value.g)+obj_value.g;\n",
      "   gl_FragColor.b=((bg_value.b-obj_value.b)*mask_value.b)+obj_value.b;\n",
      "   gl_FragColor.a=255.0;\n",
      "}\n"
   };

   // create the vertex shader
   glShaderSourceARB( g_vertexShader, 7, vertexShaderAssembly, NULL );
   glCompileShaderARB( g_vertexShader);
   glGetObjectParameterivARB( g_vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, 
                               &bVertCompiled );
   if (bVertCompiled  == false )
   {
      glGetInfoLogARB(g_vertexShader, sizeof(str), NULL, str);
      MessageBox( NULL, str, "Vertex Shader Compile Error", MB_OK|MB_ICONEXCLAMATION );
   }

   // Create the fragment shader...
   g_fragmentShader = glCreateShaderObjectARB( GL_FRAGMENT_SHADER_ARB );
   glShaderSourceARB( g_fragmentShader, 13, fragmentShaderAssembly, NULL );
   glCompileShaderARB( g_fragmentShader );
   glGetObjectParameterivARB( g_fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, 
                               &bFragCompiled );
   if( bFragCompiled == false )
   {
      glGetInfoLogARB( g_fragmentShader, sizeof(str), NULL, str );
      MessageBox( NULL, str, "Fragment Shader Compile Error", MB_OK|MB_ICONEXCLAMATION );
   }

   // Create a program object and attach the two compiled shaders...
   shader_program = glCreateProgramObjectARB();
   glAttachObjectARB( shader_program, g_vertexShader );
   glAttachObjectARB( shader_program, g_fragmentShader );

   // Link the program object and print out the info log...
   glLinkProgramARB( shader_program );
   glGetObjectParameterivARB( shader_program, GL_OBJECT_LINK_STATUS_ARB, &bLinked );

   if( bLinked == false )
   {
      glGetInfoLogARB( shader_program, sizeof(str), NULL, str );
      MessageBox( NULL, str, "Linking Error", MB_OK|MB_ICONEXCLAMATION );
   }
}

// load the background, object, and mask images into textures
int LoadGLTextures()
{
   FILE *fp;                                                                                                // Load Bitmaps And Convert To Textures
   bool status=true;                                                                                               // Status Indicator
   AUX_RGBImageRec *bmp_image;

   // since glaux puts up a message box, we check for file exists via fopen

   // load image 1
   fp=fopen("Data/multitex_image1.bmp","rb");
   if (fp!=NULL)
   {
      fclose(fp);
      bmp_image=auxDIBImageLoad("Data\\multitex_image1.bmp");
      if (bmp_image==NULL)
      {
         status=false;
         printf("bg image failed to load\n");
      }
      else
      {
         glGenTextures(1, &bg_texture);                                                                      // Create Three Textures

         // Create Nearest Filtered Texture
         glBindTexture(GL_TEXTURE_2D, bg_texture);
         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
         glTexImage2D(GL_TEXTURE_2D, 0, 3,
            bmp_image->sizeX, bmp_image->sizeY,
            0, GL_RGB, GL_UNSIGNED_BYTE, bmp_image->data);
         free(bmp_image->data);
         free(bmp_image);
      }
   }
   else
   {
      printf("bg image doesn't exist\n");
      status=false;
   }

   // load image 2
   fp=fopen("Data\\multitex_image2.bmp","rb");
   if (fp!=NULL)
   {
      fclose(fp);
      bmp_image=auxDIBImageLoad("Data\\multitex_image2.bmp");
      if (bmp_image==NULL)
      {
         status=false;
      }
      else
      {
         glGenTextures(1, &object_texture);                                                                      // Create Three Textures

         // Create Nearest Filtered Texture
         glBindTexture(GL_TEXTURE_2D, object_texture);
         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
         glTexImage2D(GL_TEXTURE_2D, 0, 3,
            bmp_image->sizeX, bmp_image->sizeY,
            0, GL_RGB, GL_UNSIGNED_BYTE, bmp_image->data);
         free(bmp_image->data);
         free(bmp_image);
      }
   }
   else
   {
      status=false;
   }

   // load mask
   fp=fopen("Data\\multitex_mask.bmp","rb");
   if (fp!=NULL)
   {
      fclose(fp);
      bmp_image=auxDIBImageLoad("Data\\multitex_mask.bmp");
      if (bmp_image==NULL)
      {
         status=false;
      }
      else
      {
         glGenTextures(1, &mask_texture);                                                                      // Create Three Textures

         // Create Nearest Filtered Texture
         glBindTexture(GL_TEXTURE_2D, mask_texture);
         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
         glTexImage2D(GL_TEXTURE_2D, 0, 3,
            bmp_image->sizeX, bmp_image->sizeY,
            0, GL_RGB, GL_UNSIGNED_BYTE, bmp_image->data);
      }
   }
   else
   {
      status=false;
   }
   return status;                                                                                  // Return The Status
}

// Window resize function
void reshape(int width, int height)
{
   if (height==0)                                                                                  // Prevent A Divide By Zero By
      height=1;                                                                                       // Making Height Equal One

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(45.0, (float)width/(float)height, 1.0f, 100.0f);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}

// Function that handles keyboard inputs
void keyboard(unsigned char key, int x, int y)
{
   switch (key)
   {
      case ESC:
         exit(0);
   }
}

void display(void)
{
   GLenum errcode;
   GLint mask_loc;
   GLint object_loc;
   GLuint myFBO;
   GLuint offscreen_texture;

   // clear screen
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glTranslatef(0,0,-4);

   // turn on the shader program
   glUseProgramObjectARB(shader_program);

   // tell the shader that the bg texture is texture unit 0
   bg_texture_loc=glGetUniformLocationARB(shader_program,"bgTexture");
   glUniform1iARB(bg_texture_loc,0);

   // tell the shader that the obj texture is texture unit 1
   obj_texture_loc=glGetUniformLocationARB(shader_program,"objTexture");
   glUniform1iARB(obj_texture_loc,1);

   // tell the shader that the mask texture is texture unit 2
   mask_texture_loc=glGetUniformLocationARB(shader_program,"maskTexture");
   glUniform1iARB(mask_texture_loc,2);

   // set up the three multitexturing units
   glActiveTextureARB(GL_TEXTURE0_ARB);
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, bg_texture);

   glActiveTextureARB(GL_TEXTURE1_ARB);
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, object_texture);

   glActiveTextureARB(GL_TEXTURE2_ARB);
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, mask_texture);

   // draw that bad boy
   glInterleavedArrays(GL_T2F_V3F,0,vertex_array);
   glDrawArrays(GL_QUADS, 0, 4);

   glFlush();
   glutSwapBuffers();
}

int main(int argc, char** argv)
{
   glutInit(&argc, argv);

   glutInitWindowSize(256,256);
   glutInitWindowPosition(100,100);
   glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);

   glutCreateWindow("Multitexturing Test");

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glClearColor(0,0,0,1);

   glEnable(GL_DEPTH_TEST);
   glDepthMask(TRUE);
   glEnable(GL_TEXTURE_2D);

   // load the images
   if (!LoadGLTextures())
   {
      printf("Failed to load textures!\n");
      exit(1);
   }

   compile_shader();

   // run the program
   glutReshapeFunc(reshape);
   glutDisplayFunc(display);
   glutKeyboardFunc(keyboard);
   glutMainLoop();
   return 0;
}


I added code in the display() function before turning on the shader program:

   GLuint myFBO;
   GLuint offscreen_texture;

   // create the offscreen texture and allocate memory for it
   glGenTextures(1,&offscreen_texture);
   glBindTexture(GL_TEXTURE_2D, offscreen_texture);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
      256,256,
      0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

   // bind the fbo and attach the offscreen texture to it
   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, myFBO);
   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
      GL_TEXTURE_2D, offscreen_texture, 0);

   // set the viewport to not overflow the edges of the offscreen texture
   glViewport(0,0,256,256);

   // clear the offscreen texture
   glClearColor(0,0,0,1);
   glClear(GL_COLOR_BUFFER_BIT);


And I added code to display the offscreen buffer, after rendering to it:

   // turn off the shader program
   glUseProgramObjectARB(0);

   // unbind the frame buffer
   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);

   // restore the viewport and clear the screen
   glViewport(0,0,256,256);
   glClear(GL_COLOR_BUFFER_BIT);

   // finally, draw the offscreen texture to the screen
   glBindTexture(GL_TEXTURE_2D, offscreen_texture);
   glInterleavedArrays(GL_T2F_V3F,0,vertex_array);
   glDrawArrays(GL_QUADS, 0, 4);

Some questions: 1) Does my shader or fragment programs need to change between the on-screen version and the off-screen version? 2) Am I missing a call to glDrawBuffer? Where should it go? Thanks, Cakemeister

Share this post


Link to post
Share on other sites
Advertisement
After much effort, I have written a program which combines multitexturing, shader programs, and an external framebuffer to achieve the desired effect. Hopefully someone can search and find this example.



#include <wchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "glee.h"
#include <GL/glut.h>
#include <GL/glaux.h>
#include "tga.h"
#include "glsl.h"
#include "glutwindow.h"
#include "glApplication.h"

#define ESC 27

struct
{
GLuint bg_texture;
GLuint object_texture;
GLuint mask_texture;
} globals;

GLuint g_FBO=0;
GLhandleARB g_shader_program=0;
GLint current_viewport[4];

bool compile_shader(void);
void print_log(GLhandleARB obj);
bool opengl_error_occurred(const char *);
bool load_textures(void);
bool create_fbo(void);
void destroy_fbo(void);
void draw_masked_texture(GLuint texture, float start_x, float start_y, float size_x, float size_y, float rot, GLuint mask);
void draw_texture(GLuint texture, float start_x, float start_y, float size_x, float size_y, float rot);
void draw_texture_via_fbo(GLuint texture, float start_x, float start_y, float size_x, float size_y, float rot);
GLuint create_blank_texture(float size_x, float size_y, GLenum);
void save_viewport(void);
void restore_viewport(void);

void save_viewport(void)
{
// save the current viewport
glGetIntegerv(GL_VIEWPORT,current_viewport);
}

void restore_viewport(void)
{
glViewport(current_viewport[0], current_viewport[1],
current_viewport[2], current_viewport[3]);
}

struct vertex
{
float tx, ty;
float x,y,z;
};

struct texvertex
{
float tx, ty;
};

struct triple
{
float x,y,z;
};

#if 0
struct vertex vertex_array_half[]=
{
{ 0,0, -.5,-.5,-1 },
{ 1,0, .5,-.5,-1},
{ 1,1, .5, .5,-1 },
{ 0,1, -.5, .5,-1 }
};

struct vertex vertex_array_one[]=
{
{ 0,0, -1,-1,-1 },
{ 1,0, 1,-1,-1},
{ 1,1, 1, 1,-1 },
{ 0,1, -1, 1,-1 }
};

#else
struct texvertex texture_array[]=
{
{ 0, 0 },
{ 1, 0 },
{ 1, 1 },
{ 0, 1 }
};

struct vertex combined_array_half[]=
{
{ 0,0, 64,64,0 },
{ 1,0, 192,64,0},
{ 1,1, 192, 192,0},
{ 0,1, 64, 192,0 }
};

struct vertex combined_array_one[]=
{
{ 0,0, 0 ,0,0 },
{ 1,0, 256,0,0},
{ 1,1, 256, 256,0 },
{ 0,1, 0, 256,0 }
};

struct triple vertex_array_half[]=
{
{ 64, 64, 0 },
{ 192, 64, 0 },
{ 192, 192, 0 },
{ 64, 192, 0}
};

struct triple vertex_array_one[]=
{
{ 0, 0, 0 },
{ 256, 0, 0 },
{ 256, 256, 0},
{ 0, 256, 0}
};


#endif

GLuint create_blank_texture(float size_x, float size_y, GLenum data_type)
{
GLuint new_texture;
int tex_size_x=1, tex_size_y=1;

// The size_x and size_y need to be a power of 2
while (tex_size_x<(int)size_x)
tex_size_x<<=1;
while (tex_size_y<(int)size_y)
tex_size_y<<=1;

glGenTextures(1,&new_texture);
glBindTexture(GL_TEXTURE_2D, new_texture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);

glTexImage2D(GL_TEXTURE_2D, 0, data_type,
tex_size_x, tex_size_y,
0, data_type, GL_UNSIGNED_BYTE, NULL);

return new_texture;
}

void draw_masked_texture(GLuint object_texture, float start_x, float start_y,
float size_x, float size_y, float rot, GLuint mask_texture)
{
GLuint bg_texture;
GLuint offscreen_texture;
GLint bg_texture_loc;
GLint obj_texture_loc;
GLint mask_texture_loc;
GLfloat texture_vertex_array[20];

// Create two textures, one will hold the background image we
// read from the screen and we will draw into the other one.
offscreen_texture=create_blank_texture(size_x,size_y,GL_RGB);
bg_texture=create_blank_texture(size_x,size_y,GL_RGB);

// get the background into a temporary texture
glBindTexture(GL_TEXTURE_2D, bg_texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
0, 0, // texel offset
(int)start_x, (int)start_y, // window coordinates of lower left corner
(int)size_x, (int)size_y);

// clear the screen
//glClearColor(1,0,1,1); // magenta
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// draw the extracted bg image
//draw_texture(bg_texture, start_x,start_y, size_x,size_y, rot);
//goto cleanup;

// turn on the fbo
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,g_FBO);

// attach the offscreen texture to the fbo
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, offscreen_texture, 0);

// check for completeness
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)!=
GL_FRAMEBUFFER_COMPLETE_EXT)
{
printf("frame buffer is not complete\n");
goto cleanup;
}

if (opengl_error_occurred("after completeness check"))
goto cleanup;

// turn on the shader program
glUseProgramObjectARB(g_shader_program);

// tell the shader that the bg texture is texture unit 0
bg_texture_loc=glGetUniformLocationARB(g_shader_program,"bgTexture");
if (bg_texture_loc==(-1))
{
printf("failed to get location of shader program variable\n");
}
else
{
glUniform1iARB(bg_texture_loc,0);
}

// tell the shader that the obj texture is texture unit 1
obj_texture_loc=glGetUniformLocationARB(g_shader_program,"objTexture");
if (obj_texture_loc==(-1))
{
printf("failed to get location of shader program variable\n");
}
else
{
glUniform1iARB(obj_texture_loc,1);
}

// tell the shader that the mask texture is texture unit 2
mask_texture_loc=glGetUniformLocationARB(g_shader_program,"maskTexture");
if (mask_texture_loc==(-1))
{
printf("failed to get location of shader program variable\n");
}
else
{
glUniform1iARB(mask_texture_loc,2);
}

// clear the offscreen texture to blue
//glClearColor(0,0,1,1);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//
//if (opengl_error_occurred("after glClear"))
// goto cleanup;

// set up the three multitexturing units
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, bg_texture);

glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, object_texture);

glActiveTextureARB(GL_TEXTURE2_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mask_texture);

if (opengl_error_occurred("after glBindTexture"))
goto cleanup;

// set up a combined texture and vertex array to draw into
// the offscreen buffer.
texture_vertex_array[0]=0.0f;
texture_vertex_array[1]=0.0f;
texture_vertex_array[2]=0.0f;
texture_vertex_array[3]=0.0f;
texture_vertex_array[4]=0.0f;

texture_vertex_array[5]=1.0f;
texture_vertex_array[6]=0.0f;
texture_vertex_array[7]=size_x;
texture_vertex_array[8]=0.0f;
texture_vertex_array[9]=0.0f;

texture_vertex_array[10]=1.0f;
texture_vertex_array[11]=1.0f;
texture_vertex_array[12]=size_x;
texture_vertex_array[13]=size_y;
texture_vertex_array[14]=0.0f;

texture_vertex_array[15]=0.0f;
texture_vertex_array[16]=1.0f;
texture_vertex_array[17]=0.0f;
texture_vertex_array[18]=size_y;
texture_vertex_array[19]=0.0f;

// draw to the offscreen buffer
// draw with vbo
glClientActiveTexture(GL_TEXTURE0_ARB);
glInterleavedArrays(GL_T2F_V3F,0,texture_vertex_array);
glClientActiveTexture(GL_TEXTURE1_ARB);
glInterleavedArrays(GL_T2F_V3F,0,texture_vertex_array);
glClientActiveTexture(GL_TEXTURE2_ARB);
glInterleavedArrays(GL_T2F_V3F,0,texture_vertex_array);
glDrawArrays(GL_QUADS, 0, 4);

if (opengl_error_occurred("befere unbinding the frame buffer"))
goto cleanup;

// turn off the shader progam
glUseProgramObjectARB(0);

// disable the multitexturing units
glActiveTextureARB(GL_TEXTURE0_ARB);
glDisable(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE2_ARB);
glDisable(GL_TEXTURE_2D);

// unbind the frame buffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);

// clear the screen
//glClearColor(0,1,1,1); // cyan
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// finally, draw the offscreen texture to the screen
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, offscreen_texture);
draw_texture(offscreen_texture, start_x,start_y, size_x,size_y, 0);

cleanup:
if (bg_texture!=0)
glDeleteTextures(1,&bg_texture);
if (offscreen_texture!=0)
glDeleteTextures(1,&offscreen_texture);
}

// draw single texture to offscreen texture and then to screen
void draw_texture_via_fbo(GLuint texture, float start_x, float start_y,
float size_x, float size_y, float rot)
{
GLuint offscreen_texture=0;

// create the offscreen texture
offscreen_texture=create_blank_texture(size_x, size_y, GL_RGB);

// bind the FBO
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,g_FBO);

// attach the offscreen texture to the fbo
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, offscreen_texture, 0);

// check for completeness
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)!=
GL_FRAMEBUFFER_COMPLETE_EXT)
{
printf("frame buffer is not complete\n");
goto cleanup;
}

if (opengl_error_occurred("after completeness check"))
goto cleanup;

// draw the texture to the fbo
draw_texture(texture, 0, 0, size_x, size_y, 0);

// unbind the fbo and draw things to screen as normal
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);

// clear the screen
//glClearColor(0,1,0,1); // green
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// draw the offscreen texture
draw_texture(offscreen_texture, start_x, start_y, size_x, size_y, rot);

cleanup:
if (offscreen_texture!=0)
glDeleteTextures(1,&offscreen_texture);

}

void draw_texture(GLuint texture, float start_x, float start_y,
float size_x, float size_y, float rot)
{
GLfloat texture_coord_array[8];
GLfloat vertex_coord_array[12];
float sx, sy;
float ex, ey;
float tx, ty;

tx=size_x/2.0;
ty=size_y/2.0;
sx=-tx;
sy=-ty;
ex=tx;
ey=ty;

texture_coord_array[0]=0.0;
texture_coord_array[1]=0.0;
texture_coord_array[2]=0.0;
texture_coord_array[3]=1.0;
texture_coord_array[4]=1.0;
texture_coord_array[5]=1.0;
texture_coord_array[6]=1.0;
texture_coord_array[7]=0.0;

glTexCoordPointer(2,GL_FLOAT, 0, texture_coord_array);

vertex_coord_array[0]=sx;
vertex_coord_array[1]=sy;
vertex_coord_array[2]=0.0f;
vertex_coord_array[3]=sx;
vertex_coord_array[4]=ey;
vertex_coord_array[5]=0.0f;
vertex_coord_array[6]=ex;
vertex_coord_array[7]=ey;
vertex_coord_array[8]=0.0f;
vertex_coord_array[9]=ex;
vertex_coord_array[10]=sy;
vertex_coord_array[11]=0.0f;

glVertexPointer(3,GL_FLOAT,0,vertex_coord_array);

// Translate so that 0,0 is at the center of the quad. Save the existing
// matrix and restore it after drawing so that the next draw will be
// in the right place.

glPushMatrix();
glTranslatef(start_x+tx, start_y+ty, 0.0);
glRotatef(rot, 0.0f, 0.0f, 1.0f); // around the z axis
glBindTexture(GL_TEXTURE_2D, texture);
glDrawArrays(GL_QUADS,0,4);
glPopMatrix();

opengl_error_occurred("at end of draw_texture");
}

bool compile_shader(void)
{
GLhandleARB vertex_shader;
GLhandleARB fragment_shader;
GLint bVertCompiled;
GLint bFragCompiled;
GLint bLinked;
char str[4096];

const char *vertexShaderAssembly[]=
{
"void main(void)\n",
"{\n",
" gl_TexCoord[0]=gl_MultiTexCoord0;\n",
" gl_TexCoord[1]=gl_MultiTexCoord1;\n",
" gl_TexCoord[2]=gl_MultiTexCoord2;\n",
" gl_Position=gl_ModelViewProjectionMatrix * gl_Vertex;\n",
"}\n"
};

const char *fragmentShaderAssembly[]=
{
"uniform sampler2D bgTexture;\n",
"uniform sampler2D objTexture;\n",
"uniform sampler2D maskTexture;\n",
"void main(void)\n",
"{\n",
" vec3 bg_value=texture2D(bgTexture, vec2(gl_TexCoord[0])).rgb;\n",
" vec3 obj_value=texture2D(objTexture, vec2(gl_TexCoord[1])).rgb;\n",
" vec3 mask_value=texture2D(maskTexture, vec2(gl_TexCoord[2])).rgb;\n",
" gl_FragColor.r=((bg_value.r-obj_value.r)*mask_value.r)+obj_value.r;\n",
" gl_FragColor.g=((bg_value.g-obj_value.g)*mask_value.g)+obj_value.g;\n",
" gl_FragColor.b=((bg_value.b-obj_value.b)*mask_value.b)+obj_value.b;\n",
" gl_FragColor.a=mask_value.r;\n",
"}\n"
};

// create vertex shader
vertex_shader = glCreateShaderObjectARB( GL_VERTEX_SHADER_ARB );

// compile it, abort if error
glShaderSourceARB( vertex_shader, 7, vertexShaderAssembly, NULL );
glCompileShaderARB( vertex_shader);
glGetObjectParameterivARB( vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB,
&bVertCompiled );
if (bVertCompiled == false )
{
glGetInfoLogARB(vertex_shader, sizeof(str), NULL, str);
MessageBox( NULL, str, "Vertex Shader Compile Error", MB_OK|MB_ICONEXCLAMATION );
return false;
}

// create the fragment shader
fragment_shader = glCreateShaderObjectARB( GL_FRAGMENT_SHADER_ARB );

// compile it, abort if error
glShaderSourceARB( fragment_shader, 13, fragmentShaderAssembly, NULL );
glCompileShaderARB( fragment_shader );
glGetObjectParameterivARB( fragment_shader, GL_OBJECT_COMPILE_STATUS_ARB,
&bFragCompiled );
if( bFragCompiled == false )
{
glGetInfoLogARB( fragment_shader, sizeof(str), NULL, str );
MessageBox( NULL, str, "Fragment Shader Compile Error", MB_OK|MB_ICONEXCLAMATION );
return false;
}

// Create a program object and attach the two compiled shaders...
g_shader_program = glCreateProgramObjectARB();
glAttachObjectARB( g_shader_program, vertex_shader );
glAttachObjectARB( g_shader_program, fragment_shader );

// link the program object, abort if error
glLinkProgramARB( g_shader_program );
glGetObjectParameterivARB( g_shader_program, GL_OBJECT_LINK_STATUS_ARB, &bLinked );
if (bLinked == false)
{
glGetInfoLogARB( g_shader_program, sizeof(str), NULL, str );
MessageBox( NULL, str, "Linking Error", MB_OK|MB_ICONEXCLAMATION );
return false;
}
return true;
}

bool load_textures()
{
FILE *fp; bool status=true; AUX_RGBImageRec *bmp_image;

// since glaux puts up a message box, we check for file exists via fopen

// load image 1
fp=fopen("Data\\multitex_image1.bmp","rb");
if (fp!=NULL)
{
fclose(fp);
bmp_image=auxDIBImageLoad("Data\\multitex_image1.bmp");
if (bmp_image==NULL)
{
status=false;
printf("bg image failed to load\n");
}
else
{
glGenTextures(1, &globals.bg_texture); // Create Three Textures

// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, globals.bg_texture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3,
bmp_image->sizeX, bmp_image->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, bmp_image->data);

free(bmp_image->data);
free(bmp_image);
}
}
else
{
printf("bg image doesn't exist\n");
status=false;
}

// load image 2
fp=fopen("Data\\multitex_image2.bmp","rb");
if (fp!=NULL)
{
fclose(fp);
bmp_image=auxDIBImageLoad("Data\\multitex_image2.bmp");
if (bmp_image==NULL)
{
status=false;
}
else
{
glGenTextures(1, &globals.object_texture); // Create Three Textures

// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, globals.object_texture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3,
bmp_image->sizeX, bmp_image->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, bmp_image->data);
free(bmp_image->data);
free(bmp_image);
}
}
else
{
status=false;
}

// load mask
fp=fopen("Data\\multitex_circlemask.bmp","rb");
if (fp!=NULL)
{
fclose(fp);
bmp_image=auxDIBImageLoad("Data\\multitex_circlemask.bmp");
if (bmp_image==NULL)
{
status=false;
}
else
{
glGenTextures(1, &globals.mask_texture); // Create Three Textures

// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, globals.mask_texture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
bmp_image->sizeX, bmp_image->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, bmp_image->data);

free(bmp_image->data);
free(bmp_image);
}
}
else
{
status=false;
}

return status; // Return The Status
}

// window resize function
void reshape(int width, int height)
{
if(height==0) // Prevent A Divide By Zero By
height=1; // Making Height Equal One

// Setup our screen so that vertex coordinates equal screen coordinates.
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,width,0,height,-2000,256);
glTranslatef(0.375, 0.375, 0.0);

glMatrixMode(GL_MODELVIEW);
glClearColor(0,0,0,1);

glutPostRedisplay();
}

// keyboard handling function
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case ESC:
exit(0);
}
}

// drawing function
void display(void)
{
GLenum errcode;
GLint bg_texture_loc;
GLint obj_texture_loc;
GLint mask_texture_loc;
GLuint offscreen_texture=0;
GLuint temp_texture=0;

// clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// draw masked object on background with function
draw_texture(globals.bg_texture, 256,128, 256,256, 0);
draw_masked_texture(globals.object_texture, 256,128, 256,256, 0,
globals.mask_texture);

glFlush();
glutSwapBuffers();
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);

glutInitWindowSize(640,480);
glutInitWindowPosition(50,50);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);

glutCreateWindow("Multitexturing Test");

glEnable(GL_DEPTH_TEST);
glDepthMask(TRUE);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

// for initialization only, the reshape function will overwrite these
glViewport(0, 0, 256, 256);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,256,0,256,-2000,256);

if (opengl_error_occurred("before loading textures"))
{
exit(1);
}

// load the images
if (!load_textures())
{
printf("Failed to load textures!\n");
exit(1);
}

if (!create_fbo())
{
printf("Failed to create FBO!\n");
exit(1);
}

if (opengl_error_occurred("after loading textures"))
{
exit(1);
}

if (!compile_shader())
{
printf("Shader compile failed\n");
exit(1);
}

// run the program
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
//glutSpecialFunc(special);
//glutIdleFunc(idle);
glutMainLoop();

destroy_fbo();
return 0;

}

bool opengl_error_occurred(const char *msg)
{
GLenum errcode;
errcode=glGetError();
while (errcode!=GL_NO_ERROR)
{
printf("OpenGL error %s: %s\n",msg,gluErrorString(errcode));
errcode=glGetError();
}
return false;
}

bool create_fbo(void)
{
// create and init the frame buffer object
glGenFramebuffersEXT(1,&g_FBO);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_FBO);

// allow drawing straight to the screen
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);

return true;
}

void destroy_fbo(void)
{
// delete the fbo
if (g_FBO!=0)
glDeleteFramebuffersEXT(1,&g_FBO);
}




Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!