Sign in to follow this  
Merowingian

OpenGL Texturing in OpenGL

Recommended Posts

Hey, I've got some problems displaying textures on a quadrangle in my program. But first I would like to make sure that I'm getting certain basics right. First, let's assume I have just called glGenTextures(3, textures), textures being an integer array of size 3. What will happen if I call glTexImage2D right after that? Will the texture data I use in this function be then associated with the first unoccupied texture name, in this case textures[0]? What if I don't use glGenTextures beforehand? Will texture names be generated automatically at each call of glTexImage3D? By which system will they be generated? Second: I want to use two functions, each one should draw a single textured object with its own texture. So the two functioned will be called in the display() function of OpenGL, followed by a flush command, since the two objects belong to the same scene. Let's look at one function: It will call glGenTextures, using a local int array as function input. Next, it will call glTexImage2D with a pointer to the texture data of course. Then the vertex data for the geometries will be specified together with the appropriate texture coordinates. At the end of the function the textures used for this object should be cleared using glDelTextures so they won't be placed more than once, since the drawing function will be called at every display call. I have a question here: texturing belongs to the rasterisation stage of the rendering pipeline. I would expect OpenGL not to perform any actual texturing before all vertex data prior to the flush command has been specified. And this won't happen before the second function has been executet also. But by then the textures for the first object will be cleared already, won't they? I know one could specify the textures in the initGL() function, but I would like everything concerning the drawing of a specific object to be in the drawing function for that object for a better structure and overview. This obviously requires creating and clearing textures at every call. Thanks in advance, cheers Marvin

Share this post


Link to post
Share on other sites
Before you can call glTexImage, you must bind some valid texture name with glBindTexture. It is not until the first time you bind a previously-unused texture name, the corresponding texture object is actually created. You can then initialize said object by calling glTexImage.

Share this post


Link to post
Share on other sites
Hey, that's good to know.

Just changed the order of commands accordingly.

Seem to be making real progress now.

But I'm now getting some access violation error with glTexImage2D. But I'm sure the data array passed on got the right size, can't be too big.

Here's the command sequence surrounding glTexImage2D:

const unsigned int textWidth = 256;
const unsigned int textHeight = 256;
char* texture;
shelf.getSurface(texture); // stores the shelf's surface texture into texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textWidth, textHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
free(texture);

Share this post


Link to post
Share on other sites
Well guys,

I've made a slight change to it:



const unsigned int textWidth = 256;
const unsigned int textHeight = 256;
const unsigned int bytesPerPix = 3;
const unsigned int textBytes = textWidth * textHeight * bytesPerPix;
char* texture = new char[textBytes];
// shelf.getSurface(texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textWidth, textHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
free(texture);

As you can see I've now commented the line "shelf.getSurface(texture);".
This version works fine, but the shelf remains blank of course, since there is no texture loaded into texture. I have found out that in C++ you are still allowed to overstep the size of an array, which you shouldn't be:


unsigned int imagePixs = width * height;
unsigned int imageBytes = imagePixs * bytesPerPix;
char* image = new char[imageBytes];
cout << image[imageBytes + 5];

For some strange reason, this sequence doesn't give me an error. And that's exactly the problem. The function shelf.getSurface is supposed to write the char* of the shelf into the char* texture (call by reference).
And for some reason, glTexImage2D seems to think texture is too big. But texture, after the call of shelf.getSurface should be an array of exactly the proper size. I've "verbally" made sure of that with commands like those above, calculating the imageBytes and creating an array of the size imageBytes. But since you cannot rely on C++ to make it really an array of that restricted size, it seems like it practically could have any size bigger than expected, no matter what you put into "new char[imageBytes]".
I really don't get it. What should I do?

Share this post


Link to post
Share on other sites
Well guys,

I've made a slight change to it:



