How to egl offscreen render to an image on linux? - c++

I'm trying to use egl to do offscreen rendering to an image.
my code doesn't generate any error. the egl part seems to be correct, the fbo is also complete. but when I read pixels using glReadPixels, I always get a black image (I cleared the entire scene with red, so the image should be red too).
I can't figure out what's wrong.
Also, I noticed that glRenderbufferStorage can only support 16bit color depth. GL_RGBA8 is consider an invalid parameter for this function. Isn't 16bit a bit low for serious opengl application?
My environment is Ubuntu 14.10 with mesa and intel graphics.
#include <QCoreApplication>
#include <QDebug>
#include <QImage>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
int main(int argc, char *argv[])
{
#define CONTEXT_ES20
#ifdef CONTEXT_ES20
EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE };
#endif
// Step 1 - Get the default display.
EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)0);
// Step 2 - Initialize EGL.
eglInitialize(eglDisplay, 0, 0);
#ifdef CONTEXT_ES20
// Step 3 - Make OpenGL ES the current API.
eglBindAPI(EGL_OPENGL_ES_API);
// Step 4 - Specify the required configuration attributes.
EGLint pi32ConfigAttribs[5];
pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE;
pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT;
pi32ConfigAttribs[4] = EGL_NONE;
#else
EGLint pi32ConfigAttribs[3];
pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
pi32ConfigAttribs[2] = EGL_NONE;
#endif
// Step 5 - Find a config that matches all requirements.
int iConfigs;
EGLConfig eglConfig;
eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1,
&iConfigs);
if (iConfigs != 1) {
printf("Error: eglChooseConfig(): config not found.\n");
exit(-1);
}
// Step 6 - Create a surface to draw to.
EGLSurface eglSurface;
eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig,
(EGLNativeWindowType)NULL, NULL);
// Step 7 - Create a context.
EGLContext eglContext;
#ifdef CONTEXT_ES20
eglContext = eglCreateContext(eglDisplay, eglConfig, NULL,
ai32ContextAttribs);
#else
eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL);
#endif
// Step 8 - Bind the context to the current thread
eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
GLuint fboId = 0;
GLuint renderBufferWidth = 1280;
GLuint renderBufferHeight = 720;
// create a framebuffer object
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
// create a texture object
/* GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//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_HINT, GL_TRUE); // automatic mipmap
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, renderBufferWidth, renderBufferHeight, 0,
GL_RGB, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// attach the texture to FBO color attachment point
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, textureId, 0);
*/
qDebug() << glGetError();
GLuint renderBuffer;
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
qDebug() << glGetError();
glRenderbufferStorage(GL_RENDERBUFFER,
GL_RGB565,
renderBufferWidth,
renderBufferHeight);
qDebug() << glGetError();
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
renderBuffer);
qDebug() << glGetError();
GLuint depthRenderbuffer;
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, renderBufferWidth, renderBufferHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE) {
printf("Problem with OpenGL framebuffer after specifying color render buffer: \n%x\n", status);
} else {
printf("FBO creation succedded\n");
}
glClearColor(1.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
qDebug() << eglSwapBuffers( eglDisplay, eglSurface);
int size = 4 * renderBufferHeight * renderBufferWidth;
printf("print size");
printf("size %d", size);
qDebug() << size;
unsigned char *data2 = new unsigned char[size];
glReadPixels(0,0,renderBufferWidth,renderBufferHeight,GL_RGB, GL_RGB565, data2);
QImage image(data2, renderBufferWidth, renderBufferHeight,renderBufferWidth*2, QImage::Format_RGB16);
image.save("result.png");
qDebug() << "done";
QCoreApplication a(argc, argv);
return a.exec();
}

OpenGL ES 2.0 has a very limited number of formats/types that are supported for glReadPixels(). The ones you are trying to use are not guaranteed to be supported:
glReadPixels(0 ,0, renderBufferWidth, renderBufferHeight,
GL_RGB, GL_RGB565, data2);
Only two formats/types are supported:
GL_RGBA/GL_UNSIGNED_BYTE.
An implementation dependent combination.
The format and type of the implementation dependent combination can be queried with:
GLint format = 0, type = 0;
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
This can give you one of the following combinations:
GL_RGB/GL_UNSIGNED_BYTE.
GL_RGB/GL_UNSIGNED_SHORT_5_6_5.
GL_RGBA/GL_UNSIGNED_SHORT_4_4_4_4.
GL_RGBA/GL_UNSIGNED_SHORT_5_5_5_1.
GL_ALPHA/GL_UNSIGNED_BYTE.
So the combination you tried to use could be supported by an implementation, if it returns the corresponding values from the glGetIntegerv() calls above. However, there was a subtle but important error in the arguments of your glReadPixels() call even if it is supported: GL_RGB565 is a value for a format, while the 6th argument is a type. The call would have to be:
glReadPixels(0 ,0, renderBufferWidth, renderBufferHeight,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data2);

