Texturing a cube with different images using OpenGL - opengl
I have a project from school I'm currently working on and I need to texture a non-rotating cube showing just 3 faces. I've tried doing it on my own but I only get one image on all the 3 faces. I don't know if it's my method that's wrong or the way I'm loading the remaining two images. I would really appreciate help from anyone.
This is how I load my textures
GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// texture coord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// this is for texture coords
//Load Image
//int width, height; // width1, height1;
//unsigned char* image = SOIL_load_image("res/images/image1.jpg", &width, &height, 0, SOIL_LOAD_RGBA);
GLuint texture1, texture2, texture3;
// texture 1
// ---------
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width, height;
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
unsigned char* image = SOIL_load_image("res/images/image1.jpg", &width, &height, 0, SOIL_LOAD_RGBA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
// texture 2
// ---------
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width1, height1;
unsigned char* image1 = SOIL_load_image("res/images/image2.jpg", &width1, &height1, 0, SOIL_LOAD_RGBA);
// note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image1);
glBindTexture(GL_TEXTURE_2D, 1);
// texture 3
// ---------
glGenTextures(1, &texture3);
glBindTexture(GL_TEXTURE_2D, texture3);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width2, height2;
unsigned char* image2 = SOIL_load_image("res/images/image3.jpg", &width2, &height2, 0, SOIL_LOAD_RGBA);
// note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, image2);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image2);
glBindTexture(GL_TEXTURE_2D, 2);
// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)
// -------------------------------------------------------------------------------------------
shader.Use();
shader.setInt("texture0", 0); // Function to get UniformLocation
shader.setInt("texture1", 0);
shader.setInt("texture2", 2);
And this is the code for when I activate and bind the texture in the rendering Loop
shader.Use();
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture1);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glActiveTexture(GL_TEXTURE1);
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture2);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glActiveTexture(GL_TEXTURE2);
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture2);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
This is my fragment shader for the program. I really don't know how to use the 3 sampler2D variables I also created here
#version 330 core
in vec2 textCoords;
//in vec2 textCoords2;
//in vec3 ourColor;
out vec4 color1;
out vec4 color2;
uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
// color = vec4(ourColor, 1.0f);
color1 = texture(texture0,textCoords) ;
//color2 = texture(texture1,textCoords2);
}
This is the result I get for now with this code, but I want different images on the three faces:
You are not binding textures correctly...
you bind txr1 and render whole cube
then you bind txr2 and render whole cube
then you bind txr3 and render whole cube
so depending on the depth test you see either only txr1 or txr3 or some z fighting mess ...
You need either separate faces with the same texture into separate VAO/VBOs (instead of having whole cube in single one)
Or use texture "atlas" (put all textures into single image) and correct texture coordinates... For example something like this:
In the new versions there is also possibility of using bindless teturing (never used that however it should be just a matter of passing texture id to the shaders)
[Edit1] texture atlas
Ok lets have some texture atlas for example this one (I just compiled):
As you can see its 7x7 square textures so each texture i = 0,1,2,...,7*7-1 starts at texture coordinate:
x = (i%7)/7.0;
y = (i/7)/7.0;
so you simply add the x,y to your texture coordinate for each vertex of each face where i is the selected texture and normalize the coordinates to size of individual texture so:
x = ((i%7)+x0)/7.0;
y = ((i/7)+y0)/7.0;
where x0,y0 are texture coordinates for normal texture (like you got now) and i is selected texture. If you have different layout of the atlas then just change the 7 for the xcount of texture in each axis in your atlas.
I modified my complete GL+GLSL+VAO/VBO C++ example and added textures for the cube:
//---------------------------------------------------------------------------
//--- GL simple ver: 1.002 --------------------------------------------------
//---------------------------------------------------------------------------
// [complete GL+GLSL+VAO/VBO C++ example](https://stackoverflow.com/a/31913542/2521214)
//---------------------------------------------------------------------------
#define GLEW_STATIC
#include "glew.c"
#include <gl\gl.h>
#include <gl\glu.h>
//---------------------------------------------------------------------------
//--- OpenGL GL example -----------------------------------------------------
//---------------------------------------------------------------------------
int xs,ys; // screen size
HDC hdc=NULL; // device context
HGLRC hrc=NULL; // rendering context
int gl_inicialized=0;
int gl_init(HWND Handle);
void gl_exit();
void gl_draw();
void gl_resize(int _xs,int _ys);
//---------------------------------------------------------------------------
//--- OpenGL GLSL example ---------------------------------------------------
//---------------------------------------------------------------------------
GLint prog_id=0, // whole program
vert_id=0, // vertex shader
geom_id=0, // geometry shader
frag_id=0; // fragment shader
char glsl_log[4096];// compile/link GLSL log
int glsl_logs=0;
void glsl_init(char *vert,char *frag); // create/compile/link GLSL program
void glsl_exit();
//---------------------------------------------------------------------------
//--- OpenGL VAO example ----------------------------------------------------
//---------------------------------------------------------------------------
#pragma pack(1)
// #define vao_indices
GLuint vbo[5]={-1,-1,-1,-1,-1};
GLuint vao[5]={-1,-1,-1,-1,-1};
const GLfloat vao_pos[]=
{
// x y z //ix
-1.0,+1.0,-1.0, //0
+1.0,+1.0,-1.0, //1
+1.0,-1.0,-1.0, //2
-1.0,-1.0,-1.0, //3
-1.0,-1.0,+1.0, //4
+1.0,-1.0,+1.0, //5
+1.0,+1.0,+1.0, //6
-1.0,+1.0,+1.0, //7
#ifndef vao_indices
-1.0,-1.0,-1.0, //3
+1.0,-1.0,-1.0, //2
+1.0,-1.0,+1.0, //5
-1.0,-1.0,+1.0, //4
+1.0,-1.0,-1.0, //2
+1.0,+1.0,-1.0, //1
+1.0,+1.0,+1.0, //6
+1.0,-1.0,+1.0, //5
+1.0,+1.0,-1.0, //1
-1.0,+1.0,-1.0, //0
-1.0,+1.0,+1.0, //7
+1.0,+1.0,+1.0, //6
-1.0,+1.0,-1.0, //0
-1.0,-1.0,-1.0, //3
-1.0,-1.0,+1.0, //4
-1.0,+1.0,+1.0, //7
#endif
};
const GLfloat vao_txr[]=
{
// x y //ix
(0.0+0.0)/7.0,(5.0+1.0)/7.0, //0
(0.0+1.0)/7.0,(5.0+1.0)/7.0, //1
(0.0+1.0)/7.0,(5.0+0.0)/7.0, //2
(0.0+0.0)/7.0,(5.0+0.0)/7.0, //3
(5.0+0.0)/7.0,(5.0+0.0)/7.0, //4
(5.0+1.0)/7.0,(5.0+0.0)/7.0, //5
(5.0+1.0)/7.0,(5.0+1.0)/7.0, //6
(5.0+0.0)/7.0,(5.0+1.0)/7.0, //7
#ifndef vaices
(5.0+0.0)/7.0,(4.0+0.0)/7.0, //3
(5.0+1.0)/7.0,(4.0+0.0)/7.0, //2
(5.0+1.0)/7.0,(4.0+1.0)/7.0, //5
(5.0+0.0)/7.0,(4.0+1.0)/7.0, //4
(3.0+1.0)/7.0,(2.0+0.0)/7.0, //2
(3.0+1.0)/7.0,(2.0+1.0)/7.0, //1
(3.0+0.0)/7.0,(2.0+1.0)/7.0, //6
(3.0+0.0)/7.0,(2.0+0.0)/7.0, //5
(0.0+1.0)/7.0,(6.0+1.0)/7.0, //1
(0.0+0.0)/7.0,(6.0+1.0)/7.0, //0
(0.0+0.0)/7.0,(6.0+0.0)/7.0, //7
(0.0+1.0)/7.0,(6.0+0.0)/7.0, //6
(2.0+1.0)/7.0,(6.0+1.0)/7.0, //0
(2.0+1.0)/7.0,(6.0+0.0)/7.0, //3
(2.0+0.0)/7.0,(6.0+0.0)/7.0, //4
(2.0+0.0)/7.0,(6.0+1.0)/7.0, //7
#endif
};
const GLfloat vao_col[]=
{
// r g b //ix
0.0,0.0,0.0, //0
1.0,0.0,0.0, //1
1.0,1.0,0.0, //2
0.0,1.0,0.0, //3
0.0,0.0,1.0, //4
1.0,0.0,1.0, //5
1.0,1.0,1.0, //6
0.0,1.0,1.0, //7
#ifndef vao_indices
0.0,0.0,0.0, //0
1.0,0.0,0.0, //1
1.0,0.0,1.0, //5
0.0,0.0,1.0, //4
1.0,0.0,0.0, //1
1.0,1.0,0.0, //2
1.0,1.0,1.0, //6
1.0,0.0,1.0, //5
1.0,1.0,0.0, //2
0.0,1.0,0.0, //3
0.0,1.0,1.0, //7
1.0,1.0,1.0, //6
0.0,1.0,0.0, //3
0.0,0.0,0.0, //0
0.0,0.0,1.0, //4
0.0,1.0,1.0, //7
#endif
};
#ifndef vao_indices
const GLfloat vao_nor[]=
{
// nx ny nz //ix
0.0, 0.0,-1.0, //0
0.0, 0.0,-1.0, //1
0.0, 0.0,-1.0, //2
0.0, 0.0,-1.0, //3
0.0, 0.0,+1.0, //4
0.0, 0.0,+1.0, //5
0.0, 0.0,+1.0, //6
0.0, 0.0,+1.0, //7
0.0,-1.0, 0.0, //0
0.0,-1.0, 0.0, //1
0.0,-1.0, 0.0, //5
0.0,-1.0, 0.0, //4
+1.0, 0.0, 0.0, //1
+1.0, 0.0, 0.0, //2
+1.0, 0.0, 0.0, //6
+1.0, 0.0, 0.0, //5
0.0,+1.0, 0.0, //2
0.0,+1.0, 0.0, //3
0.0,+1.0, 0.0, //7
0.0,+1.0, 0.0, //6
-1.0, 0.0, 0.0, //3
-1.0, 0.0, 0.0, //0
-1.0, 0.0, 0.0, //4
-1.0, 0.0, 0.0, //7
};
#endif
#ifdef vao_indices
const GLuint vao_ix[]=
{
0,1,2,3,
4,5,6,7,
3,2,5,4,
2,1,6,5,
1,0,7,6,
0,3,4,7,
};
#endif
#pragma pack()
void vao_init();
void vao_exit();
void vao_draw();
//---------------------------------------------------------------------------
//--- bodies: ---------------------------------------------------------------
//---------------------------------------------------------------------------
int gl_init(HWND Handle)
{
if (gl_inicialized) return 1;
hdc = GetDC(Handle); // get device context
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory( &pfd, sizeof( pfd ) ); // set the pixel format for the DC
pfd.nSize = sizeof( pfd );
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 24;
pfd.iLayerType = PFD_MAIN_PLANE;
SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
hrc = wglCreateContext(hdc); // create current rendering context
if(hrc == NULL)
{
ShowMessage("Could not initialize OpenGL Rendering context !!!");
gl_inicialized=0;
return 0;
}
if(wglMakeCurrent(hdc, hrc) == false)
{
ShowMessage("Could not make current OpenGL Rendering context !!!");
wglDeleteContext(hrc); // destroy rendering context
gl_inicialized=0;
return 0;
}
gl_resize(1,1);
glEnable(GL_DEPTH_TEST); // Zbuf
glDisable(GL_CULL_FACE); // vynechavaj odvratene steny
glDisable(GL_TEXTURE_2D); // pouzivaj textury, farbu pouzivaj z textury
glDisable(GL_BLEND); // priehladnost
glShadeModel(GL_SMOOTH); // gourard shading
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // background color
gl_inicialized=1;
glewInit();
return 1;
}
//---------------------------------------------------------------------------
void gl_exit()
{
if (!gl_inicialized) return;
wglMakeCurrent(NULL, NULL); // release current rendering context
wglDeleteContext(hrc); // destroy rendering context
gl_inicialized=0;
}
//---------------------------------------------------------------------------
void gl_resize(int _xs,int _ys)
{
xs=_xs;
ys=_ys;
if (xs<=0) xs = 1; // Prevent a divide by zero
if (ys<=0) ys = 1;
if (!gl_inicialized) return;
glViewport(0,0,xs,ys); // Set Viewport to window dimensions
glMatrixMode(GL_PROJECTION); // operacie s projekcnou maticou
glLoadIdentity(); // jednotkova matica projekcie
gluPerspective(30,float(xs)/float(ys),0.1,100.0); // matica=perspektiva,120 stupnov premieta z viewsize do 0.1
glMatrixMode(GL_TEXTURE); // operacie s texturovou maticou
glLoadIdentity(); // jednotkova matica textury
glMatrixMode(GL_MODELVIEW); // operacie s modelovou maticou
glLoadIdentity(); // jednotkova matica modelu (objektu)
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void glsl_init(char *vert,char *geom,char *frag)
{
const int _size=1024;
GLint status,siz=0,i;
const char * VS = vert;
const char * GS = geom;
const char * FS = frag;
glsl_logs=0;
if (prog_id<=0) prog_id=glCreateProgram();
if (vert_id<=0) vert_id=glCreateShader(GL_VERTEX_SHADER); else glDetachShader(prog_id,vert_id);
if (vert)
{
glShaderSource(vert_id, 1, &VS,NULL);
glCompileShader(vert_id);
glAttachShader(prog_id,vert_id);
glGetShaderiv(vert_id,GL_COMPILE_STATUS,&status);
const char t[]="[Vertex]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
glGetShaderInfoLog(vert_id,_size,&siz,glsl_log+glsl_logs);
glsl_logs+=siz;
}
if (geom_id<=0) geom_id=glCreateShader(GL_GEOMETRY_SHADER); else glDetachShader(prog_id,geom_id);
if (geom)
{
glShaderSource(geom_id, 1, &GS,NULL);
glCompileShader(geom_id);
glAttachShader(prog_id,geom_id);
glGetShaderiv(geom_id,GL_COMPILE_STATUS,&status);
const char t[]="[Geometry]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
glGetShaderInfoLog(geom_id,_size,&siz,glsl_log+glsl_logs);
glsl_logs+=siz;
}
if (frag_id<=0) frag_id=glCreateShader(GL_FRAGMENT_SHADER); else glDetachShader(prog_id,frag_id);
if (frag)
{
glShaderSource(frag_id, 1, &FS,NULL);
glCompileShader(frag_id);
glAttachShader(prog_id,frag_id);
glGetShaderiv(frag_id,GL_COMPILE_STATUS,&status);
const char t[]="[Fragment]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
glGetShaderInfoLog(frag_id,_size,&siz,glsl_log+glsl_logs);
glsl_logs+=siz;
}
glLinkProgram(prog_id);
glGetProgramiv(prog_id,GL_LINK_STATUS,&status);
const char t[]="[Program]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
glGetProgramInfoLog(prog_id,_size,&siz,glsl_log+glsl_logs);
glsl_logs+=siz;
glReleaseShaderCompiler();
glsl_log[glsl_logs]=0;
}
//------------------------------------------------------------------------------
void glsl_exit()
{
glUseProgram(0);
if (vert_id>0) { glDetachShader(prog_id,vert_id); glDeleteShader(vert_id); }
if (geom_id>0) { glDetachShader(prog_id,geom_id); glDeleteShader(geom_id); }
if (frag_id>0) { glDetachShader(prog_id,frag_id); glDeleteShader(frag_id); }
if (prog_id>0) { glDeleteShader(prog_id); }
glsl_log[0]=0;
}
//---------------------------------------------------------------------------
//------------------------------------------------------------------------------
void vao_init()
{
GLuint i;
glGenVertexArrays(4,vao);
glGenBuffers(4,vbo);
glBindVertexArray(vao[0]);
i=0; // vertex
glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(vao_pos),vao_pos,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
i=1; // indices
#ifdef vao_indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,vbo[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(vao_ix),vao_ix,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribIPointer(i,4,GL_UNSIGNED_INT,0,0);
#endif
i=2; // normal
#ifndef vao_indices
glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(vao_nor),vao_nor,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
#endif
i=3; // color
glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(vao_col),vao_col,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
i=4; // textures
glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(vao_txr),vao_txr,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,2,GL_FLOAT,GL_FALSE,0,0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
}
//---------------------------------------------------------------------------
void vao_exit()
{
glDeleteVertexArrays(5,vao);
glDeleteBuffers(5,vbo);
}
//---------------------------------------------------------------------------
void vao_draw()
{
glBindVertexArray(vao[0]);
#ifndef vao_indices
glDrawArrays(GL_QUADS,0,sizeof(vao_pos)/sizeof(vao_pos[0])); // QUADS ... no indices
#endif
#ifdef vao_indices
glDrawElements(GL_QUADS,sizeof(vao_ix)/sizeof(vao_ix[0]),GL_UNSIGNED_INT,0); // indices (choose just one line not both !!!)
#endif
glBindVertexArray(0);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Of coarse you need to add textures to shaders and pass the sampler unit along with texture coordinates too. Also this will not work with indices enabled as the example was not build for that and I am too lazy to recode it. What is important here is this:
const GLfloat vao_txr[]=
{
// x y //ix
(0.0+0.0)/7.0,(5.0+1.0)/7.0, //0
(0.0+1.0)/7.0,(5.0+1.0)/7.0, //1
(0.0+1.0)/7.0,(5.0+0.0)/7.0, //2
(0.0+0.0)/7.0,(5.0+0.0)/7.0, //3
(5.0+0.0)/7.0,(5.0+0.0)/7.0, //4
(5.0+1.0)/7.0,(5.0+0.0)/7.0, //5
(5.0+1.0)/7.0,(5.0+1.0)/7.0, //6
(5.0+0.0)/7.0,(5.0+1.0)/7.0, //7
#ifndef vaices
(5.0+0.0)/7.0,(4.0+0.0)/7.0, //3
(5.0+1.0)/7.0,(4.0+0.0)/7.0, //2
(5.0+1.0)/7.0,(4.0+1.0)/7.0, //5
(5.0+0.0)/7.0,(4.0+1.0)/7.0, //4
(3.0+1.0)/7.0,(2.0+0.0)/7.0, //2
(3.0+1.0)/7.0,(2.0+1.0)/7.0, //1
(3.0+0.0)/7.0,(2.0+1.0)/7.0, //6
(3.0+0.0)/7.0,(2.0+0.0)/7.0, //5
(0.0+1.0)/7.0,(6.0+1.0)/7.0, //1
(0.0+0.0)/7.0,(6.0+1.0)/7.0, //0
(0.0+0.0)/7.0,(6.0+0.0)/7.0, //7
(0.0+1.0)/7.0,(6.0+0.0)/7.0, //6
(2.0+1.0)/7.0,(6.0+1.0)/7.0, //0
(2.0+1.0)/7.0,(6.0+0.0)/7.0, //3
(2.0+0.0)/7.0,(6.0+0.0)/7.0, //4
(2.0+0.0)/7.0,(6.0+1.0)/7.0, //7
#endif
};
As you can see the cooridantes are in form of start_of_texture+texture_coordinate and I chose 6 different textures from the atlas for each face...
Here preview (disabled colors so texture colors are more visible):
And for the completeness here the shaders (however your texturing works so no need to change yours):
// Fragment
#version 400 core
#extension GL_ARB_explicit_uniform_location : enable
layout(location =64) uniform vec3 lt_pnt_pos;// point light source position [GCS]
layout(location =67) uniform vec3 lt_pnt_col;// point light source color&strength
layout(location =70) uniform vec3 lt_amb_col;// ambient light source color&strength
layout(location =73) uniform sampler2D txr;
in vec3 pixel_pos; // fragment position [GCS]
in vec3 pixel_col; // fragment surface color
in vec3 pixel_nor; // fragment surface normal [GCS]
in vec2 pixel_txr; // fragment texture coord
out vec4 col;
void main()
{
float li;
vec3 c,lt_dir;
lt_dir=normalize(lt_pnt_pos-pixel_pos); // vector from fragment to point light source in [GCS]
li=dot(pixel_nor,lt_dir);
if (li<0.0) li=0.0;
c =texture(txr,pixel_txr).rgb;
// c*=pixel_col;
c*=(lt_amb_col+(lt_pnt_col*li));
col=vec4(c,1.0);
}
// Vertex
#version 400 core
#extension GL_ARB_explicit_uniform_location : enable
layout(location = 0) in vec3 pos;
layout(location = 2) in vec3 nor;
layout(location = 3) in vec3 col;
layout(location = 4) in vec2 txr;
layout(location = 0) uniform mat4 m_model; // model matrix
layout(location =16) uniform mat4 m_normal; // model matrix with origin=(0,0,0)
layout(location =32) uniform mat4 m_view; // inverse of camera matrix
layout(location =48) uniform mat4 m_proj; // projection matrix
out vec3 pixel_pos; // fragment position [GCS]
out vec3 pixel_col; // fragment surface color
out vec3 pixel_nor; // fragment surface normal [GCS]
out vec2 pixel_txr; // fragment texture coord
void main()
{
pixel_col=col;
pixel_pos=(m_model*vec4(pos,1)).xyz;
pixel_nor=(m_normal*vec4(nor,1)).xyz;
pixel_txr=txr;
gl_Position=m_proj*m_view*m_model*vec4(pos,1);
}
And here the C++/VCL code for my window:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <jpeg.hpp>
#pragma hdrstop
#include "Unit1.h"
#include "gl_simple.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
GLfloat lt_pnt_pos[3]={+2.5,+2.5,+2.5};
GLfloat lt_pnt_col[3]={0.8,0.8,0.8};
GLfloat lt_amb_col[3]={0.2,0.2,0.2};
GLuint txrid=0;
//---------------------------------------------------------------------------
void gl_draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_CULL_FACE);
// load values into shader
GLint i,id;
GLfloat m[16];
glUseProgram(prog_id);
/*
id=glGetUniformLocation(prog_id,"lt_pnt_pos"); glUniform3fv(id,1,lt_pnt_pos);
id=glGetUniformLocation(prog_id,"lt_pnt_col"); glUniform3fv(id,1,lt_pnt_col);
id=glGetUniformLocation(prog_id,"lt_amb_col"); glUniform3fv(id,1,lt_amb_col);
glGetFloatv(GL_MODELVIEW_MATRIX,m);
id=glGetUniformLocation(prog_id,"m_model" ); glUniformMatrix4fv(id,1,GL_FALSE,m);
m[12]=0.0; m[13]=0.0; m[14]=0.0;
id=glGetUniformLocation(prog_id,"m_normal" ); glUniformMatrix4fv(id,1,GL_FALSE,m);
for (i=0;i<16;i++) m[i]=0.0; m[0]=1.0; m[5]=1.0; m[10]=1.0; m[15]=1.0;
id=glGetUniformLocation(prog_id,"m_view" ); glUniformMatrix4fv(id,1,GL_FALSE,m);
glGetFloatv(GL_PROJECTION_MATRIX,m);
id=glGetUniformLocation(prog_id,"m_proj" ); glUniformMatrix4fv(id,1,GL_FALSE,m);
*/
id=64; glUniform3fv(id,1,lt_pnt_pos);
id=67; glUniform3fv(id,1,lt_pnt_col);
id=70; glUniform3fv(id,1,lt_amb_col);
id=73; glUniform1i(id,0); // texture unit
glGetFloatv(GL_MODELVIEW_MATRIX,m);
id=0; glUniformMatrix4fv(id,1,GL_FALSE,m);
m[12]=0.0; m[13]=0.0; m[14]=0.0;
id=16; glUniformMatrix4fv(id,1,GL_FALSE,m);
for (i=0;i<16;i++) m[i]=0.0; m[0]=1.0; m[5]=1.0; m[10]=1.0; m[15]=1.0;
id=32; glUniformMatrix4fv(id,1,GL_FALSE,m);
glGetFloatv(GL_PROJECTION_MATRIX,m);
id=48; glUniformMatrix4fv(id,1,GL_FALSE,m);
// draw VAO cube
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,txrid);
vao_draw();
glBindTexture(GL_TEXTURE_2D,0);
glDisable(GL_TEXTURE_2D);
// turn of shader
glUseProgram(0);
// render the cube in old style GL
if (0)
{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
#ifndef vao_indices
glBegin(GL_QUADS);
for (int i=0;i<6*4*3;i+=3)
{
glNormal3fv(vao_nor+i);
glColor3fv (vao_col+i);
glVertex3fv(vao_pos+i);
}
glEnd();
#else
int i,j,k;
const GLfloat vao_nor[]=
{
// nx ny nz
0.0, 0.0,-1.0,
0.0, 0.0,+1.0,
0.0,-1.0, 0.0,
+1.0, 0.0, 0.0,
0.0,+1.0, 0.0,
-1.0, 0.0, 0.0,
};
glBegin(GL_QUADS);
for (j=0;j<6*4;j++)
{
i=vao_ix[j]; i+=i+i;
k=j>>2; k+=k+k;
glNormal3fv(vao_nor+k);
glColor3fv (vao_col+i);
glVertex3fv(vao_pos+i);
}
glEnd();
#endif
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
}
// rotate the cube to see animation
glMatrixMode(GL_MODELVIEW);
glRotatef(1.0,0.0,1.0,0.0);
glRotatef(1.0,1.0,0.0,0.0);
// render point light source in [GCS]
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
GLfloat x,y,z,d=0.25;
x=lt_pnt_pos[0];
y=lt_pnt_pos[1];
z=lt_pnt_pos[2];
glBegin(GL_LINES);
glColor3fv(lt_pnt_col);
glVertex3f(x-d,y,z);
glVertex3f(x+d,y,z);
glVertex3f(x,y-d,z);
glVertex3f(x,y+d,z);
glVertex3f(x,y,z-d);
glVertex3f(x,y,z+d);
glEnd();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glFlush();
SwapBuffers(hdc);
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
gl_init(Handle);
// load shaders
int hnd,siz; char vertex[4096],fragment[4096];
hnd=FileOpen("normal_shading.glsl_vert",fmOpenRead); siz=FileSeek(hnd,0,2); FileSeek(hnd,0,0); FileRead(hnd,vertex ,siz); vertex [siz]=0; FileClose(hnd);
hnd=FileOpen("normal_shading.glsl_frag",fmOpenRead); siz=FileSeek(hnd,0,2); FileSeek(hnd,0,0); FileRead(hnd,fragment,siz); fragment[siz]=0; FileClose(hnd);
glsl_init(vertex,NULL,fragment);
hnd=FileCreate("GLSL.txt"); FileWrite(hnd,glsl_log,glsl_logs); FileClose(hnd);
// load texture atlas
Byte q;
unsigned int *pp;
int xs,ys,x,y,adr,*txr;
union { unsigned int c32; Byte db[4]; } c;
TJPEGImage *jpg=new TJPEGImage;
Graphics::TBitmap *bmp=new Graphics::TBitmap;
if (bmp)
{
if (jpg)
{
jpg->LoadFromFile("textures128x128.jpg");
bmp->Assign(jpg);
delete jpg;
}
glGenTextures(1,&txrid);
bmp->HandleType=bmDIB; // allow direct access to pixels
bmp->PixelFormat=pf32bit; // set pixel to 32bit so int is the same size as pixel
xs=bmp->Width; // resolution should be power of 2
ys=bmp->Height;
txr=new int[xs*ys]; // create linear framebuffer
for(adr=0,y=0;y<ys;y++)
{
pp=(unsigned int*)bmp->ScanLine[y];
for(x=0;x<xs;x++,adr++)
{
// rgb2bgr and copy bmp -> txr[]
c.c32=pp[x];
q =c.db[2];
c.db[2]=c.db[0];
c.db[0]=q;
txr[adr]=c.c32;
}
}
glEnable(GL_TEXTURE_2D); // copy it to gfx card
glBindTexture(GL_TEXTURE_2D,txrid);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0, GL_RGBA, GL_UNSIGNED_BYTE, txr);
glDisable(GL_TEXTURE_2D);
delete[] txr;
delete bmp;
}
vao_init();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
glDeleteTextures(1,&txrid);
gl_exit();
glsl_exit();
vao_exit();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
gl_resize(ClientWidth,ClientHeight);
glMatrixMode(GL_PROJECTION);
glTranslatef(0,0,-15.0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
gl_draw();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
gl_draw();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
{
GLfloat dz=2.0;
if (WheelDelta<0) dz=-dz;
glMatrixMode(GL_PROJECTION);
glTranslatef(0,0,dz);
gl_draw();
}
//---------------------------------------------------------------------------
Again most of the code is not important for you look just for the code related to vao_ stuff.
Related
C++ freetype add border to text with color and lenght
I've made an OpenGL c++ program that can display some text into the screen. I've followed some tutorials and got help from this question. With that, I've managed to write a function called add_border but I didn't quite understand how this all works and couldn't manage to display border on the screen. Here is what I have so far: text.fs #version 300 es precision mediump float; in vec2 vUV; uniform sampler2D u_texture; uniform vec3 textColor; out vec4 fragColor; void main() { vec2 uv = vUV.xy; float text = texture(u_texture, uv).r; fragColor = vec4(textColor.rgb*text, text); } text.vs #version 300 es precision mediump float; layout (location = 0) in vec4 in_attr; out vec2 vUV; uniform mat4 projection; uniform mat4 model; void main() { vUV = in_attr.zw; gl_Position = projection * model * vec4(in_attr.xy, 1.0f, 1.0f); } Text.cpp void Text::render_text(std::string text, float x, float y, float z, std::string hex_color, float angle_rad, bool has_bg) { static const int scale = 1; y /= 2; shader.use(); glUniform3f(glGetUniformLocation(shader.ID, "textColor"), 0.9, 0.9, 0.9); color.get_color_float(Utils::BLUE)); glActiveTexture(GL_TEXTURE0); glBindVertexArray(VAO); GLfloat vertices[6][4] = { { 0.0, 1.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 }, { 1.0, 0.0, 1.0, 1.0 }, { 0.0, 1.0, 0.0, 0.0 }, { 1.0, 0.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0, 0.0 } }; glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData glBindBuffer(GL_ARRAY_BUFFER, 0); glm::mat4 rotateM = glm::rotate(glm::mat4(1.0f), glm::radians(angle_rad), glm::vec3(0.0f, 0.0f, 1.0f)); glm::mat4 transOriginM = glm::translate(glm::mat4(1.0f), glm::vec3(x, y, z)); std::string::const_iterator c; GLfloat char_x = 0.0f; for (c = text.begin(); c != text.end(); c++) { Character ch = Characters[*c]; GLfloat w = ch.Size.x * scale; GLfloat h = ch.Size.y * scale; GLfloat xrel = char_x + ch.Bearing.x * scale; GLfloat yrel = y - (ch.Size.y - ch.Bearing.y) * scale; char_x += (ch.Advance >> 6) * scale; ) glm::mat4 scaleM = glm::scale(glm::mat4(1.0f), glm::vec3(w, h, 1.0f)); glm::mat4 transRelM = glm::translate(glm::mat4(1.0f), glm::vec3(xrel, yrel, z)); glm::mat4 modelM = transOriginM * rotateM * transRelM * scaleM; GLint model_loc = glGetUniformLocation(shader.ID, "model"); glUniformMatrix4fv(model_loc, 1, GL_FALSE, glm::value_ptr(modelM)); glBindTexture(GL_TEXTURE_2D, ch.TextureID); glDrawArrays(GL_TRIANGLES, 0, 6); } glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); } void Text::add_border(){ if(FT_Outline_New(ft_lib, 10000, 1000, &border) != 0){ VI_ERROR("Error"); } FT_Stroker_New(ft_lib, &stroker); FT_Stroker_Set(stroker, 2 * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); FT_Get_Glyph(face->glyph, &glyph); FT_Glyph_Stroke(&glyph, stroker, false); if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { FT_Raster_Params params; params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; //params.gray_spans = outlineRenderCallback; //params.user = user_data; FT_Outline_Render(ft_lib, &border, ¶ms); } } Text::Text(text_attributes&& atrib, int gl_width, int gl_height) :SCR_WIDTH(gl_width), SCR_HEIGHT(gl_height) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); shader = Shader("./src/opengl/shaders/text.vs", "./src/opengl/shaders/text.fs"); glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(SCR_WIDTH), 0.0f, static_cast<float>(SCR_HEIGHT)); shader.use(); glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); if (FT_Init_FreeType(&ft_lib)) { VI_ERROR("ERROR::FREETYPE: Could not init FreeType Library"); exit(0); } std::string font_name = "./src/opengl/fonts/" + *atrib.__font_name + ".ttf"; if (FT_New_Face(ft_lib, font_name.c_str(), 0, &face)) { VI_ERROR("ERROR::FREETYPE: Failed to load font"); exit(0) ; } else { FT_Set_Pixel_Sizes(face, 0, atrib.__font_size); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); for (unsigned char c = 0; c < 128; c++) { if (FT_Load_Char(face, c, FT_LOAD_RENDER)) { VI_ERROR("ERROR::FREETYTPE: Failed to load Glyph"); continue; } add_border(); GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer ); 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_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); Character character = { texture, glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), static_cast<unsigned int>(face->glyph->advance.x) }; Characters.insert(std::pair<char, Character>(c, character)); } glBindTexture(GL_TEXTURE_2D, 0); } FT_Done_Face(face); FT_Outline_Done(ft_lib, &border); FT_Done_FreeType(ft_lib); glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } I've read somewhere that changing FT_LOAD_RENDER to FT_LOAD_DEFAULT in FT_Load_Char() causes the text to disappear completely Right now this code compiles and runs just fine, however there is no border around the text. I want to add some parameters to the add_border function to have it display different border's with the given parameters such as border thickness and border color. What am I doing wrong? How can I have it display border like I want it to?
Based on the comments above: The below example is based on my own lib (although very shortened), where i am collecting the coverage into an span array and render it later. It is also possible to render the coverage(s)/scanline directly onto a bitmap. //structure to set the bounds //and to hold a list of the coverage(s) //basically the 'raw' data to produce a single glyph image struct my_spans { int x_min, y_min; int x_max, y_max; FT_Span *span_array; //needed later to reproduce the (glyph) image }; struct my_spans spans; //initialize properly //set the raster params accordingly FT_Raster_Params params; memset(¶ms, 0, sizeof(params)); params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; //direct rendering params.gray_spans = outlineRenderCallback; //our callback below params.user = &spans; //userdata will be our struct //will be called for each scanline, thus the single y coordinate void outlineRenderCallback( int y, int count, const FT_Span *ft_spans, void *user ){ struct my_spans *spans = (struct my_spans*) user; FT_Span span; //increase array capacity by count //foreach span for (int i=0; i < count; ++i, ++ft_spans) { //horizontal boundary spans->x_min = min(spans->x_min, ft_spans->x); spans->x_max = max(spans->x_max, ft_spans->x + ft_spans->len - 1); //span copy, although possible to write into array directly span.x = ft_spans->x; span.y = y; span.len = ft_spans->len; span.coverage = ft_spans->coverage; //push span to array, if not written directly } //vertical boundary spans->y_min = min(spans->y_min, y); spans->y_max = max(spans->y_max, y); } Reference: FT_Outline_Render FT_Raster_Params FT_SpanFunc FT_Span
Apply succesive shaders
Recently I've found the following link about simulating fluids on the GPU. I decided to try to implement it using OpenGL but I got stuck on how to apply successive shaders. For example, I'd need to apply the advection shader, take its output and apply it into the difuse shader (from the link: "The operator is defined as the composition of operators for advection, diffusion, force application, and projection") but I can't figure out how. I've re-read learn opengl framebuffers tutorial but I'm still lost. Right now I'm trying to do the following, to test communication between shaders: 1- load texture; 2- apply kernel 1 (inverse shader); 3- apply kernel 2 (advect shader); Step 1 is done only once, while steps 2 and 3 are done while the windows is open. Here is the shader code: ///////////////////////////// // read image - shader.frag ///////////////////////////// #version 330 core out vec4 FragColor; in vec2 uv; uniform sampler2D texture1; void main() { FragColor = texture(texture1, uv); } ///////////////////////////// // color inversion shader ///////////////////////////// #version 330 core out vec4 FragColor; in vec2 uv; const float offset = 1.0 / 300.0; void main() { FragColor = vec4(vec3(1.0 - texture(screenTexture, uv)), 1.0); } ///////////////////////////// // advect shader ///////////////////////////// #version 330 core out vec4 FragColor; in vec2 uv; uniform float dt; uniform float sigma_x_inv; uniform sampler2D u; uniform sampler2D x; void main() { // change texture2D to texture vec2 pos = uv - dt * sigma_x_inv * texture(u, uv).xy; FragColor = texture(x, pos); } ///////////////////////////// // vertex shader ///////////////////////////// #version 330 core layout (location = 0) in vec3 aPos; out vec2 uv; void main() { gl_Position = vec4(aPos, 1.0); uv = aPos.xy; } Here is part of my code, mostly taken from here (learn opengl). The screen is just black. If I use one framebuffer(like shown in learn opengl) I can pass data to one shader just fine - I managed to see the inversion and advection shaders working in isolation - but when I add a new frame buffer the screen just goes black. I've also tried using one framebuffer for the two shaders but it didn't work. Also, how could I pass two textures to one shader? The advection shader, for example, needs to textures, representing two different vector fields. Bellow is my code. #include "include/glad/glad.h" #include <GLFW/glfw3.h> #include "include/shader.hpp" #define STB_IMAGE_IMPLEMENTATION #include "include/stb_image.h" #include <glm/glm.hpp> #include <chrono> #include <iostream> void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window); unsigned int loadTexture(char const * path); // settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600; unsigned int s_width = SCR_WIDTH; unsigned int s_height = SCR_HEIGHT; float sigma_x_inv = 1.0f / SCR_WIDTH; const float dt = 1/60; int main() { // glfw: initialize and configure // ------------------------------ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif // glfw window creation // -------------------- GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // glad: load all OpenGL function pointers // --------------------------------------- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // build and compile our shader program // ------------------------------------ Shader shader("shaders/shader.vert", "shaders/shader.frag"); Shader advectShader("shaders/shader.vert", "shaders/advect.frag"); Shader inversionShader("shaders/shader.vert", "shaders/inversion.frag"); Shader boundaryShader("shaders/shader.vert", "shaders/boundary.frag"); Shader divergenceShader("shaders/shader.vert", "shaders/divergence.frag"); Shader gradientShader("shaders/shader.vert", "shaders/gradient.frag"); // set up vertex data (and buffer(s)) and configure vertex attributes // ------------------------------------------------------------------ float planeVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. // positions // texCoords -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f }; float quadVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. // positions // texCoords -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f }; // plane VAO unsigned int planeVAO, planeVBO; glGenVertexArrays(1, &planeVAO); glGenBuffers(1, &planeVBO); glBindVertexArray(planeVAO); glBindBuffer(GL_ARRAY_BUFFER, planeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); // screen quad VAO unsigned int quadVAO, quadVBO; glGenVertexArrays(1, &quadVAO); glGenBuffers(1, &quadVBO); glBindVertexArray(quadVAO); glBindBuffer(GL_ARRAY_BUFFER, quadVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); // load and create a texture // ------------------------- unsigned int texture1, texture2; // texture 1 // --------- stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. unsigned int blackTexture = loadTexture("textures/black.png"); unsigned int awesomeTexture = loadTexture("textures/awesomeface.png"); shader.use(); shader.setInt("texture1", 0); // framebuffer configuration // ------------------------- unsigned int framebuffer; glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); // create a color attachment texture unsigned int textureColorbuffer; glGenTextures(1, &textureColorbuffer); glBindTexture(GL_TEXTURE_2D, textureColorbuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0); // framebuffer configuration // ------------------------- unsigned int framebuffer2; glGenFramebuffers(1, &framebuffer2); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2); // create a color attachment texture unsigned int textureColorbuffer2; glGenTextures(1, &textureColorbuffer2); glBindTexture(GL_TEXTURE_2D, textureColorbuffer2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer2, 0); // create a renderbuffer object for depth and // stencil attachment (we won't be sampling these) unsigned int rbo; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); // use a single renderbuffer object for both a depth AND stencil buffer. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT); // now actually attach it glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now that we actually created the framebuffer and added all // attachments we want to check if it is actually complete now if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl; glBindFramebuffer(GL_FRAMEBUFFER, 0); // tell opengl for each sampler to which texture // unit it belongs to (only has to be done once) // ------------------------------------------------------------------------------------------- // advectShader.use(); // don't forget to activate/use the shader before setting uniforms! // // either set it manually like so: // advectShader.setInt("u", 0); // // or set it via the texture class // advectShader.setInt("x", 1); divergenceShader.use(); divergenceShader.setFloat("sigma_x_inv", sigma_x_inv); boundaryShader.use(); boundaryShader.setFloat("scale", 1.0f); shader.use(); // Program start time auto start = std::chrono::system_clock::now(); // render // ------ // bind to framebuffer and draw scene as we normally would to color texture glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad) glClearColor(0.3f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glActiveTexture(GL_TEXTURE0); shader.use(); glBindVertexArray(planeVAO); glBindTexture(GL_TEXTURE_2D, awesomeTexture); glDrawArrays(GL_TRIANGLES, 0, 6); // render loop // ----------- while (!glfwWindowShouldClose(window)) { // input // ----- processInput(window); // ---- glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2); glDisable(GL_DEPTH_TEST); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); inversionShader.use(); glBindVertexArray(planeVAO); glBindTexture(GL_TEXTURE_2D, textureColorbuffer2); glDrawArrays(GL_TRIANGLES, 0, 6); // test boy // ----------------------------- // now bind back to default framebuffer and draw a quad plane // with the attached framebuffer color texture glBindFramebuffer(GL_FRAMEBUFFER, 0); glDisable(GL_DEPTH_TEST); // glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // glClear(GL_COLOR_BUFFER_BIT); // density step // ----------------------------- // boundaryShader.use(); // boundaryShader.setFloat("scale", 1.0f); // boundaryShader.setVec2("offset", 0.5, 0.5); // pass current time to shader advectShader.use(); auto now = std::chrono::system_clock::now(); std::chrono::duration<float> diff = now - start; advectShader.setFloat("dt", diff.count()); advectShader.setFloat("sigma_x_inv", 1000 * 1 / s_width); glBindVertexArray(quadVAO); glBindTexture(GL_TEXTURE_2D, textureColorbuffer); glDrawArrays(GL_TRIANGLES, 0, 6); // needs to check how to get shader // velocity step // ----------------------------- // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) // ------------------------------------------------------------------------------- glfwSwapBuffers(window); glfwPollEvents(); } // optional: de-allocate all resources once they've outlived their purpose: // ------------------------------------------------------------------------ glDeleteVertexArrays(1, &planeVAO); glDeleteVertexArrays(1, &quadVAO); glDeleteBuffers(1, &planeVBO); glDeleteBuffers(1, &quadVBO); glDeleteFramebuffers(1, &framebuffer); // glfw: terminate, clearing all previously allocated GLFW resources. // ------------------------------------------------------------------ glfwTerminate(); return 0; } // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly // --------------------------------------------------------------------------------------------------------- void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); } // glfw: whenever the window size changed (by OS or user resize) this callback function executes // --------------------------------------------------------------------------------------------- void framebuffer_size_callback(GLFWwindow* window, int width, int height) { s_width = width; s_height = height; // make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays. glViewport(0, 0, width, height); } // utility function for loading a 2D texture from file // --------------------------------------------------- unsigned int loadTexture(char const * path) { unsigned int textureID; glGenTextures(1, &textureID); int width, height, nrComponents; unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0); if (data) { GLenum format; if (nrComponents == 1) format = GL_RED; else if (nrComponents == 3) format = GL_RGB; else if (nrComponents == 4) format = GL_RGBA; glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); // set the texture wrapping parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // set texture filtering parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_image_free(data); } else { std::cout << "Texture failed to load at path: " << path << std::endl; stbi_image_free(data); } return textureID; }
OpenGL - Load mutliple texures in one function
I've already constructed a 15x15 grid of cubes with glutSolidCube(). Then i have a menu handler in which when I click "Start Game", loads the texture I used to all of the cubes, calling a custom glutSolidCube and having glTexCoord2d before each declaration of vertices, cause we can't have textures on the latter I think. For uploading the texture from an image, I'm using a STB_IMAGE_IMPLEMENTATION implementation having also a header file included. The function loadTextureFromFile(const char *filename) does the loading part. How can I upload more textures (I want 2 more, in the same loadTextureFromFile() function preferably) and how to handle each texture with the glTexCoord2d()? Here's my entire code: #include<iostream> #include <stdio.h> #include <stdlib.h> #include <math.h> #include <GL/gl.h> // openGL header #include <GL/glu.h> // glut header #include <GL/glut.h> // glut header #define STB_IMAGE_IMPLEMENTATION /////////////////////////////////////Textures==============================================///////////////////////////////////// #include "stb_image.h" GLuint texture; //the array for our texture void loadTextureFromFile(const char *filename) { glClearColor(0.0, 0.0, 0.0, 0.0); //glShadeModel(GL_FLAT); //glEnable(GL_DEPTH_TEST); unsigned int texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); // set the texture wrapping/filtering options (on the currently bound texture object) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // load and generate the texture int width, height, nrChannels; unsigned char *data = stbi_load("paper.bmp", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); //glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture" << std::endl; } stbi_image_free(data); } void FreeTexture(GLuint texture) { glDeleteTextures(1, &texture); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void drawBox(GLfloat size, GLenum type) { static GLfloat n[6][3] = { {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0} }; static GLint faces[6][4] = { {0, 1, 2, 3}, {3, 2, 6, 7}, {7, 6, 5, 4}, {4, 5, 1, 0}, {5, 6, 2, 1}, {7, 4, 0, 3} }; GLfloat v[8][3]; GLint i; v[0][0] = v[1][0] = v[2][0] = v[3][0] = -size / 2; v[4][0] = v[5][0] = v[6][0] = v[7][0] = size / 2; v[0][1] = v[1][1] = v[4][1] = v[5][1] = -size / 2; v[2][1] = v[3][1] = v[6][1] = v[7][1] = size / 2; v[0][2] = v[3][2] = v[4][2] = v[7][2] = -size / 2; v[1][2] = v[2][2] = v[5][2] = v[6][2] = size / 2; for (i = 5; i >= 0; i--) { glBegin(type); glNormal3fv(&n[i][0]); glTexCoord2d(0.0,0.0); glVertex3fv(&v[faces[i][0]][0]); glTexCoord2d(0.0,1.0); glVertex3fv(&v[faces[i][1]][0]); glTexCoord2d(1.0,1.0); glVertex3fv(&v[faces[i][2]][0]); glTexCoord2d(1.0,0.0); glVertex3fv(&v[faces[i][3]][0]); glEnd(); } } void APIENTRY myglutSolidCube(GLdouble size) { drawBox(size, GL_QUADS); } //int red_color[]={255,0,0}; //int blue_colot[]={0,0,255}; //////////////////////////////=========MENU============///////////// enum MENU_TYPE //menu options-values { MENU_START, MENU_EXIT, }; //create the menu - Prototype void my_createmenu(void); // Menu handling function declaration - Prototype void menu(int); void init() { //for 3d lighting glEnable(GL_DEPTH_TEST); //depth test glEnable(GL_LIGHTING); //enable light from a single source glEnable(GL_LIGHT0); //enable white light , diffuse and specular components glEnable(GL_COLOR_MATERIAL); //track the current color } void display() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Black and opaque glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //define the projection matrix just once and use the modelview matrix all other times glMatrixMode(GL_PROJECTION); //Applies subsequent matrix operations to the projection matrix stack glLoadIdentity();//Reset GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); //The params parameter returns four values: the x and y window coordinates of the viewport, followed by its width and height double aspect = (double)viewport[2] / (double)viewport[3]; // y/width would be 1.0 gluPerspective(60,aspect, 1, 100); //using perspective projection //gluOrtho2D(0.0,600.0,-60.0,600.0); glMatrixMode(GL_MODELVIEW); //for trasformations - Applies subsequent matrix operations to the texture matrix stack glLoadIdentity(); // move back a bit for viewer , cause of gluPerspective glTranslatef( 0, 0, -35 ); float e=0,f=0; //construct the grid with reference the central cube for(int i=0;i<8;i++) { for(int j=0;j<8;j++) { glPushMatrix(); glTranslatef(0.0f+e,0.0f+f,0.0f); //right and below glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d glColor3ub(245, 245, 220); //Beige glutSolidCube(2.25); glPopMatrix(); glPushMatrix(); glTranslatef(0.0f-e,0.0f+f,0.0f); //left and below glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d glColor3ub(245, 245, 220); //Beige glutSolidCube(2.25); glPopMatrix(); glPushMatrix(); glTranslatef(0.0f+e,0.0f-f,0.0f); //right and up glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d glColor3ub(245, 245, 220); //Beige glutSolidCube(2.25); glPopMatrix(); glPushMatrix(); glTranslatef(0.0f-e,0.0f-f,0.0f); //left and up glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d glColor3ub(245, 245, 220); //Beige glutSolidCube(2.25); glPopMatrix(); f += -2.63; } f=0; e+=2.63; } glutSwapBuffers(); //implicit glFlush } //for the second part of program void display_game() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Black and opaque glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //define the projection matrix just once and use the modelview matrix all other times glMatrixMode(GL_PROJECTION); //Applies subsequent matrix operations to the projection matrix stack glLoadIdentity();//Reset GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); //The params parameter returns four values: the x and y window coordinates of the viewport, followed by its width and height double aspect = (double)viewport[2] / (double)viewport[3]; // y/width would be 1.0 gluPerspective(60,aspect, 1, 100); //using perspective projection //glOrtho(0.0f, 600.0f, 600.0f, 0.0f, 0.0f, 1.0f); glMatrixMode(GL_MODELVIEW); //for trasformations - Applies subsequent matrix operations to the texture matrix stack glLoadIdentity(); // move back a bit for viewer , cause of gluPerspective glTranslatef( 0, 0, -35 ); float e=0,f=0; glEnable(GL_TEXTURE_2D); //construct the grid with reference the central cube for(int i=0;i<8;i++) { for(int j=0;j<8;j++) { glPushMatrix(); glTranslatef(0.0f+e,0.0f+f,0.0f); //right and below glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d //glColor3ub(245, 245, 220); //Beige //glColor3ub( rand()%255,rand()%255, rand()%255 ); myglutSolidCube(2.25); glPopMatrix(); glPushMatrix(); glTranslatef(0.0f-e,0.0f+f,0.0f); //left and below glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d //glColor3ub( rand()%255,rand()%255, rand()%255 ); myglutSolidCube(2.25); glPopMatrix(); glPushMatrix(); glTranslatef(0.0f+e,0.0f-f,0.0f); //right and up glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d myglutSolidCube(2.25); glPopMatrix(); glPushMatrix(); glTranslatef(0.0f-e,0.0f-f,0.0f); //left and up glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d myglutSolidCube(2.25); glPopMatrix(); f += -2.63; } f=0; e+=2.63; } //SEED to some constant value for 2nd part of the program. If it is not used , cubes would change color in runtime //srand(0x98765432); glutSwapBuffers(); //implicit glFlush glDisable(GL_TEXTURE_2D); } void reshape(GLsizei width, GLsizei height) { // GLsizei for non-negative integer // Compute aspect ratio of the new window if (height == 0) height = 1; // To prevent divide by 0 GLfloat aspect = (GLfloat)width / (GLfloat)height; // Set the viewport to cover the new window glViewport(0, 0, width, height); // Set the aspect ratio of the clipping volume glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix glLoadIdentity(); // Reset // Enable perspective projection with fovy, aspect, zNear and zFar gluPerspective(45.0f, aspect, 0.1f, 100.0f); } void timer(int extra) { glutPostRedisplay(); glutTimerFunc(16, timer, 0); } void mouseEscape( int button, int state, int x, int y ) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN &&button==MENU_EXIT) { int windowID = glutCreateWindow("CUBES"); glutDestroyWindow(windowID); exit(0); } glutPostRedisplay(); } //for loading the texture const char* filename = "salt_on_spoon.bmp"; int main(int argc, char **argv) { glutInit(&argc, argv); glutInitWindowSize(600,600); glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE| GLUT_MULTISAMPLE); glEnable(GL_MULTISAMPLE); //anti-alliasing glutCreateWindow("CUBES"); //create and handle the menu my_createmenu(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutTimerFunc(0, timer, 0); init(); //glEnable(GL_TEXTURE_2D); //for texture //glutMouseFunc(mouseEscape); //glutKeyboardFunc(keyEscape); //Load our texture //loadTextureFromFile(filename); glutMainLoop(); //Free our texture //FreeTexture(texture); return 0; } //create the menu-entries void my_createmenu(void) { // Create a menu glutCreateMenu(menu); // Add menu items glutAddMenuEntry("Start Game", MENU_START); glutAddMenuEntry("Exit", MENU_EXIT); // Associate a mouse button with menu glutAttachMenu(GLUT_RIGHT_BUTTON); } // Menu handling function-what to do in each value void menu(int item) { switch (item) { case MENU_START: { //glEnable(GL_TEXTURE_2D); //for texture //Load our texture loadTextureFromFile(filename); glutDisplayFunc(display_game); } break; case MENU_EXIT: { int windowID = glutCreateWindow("CUBES"); //exit game glutDestroyWindow(windowID); exit(0); } break; default: { /* Nothing */ } break; } glutPostRedisplay(); return; } I'm doing the texture loading part in the menu function. How will I be able to handle three textures? The ultimate goal is to make a rand call also for the three textures to be rendered on the cubes. I also have two pictures: 1st: when the program begins: 2nd: after clicking "Star Game" where you can see the texture rendered in all of the cubes: The goal is for more 2 types of textures and all of them render in random cubes.
You can create more than 1 texture object. glBindTexture binds a named texture to a texturing target, that is a global state. glTexImage2D specify a two-dimensional texture image for the texture, which is currently bound to the specified target. glTexParameter set parameter to the texture object. I recommend to write a function which loads a texture form a file to a given texture object (name id): void loadTextureFromFile(const char *filename, unsigned int texture) { glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // load and generate the texture int width, height, nrChannels; unsigned char *data = stbi_load(filename, &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); //glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture" << std::endl; } stbi_image_free(data); } const char* filename1 = "salt_on_spoon.bmp"; const char* filename2 = ...; const char* filename3 = ...; unsigned int tob[3]; int main(int argc, char **argv) { // [...] glGenTextures(3, &tob[0]); loadTextureFromFile(filename1, tob[0]); loadTextureFromFile(filename2, tob[1]); loadTextureFromFile(filename3, tob[2]); // [...] } When two-dimensional texturing is enabled, then the image of the texture object, which is currently bound to the target GL_TEXTURE_2D is wrapped on the mesh. You've to bind the proper texture object, before you draw the geometry. e.g: for(int i=0;i<8;i++) { for(int j=0;j<8;j++) { glBindTexture(GL_TEXTURE_2D, tob[0]); glPushMatrix(); glTranslatef(0.0f+e,0.0f+f,0.0f); //right and below glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d myglutSolidCube(2.25); glPopMatrix(); glBindTexture(GL_TEXTURE_2D, tob[1]); glPushMatrix(); glTranslatef(0.0f-e,0.0f+f,0.0f); //left and below glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d myglutSolidCube(2.25); glPopMatrix(); glBindTexture(GL_TEXTURE_2D, tob[2]); glPushMatrix(); glTranslatef(0.0f+e,0.0f-f,0.0f); //right and up glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d myglutSolidCube(2.25); glPopMatrix(); glBindTexture(GL_TEXTURE_2D, tob[0]); glPushMatrix(); glTranslatef(0.0f-e,0.0f-f,0.0f); //left and up glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d myglutSolidCube(2.25); glPopMatrix(); f += -2.63; } f=0; e+=2.63; } Note, the distribution of the textures is just an example. You've to ensure that unsigned int tob[3]; is declared before, in global namespace.
Straight copying input texture to output produces unexpected results in OpenGL
This is my first OpenGL program. I have written almost the same thing in WebGL which it works. I am translating that to OpenGL. However I am using sample code from many places and I don't know if everything makes sense. Obviously there's something wrong which I can't figure out and causes the output to be close but still different. I am creating a 2x2 texture filling it with data { 1.0,2.0,3.0,4.0 } and using a simple shader to copy to an output texture of the same size. What is get is: Result: [1,2,0,4,] Below I'm pasting my code and my shader scripts as well. Thanks for reviewing this. Vertex Shader: #version 330 core layout (location = 0) in vec3 position; layout (location = 1) in vec2 texCoord; out vec2 TexCoord; void main() { gl_Position = vec4(position, 1.0f); TexCoord = texCoord; } Frag Shader: #version 330 core precision highp float; in vec2 TexCoord; out vec4 TexelValue; // Texture samplers uniform sampler2D A; void main() { TexelValue = vec4(texture(A, TexCoord).r); } Code with error checking removed: // Window dimensions const GLuint WIDTH = 800, HEIGHT = 600; void createTexture(GLuint texture, int width, int height, GLint internalFormat, GLenum format, GLenum type, const void *data) { glBindTexture(GL_TEXTURE_2D, texture); // Set our texture parameters 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_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // set texenv to replace instead of the default modulate glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, data); } void uploadAndBindGeometry(const void* vertices, int verticesByteLength) { GLuint VBO, VAO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, verticesByteLength, vertices, GL_STATIC_DRAW); // Position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid *)0); glEnableVertexAttribArray(0); // Texture Coordinate attribute glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid *)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); } void bindInputTexture(int index, GLuint texture, GLint location) { glActiveTexture(GL_TEXTURE0 + index); glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(location, index); } void initFBO(GLuint *fb, int width, int height) { glGenFramebuffersEXT(1, fb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, *fb); glViewport(0, 0, width, height); } // The MAIN function, from here we start the application and run the game loop int main() { glfwInit(); GLuint fb; // Set all the required options for GLFW glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Create a GLFWwindow object that we can use for GLFW's functions GLFWwindow *window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); int screenWidth, screenHeight; glfwGetFramebufferSize(window, &screenWidth, &screenHeight); glfwMakeContextCurrent(window); // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions glewExperimental = GL_TRUE; glewGetExtension("GL_ARB_texture_float"); glewGetExtension("GL_EXT_framebuffer_object"); glewGetExtension("GL_ARB_color_buffer_float"); glDisable(GL_BLEND); glDisable(GL_ALPHA); glDisable(GL_DEPTH); glDisable(GL_STENCIL); // Build and compile our shader program Shader ourShader("core.vs", "core.frag"); // Set up vertex data (and buffer(s)) and attribute pointers GLfloat vertices[] = { // Positions // Texture Coords 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // Top Right 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Bottom Right -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // Bottom Left -1.0f, 1.0f, 0.0f, 0.0f, 1.0f // Top Left }; uploadAndBindGeometry(vertices, sizeof(vertices)); // Load and create textures float adata[] = { 1.0,2.0,3.0,4.0 }; int adims[] = { 2, 2 }; int cdims[] = { 2, 2 }; float cdata[2 * 2] = { 0 }; // =================== // Texture // =================== GLuint texture[2]; glGenTextures(2, &texture[0]); createTexture(texture[0], adims[1], adims[0], GL_R32F, GL_RED, GL_FLOAT, (void*)adata); createTexture(texture[1], cdims[1], cdims[0], GL_R32F, GL_RED, GL_FLOAT, (void*)NULL); // Draw the triangle ourShader.Use(); initFBO(&fb, cdims[1], cdims[0]); glBindTexture(GL_TEXTURE_2D, texture[1]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0); int locationA = glGetUniformLocation(ourShader.Program, "A"); bindInputTexture(0, texture[0], locationA); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glFlush(); // read output glReadBuffer(GL_COLOR_ATTACHMENT0); glReadPixels(0, 0, cdims[1], cdims[0], GL_RED, GL_FLOAT, cdata); std::cout << "Result: ["; for (int i = 0; i < 2 * 2; ++i) { std::cout << cdata[i] << ","; } std::cout << "]" << std::endl; // Terminate GLFW, clearing any resources allocated by GLFW. glfwTerminate(); return EXIT_SUCCESS; }
Obviously there's something wrong which I can't figure out and causes the output to be close but still different. Changed my coordinates to these and it started working. Of course I don't understand why When you draw the rectangle, then you use the primitive type triangle stripe GL_TRIANGLE_STRIP The order of the vertex coordinates in a triangle strip looks like this: 0 2 4 x x x | / | / | | / | / | x x x 1 3 5 The vertices of your question GLfloat vertices[] = { // Positions // Texture Coords 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // Top Right 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // Bottom Right -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // Bottom Left -1.0f, 1.0f, 0.0f, 0.0f, 1.0f // Top Left }; have the following order: 3 0 x x | | | | x-----x 2 1 The primitives with this order would draw a quad, by the use of the primitive type GL_TRIANGLE_FAN The new and changed vertices GLfloat vertices[] = { -1.0, 1.0, 0.0, 0.0, 1.0, // upper left -1.0, -1.0, 0.0, 0.0, 0.0, // lower left 1.0, 1.0, 0.0, 1.0, 1.0, // upper right 1.0, -1.0, 0.0, 1.0, 0.0 // lower right }; have the proper order of a triangle strip: 0 2 x x | / | | / | x x 1 3
Changed my coordinates to these and it started working. Of course I don't understand why: GLfloat vertices[] = { -1.0, 1.0, 0.0, 0.0, 1.0, // upper left -1.0, -1.0, 0.0, 0.0, 0.0, // lower left 1.0, 1.0, 0.0, 1.0, 1.0, // upper right 1.0, -1.0, 0.0, 1.0, 0.0 // lower right };
loading bmp images OPENGL 3.x - only loading one pixel?
So Im having a bit of trouble loading texture images. I am not exactly sure what I could be doing wrong. It seems to only be reading the last pixel and I am not sure why? Any help is appreciated. Here is my code: #include "Angel.h" #include <glew.h> #include <glut.h> #include <typeinfo> #include <iostream> #include <stdlib.h> #include <stdio.h> #include <stdint.h> using namespace std; vec4 gridLines[] = { vec4(-0.5, -0.5, 0.0, 1.0), //v1 vec4(0.5, -0.5, 0.0, 1.0), //v2 vec4(-0.5, 0.5, 0.0, 1.0), //v3 vec4(0.5, 0.5, 0.0, 1.0), //v4 }; GLuint vertexID[3]; GLuint bufferID2; GLuint ProjectionLocation, ModelViewLocation; mat4 instance; //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- float roundTo(float value, int digits)//Ensures rounding is done correct { //check to see if the value is very close to zero if ((int)(value*10.0) == 0){ return 0.0; } double factor = pow(10.0, digits - ceil(log10(fabs(value)))); return round(value * factor) / factor; } void init(void) //Initialize Buffers for all objects { //1. Load shaders and use the resulting shader program GLuint program = InitShader("vshader81.glsl", "fshader81.glsl"); glUseProgram(program); GLuint vPosition = glGetAttribLocation(program, "vPosition"); GLuint vColor = glGetAttribLocation(program, "vColor"); glGenVertexArrays(1, &vertexID[1]); vec4 colors2[] = { vec4(1.0, 1.0, 1.0, 1.0), //1 vec4(1.0, 1.0, 1.0, 1.0), //2 vec4(1.0, 1.0, 1.0, 1.0), //3 vec4(1.0, 1.0, 1.0, 1.0), //4 }; // Create and initialize a buffer object glBindVertexArray(vertexID[1]); glGenBuffers(1, &bufferID2); glBindBuffer(GL_ARRAY_BUFFER, bufferID2); glBufferData(GL_ARRAY_BUFFER, sizeof(gridLines)+sizeof(colors2), NULL, GL_STATIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(gridLines), gridLines); glBufferSubData(GL_ARRAY_BUFFER, sizeof(gridLines), sizeof(colors2), colors2); glEnableVertexAttribArray(vPosition); glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); GLuint textureid; // Texture coordinates vec4 tex_coords[] = { vec4(-0.5, -0.5, 0.0, 1.0), //v1 vec4(0.5, -0.5, 0.0, 1.0), //v2 vec4(-0.5, 0.5, 0.0, 1.0), //v3 vec4(0.5, 0.5, 0.0, 1.0), //v4 }; glGenTextures(1, &textureid); glBindTexture(GL_TEXTURE_2D, textureid); /***********************************************/ const char * imagepath = "checkboard2.bmp"; // Data read from the header of the BMP file unsigned char header[54]; // Each BMP file begins by a 54-bytes header unsigned int dataPos; // Position in the file where the actual data begins unsigned int width, height; unsigned int imageSize; // = width*height*3 // Actual RGB data unsigned char * data; // Open the file FILE * file = fopen(imagepath, "rb"); if (!file) { printf("Image could not be opened\n"); } if (fread(header, 1, 54, file) != 54){ // If not 54 bytes read : problem printf("Not a correct BMP file\n"); } if (header[0] != 'B' || header[1] != 'M'){ printf("Not a correct BMP file\n"); } cout << "great.." << endl; // Read ints from the byte array dataPos = *(int*)&(header[0x0A]); imageSize = *(int*)&(header[0x22]); cout << "Image Size: " << imageSize << endl; width = *(int*)&(header[0x12]); cout << "width: " << width << endl; height = *(int*)&(header[0x16]); // Some BMP files are misformatted, guess missing information if (imageSize == 0) imageSize = width*height * 3; // 3 : one byte for each Red, Green and Blue component if (dataPos == 0) dataPos = 54; // The BMP header is done that way // Create a buffer data = new unsigned char[imageSize]; // Read the actual data from the file into the buffer fread(data, 1, imageSize, file); //Everything is in memory now, the file can be closed fclose(file); //GLuint Texture = loadBMP_custom("brick_converted.bmp"); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data); // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //glActiveTexture(GL_TEXTURE0); GLuint vTexCoord = glGetAttribLocation(program, "vTexCoord"); glEnableVertexAttribArray(vTexCoord); glVertexAttribPointer(vTexCoord, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(gridLines))); glUniform1i(glGetUniformLocation(program, "texture"), 0); //4. Bind all Buffers glBindVertexArray(0); //5.Set Background Color glClearColor(0.5, 0.5, 0.5, 0.0); // background } //---------------------------------------------------------------------------- // Draw on Screen //---------------------------------------------------------------------------- void paintOnScreen() { glBindVertexArray(vertexID[1]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } void display(void) //Display to screen { //1.Clear the window glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_CULL_FACE); //2.Translations/Rotations/Projections etc.. glViewport(0, 0, 300, 300); //3.Draw Objects paintOnScreen(); glBindVertexArray(0); //3.Force OpenGL to render glFlush(); } void reshape(int width, int height) { glViewport(0, 0, width, height); //aspect = GLfloat(width)/height; } void keyboard(unsigned char key, int x, int y) { switch (key) { case 033: //ESC exit(EXIT_SUCCESS); break; } } //---------------------------------------------------------------------------- int main(int argc, char **argv) { // Initialize glut library glutInit(&argc, argv); // Create the window glutInitDisplayMode(GLUT_RGBA); glutInitWindowSize(300, 300); glutInitWindowPosition(300, 200); glutCreateWindow("Test"); // Initialize glew library glewInit(); // Your own initialization init(); // Set callback functions glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); // Start the main loop glutMainLoop(); return 0; } and my fragment shader: #version 150 in vec2 texCoord; out vec4 fColor; uniform sampler2D texture; void main() { fColor = texture2D( texture, texCoord ); } and my vertex shader: #version 150 in vec4 vPosition; in vec2 vTexCoord; out vec2 texCoord; void main() { texCoord = vTexCoord; gl_Position = vPosition; }
You do not specify the texture coords correctly. You define an tex_coords array, but this data is never copied to a VBO (or referenced in the code at all). You set up the vTexCoord attribute pointer to point to the place in the VBO where you copied your colors2 data array, which is all 1.0, so you are constantly accessing the very last texel.