const unsigned int textWidth = 256;
const unsigned int textHeight = 256;
const unsigned int bytesPerPix = 3;
const unsigned int textBytes = textWidth * textHeight * bytesPerPix;
char* texture = new char[textBytes];
// shelf.getSurface(texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textWidth, textHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
free(texture);

As you can see I've now commented the line "shelf.getSurface(texture);".
This version works fine, but the shelf remains blank of course, since there is no texture loaded into texture. I have found out that in C++ you are still allowed to overstep the size of an array, which you shouldn't be:


unsigned int imagePixs = width * height;
unsigned int imageBytes = imagePixs * bytesPerPix;
char* image = new char[imageBytes];
cout << image[imageBytes + 5];

For some strange reason, this sequence doesn't give me an error. And that's exactly the problem. The function shelf.getSurface is supposed to write the char* of the shelf into the char* texture (call by reference).
And for some reason, glTexImage2D seems to think texture is too big. But texture, after the call of shelf.getSurface should be an array of exactly the proper size. I've "verbally" made sure of that with commands like those above, calculating the imageBytes and creating an array of the size imageBytes. But since you cannot rely on C++ to make it really an array of that restricted size, it seems like it practically could have any size bigger than expected, no matter what you put into "new char[imageBytes]".
I really don't get it. What should I do?

Share this post


Link to post
Share on other sites
Well guys,

I've made a slight change to it:



const unsigned int textWidth = 256;
const unsigned int textHeight = 256;
const unsigned int bytesPerPix = 3;
const unsigned int textBytes = textWidth * textHeight * bytesPerPix;
char* texture = new char[textBytes];
// shelf.getSurface(texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textWidth, textHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
free(texture);

As you can see I've now commented the line "shelf.getSurface(texture);".
This version works fine, but the shelf remains blank of course, since there is no texture loaded into texture. I have found out that in C++ you are still allowed to overstep the size of an array, which you shouldn't be:


unsigned int imagePixs = width * height;
unsigned int imageBytes = imagePixs * bytesPerPix;
char* image = new char[imageBytes];
cout << image[imageBytes + 5];

For some strange reason, this sequence doesn't give me an error. And that's exactly the problem. The function shelf.getSurface is supposed to write the char* of the shelf into the char* texture (call by reference).
And for some reason, glTexImage2D seems to think texture is too big. But texture, after the call of shelf.getSurface should be an array of exactly the proper size. I've "verbally" made sure of that with commands like those above, calculating the imageBytes and creating an array of the size imageBytes. But since you cannot rely on C++ to make it really an array of that restricted size, it seems like it practically could have any size bigger than expected, no matter what you put into "new char[imageBytes]".
I really don't get it. What should I do?

Share this post


Link to post
Share on other sites
Well I can't say for sure what the problem is... but I'm not sure what the method getSurface() does exactly. In the first example, you created the texture with just:

char *texture;

and then proceeded to call:

shelf.getSurface(texture)

Now what I'm wondering is, is whether or not the getSurface() method actually wants the pointer you pass in to already be pointing to valid memory, because if you don't call:

texture = new char[...]

then it doesn't point to anything, and the only way the getSurface function could do anything at all useful would be if its declaration was:

void getSurface(char *& ReferenceToPointer);

Otherwise the uninitialized pointer is useless to the function.

Share this post


Link to post
Share on other sites
OK, again:

I'm using an Object of the class Shelf. The class Shelf is supposed to describe all important properties of a shelf in an abstract way, independent of the rendering process. That is dimensions, position, thickness etc. and of course, the surface, represented by an array of characters representing the rgb-values of a each rectangle on the surface. In other words, the surface of the shelf is what the rendering pipeline will use as the shelf's texture.

So shelf being an object of the Shelf class, the function call getSurface(char* &dest) will take the "texture" argument "call by reference" and put the surface's pointer value into it, so after calling getSurface you should be able to use the shelf's surface via texture.