Related

how to unbind glBindFramebuffer in c++ opengles ios

i am porting a program that run on windows and android to ios.
the following code works on both platform but on ios it stops rendering after that code is being executed, i suspect that the bind never gets unbinded, what is the proper way of doing it?
the objective of the code is to get the textures pixels.
this is the code:
void Texture::Bind()
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTextureID);
}
GLubyte* Texture::GetPixels()
{
Bind();
int data_size = mWidth * mHeight * 4;
GLubyte* pixels = new GLubyte[data_size];
#ifdef _WIN32
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
#else
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextureID, 0);
glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
#endif
return pixels;
}
iOS does not work with default framebuffer indexed with 0. You need to bind the buffer you use as main. It depends on the tool you used but if you are using directly an UIView then you should find some code similar to the following:
- (instancetype)initWithView:(UIView *)view {
if((self = [super init])) {
{
GLuint bufferID = 0;
glGenFramebuffers(1, &bufferID);
glBindFramebuffer(GL_FRAMEBUFFER, bufferID);
self.frameBufferID = bufferID;
}
{
GLuint bufferID = 0;
glGenRenderbuffers(1, &bufferID);
glBindRenderbuffer(GL_RENDERBUFFER, bufferID);
view.layer.contentsScale = UIScreen.mainScreen.scale;
[[EAGLContext currentContext] renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)view.layer];
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, bufferID);
self.colorBufferID = bufferID;
GLint width, height;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
self.bufferWidth = width;
self.bufferHeight = height;
}
}
return self;
}
You are looking for a call to renderbufferStorage:fromDrawable:. Near it a frame buffer should be created which is associated to this render buffer. The id of that frame buffer is what you need to bind.
So in the snipped above you would use self.frameBufferID.
As for the snippet I posted it is a part of a project which generates frame and render buffer from a given UIView. First it generates frame buffer and binds it. Next render buffer is created and bound. Render buffer is then setup through native iOS code with layer. We attach render buffer to frame buffer. At the end width and height are extracted.
Before drawing to this object the following bind method is called:
- (void)bind {
glBindFramebuffer(GL_FRAMEBUFFER, self.frameBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, self.colorBufferID);
}

Why am I getting a GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT here?

