16. OpenGL Texturing
Because it is so much simpler at the moment, I am going to show you how to use
textures under Windows only, the only thing is the actual, The original loading
code I was using had it’s limitations so I have reworked it to make it more general.
But back to the actual texturing, because it is under windows we have to include
the windows header file, then we also need to add the stdio header file.
using GLuint we create a variable for the texture, called ‘texture’, but you can call it
whatever you wish.
in the ‘display’ function we first set the variable ‘texture’ to the actual
loaded image using:
texture = LoadTexture( “texture.raw”, 256, 256 );
where 256, 256 is the width and the height of the file respectively.
then we enable the 2D Texturing, this is done with:
glEnable( GL_TEXTURE_2D );
and bind the texture with:
glBindTexture( GL_TEXTURE_2D, texture );
then after drawing everything we need with the texture, we clear it to save
system resources.
——————————————————————————
Section 1: The loading of the texture:
GLuint LoadTexture( const char * filename, int width, int height )
{
GLuint texture;
unsigned char * data;
FILE * file;
The following code will read in our RAW file
file = fopen( filename, “rb” ); We need to open our file
if ( file == NULL ) return 0; If our file is empty, set our texture to empty
data = (unsigned char *)malloc( width * height * 3 ); assign the nessecary memory for the texture
fread( data, width * height * 3, 1, file ); read in our file
fclose( file ); close our file, no point leaving it open
glGenTextures( 1, &texture ); then we need to tell OpenGL that we are generating a texture
glBindTexture( GL_TEXTURE_2D, texture ); now we bind the texture that we are working with
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); set texture environment parameters
The parameter GL_MODULATE will blend the texture with whatever is underneath, setting it to GL_DECAL
will tell the texture to replace whatever is on the object.
here we are setting what textures to use and when. The MIN filter is which quality to show
when the texture is near the view, and the MAG filter is which quality to show when the texture
is far from the view.
The qualities are (in order from worst to best)
GL_NEAREST
GL_LINEAR
GL_LINEAR_MIPMAP_NEAREST
GL_LINEAR_MIPMAP_LINEAR
The two mipmap variables only work in textures with generated mipmaps, so you will see that in action
in a later tutorial.
And if you go and use extensions, you can use Anisotropic filtering textures which are of an
even better quality, but this will do for now.
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
Here we are setting the parameter to repeat the texture instead of clamping the texture
to the edge of our shape.
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
Generate the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
free( data ); free the texture
return texture; return the texture data
}
——————————————————————————–
Section 2: Cleaning Up:
If we decide not to clean up after our work, you will find that the program will inevitably
slow down your computer, taking more and more memory.
void FreeTexture( GLuint texture )
{
glDeleteTextures( 1, &texture ); Delete our texture, simple enough.
}
——————————————————————————-
Section 3: Texture Coordinates
This is how texture coordinates are arranged
0,1 —– 1,1
| |
| |
| |
0,0 —– 1,0
With 0,0 being the bottom left and 1,1 being the top right.
Now the point of using the value 0,1 instead of 0,10, is so that it is mapping 1 texture to the
coordinates. Changing that to 10 would then try to map 10 textures to the one quad. Which because
I have the repeat parameter set in our texture, it would draw 10 across and 10 down, if we had
it clamped, we would be still drawing 1. The repeat function is good for things like
brick walls.
To assign texture coordinates to a vertex look at the following code:
glBegin (GL_QUADS);
glTexCoord2d(0.0,0.0);
with our vertices we have to assign a texcoord so that our texture has some points to draw to
glVertex2d(-1.0,-1.0);
glTexCoord2d(1.0,0.0);
glVertex2d(+1.0,-1.0);
glTexCoord2d(1.0,1.0);
glVertex2d(+1.0,+1.0);
glTexCoord2d(0.0,1.0);
glVertex2d(-1.0,+1.0);
glEnd();
For every vertex, we are assigning a texture coordinate that corresponds with it. Keep in mind
that this does not mean that if a vertex is a -10, 20, the texture coordinates will be -10, 20.
They will infact be something along the lines of 0,1.
———————————————————————
So now you should have a rough idea of the basics associated with texturing.
If you have any questions, feel free to email me at swiftless@gmail.com
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. |
// Because it is so much simpler at the moment, I am going to show you how to use // textures under Windows only, the only thing is the actual, The original loading // code I was using had it’s limitations so I have reworked it to make it more general. // But back to the actual texturing, because it is under windows // using GLuint we create a variable for the texture, called // in the ‘display’ function we first set the variable ‘texture’ // then after drawing everything we need with the texture, we // —————————————————————————— //GLuint LoadTexture( const char * filename, int width, int // The following code will read in our RAW file // glGenTextures( 1, &texture ); //then we need to tell OpenGL //here we are setting what textures to use and when. The MIN //The qualities are (in order from worst to best) // The two mipmap variables only work in textures with generated //And if you go and use extensions, you can use Anisotropic // glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, //Here we are setting the parameter to repeat the texture // glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, //Generate the texture
//——————————————————————————– //If we decide not to clean up after our work, you will find that
//——————————————————————————- //This is how texture coordinates are arranged // With 0,0 being the bottom left and 1,1 being the top right. // Now the point of using the value 0,1 instead of 0,10, is so // To assign texture coordinates to a vertex look at the //For every vertex, we are assigning a texture coordinate //——————————————————————— //So now you should have a rough idea of the basics associated #include <GL/gl.h> GLuint texture; //the array for our texture GLfloat angle = 0.0; //function to load the RAW file GLuint LoadTexture( const char * filename, int width, int //The following code will read in our RAW file glGenTextures( 1, &texture ); //generate the texture with //here we are setting what textures to use and when. The MIN //The qualities are (in order from worst to best) //And if you go and use extensions, you can use Anisotropic //Here we are setting the parameter to repeat the texture //Generate the texture void FreeTexture( GLuint texture ) void square (void) {
//This is how texture coordinates are arranged // With 0,0 being the bottom left and 1,1 being the top right. // Now the point of using the value 0,1 instead of 0,10, is so void display (void) { int main (int argc, char **argv) { //Load our texture glutMainLoop (); //Free our texture return 0; |
Is there any way to Blend Textures??
My searches have all shown that .RAW is the modern camera’s equivalent to a negative but nothing has revealed by what means I might convert an image to that filetype. Should I figure out how to use BMP instead?
Many thanks
can u tell me y u allocated hiegth*width*3 bytes of memry??……..especialyy ” *3 “??
Because each pixel color are stored 3 bytes ( RGB ), so, Height x Width = Dimension, Dimension x 3 = Total bytes
Because it uses the RGB system, one byte for each primary color, red,green and blue.
Hi Swiftless,
Your tutorials are awesome and have helped me alot!
Thank you very much for all your great work.
I don’ jnow about the others, but when I try to open the archives of the textures, WinRar tells me they’re corrupted or damaged… Can you upload correctly the two files?
you tutorial 100% rate and
i want function load bmp like load file.raw
hey em writing ur code as it is but it gives a yellow window screen as output. can u plz tell me what is the problem?
Hi Swiftless!
I wrote a class-based image loader, but I have many problems with that.
First, it loads the RAW file with its parameters, but if I run my program I just see a blank white screen.
Second, if I don’t set the parameters of the bitmap outside of the load-function, every parameters will be 0.
Here is the code:
// ctexture.h
#include
#include
using namespace std;
class CTexture
{
public:
int Load(char* Filename, int Width, int Height);
void SetActive();
void Delete();
unsigned int GetID();
int Width;
int Height;
unsigned int ID;
int GetWidth();
int GetHeight();
private:
GLuint Texture;
unsigned char* Data;
};
int CTexture::Load(char* Filename, int Width, int Height)
{
FILE* File;
File=fopen(Filename,”rb”);
Data=(unsigned char*)malloc(Width*Height*3);
fread(Data,Width*Height*3,1,File);
fclose(File);
glGenTextures(1,&Texture);
glBindTexture(GL_TEXTURE_2D,Texture);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,Width,Height,0,GL_RGB,GL_UNSIGNED_BYTE,Data);
free(Data);
return Texture;
}
void CTexture::SetActive()
{
glBindTexture(GL_TEXTURE_2D,ID);
}
void CTexture::Delete()
{
glDeleteTextures(1,&ID);
}
unsigned int CTexture::GetID()
{
return ID;
}
int CTexture::GetWidth()
{
return Width;
}
int CTexture::GetHeight()
{
return Height;
}
// main.cpp
#include
#include
#include
#include
#include
using namespace std;
CTexture Default;
GLvoid InitTextures(GLvoid)
{
glEnable(GL_TEXTURE_2D);
Default.Width=256;
Default.Height=256;
Default.ID=34;
Default.Load(“default.raw”,Default.Width,Default.Height);
cout<<"Image width is: "<<Default.Width<<endl;
cout<<"Image height is: "<<Default.Height<<endl;
cout<<"ID: "<<Default.ID<<endl;
}
void Display(void)
{
InitTextures();
glClearColor(0.0f,0.0f,0.0f,0.0f);
glClear(GL_COLOR_BUFFER_BIT);
Default.SetActive();
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f); glVertex2f(-1.0f,1.0f);
glTexCoord2f(1.0f,0.0f); glVertex2f(1.0f,1.0f);
glTexCoord2f(1.0f,1.0f); glVertex2f(1.0f,-1.0f);
glTexCoord2f(0.0f,1.0f); glVertex2f(-1.0f,-1.0f);
glEnd();
glFlush();
}
int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE);
glutCreateWindow("OpenGL");
glutDisplayFunc(Display);
glutMainLoop();
}
Otherwise, I use Microsoft Visual C++ 2008 for programming.
I don't know what is the problem.
Thank you very much!
I found the solution for the problem, I don’t need any help now.
hi after running this sample code i got only white square which one is rotating. i placed raw file to same folder.but there is no error and no texture.
Hi, Swiftless!
(sorry for my english because i’m hungarian and i’m 13 years old)
This is a great tutorial. I tried, it works. I tried it on flat surface and cube. But this program can read only one texture file. How can I do that read more than one texture file? Thanks!
Hi Janus,
That’s a good effort, I started OpenGL at about that age.
To make it work with multiple textures, you need to create another variable to store the new texture. You then call virtually the exact same line of code, only this time you set the new texture variable and provide the path to the new texture.
Eg:
GLuint texture1 = loadTexture(first_path);
GLuint texture2 = loadTexture(second_path);
Cheers,
Swiftless
Hi, Swiftless!
This idea is very good.
It works perfectly.
Thank you very much.
(Nagyon szépen köszönöm! :D)
Hi!
How can I change the texture image?
If I change the path-name, I’ll get either get a blank white square or the same texture.bmp file that I downloaded from this site…
Can anyone help me please..
Hi Nikhi,
It sounds like you are typing your path wrong. If the texture exists, and it is a .raw file, then you will see it. Unless there is something horribly wrong with your drivers. But I’d be more willing to put my money on a minor programming error.
Cheers,
Swiftless
First sorry for my bad english. Second, congratulations for tutorial, very good. For loading bitmaps with your code increase before “fread(data, width * height * 3, 1, file)” a ‘jump’ in bitmap file:
example:
unsigned long size = width * height * 3;
fseek(file, 52, SEEK_CUR);
fread(data, size, 1, file);
‘file = bitmap’
’52 = size of header (only bitmaps)’
‘SEEK_CUR = relation of moviment the cursor ‘
after you corrige the color (BGR for RGB)
char aux;
for(int bit_pixel = 0; bit_pixel < size; bit_pixel += 3){
aux = data[bit_pixel];
data[bit_pixel] = data[bit_pixel + 2];
data[bit_pixel + 2] = aux;
}
continue with your work, very good.
by
Hey Bruno,
That makes sense, usually when working with BMP files, I use the header to get the width and height, but if you know all the details, then you can definitely skip the header and adjust the format from BGR to RGB.
Cheers,
Swiftless
unsigned long size = width * height * 3;
fseek(file, 51, SEEK_CUR); // <- here must be 51, not 52
fread(data, size, 1, file);
after some playing with constants, i've caught right one, one my machine this causing to be a right colored bitmap
the texture.raw file, where do i get that file to run this tutorial?
Under the source code there is a link:
Download Texture(.RAW file)
http://www.swiftless.com/tutorials/opengl/texture_under_windows.html/cplusplus/texture.zip
I came across this site a while ago, and I’ve been reading your tutorials. I already made a texture loader, and stumbled across your code. I noticed how it’s very similar, but yours is also somewhat defective. In my computer, as well as others, if not all, BMP image data is stored in BGR format, instead of RGB. Your code loads a BMP, but miscolored. Here’s my code, which fixes this issue, allowing properly colored BMP textures:
GLuint ltex( const char * filename, int width, int height ){
GLuint t;
char * data = new char[width * height * 3];
FILE * file;
file = fopen( filename, “rb” );
if ( file == NULL ) return 0;
fread( data, width * height * 3, 1, file );
fclose( file );
char * data2 = new char[width * height * 3];
for(int i = 0; i < width * height * 3; i+=3){
data2[i] = data[i + 2];
data2[i+1] = data[i + 1];
data2[i+2] = data[i];
}
glGenTextures( 1, &t );
glBindTexture( GL_TEXTURE_2D, t );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,GL_RGB, GL_UNSIGNED_BYTE, data2);
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data2 );
delete[] data;
delete[] data2;
return t;
}
Sorry, ignore this. I posted the wrong one. This one is from a different project, and has several errors…
Hi Daniel,
My code doesn’t load a bitmap file, it loads a RAW file which is stored in RGB interleaved format. If your code above does read a BMP file correctly, I would have to ask where the BITMAP HEADER is read in? Otherwise you will get extra data at the start of your file which will be loaded into your texture.
Cheers,
Swiftless
Dear Swiftless,
could you please explain to us about the mismatch colour and how to fix it, I am experiencing the same problem. Thanks.
Hi, great tutorial :D.
Just one thing though…Mine turns up as just a blank white square. So, I’m wondering, where am I supposed to put the texture I want to use so that it will load correctly?
Sorry if it’s a silly question :X
Hey Barry,
The textures can be wherever you like, the file paths can be either relative or absolute, but for this tutorial, I place them in the same folder as the executable.
Cheers,
Swiftless
glEnable(GL_TEXTURE_2D);
For future readers: make sure the file path has forward slashes (/) instead of the standard (\). This is a really easy mistake that may save you some headache.
Btw, started learning opengl here. Now I have an ios app out. Check out “Fission HD” on YouTube. Thanks
About my last comment: I just read your tutorial “OpenGL Texture Coordinate Generation” and everything is a little bit more clear to me now! Thanks!
Hi Swiftless!
Great tutorial, as always!.
I have a sugestion for your OpenGL tutorials. I (humble beginner) still don’t understand why this texturing example won’t work on a cube, sphere or torus (the mapping seems to be different) so when I try any of these shapes I get flat colors. Maybe you could post some very basic examples of different mappings for different shapes? Just a suggestion though. 🙂
Beatriz / future readers:
Trying something like that given below to map the texture to different objects. The rest of the code can remain the same. I hope it makes things a little clearer.
shader.vert:
varying vec2 Pos;
void main() {
// Set the position of the current vertex
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
Pos = vec2(gl_Vertex.x, gl_Vertex.y);
}
shader.frag:
uniform sampler2D color_texture;
varying vec2 Pos;
void main() {
// Set the output color of our current pixel
gl_FragColor = texture2D(color_texture, Pos);
}