Now as I was saying, I made sure that the texture array has a fixed and unchangeable size, not to overstep the allowed number of characters.

But for some strange reason, after applying getSurface to texture and passing the new texture on to glTexImage2D for the texture data required, I get an access violation error, as if to say that "surface" (equals texture) is too big.

Well I don't get how texture could be "too big", since I extra made sure it doesn't.

You guys might wanna know how surface gets its content.
Well here's the code setting the shelf in the main.cpp file:


void setShelf() {

char* ppmFn = "holz.ppm";
PPMReader ppm = PPMReader(ppmFn);
char* surface;
ppm.getImage(surface);
shelf = Shelf(1.5, 1.5, 1.5, surface);

}

PPMReader's constructor loads the ppmFile specified by ppmFn into ppm's attributes height, width, bitdepth and image (the actual image data, i.e. an char*).
The last three commands place the ppm's image pointer into "surface", very much like getSurface would do, and then pass on surface to Shelf's constructor. Shelf's constructor will set the x-, y- and z-position (the first three arguments) and the surface pointer as passed on to it by the arguments.

I'll give you the functions to make sure you understand:


PPMReader::PPMReader(char * filename) {
loadPPMFile(filename);
}

void PPMReader::loadPPMFile(char * filename) {

const int readBufferSize = 20;
ifstream ifs;
char buffer[readBufferSize];
ifs.open(filename, ifstream::binary);

ifs.getline(buffer, readBufferSize);
ifs.getline(buffer, readBufferSize, ' ');
width = atoi(buffer);
ifs.getline(buffer, readBufferSize);
height = atoi(buffer);
ifs.getline(buffer, readBufferSize);
unsigned int bitDepth = atoi(buffer);
bytesPerPix = (bitDepth == 255) ? 3 : 6;

unsigned int imagePixs = width * height;
unsigned int imageBytes = imagePixs * bytesPerPix;
image = new char[imageBytes];
ifs.read(image, imageBytes);
ifs.close();

}


Shelf::Shelf(float x, float y, float z, char* surface) {
setPosition(x, y, z);
this->surface = surface;
}


The getSurface of Shelf is implemented as inline void in the header file:

inline void getSurface(const char* &dest) { dest = surface; }


...as is the getImage of PPMReader:

inline void getImage(char* &dest) { dest = image; };



Got it all? My problem is still the same. I can assure you, that my ppm-file's size IS 256x256 and that the failbit used in ifstream in PPMReader is 0 at the end of loadPPM.

So somewhere in my main.cpp I was having the following code:


const unsigned int textWidth = 256;
const unsigned int textHeight = 256;
const unsigned int bytesPerPix = 3;
const unsigned int textBytes = textWidth * textHeight * bytesPerPix;
char* texture = new char[textBytes];
// shelf.getSurface(texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textWidth, textHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
free(texture);


Which is fine but without texture, unless I uncomment the line

shelf.getSurface(texture);

As I said, this would lead to an access violation error which I do not understand. How does texture get bigger than allowed despite my effords to declare its size?

Share this post


Link to post
Share on other sites
Well this is more or less a shot in the dark but... have you tried calling:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

If, for some odd reason, this isn't what the system is defaulting to, you might have a problem... then again... that doesn't explain why the empty byte array works fine. So that, most likely, is not the problem. Sorry :/

Also, have you bound a texture object before calling glTexImage2D ? That shouldn't affect it either, as far as I know... worth a try I suppose.

Also, is there any particular reason you prefer
getSurface(surf) over surf = getSurface()
and
PPMReader ppm = PPMReader(ppmFn) over PPMReader ppm(ppmFn); ?

Just a matter of personal preference, I suppose. :)