I have the following code. I'm trying to create a Multisample Framebuffer that has two color attachments and a depth-stencil attachment.
/* Generate Framebuffer and textures & renderbuffers */
glGenFramebuffers(1, &m_framebuffer);
glGenTextures(1, &m_fboColorAttachment);
glGenTextures(1, &m_fboAdditionalInfo);
glGenRenderbuffers(1,&m_fboRenderbufferDepthStencil);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
/* setup color output 0 */
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_fboColorAttachment);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, renderDimensionsX, renderDimensionsY, GL_FALSE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_fboColorAttachment, 0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
/* setup color output 1 */
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_fboAdditionalInfo);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_R32UI, renderDimensionsX, renderDimensionsY, GL_FALSE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, m_fboAdditionalInfo, 0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
/* setup depth and stencil */
glBindRenderbuffer(GL_RENDERBUFFER, m_fboRenderbufferDepthStencil);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, renderDimensionsX, renderDimensionsY);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_fboRenderbufferDepthStencil);
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
{
std::wstring statusStr = L"WTF error";
if(status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
statusStr = L"Attachment";
else if(status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
statusStr = L"Missing attachment";
else if(status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER)
statusStr = L"Draw buffer";
else if(status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER)
statusStr = L"Read buffer";
else if(status == GL_FRAMEBUFFER_UNSUPPORTED)
statusStr = L"Unsupported";
else if(status == GL_FRAMEBUFFER_UNDEFINED)
statusStr = L"Undefined";
else if(status == GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE)
statusStr = L"Multisample";
else if(status == GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS)
statusStr = L"Layer targets";
drawFuncLog << L"Framebuffer status: " << statusStr << L"\r\n";
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
I'm getting the GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT status returned. As near as I can tell, everything has been created as multisampled and the number of multisample levels matches across the attachments. Incomplete Attachment apparently means one of my attachments is incomplete, which I think is the depth-stencil renderbuffer.
See OpenGL 4.6 API Core Profile Specification; 9.4.2 Whole Framebuffer Completeness; page 326:
The framebuffer object bound to target is said to be framebuffer complete if all the following conditions are true:
......
The value of TEXTURE_FIXED_SAMPLE_LOCATIONS is the same for all attached textures; and, if the attached images are a mix of renderbuffers and textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
This means you have to pass GL_TRUE, to the last parameter of glTexImage2DMultisample for both texture attachments, to solve the issue:
glTexImage2DMultisample(
GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, renderDimensionsX, renderDimensionsY, GL_TRUE);
glTexImage2DMultisample(
GL_TEXTURE_2D_MULTISAMPLE, 4, GL_R32UI, renderDimensionsX, renderDimensionsY, GL_TRUE);

Something wrong with converting SDL surface to GL texture

I can't find my mistake, why text has not been created? When using texture instead of text I get nothing or black background with colored points, please help
GLuint texture;
SDL_Surface *text = NULL;
TTF_Font *font = NULL;
SDL_Color color = {0, 0, 0};
font = TTF_OpenFont("../test.ttf", 20);
text = TTF_RenderText_Solid(font, "Hello, SDL !!!", color);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, text->w, text->h, 0, GL_RGB, GL_UNSIGNED_BYTE, text->pixels);
SDL_FreeSurface(text);
One thing you could add is to specify texture filters, e.g.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
Few things you have to check first
is the font loaded properly? check if "font == NULL", maybe your
font path is wrong
is the shader (if you use a shader) setup properly?
My guess is that you set the wrong pixel format type in glTexImage2D cause random color dots apear on your texture
Below is my code that load image via SDL_image for OpenGL use, I think it would be a good start to figure out what step you missed or forgot.
BTW, this code is not perfect. The types of pixel format is more than four (like index color) and I only handle some of them.
/*
* object_, originalWidth_ and originalHeight_ are private variables in
* this class, don't panic.
*/
void
Texture::Load(string filePath, GLint minMagFilter, GLint wrapMode)
{
SDL_Surface* image;
GLenum textureFormat;
GLint bpp; //Byte Per Pixel
/* Load image file */
image = IMG_Load(filePath.c_str());
if (image == nullptr) {
string msg("IMG error: ");
msg += IMG_GetError();
throw runtime_error(msg.c_str());
}
/* Find out pixel format type */
bpp = image->format->BytesPerPixel;
if (bpp == 4) {
if (image->format->Rmask == 0x000000ff)
textureFormat = GL_RGBA;
else
textureFormat = GL_BGRA;
} else if (bpp == 3) {
if (image->format->Rmask == 0x000000ff)
textureFormat = GL_RGB;
else
textureFormat = GL_BGR;
} else {
string msg("IMG error: Unknow pixel format, bpp = ");
msg += bpp;
throw runtime_error(msg.c_str());
}
/* Store widht and height */
originalWidth_ = image->w;
originalHeight_ = image->h;
/* Make OpenGL texture */
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &object_);
glBindTexture(GL_TEXTURE_2D, object_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minMagFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, minMagFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(
GL_TEXTURE_2D, // texture type
0, // level
bpp, // internal format
image->w, // width
image->h, // height
0, // border
textureFormat, // format(in this texture?)
GL_UNSIGNED_BYTE, // data type
image->pixels // pointer to data
);
/* Clean these mess up */
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
SDL_FreeSurface(image);
}
For more information, you should check out SDL wiki or deep into it's source code to fully understand the architecture of SDL_Surface.

How to draw bitmap as OpenGL texture in C++?

I have a bitmap, and its handle (Win32 HBITMAP). Any suggestion of how to draw this bitmap on an OpenGL quad (with scaling and pulling the 4 corners of the bitmap to fit the 4 vertexes of the quad)?
You need to retrieve the data contained in the HBITMAP, see http://msdn.microsoft.com/en-us/library/dd144879(v=vs.85).aspx Then you can upload the DIB data to OpenGL using glTexImage2D or glTexSubImage2D
With a texture being created you can apply this like usual (enable texturing, give each corner of the quad a texture coordinate).
EDIT due to comment
This (untested!) code should do the trick
GLuint load_bitmap_to_texture(
HDC device_context,
HBITMAP bitmap_handle,
bool flip_image) /* untested */
{
const int BytesPerPixel = sizeof(DWORD);
SIZE bitmap_size;
if( !GetBitmapDimensionEx(bitmap_handle, &bitmap_size) )
return 0;
ssize_t bitmap_buffer_size = bitmap_size.cx * bitmap_size.cy * BytesPerPixel;
#ifdef USE_DWORD
DWORD *bitmap_buffer;
#else
void *bitmap_buffer;
#endif
bitmap_buffer = malloc(bitmap_buffer_size);
if( !bitmap_buffer )
return 0;
BITMAPINFO bitmap_info;
memset(&bitmap_info, 0, sizeof(bitmap_info));
bitmap_info.bmiHeader.biSize = sizeof(bitmap_info.bmiHeader);
bitmap_info.bmiHeader.biWidth = bitmap_size.cx;
bitmap_info.bmiHeader.biHeight = bitmap_size.cy;
bitmap_info.bmiHeader.biPlanes = 1;
bitmap_info.bmiHeader.biBitCount = BitsPerPixel;
bitmap_info.bmiHeader.biCompression = BI_RGB;
if( flip_image ) /* this tells Windows where to set the origin (top or bottom) */
bitmap_info.bmiHeader.biHeight *= -1;
if( !GetDIBits(device_context,
bitmap_handle,
0, bitmap_size.cy,
bitmap_buffer,
&bitmap_info,
DIB_RGB_COLORS /* irrelevant, but GetDIBits expects a valid value */ )
) {
free(bitmap_buffer);
return 0;
}
GLuint texture_name;
glGenTextures(1, &texture_name);
glBindTexture(GL_TEXTURE_2D, texture_name);
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
bitmap_size.cx, bitmap_size.cy, 0,
GL_RGBA,
#ifdef USE_DWORD
GL_UNSIGNED_INT_8_8_8_8,
#else
GL_UNSIGNED_BYTE,
#endif
bitmap_buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
free(bitmap_buffer);
return texture_name;
}

Problem Loading multiple textures using multiple shaders with GLSL

I am trying to use multiple textures in the same scene but no matter what I try the same texture is loaded for each object. So this what I am doing at the moment, I initialise each shader:
rightWall.SendShaders("wall.vert","wall.frag","brick3.bmp", "wallTex", 0);
demoFloor.SendShaders("floor.vert","floor.frag","dirt1.bmp", "floorTex", 1);
The code in SendShaders is:
GLuint vert,frag;
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
char *vs = NULL,*fs = NULL;
vert = glCreateShader(GL_VERTEX_SHADER);
frag = glCreateShader(GL_FRAGMENT_SHADER);
vs = textFileRead(vertFile);
fs = textFileRead(fragFile);
const char * ff = fs;
const char * vv = vs;
glShaderSource(vert, 1, &vv, NULL);
glShaderSource(frag, 1, &ff, NULL);
free(vs); free(fs);
glCompileShader(vert);
glCompileShader(frag);
program = glCreateProgram();
glAttachShader(program, frag);
glAttachShader(program, vert);
glLinkProgram(program);
glUseProgram(program);
LoadGLTexture(textureImage, texture);
And then in the main loop:
rightWall.UseShader("wallTex");
rightWall.Draw();
demoFloor.UseShader("floorTex");
demoFloor.Draw();
The code in UseShader:
void GraphicsObject::UseShader(char textureName []){
glUseProgram(program);
GLint location = glGetUniformLocation(program, textureName);
glUniform1i(location, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
}
And finally, the texture load methods:
int GraphicsObject::LoadGLTexture(const char fileName []){
AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture
memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL
int arraySize = strlen(fileName);
arraySize += 1;
if (TextureImage[0]=LoadBMP(fileName, arraySize))
{
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TextureImage[0]->sizeX,
TextureImage[0]->sizeY, 0, GL_RGB,
GL_UNSIGNED_BYTE, TextureImage[0]->data);
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);
}
if (TextureImage[0])
{
if (TextureImage[0]->data)
{
free(TextureImage[0]->data);
}
free(TextureImage[0]);
}
return 1;
}
AUX_RGBImageRec* GraphicsObject::LoadBMP(const char fileName[], int arraySize){
FILE *File=NULL;
LPWSTR pwszFileName;
int lenW;
BSTR unicodestr;
lenW = MultiByteToWideChar(CP_ACP, 0, fileName, arraySize, 0,0);
DWORD bottom = GetLastError();
unicodestr = SysAllocStringLen(0, lenW);
MultiByteToWideChar(CP_ACP,0, fileName, arraySize,
unicodestr,lenW);
SysFreeString(unicodestr);
DWORD tit = GetLastError();
if (!fileName)
{
return NULL;
}
File=fopen(fileName,"r");
if (File)
{
fclose(File);
return auxDIBImageLoad((LPCWSTR)unicodestr);
}
return NULL;
}
Which ever shader is initialised last is the texture which is used for both objects. Thank you for your time and I appreciate any comments.
Like you have to call glUseProgram(program) before using the shader for rendering, you also have to bind the right texture directly before rendering.
The code should look like this:
glUseProgram(program1);
glBindTexture(GL_TEXTURE_2D, texture1);
// render calls for object 1
glUseProgram(program2);
glBindTexture(GL_TEXTURE_2D, texture2);
// render calls for object 2
Moreover also Uniforms must be set directly before rendering, and not at shader intialization.
So in your case the part
GLint location = glGetUniformLocation(program, textureName);
glUniform1i(location, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
does not belong in the function SendShaders, but in UseShader!
I'm going to point out the obvious just to make sure you can rule it out.
Is your texture image data actually different? Have you checked your texture loading code to make sure you are getting different files for the texture?