I need to have an image as output of my code (dimension: 3507x3281) composed by two triangles (upper-left corner and lower-right corner), each triangle will give me one different color/image on my output.
I read both images and bound them with 2 textures (texture_1 and texture_2).
Afterwards I created both triangles related to their respective image.
I created and bound the Framebuffer Object and attached the textures. Finally, I saved the content to a image file (.ppm).
PROBLEM:
My result (output image) is coherent and geometrically correct. However, only part of my output image is visible. The part that it is visible has 1366x768 as dimension, which is exactely my screen resolution. Am I missing something on the code?
Is there anything related to the options "GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER and GL_FRAMEBUFFER"? Only "GL_DRAW_FRAMEBUFFER" gives the coherent result.
Am I really using the Framebuffer? Because, I read that since you use the FBO this kind of problem does not appear.
CODE:
#include <windows.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cstdio>
#include <string>
/// Definitions
#define checkImageWidth 500 /// for image - texture 1
#define checkImageHeight 500
#define width 2464 /// for image - texture 2
#define height 1648
static GLuint texture_1, texture_2;
static GLubyte checkImage[checkImageHeight][checkImageWidth][3];
GLuint fb = 1; ///Frame-buffer Object
/// Headers
GLuint raw_texture_load();
void FBO_2_PPM_file(int output_width, int output_height);
/// Functions
GLuint raw_texture_load()
{
/// image used for texture 1
unsigned char *data;
FILE *file;
// open texture data
file = fopen("C:\\Dataset\\image_1.raw", "rb");
if (file == NULL) return 0;
// allocate buffer
data = (unsigned char*) malloc(width * height * 3);
// read texture data
fread(data, width * height * 3, 1, file);
fclose(file);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/// Texture 1
// allocate a texture name
glGenTextures(1, &texture_1);
// select our current texture
glBindTexture(GL_TEXTURE_2D, texture_1);
// select modulate to mix texture with color for shading
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_DECAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_DECAL);
// when texture area is small, bilinear filter the closest mipmap
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// when texture area is large, bilinear filter the first mipmap
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// texture should tile
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// build our texture mipmaps
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
// free buffer
free(data);
/// image used for texture 2
FILE *image_4tx2;
if( (image_4tx2 = fopen("C:\\dataset\\image2.ppm","r")) == NULL )
{
printf("\n Problem with input for texture 2\n");
system("pause");
exit(1);
}
int i, j, max_ND, n_col, n_lin, Red, G, B;
char s1[20];
/// Read header
fscanf(image_4tx2,"%s",&s1);
fscanf(image_4tx2,"%s %s %s %s",&s1, &s1, &s1, &s1);
fscanf(image_4tx2,"%d %d",&n_col, &n_lin);
fscanf(image_4tx2,"%d",&max_ND);
for (i = 0; i < checkImageWidth; i++)
{
for (j = 0; j < checkImageHeight; j++)
{
fscanf(image_4tx2,"%d %d %d ",&Red, &G, &B);
checkImage[i][j][0] = (GLubyte) Red;
checkImage[i][j][1] = (GLubyte) G;
checkImage[i][j][2] = (GLubyte) B;
}
}
fclose(image_4tx2);
/// Texture 2
glGenTextures(2, &texture_2);
glBindTexture(GL_TEXTURE_2D, texture_2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, checkImageWidth, checkImageHeight,
0, GL_RGB, GL_UNSIGNED_BYTE, checkImage);
return texture_1;
}
void render()
{
GLdouble COORD_1[3], COORD_2[3], COORD_3[3], COORD[3];
/// Output image size
double col_siz_double = 3507.0;
double row_siz_double = 3281.0;
int col_siz_output_image = 3507;
int row_siz_output_image = 3281;
/// Aspect ratio
double ratio_col_row = col_siz_double/row_siz_double;
double aspect_E, aspect_N;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(ratio_col_row>=0.0)
{
aspect_E = 1.0;
aspect_N = 1.0/ratio_col_row;
glOrtho(0.0, 1.0*aspect_E, 0.0, 1.0*aspect_N, 0.0, 1.0);
}
else
{
aspect_E = 1.0/ratio_col_row;
aspect_N = 1.0;
glOrtho(0.0, 1.0*aspect_E, 0.0, 1.0*aspect_N, 0.0, 1.0);
}
gluLookAt( 0.0, 0.0, 1.0, /* eye */
0.0, 0.0, 0.0, /* center */
0, 1, 0); /* up */
/// Viewport
glViewport(0,0,col_siz_output_image,row_siz_output_image);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
/// Triangle 1 (upper-left half of the output)
glBindTexture(GL_TEXTURE_2D, texture_1);
glBegin(GL_TRIANGLES);
glTexCoord2d(0.0, 0.0);
COORD[0]= 0.0*aspect_E;
COORD[1]= 0.0*aspect_N;
COORD[2]= 1.0;
glVertex3d(COORD[0], COORD[1], COORD[2]);
glTexCoord2d(1.0, 1.0);
COORD[0]= 1.0*aspect_E;
COORD[1]= 1.0*aspect_N;
COORD[2]= 1.0;
glVertex3d(COORD[0], COORD[1], COORD[2]);
glTexCoord2d(0.0, 1.0);
COORD[0]= 0.0*aspect_E;
COORD[1]= 1.0*aspect_N;
COORD[2]= 1.0;
glVertex3d(COORD[0], COORD[1], COORD[2]);
glEnd();
/// Triangle 2 (low-right half of the output)
glBindTexture(GL_TEXTURE_2D, texture_2);
glBegin(GL_TRIANGLES);
glTexCoord2d(0.0, 0.0);
COORD[0]= 0.0*aspect_E;
COORD[1]= 0.0*aspect_N;
COORD[2]= 1.0;
glVertex3d(COORD[0], COORD[1], COORD[2]);
glTexCoord2d(1.0, 1.0);
COORD[0]= 1.0*aspect_E;
COORD[1]= 1.0*aspect_N;
COORD[2]= 1.0;
glVertex3d(COORD[0], COORD[1], COORD[2]);
glTexCoord2d(1.0, 0.0);
COORD[0]= 1.0*aspect_E;
COORD[1]= 0.0*aspect_N;
COORD[2]= 1.0;
glVertex3d(COORD[0], COORD[1], COORD[2]);
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
static const GLenum draw_buffers[] =
{
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1
};
/// Generating and Biding the Framebuffer Object (FBO)
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb);
///Attaching both 2D texture to the FBO as color attachments
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, draw_buffers[0], GL_TEXTURE_2D, texture_2, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, draw_buffers[1], GL_TEXTURE_2D, texture_1, 0);
/// Specifying a list of color buffers to be drawn into
glDrawBuffers(2, draw_buffers);
/// Checking the FBO status
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if( status != GL_FRAMEBUFFER_COMPLETE)
{
printf("\n\nFramebuffer status: %s\n\n",status);
system("pause");
}
/// Saving the results from the FBO (fb) to a PPM image file
FBO_2_PPM_file(col_siz_output_image,row_siz_output_image);
}
void init()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
texture_1 = raw_texture_load();
render();
}
void FBO_2_PPM_file(int output_width, int output_height)
{
FILE *output_image;
/// READ THE PIXELS VALUES from FBO AND SAVE TO A .PPM FILE
int i, j, k;
unsigned char *pixels = (unsigned char*)malloc(output_width*output_height*4);
/// READ THE CONTENT FROM THE FBO
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT1);
glReadPixels(0, 0, output_width, output_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
output_image = fopen("C:\\Dataset\\output.ppm", "wt");
if(output_image == NULL)
{
printf("Problem # output file!\n\n");
system("pause");
}
fprintf(output_image,"P3\n");
fprintf(output_image,"# Created by Ricao\n");
fprintf(output_image,"%d %d\n",output_width,output_height);
fprintf(output_image,"255\n");
k = 0;
for(i=output_height-1; i>-1; i--)
{
for(j=0; j<output_width; j++)
{
k = (i*output_width)+j;
/// saving only RGB
fprintf(output_image,"%u %u %u ",(unsigned int)pixels[4*k],(unsigned int)pixels[(4*k)+1],
(unsigned int)pixels[(4*k)+2]);
}
fprintf(output_image,"\n");
}
free(pixels);
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(3507, 3281);
glutCreateWindow("Do not close this window!");
glutHideWindow();
/// Checking GLEW library
glewExperimental=TRUE;
GLenum err=glewInit();
if(err!=GLEW_OK)
{
printf("glewInit failed, aborting.");
printf("\tError: %s\n\n",glewGetErrorString(err));
system("pause");
}
if (GLEW_EXT_framebuffer_object != GL_TRUE)
{
printf("\n\n\t ** Error! GLEW_EXT_framebuffer_object != GL_TRUE \n\n");
system("pause");
}
/// To check the max size of the Framebuffer
int dims[2];
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &dims[0]);
///Executing the rendering process
init();
return 0;
Related
I am trying the texture mapping feature of OpenGL and the texture is displayed on the screen but not on the area that I set.
The area is a quad with 100.0 length and the texture is displayed only on the bottom.
When using GL_RGB in glTexImage2D, only one third of the quad is filled and when I change it to GL_RGBA, it becomes one quarter of the quad.
Main parameters declaration:
BYTE* m_pBMPBuffer;
int m_iWidth;
int m_iHeight;
GLuint m_uiTexture;
Code for setting up the texture mapping:
void CTextureMappingView::InitializeTexture()
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &m_uiTexture);
glBindTexture(GL_TEXTURE_2D, m_uiTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
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, GL_RGB, m_iWidth, m_iHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, m_pBMPBuffer);
}
Buffer Initialization:
m_iWidth = 64;
m_iHeight = 64;
m_pBMPBuffer = new BYTE[m_iWidth * m_iHeight * 3];
for (int i = 0 ; i < m_iWidth * m_iHeight ; i += 3)
{
m_pBMPBuffer[i] = 255;
m_pBMPBuffer[i + 1] = 0;
m_pBMPBuffer[i + 2] = 0;
}
Rendering:
void CTextureMappingView::RenderScene()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(XAngle, 1.0f, 0.0f, 0.0f);
glRotatef(YAngle, 0.0f, 1.0f, 0.0f);
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBindTexture(GL_TEXTURE_2D, m_uiTexture);
glBegin(GL_POLYGON);
glTexCoord2d(0.0, 0.0);
glVertex3d(0.0, 0.0, 0.0);
glTexCoord2d(0.0, 1.0);
glVertex3d(0.0, 100.0, 0.0);
glTexCoord2d(1.0, 1.0);
glVertex3d(100.0, 100.0, 0.0);
glTexCoord2d(1.0, 0.0);
glVertex3d(100.0, 0.0, 0.0);
glEnd();
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
Current result:
You only initialize a third of your texture:
for (int i = 0 ; i < m_iWidth * m_iHeight ; i += 3)
You should go up to m_iWidth * m_iHeight * 3 since that's what you allocated.
I have been trying draw a hut (as a cylinder with a cone on top) and add a brick txture to the wall and a roof-tile texture to the roof. However, I am only getting the first texture that I load (the bricks).
Here is my code (Please note that I have tried to switch between textures using glActiveTexture):
void drawCylinder()
{
int width, height;
unsigned char * data_for_wall = SOIL_load_image("./bricks.jpg", &width, &height, NULL, 0);
glDisable(GL_LIGHTING);
glGenTextures( 2, textures );
glActiveTexture(GL_TEXTURE0);
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Generate mipmaps, by the way.
glGenerateMipmap(GL_TEXTURE_2D);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, width, height, GL_RGB, GL_UNSIGNED_BYTE, data_for_wall);
for(float theta = 0.0; theta <= 360.0; theta += 10.0 )
{
//colors[k] = color4(0.69, 0.35, 0.0, 1.0); //This color is brown.
tex_coords[global_index]=vec2(theta*DegreesToRadians, 0.0);
float x = 0.15*sin(theta*DegreesToRadians);
float y = 0.15*cos(theta*DegreesToRadians);
points[global_index] = Translate(0.6, 0.0, 0.35)*point4(x, 0.0, y, 1.0);
// This is the
// bottom of the cylinder. The points are plotted in a full circle. The first three numbers are the x,y and z values
// respectively. The last number (ie. 1.0) is not important - it just converts to homogeneous coordinates.
++global_index;
tex_coords[global_index] = vec2(theta*DegreesToRadians, 0.25);
points[global_index] = Translate(0.6, 0.0, 0.35)*point4(x, 0.25, y, 1.0);
// This is the
// top of the cylinder
++global_index;
}
}
//The roof of the hut
void drawCone()
{
int width, height;
unsigned char * data_for_roof = SOIL_load_image("./roof_tiles.jpg", &width, &height, NULL, 0);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1);
glBindTexture( GL_TEXTURE_2D, textures[1] );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Generate mipmaps, by the way.
glGenerateMipmap(GL_TEXTURE_2D);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, width, height, GL_RGB, GL_UNSIGNED_BYTE, data_for_roof);
int index = 0;
int l = 0;
for(float theta = 0.0; theta <= 360.0; theta += 10.0)
{
tex_coords[global_index]=vec2(theta*DegreesToRadians, 0.25);
points[global_index] = Translate(0.6, 0.0, 0.35)*point4(0.0, 0.5, 0.0, 1.0); // This is the top of the cone.
++global_index;
tex_coords[global_index] = vec2(theta*DegreesToRadians, 0.5);
points[global_index] = Translate(0.6, 0.0, 0.35)*point4(0.25*sin(theta*DegreesToRadians), 0.25, 0.25*cos(theta*DegreesToRadians), 1.0);
// This is the
// bottom of the cone.
++global_index;
}
}
And here is the display function:
void
display( void )
{
mat4 mv = Translate(0.0, -0.065, -rad)*RotateX(Theta[0])*RotateY(Theta[1])*RotateZ(Theta[2]);
mat4 p = Perspective(10.0, aspectRatio, zNear, zFar);
glUniformMatrix4fv( matrix_loc, 1, GL_TRUE, mv );
glUniformMatrix4fv( projection_loc, 1, GL_TRUE, p );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUniform3fv( theta, 1, Theta );
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glDrawArrays( GL_TRIANGLE_STRIP, 0, 74 );
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glDrawArrays( GL_TRIANGLE_STRIP, 74, 74);
glutSwapBuffers();
}
I am not sure if it is important to include the fragment shader but I will do it anyways:
#version 150
in vec2 texCoord;
out vec4 fColor;
uniform sampler2D texture;
void main()
{
fColor = texture2D( texture, texCoord );
}
I have been struggling for hours to get this right. Does anyone know what I have done wrong?
glActiveTexture() is used to set the texture slot that you are binding a texture to when multi-texturing (rendering more than one texture in a single pass). For example, you might have one texture for a texture map, another for normal map and so on.
However, you are not multi-texturing, because you render the walls and the cone in separate passes (i.e. two separate calls to glDrawArrays()), and your shader only uses a single texture per pass. So within each pass you are only rendering a single texture, which will be in slot 0.
If you set the active texture to GL_TEXTURE1 and then call glBindTexture() then the texture will be bound to slot 1, and slot 0 will remain unchanged.
So, set the active texture slot to 0 both times. Remove this line from your display() function:
glActiveTexture(GL_TEXTURE1);
I must be missing something obvious in using FBO :
I call TMyForm::Init() once at the start of my application :
class TMyForm
{ ...
private:
Gluint mTextureId, mFboId;
int mWidth, mHeight;
}
void TMyForm::Init()
{
mWidth = 1920;
mHeight = 1080;
...
// create a texture object
glEnable(GL_TEXTURE_2D);
glClearColor ( 0.0, 0.0, 0.0, 1.0 );
glGenTextures(1, &mTextureId);
glBindTexture(GL_TEXTURE_2D, mTextureId);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// create a framebuffer object
glGenFramebuffersEXT(1, &mFboId);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFboId);
// attach the texture to FBO color attachment point
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, mTextureId, 0);
// switch back to window-system-provided framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
And in the Draw() function I send the buffer to a card (the rendered scene is ok) and to a preview window (all black or all white depending if I switch back to default window context or the fbo context) :
void TMyForm::Draw()
{
// set rendering destination to FBO
glEnable(GL_TEXTURE_2D);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFboId);
//---
glViewport(-1920, -1080, 1920 * 2, 1080 * 2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(double(-iWidth)*viewport_ratio, double(iWidth)*viewport_ratio, double(-iHeight), double(iHeight), 1000.0, 100000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Render();
glFlush();
//--- 1 : send to card
delete[] mBufferPlayout;
mBufferPlayout = NULL;
try
{
mBufferPlayout = new GLubyte [mWidth * mHeight * 4];
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(0,0, mWidth, mHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE, mBufferPlayout);
DisplayFrame(mBufferPlayout);
}
catch (TSCDbException &e) { ShowMessage(GetLastError()); }
//--- 2 : Texturing to the preview window :
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, mTextureId);
//glGenerateMipmapEXT(GL_TEXTURE_2D);
int iWidthPreview = mWidth / 2; // ie 960
int iHeightPreview = mHeight / 2; // ie 540
glViewport(-iWidthPreview, -iHeightPreview, iWidthPreview * 2, iHeightPreview * 2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(double(-iWidthPreview), double(iWidthPreview), double(-iHeightPreview), double(iHeightPreview), 1000.0, 100000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -50000.0);
mxIncrust0 = 0.0; myIncrust0 = 0.0;
mxIncrust1 = iWidthPreview; myIncrust1 = iHeightPreview;
glBegin(GL_QUADS);
glColor4ub(255,255,255,255);
glTexCoord2d(0.0, 0.0); glVertex2d(mxIncrust0, myIncrust0);
glTexCoord2d(0.0, 1.0); glVertex2d(mxIncrust0, myIncrust1);
glTexCoord2d(1.0,1.0); glVertex2d(mxIncrust1, myIncrust1);
glTexCoord2d(1.0,0.0); glVertex2d(mxIncrust1, myIncrust0);
glEnd();
glDisable(GL_TEXTURE_2D);
glFlush();
//---
SwapBuffers(ghDC);
}
So my problem is the "part 2" which does not do what I wish : texturing the fbo content to the current window.
I tried changing the "glTexCoord2d" with no success.
I'm trying to write a small, portable 2D engine for iOS to learn C++ and OpenGL. Right now I'm trying to display a texture that I've loaded in. I've been successful displaying a texture when loading in the with CoreGraphic libraries, but now I'm trying to load the file in C++ with fread and libpng and all I see is a white box.
My texture is 64x64 so it's not a power of 2 problem. Also I have enabled GL_TEXTURE_2D.
The first block of code is used to load the png, convert the png to image data, and load the data into OpenGL.
void AssetManager::loadImage(const std::string &filename)
{
Texture texture(filename);
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
png_bytep *row_pointers = NULL;
int bitDepth, colourType;
FILE *pngFile = fopen(std::string(Game::environmentData.basePath + "/" + filename).c_str(), "rb");
if(!pngFile)
return;
png_byte sig[8];
fread(&sig, 8, sizeof(png_byte), pngFile);
rewind(pngFile);//so when we init io it won't bitch
if(!png_check_sig(sig, 8))
return;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
if(!png_ptr)
return;
if(setjmp(png_jmpbuf(png_ptr)))
return;
info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
return;
png_init_io(png_ptr, pngFile);
png_read_info(png_ptr, info_ptr);
bitDepth = png_get_bit_depth(png_ptr, info_ptr);
colourType = png_get_color_type(png_ptr, info_ptr);
if(colourType == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
/*if(colourType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)
png_set_gray_1_2_4_to_8(png_ptr);*/
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
if(bitDepth == 16)
png_set_strip_16(png_ptr);
else if(bitDepth < 8)
png_set_packing(png_ptr);
png_read_update_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &texture.width, &texture.height,
&bitDepth, &colourType, NULL, NULL, NULL);
int components = GetTextureInfo(colourType);
if(components == -1)
{
if(png_ptr)
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return;
}
GLubyte *pixels = (GLubyte *)malloc(sizeof(GLubyte) * (texture.width * texture.height * components));
row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * texture.height);
for(int i = 0; i < texture.height; ++i)
row_pointers[i] = (png_bytep)(pixels + (i * texture.width * components));
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, NULL);
// make it
glGenTextures(1, &texture.name);
// bind it
glBindTexture(GL_TEXTURE_2D, texture.name);
GLuint glcolours;
switch (components) {
case 1:
glcolours = GL_LUMINANCE;
break;
case 2:
glcolours = GL_LUMINANCE_ALPHA;
break;
case 3:
glcolours = GL_RGB;
break;
case 4:
glcolours = GL_RGBA;
break;
}
glTexImage2D(GL_TEXTURE_2D, 0, components, texture.width, texture.height, 0, glcolours, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(pngFile);
free(row_pointers);
free(pixels);
textures.push_back(texture);
}
Here is the code for my Texture class:
class Texture
{
public:
Texture(const std::string &filename) { this->filename = filename; }
unsigned int name;
unsigned int size;
unsigned int width;
unsigned int height;
std::string filename;
};
Here is how I setup my view:
void Renderer::Setup(Rectangle rect, CameraType cameraType)
{
_viewRect = rect;
glViewport(0,0,_viewRect.width,_viewRect.height);
if(cameraType == Renderer::Orthographic)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(_viewRect.x,_viewRect.width,_viewRect.y,_viewRect.height,kZNear,kZFar);
glMatrixMode(GL_MODELVIEW);
}
else
{
GLfloat size = kZNear * tanf(DegreesToRadians(kFieldOfView) / 2.0);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustumf(-size, size, -size / (_viewRect.width / _viewRect.height), size / (_viewRect.width / _viewRect.height), kZNear, kZFar);
glMatrixMode(GL_MODELVIEW);
}
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_ONE, GL_SRC_COLOR);
glEnable(GL_BLEND);
}
Now here is where I draw the texture:
void Renderer::DrawTexture(int x, int y, Texture &texture)
{
GLfloat vertices[] = {
x, _viewRect.height - y, 0.0,
x, _viewRect.height - (y + texture.height), 0.0,
x + texture.width, _viewRect.height - y, 0.0,
x + texture.width, _viewRect.height - (y + texture.height), 0.0
};
static const GLfloat normals[] = {
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0
};
GLfloat texCoords[] = {
0.0, 1.0,
0.0, 0.0,
1.0, 1.0,
1.0, 0.0
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glLoadIdentity();
glTranslatef(0.0, 0.0, -3.0);
glBindTexture(GL_TEXTURE_2D, texture.name);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glNormalPointer(GL_FLOAT, 0, normals);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
UPDATE:
I changed the function I use to generate a texture. It now create a random test texture. I still see a white texture no matter what. Gonna keep digging into how I'm renderering.
Here's the new function:
void AssetManager::CreateNoisyTexture(const char * key)
{
Texture texture(key, 64, 64);
const unsigned int components = 4;
GLubyte *pixels = (GLubyte *)malloc(sizeof(GLubyte) * (texture.width * texture.height * components));
GLubyte *pitr1 = pixels;
GLubyte *pitr2 = pixels + (texture.width * texture.height * components);
while (pitr1 != pitr2) {
*pitr1 = rand() * 0xFF;
*(pitr1 + 1) = rand() * 0xFF;
*(pitr1 + 2) = rand() * 0xFF;
*(pitr1 + 3) = 0xFF;
pitr1 += 4;
}
glGenTextures(1, &texture.name);
glBindTexture(GL_TEXTURE_2D, texture.name);
glTexImage2D(GL_TEXTURE_2D, 0, components, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
free(pixels);
printf("Created texture with key: %s name: %d", texture.key, texture.name);
textures.push_back(texture);
}
Ok I figured it out. The problem was that I was using the wrong internal pixel format.
glTexImage2D(GL_TEXTURE_2D, 0, 4, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
Should be:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
I needed to pass in GL_RGBA instead of 4. In the docs I read this:
internalFormat - Specifies the number of color components in the texture. Must be 1, 2, 3, or 4, or one of the following symbolic constants:
I figured it didn't matter but I guess it does. One other thing to note, I figured this out by using glGetError() to figure out where the error was occurring. When I call glTexImage2D() the error was GL_INVALID_OPERATION.
Thanks for your help IronMensan!
UPDATE:
So the reason why I couldn't send 4 is because it is not allowed and internalFormat and format need to be the same in the OpenGL ES 1.1 spec. You can only send GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, or GL_LUMINANCE_ALPHA. Lesson learned.
I'm currently trying to implement in OpenGL image processing algorithms.
I would like to successively use several shaders in order to perform several filters (Sobel Gaussian,...).
I understood that to do this I had to render to texture thanks to a FBO. I read a lot of things about that, and wrote a code. But I'm not getting the result I expected.
For the moment, I'm just trying to use two shaders. So, I have an original image which is the input of my first shader. Then, I want to render the output of the shader to a texture which will then be the input of my second shader (ping-pong technique). And finally, I want to display the output of the second shader.
But as result, I'm getting the original image.
My code is the following:
/******************** Shaders Function *******************************/
void setupShaders(char *vert, char *frag, GLuint p) {
GLuint v, f;
char *vs = NULL,*fs = NULL;
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
vs = textFileRead(vert);
fs = textFileRead(frag);
const char * ff = fs;
const char * vv = vs;
glShaderSource(v, 1, &vv, NULL);
glShaderSource(f, 1, &ff, NULL);
free(vs);free(fs);
glCompileShader(v);
glCompileShader(f);
p = glCreateProgram();
glAttachShader(p,f);
glAttachShader(p,v);
glLinkProgram(p);
glUseProgram(p);
}
/******************** Texture Function ***********************************/
void setupTexture(void) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
/******************** Quad Drawing Function ******************************/
void ShaderDraw(void){
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(0.0, height, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(width, height, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(width, height, 0.0);
glEnd();
}
/******************** Initialization Function ***************************/
void init(void)
{
//Checking GLSL
glewInit();
if (glewIsSupported("GL_VERSION_2_0"))
printf("Ready for OpenGL 2.0\n");
else {
printf("OpenGL 2.0 not supported\n");
exit(1);
}
// Init
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
}
/******************** Display Function **********************************/
void display(void)
{
glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-4.0, -4.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-4.0, 4.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(4.0, 4.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(4.0, -4.0, 0.0);
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
}
/******************** Reshape Function *********************************/
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -7.0);
}
/******************** Main Function *************************************/
int main(int argc, char** argv)
{
// Glut Initialisation
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
// Window Generation
glutInitWindowSize(1000,800);
glutInitWindowPosition(100, 100);
glutCreateWindow("Night Vision");
// Initialisation Function
init();
// Downloading Image
data = cLoadBitmap("lena.bmp", &height, &width);
checkGLErrors ("Downloading Image");
int read_tex = 0;
int write_tex = 1;
// Generating Texture
glEnable(GL_TEXTURE_2D);
glGenTextures(2, texImg);
// Init Texture0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texImg[read_tex]);
setupTexture();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
checkGLErrors ("InitTexture0");
// Init Texture1
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texImg[write_tex]);
setupTexture();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
checkGLErrors ("InitTexture1");
// Setup Framebuffer Object
GLuint fb;
glGenFramebuffersEXT(1, &fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
checkGLErrors ("Framebuffer->fb");
GLenum att_point[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
glBindTexture(GL_TEXTURE_2D, texImg[read_tex]);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, att_point[read_tex], GL_TEXTURE_2D, texImg[read_tex], 0);
glBindTexture(GL_TEXTURE_2D, texImg[write_tex]);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, att_point[write_tex], GL_TEXTURE_2D, texImg[write_tex], 0);
checkFramebufferStatus();
//set the write texture as output buffer for the shader
glDrawBuffer(att_point[write_tex]);
// create, init and enable the shader
setupShaders("filter.vert", "sobel_filter_3.frag", p1);
checkGLErrors ("Shaders 1");
// attach the input texture(read texture) to the first texture unit
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texImg[read_tex]);
GLuint texLoc;
texLoc = glGetUniformLocation(p1,"tex");
glUniform1i(texLoc, 0);
// draw a square with the texture on it so to perform the computation
ShaderDraw();
// swap the buffers
read_tex = 1;
write_tex = 0;
// Delete program 1
glDeleteProgram(p1);
// set the write texture as output buffer for the shader
glDrawBuffer(att_point[write_tex]);
// create, init and enable the shaders
setupShaders("filter.vert", "gaussian7.frag", p2);
checkGLErrors ("Shaders 2");
// attach the input texture(read texture) to the first texture unit
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texImg[read_tex]);
texLoc = glGetUniformLocation(p2,"tex");
glUniform1i(texLoc, 0);
// draw a square with the texture on it so to perform the computation
ShaderDraw();
// Delete program 2 & disable the FBO
glDeleteProgram(p2);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glUseProgram(0);
// Bind the texture to display
glBindTexture(GL_TEXTURE_2D,texImg[0]);
// Glut Functions: Display, Reshape, Keyboard
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
// Calling Main
glutMainLoop();
return 0;
}
Does someone have an idea of what is wrong???
You are trying to simultaneously use the FBO as render source and render target. Afaik you cannot do that - if you want to use a texture bound to an FBO as render source, you need to unbind the FBO (either by calling glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); or by binding another FBO).
It looks like you are trying to save memory that way by using your start texture as the FBO's color buffer there. I am not sure whether this is possible as well.
So you may want try to create two FBOs, each with a single color buffer, and swap the entire FBOs, and start with rendering your texture to the first FBO. Also, don't use your start texture as a color buffer for an FBO, but create a separate color buffer for each FBO instead.
You also don't need to bind a texture to a texture unit before attaching it to an FBO.