Anyway, other than a problem with the image (which you said there wasn't) or a problem with the loading of the image (I'm not familiar with PPM, so I can't comment on the correctness of that code) then I'm not sure what the problem is, I'm sorry :(

Share this post


Link to post
Share on other sites
Quote:
Original post by Merowingian
So somewhere in my main.cpp I was having the following code:

const unsigned int textWidth = 256;
const unsigned int textHeight = 256;
const unsigned int bytesPerPix = 3;
const unsigned int textBytes = textWidth * textHeight * bytesPerPix;
char* texture = new char[textBytes];
// shelf.getSurface(texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textWidth, textHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
free(texture);


I think that the above codes except glTexImage2D() should be done in your PPMReader::loadPPMFile(). I mean you better get the width/height of texture and the pointer to the texture data from your PPMReader object, for example, your main() would be:

GLint width = ppm.getWidth();
GLint height = ppm.getHeight();
const GLvoid* texture = (const GLvoid*)ppm.getImage();

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);






You don't need to re-allocate a memory for the texture data in main() again. If your Shelf class holds these properties, then use Self object instead of PPMReader object, for instance:

const GLvoid* texture = (const GLvoid*)shelf.getSurface();

[EDIT]
As Naxos pointed out, make sure your PPMReader is working properly, too. Here is my PPM reader/writer class. It reads both P3(Ascii) and P6(binary) formats. Check it out.

imagePpm.zip
[/EDIT]

[Edited by - songho on August 7, 2007 12:57:00 AM]

Share this post


Link to post
Share on other sites
@Naxos:

sorry, the alignment thing doesn't make a difference.

And it's not really that I PREFER getSurface(surf) over surf = getSurface() etc., it's just that C++ seems to be too stupid to return a char* from a function.



@songho:

I see your point, but I was going to write a Texture class holding the width and height information later on, so I can retrieve that information from there.
As you can see in my code, the PPMReader gets discarded after loading the texture infomation into the shelf's surface attribute. So I can't get width and height from there.
I'm thinking of replacing the surface attribute of the Shelf class with an object of the Texture class (still to be written). As said, the Texture class will then hold the image data PLUS width and height information.
For the time being, I have to resort to predefined width and height values.

Omitting the memory allocation line unfortunately doesn't change anything. Actually, I already thought it might be totally unneccesary, but I thought that this way I could make C++ understand that whatever gets assigned to texture should BY NO MEANS be bigger than the array size defined in that statement. But obviously C++ doesn't work that way.
How can I tell C++ NEVER to allow an assignement bigger than x characters to the texture variable, or let's say to the surface variable? Obviously it's surface that is too big, causing the problem.
Look at my void PPMReader::loadPPMFile(char * filename) again, you'll see that image gets its predefined size at image = new char[imageBytes];.
But perhaps that line is unneccessary too, then, maybe the follwing read command is still allowed to place ANY number of characters into image.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sharlin
Before you can call glTexImage, you must bind some valid texture name with glBindTexture. It is not until the first time you bind a previously-unused texture name, the corresponding texture object is actually created. You can then initialize said object by calling glTexImage.
That's true except for the first sentence. Texture object 0 (the default texture) is initially bound so any texture operations will operate on that unless you bind a different texture.
Quote:
Original post by Merowingian
void setShelf()
{
char* ppmFn = "holz.ppm";
PPMReader ppm = PPMReader(ppmFn);
char* surface;
ppm.getImage(surface);
shelf = Shelf(1.5, 1.5, 1.5, surface);
}
So what happens with ppm goes out of scope? Does its destructor delete [] PPMReader::image?
Quote:
Original post by Merowingian
Which is fine but without texture, unless I uncomment the line
shelf.getSurface(texture);
As I said, this would lead to an access violation error which I do not understand.
Since all PPMReader::getImage() and Shelf::getSurface() do is set some pointer to point to the same data as PPMReader::image, if PPMReader's destructor delete[]s that data, than trying to access it should cause an access violation.
Quote:
Original post by Merowingian
And it's not really that I PREFER getSurface(surf) over surf = getSurface() etc., it's just that C++ seems to be too stupid to return a char* from a function.
C++'s stupidity is a subject of much debate/argument, but it has no trouble returning a char*.

And although I didn't notice anything wrong with this (I didn't really look though), since you're using C++, why not use std::string for strings instead of a char pointer?.

Share this post


Link to post
Share on other sites
You're so right, Kalidor!!!

I haven't defined any destructor for PPMReader, so it will DESTROY the image!
Passing on the image pointer to the shelf therefore will cause "structure" to point to inaccessible memory when used outside the scope of setShelf().
Well I've tried to solve this problem by modifying the setShelf() function in my main.cpp like this:

void setShelf() {

char* ppmFn = "holz.ppm";
PPMReader ppm = PPMReader(ppmFn);
char* surface = new char[256 * 256 * 3];
char* image;
ppm.getImage(image);
memcpy(surface, image, 256 * 256 * 3);
shelf = Shelf(1.5, 1.5, 1.5, surface);

}


You see, I'm copying the whole image byte by byte into a new array, to be independent of ppm's existence.

The access violation error is now GONE, but the shelf remains WHITE. I'm trying to figure out how this is possible. Any hints?

Share this post


Link to post
Share on other sites
Did you change the texture's minification filter? The default is GL_NEAREST_MIPMAP_LINEAR, which is a mipmapping minification filter. If the texture uses a mipmapping filter but doesn't have all mipmap levels specified than it's as if texturing were disabled for the texture unit that texture is bound to. It looks like you're only specifying level 0 of the texture so I would try setting GL_TEXTURE_MIN_FILTER to GL_NEAREST or GL_LINEAR. You can do that with glTexParameter*.

Share this post


Link to post
Share on other sites
yeah, but i want to start without using mipmaps first.

mipmapping is just an optional improvement, you should be able to use texturing with just linear filtering. these are my opengl texturing settings:


glEnable(GL_TEXTURE_2D);
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_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);


meanwhile, I have also applied changes to the Shelf constructor:

Shelf::Shelf(float x, float y, float z, char* surface) {
setPosition(x, y, z);
this->surface = new char[256 * 256 * 3];
memcpy((char*)(this->surface), surface, 256 * 256 * 3);
}


All this hasn't helped yet, sorry :





Share this post


Link to post
Share on other sites
Hhmmm...

well, just to remind you, this isn't about memory access violation any more.

It's just that the textures are not seen on my objects at all, they just remain plain white.

Any new hints at where the problem could be?

Share this post


Link to post
Share on other sites
Yeah, here it is:



void drawShelf() {

Dimensions dims = Shelf::getDimensions();
float innerWidth = dims.width - 2 * Shelf::getThickness();
float innerHeight = dims.height - 2 * Shelf::getThickness();

glPushMatrix();
Position position = shelf.getPosition();
glTranslatef(position.x, position.y, position.z);
bool textFlags[6] = { true, true, true, true, true, true };
GLuint* textures = (GLuint*)(malloc(sizeof(GLuint)));
glGenTextures(1, textures);
glBindTexture(GL_TEXTURE_2D, textures[0]);
const unsigned int textWidth = 256;
const unsigned int textHeight = 256;
const unsigned int bytesPerPix = 3;
const unsigned int textBytes = textWidth * textHeight * bytesPerPix;
char* texture = new char[textBytes];
shelf.getSurface(texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textWidth, textHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);

// zeichne linkes Seitenbrett
drawTextQuad(Shelf::getThickness(), dims.height, dims.length, textFlags);

// zeichne rechtes Seitenbrett
glPushMatrix();
glTranslatef(Shelf::getThickness() + innerWidth, 0.0f, 0.0f);
drawTextQuad(Shelf::getThickness(), dims.height, dims.length, textFlags);
glPopMatrix();

// zeichne unteres Brett
glPushMatrix();
glTranslatef(Shelf::getThickness(), 0.0f, 0.0f);
drawTextQuad(innerWidth, Shelf::getThickness(), dims.length, textFlags);

// zeichne oberes Brett
glTranslatef(0.0f, Shelf::getThickness() + innerHeight, 0.0f);
drawTextQuad(innerWidth, Shelf::getThickness(), dims.length, textFlags);
glPopMatrix();

glPopMatrix();
glDeleteTextures(1, textures);

}



void drawQuad(float width, float height, float length) {

drawLRQuadWall(height, length);

glPushMatrix();
glTranslatef(width, 0.0f, 0.0f);
drawLRQuadWall(height, length);
glPopMatrix();

drawBTQuadWall(width, length);

glPushMatrix();
glTranslatef(0.0f, height, 0.0f);
drawBTQuadWall(width, length);
glPopMatrix();

drawBFQuadWall(width, height);

glPushMatrix();
glTranslatef(0.0f, 0.0f, length);
drawBFQuadWall(width, height);
glPopMatrix();

}




void drawTextQuad(float width, float height, float length, textFlagAr textFlags) {

if (textFlags[0]) drawTextLRQuadWall(height, length); else drawLRQuadWall(height, length);

glPushMatrix();
glTranslatef(width, 0.0f, 0.0f);
if (textFlags[1]) drawTextLRQuadWall(height, length); else drawLRQuadWall(height, length);
glPopMatrix();

if (textFlags[2]) drawTextBTQuadWall(width, length); else drawBTQuadWall(width, length);

glPushMatrix();
glTranslatef(0.0f, height, 0.0f);
if (textFlags[3]) drawTextBTQuadWall(width, length); else drawBTQuadWall(width, length);
glPopMatrix();

if (textFlags[4]) drawTextBFQuadWall(width, height); else drawBFQuadWall(width, height);

glPushMatrix();
glTranslatef(0.0f, 0.0f, length);
if (textFlags[5]) drawTextBFQuadWall(width, height); else drawBFQuadWall(width, height);
glPopMatrix();

}

void drawLRQuadWall(float height, float length) {
glBegin(GL_POLYGON);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, height, 0.0f);
glVertex3f(0.0f, height, length);
glVertex3f(0.0f, 0.0f, length);
glEnd();
}

void drawBTQuadWall(float width, float length) {
glBegin(GL_POLYGON);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(width, 0.0f, 0.0f);
glVertex3f(width, 0.0f, length);
glVertex3f(0.0f, 0.0f, length);
glEnd();
}

void drawBFQuadWall(float width, float height) {
glBegin(GL_POLYGON);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, height, 0.0f);
glVertex3f(width, height, 0.0f);
glVertex3f(width, 0.0f, 0.0f);
glEnd();
}

void drawTextLRQuadWall(float height, float length) {
glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, height, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(0.0f, height, length);
glTexCoord2f(1.0f, 0.0f); glVertex3f(0.0f, 0.0f, length);
glEnd();
}

void drawTextBTQuadWall(float width, float length) {
glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(width, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(width, 0.0f, length);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 0.0f, length);
glEnd();
}

void drawTextBFQuadWall(float width, float height) {
glBegin(GL_POLYGON);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(width, 0.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(width, height, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, height, 0.0f);
glEnd();
}

Share this post


Link to post
Share on other sites
Sorry, forgot the definitions:


const unsigned int numOfQuadSides = 6;

typedef bool textFlagAr[numOfQuadSides];

void drawQuad(float width, float height, float length);

void drawTextQuad(float width, float height, float length, textFlagAr textFlags);

void drawLRQuadWall(float height, float length);

void drawBTQuadWall(float width, float length);

void drawBFQuadWall(float width, float height);

void drawTextLRQuadWall(float height, float length);

void drawTextBTQuadWall(float width, float length);

void drawTextBFQuadWall(float width, float height);

Share this post


Link to post
Share on other sites
I think you need to set these each time you create and bind a new texture:

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_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

Also, make doubly sure that texturing is enabled before you draw. I didn't see a glEnable(GL_TEXTURE_2D) call, so I wasn't sure.


Also, every time you draw the object you are creating the texture, using it, and deleting it. This is not the ideal solution. It will get slow really fast, because that means that the texture data has to be sent to gpu memory for every texture, every single frame! If you don't know, these transfers are not quick.

Instead, you should create the textures outside of the drawing code, and only call glTexImage2D(...) once for each texture created. Then, when you want to use a texture, just call glBindTexture(GL_TEXTURE_2D, texID). Once you no longer need the textures (most likely when the program ends, or when you load a different level, for example), then you call glDeleteTextures.

For example:

const unsigned int TexCount = 4;
GLuint TextureIDs[TexCount];

std::string texFiles[] =
{ "tex1.bmp", "shelf.bmp", "sky.bmp", "dirt.bmp" };

void initGL()
{
//initialize viewport, perspective, anything else you need

//Load textures
glGenTextures(TexCount, TextureIDs);

for(int i=0;i<TexCount;++i)
{
unsigned int width, height;
glBindTexture(GL_TEXTURE_2D, TextureIDs[i]);
char* texData = MyTextureLoadingFunction(texFiles[i].c_str(), width, height);

glTexEnvi(...);
glTexParameteri(...);
glTexParameteri(...);
glTexParameteri(...);
glTexParameteri(...);

glTexImage2D(..., width, height, ..., texData);
}
glEnable(GL_TEXTURE_2D);
}


void drawStuff()
{
//.. drawing code, transforms, whatever
glBindTexture(GL_TEXTURE_2D, TextureIDs[0]);
drawMyObject();

//more transforms and whatnot
glBindTexture(GL_TEXTURE_2D, TextureIDs[1]);
drawMyShelf();

//more transforms and whatnot
glBindTexture(GL_TEXTURE_2D, TextureIDs[2]);
drawMySkyPlane();

// etc, etc...

}

//Then when you don't need the textures anymore

void cleanupTextures()
{
glDeleteTextures(TexCount, TextureIDs);
}





Anyway... make sure texturing is enabled, and make sure you set the parameters you want for each texture (Even if they are the same! You must!). Also, don't forget to call glTexEnvi() and setup that properly for each texture.

Share this post


Link to post
Share on other sites
Quote:
Original post by NaxosAnyway... make sure texturing is enabled, and make sure you set the parameters you want for each texture (Even if they are the same! You must!). Also, don't forget to call glTexEnvi() and setup that properly for each texture.
Most of Naxos' post was spot-on but that last sentence is just slightly wrong. Texture parameters are per-texture-object state so you need to set them for each texture you create (and just to reiterate, don't recreate a texture every frame). Texture environment settings, however, are per-texture-unit state. So if the current texture unit is GL_TEXTURE0 and you bind texture object 1, then change texture environment settings, then bind texture object 2, the texture environment settings you just set are still in effect on texture unit GL_TEXTURE0. You change the current texture unit with glActiveTexture, but this gets into using multiple textures at once (multitexturing) so if you don't need that then just stick with using texture unit GL_TEXTURE0 for now.

Share this post


Link to post
Share on other sites
Hey guys,

thanks for your help so far, I just got a new Macbook and I need to transfer all my data to that new notebook before I can continue programming.

I'll get back to ya'll later.

Cheers
Marvin

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Forum Statistics

    • Total Topics
      627736
    • Total Posts
      2978868
  • Similar Content

    • By DelicateTreeFrog
      Hello! As an exercise for delving into modern OpenGL, I'm creating a simple .obj renderer. I want to support things like varying degrees of specularity, geometry opacity, things like that, on a per-material basis. Different materials can also have different textures. Basic .obj necessities. I've done this in old school OpenGL, but modern OpenGL has its own thing going on, and I'd like to conform as closely to the standards as possible so as to keep the program running correctly, and I'm hoping to avoid picking up bad habits this early on.
      Reading around on the OpenGL Wiki, one tip in particular really stands out to me on this page:
      For something like a renderer for .obj files, this sort of thing seems almost ideal, but according to the wiki, it's a bad idea. Interesting to note!
      So, here's what the plan is so far as far as loading goes:
      Set up a type for materials so that materials can be created and destroyed. They will contain things like diffuse color, diffuse texture, geometry opacity, and so on, for each material in the .mtl file. Since .obj files are conveniently split up by material, I can load different groups of vertices/normals/UVs and triangles into different blocks of data for different models. When it comes to the rendering, I get a bit lost. I can either:
      Between drawing triangle groups, call glUseProgram to use a different shader for that particular geometry (so a unique shader just for the material that is shared by this triangle group). or
      Between drawing triangle groups, call glUniform a few times to adjust different parameters within the "master shader", such as specularity, diffuse color, and geometry opacity. In both cases, I still have to call glBindTexture between drawing triangle groups in order to bind the diffuse texture used by the material, so there doesn't seem to be a way around having the CPU do *something* during the rendering process instead of letting the GPU do everything all at once.
      The second option here seems less cluttered, however. There are less shaders to keep up with while one "master shader" handles it all. I don't have to duplicate any code or compile multiple shaders. Arguably, I could always have the shader program for each material be embedded in the material itself, and be auto-generated upon loading the material from the .mtl file. But this still leads to constantly calling glUseProgram, much more than is probably necessary in order to properly render the .obj. There seem to be a number of differing opinions on if it's okay to use hundreds of shaders or if it's best to just use tens of shaders.
      So, ultimately, what is the "right" way to do this? Does using a "master shader" (or a few variants of one) bog down the system compared to using hundreds of shader programs each dedicated to their own corresponding materials? Keeping in mind that the "master shaders" would have to track these additional uniforms and potentially have numerous branches of ifs, it may be possible that the ifs will lead to additional and unnecessary processing. But would that more expensive than constantly calling glUseProgram to switch shaders, or storing the shaders to begin with?
      With all these angles to consider, it's difficult to come to a conclusion. Both possible methods work, and both seem rather convenient for their own reasons, but which is the most performant? Please help this beginner/dummy understand. Thank you!
    • By JJCDeveloper
      I want to make professional java 3d game with server program and database,packet handling for multiplayer and client-server communicating,maps rendering,models,and stuffs Which aspect of java can I learn and where can I learn java Lwjgl OpenGL rendering Like minecraft and world of tanks
    • By AyeRonTarpas
      A friend of mine and I are making a 2D game engine as a learning experience and to hopefully build upon the experience in the long run.

      -What I'm using:
          C++;. Since im learning this language while in college and its one of the popular language to make games with why not.     Visual Studios; Im using a windows so yea.     SDL or GLFW; was thinking about SDL since i do some research on it where it is catching my interest but i hear SDL is a huge package compared to GLFW, so i may do GLFW to start with as learning since i may get overwhelmed with SDL.  
      -Questions
      Knowing what we want in the engine what should our main focus be in terms of learning. File managements, with headers, functions ect. How can i properly manage files with out confusing myself and my friend when sharing code. Alternative to Visual studios: My friend has a mac and cant properly use Vis studios, is there another alternative to it?  
    • By ferreiradaselva
      Both functions are available since 3.0, and I'm currently using `glMapBuffer()`, which works fine.
      But, I was wondering if anyone has experienced advantage in using `glMapBufferRange()`, which allows to specify the range of the mapped buffer. Could this be only a safety measure or does it improve performance?
      Note: I'm not asking about glBufferSubData()/glBufferData. Those two are irrelevant in this case.
    • By xhcao
      Before using void glBindImageTexture(    GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format), does need to make sure that texture is completeness. 
  • Popular Now