• Advertisement
Sign in to follow this  

[Opengl] Some info about textures

This topic is 3469 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello guys, i am studying on the Redbook and i have just finished chpaters 8 and 9 (raster graphic and textures). There is something giving me troubles.
void makeCheckImage(void)
{
   int i, j, c;
    
   for (i = 0; i < checkImageHeight; i++) {
      for (j = 0; j < checkImageWidth; j++) {
         c = ((((i&0x8)==0)^((j&0x8))==0))*255;
         checkImage[j][0] = (GLubyte) c;
         checkImage[j][1] = (GLubyte) c;
         checkImage[j][2] = (GLubyte) c;
         checkImage[j][3] = (GLubyte) 255;
      }
   }
}
What's the mean of this code:
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
? I khnow from the result image that sometime c is 255 and sometime it's 0 but can someone show me the "long" form of this short one? This is more a c++ question i khnow :D The whole routine creates a 2D array where for each pixel the r,g,b and a components are specified. Am i right? Tell me if i am right coz i am not sure :D Why doed it use GLubytes and not some other format? Now i can imagine the clue in creating a 2d-texture since it will be sticked onto a polygon for example. There is, but, an example on the redbook (the 9.6 one) where to create a texture he uses a 1D array. I wont post the whole code or will be too long. In this ex there is:
void makeStripeImage(void)
{
   int j;
    
   for (j = 0; j < stripeImageWidth; j++) {
      stripeImage[4*j] = (GLubyte) ((j<=4) ? 255 : 0);
      stripeImage[4*j+1] = (GLubyte) ((j>4) ? 255 : 0);
      stripeImage[4*j+2] = (GLubyte) 0;
      stripeImage[4*j+3] = (GLubyte) 255;
   }
}
He uses this texture onto a solid teapot. Can some1 explain how can i map this 1d texture on a 3S object? Is this related in some way with the use of automatic coords generation? I can't understand what the book says: "Since only one property is being shown (the distance from the plane), a one-dimensional texture map suffices"! I am asking these things since i have to load bmp/png images in Opengl but i wanna first understand this stuff. I wont be at home this night so cu tomorrow and have a nice day :D thanks guys

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by broady

The whole routine creates a 2D array where for each pixel the r,g,b and a components are specified. Am i right? Tell me if i am right coz i am not sure :D
Why doed it use GLubytes and not some other format?



Well I don't see it creating an array, but yes it fills a 2D array with some values. In a texture each element in an array is called a "texel", and each texel has several components (based on the texture format). This texture here uses a very very common format, usually referred to as RGBA8. The "RGBA" refers to the 4 components (red, green, blue, and alpha) while the "8" refers to the 8-bits per component used (for a total of 32 bits per texel). The code use GLUbyte for each component since the GLUbyte type is 1 byte, or 8 bits. Think of each texel as having 4 GLUbytes in a row, side-by-side.

Since each component is a single unsigned byte, it has a maximum value of 28 - 1 (255). This means if you have red, green, and blue components set to 255 you get a value of white, and all set to zero you get black. The alpha value usually controls transparency, so 255 would be fully visible and 0 would be completely invisible.


Quote:
Original post by broady
What's the mean of this code:
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
? I khnow from the result image that sometime c is 255 and sometime it's 0 but can someone show me the "long" form of this short one? This is more a c++ question i khnow :D


That bit of code is actually pretty simple, it's just a little hard to understand due to the hex and the bitwise operators. Lets break it down here:

(i & 0x8) == 0

Okay, so have i, which tells us which row of the texel we're currently operating on. The "&" operator does a bitwise "AND" operation: this means that the the CPU will go through each individual bit of both values and the the corresponding bit in the result will be set to "1" if both bits are 1, and "0" otherwise (if this is new to you, do some reading on Bitwise operations). Now, the value of 0x8 (which is just decimal 8) comes out to a bit pattern of "1000". Now look at what happens when you increment a number starting at zero:

00000, 00001, 00010, 00011, 00100, 00101, 00110, 00111,
01000, 01001, 01010, 01011, 01100, 01101, 01110, 01111,
10000, 10001, 10010, 10011, 10100, 10101, 10110, 10111,


Notice what happens here: every 8 increments, the 4th bit gets flipped. In other words value of "(i & 0x8)" will be 0 for 8 numbers, then it will be non-zero for 8, and so on. When we compare that to 0 in "(i & 0x8) == 0" we get 8 0's, then 8 1's, etc. Now since "i" is the row loop control variable, this means we have 8 row's with 0's followed by 8 rows with 1's.

Okay, now look at the other side:

(j&0x8))==0

It's very similar to what we looked at before. In fact it's exactly the same, just with the column loop control variable. This means for 8 columns it'll evaluate to 0, then it'll evaluate to 1 for 8 columns.

Alright, now we'll put together both sides:

((i&0x8)==0)^((j&0x8)==0)

This is using the bitwise exclusive-or operation. This operation will put out a 1 when either the left side or the right side has a value of 1, but not when they're both 1. This means that rather than having entire rows and columns that are filled with 1's, the areas where they both overlap will come out to zero. Which means you'll have an 8x8 block of 1's, then a block of 0's, and so on...just like a checkerboard pattern (hence the name of the function).

Before the value is used, it's multiplied by 255. This is because as explained earlier, the max value for each component is 255. This way you get all white texels, or all black texels.

Share this post


Link to post
Share on other sites
MJP u have been so kind answering in a so clear way. Really appreciated.

just 1 more thing: can u make me an example where i have to use a 1D texture?
thanks

Share this post


Link to post
Share on other sites
Quote:
Original post by broady
MJP u have been so kind answering in a so clear way. Really appreciated.

just 1 more thing: can u make me an example where i have to use a 1D texture?
thanks


You'll usually use 1D textures on their own very rarely. However you will get to know about multi-texturing soon (using multiple textures at the same spot, combining them somehow).

For example a typical use would be to draw a grass texture on a mountain and blend it with a 1D color texture, depending on the height. The 1D texture could have colors for beach and other low level terrain in the first elements of the array and mountain tops/higher levels of terrain at the end of the 1D array. This way the texture of your terrain will look very smooth and unique, without much technical performance loss.

Share this post


Link to post
Share on other sites
Thanks for the reply mate i have the idea now. I will continue writing here since it's related.

1) Ok we said that the previous c++ code was filling a 2D array. Hmmm. Why has it 3 components if it's 2D? It is decleared in this way:

GLubyte checkImage[checkImageHeight][checkImageWidth][4];

I khnow the 4 is for the r,g,b and a values but it's not 2D in this way -.-


2) I have a general question about the 2 functions glDrawPixels() and glReadPixels(). Let's start from the first one:

void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);

For example i filled my array with the previous function makecheckimage. Now i wanna draw all the 4 componentes for the format so i use GL_RGBA for format. Now type is easy since i created the array and i khnow i used unsignedbytes. What happens when i wanna read from the framebuffer? I am confused since in my book there is no a reading pixel example.

Ok here it is:

void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);

Ok this function copyies the rectangle in the framebuffer into the array pointed by pixels. So first of all i go to create the array to store the data right? From the book: "format indicates the kind of pixel data elements that are read (an index value or an R, G, B, or A component value), and type indicates the data type of each element." Ok let's say i wanna read just the red component so i use GL_RED for format parameter. But i dont khnow what to pass to format. Do i need to khnow the data type used in the framebuffer? Do i khnow it? It's different from the drawfunction since there is me who has created the array and i khnow the type i used for it.

3) why dont i need the format and type parameters when i use the copyfunction (the from buffer to buffer one)?

Can someone clarify this nooby things for me?
Thanks guys

Share this post


Link to post
Share on other sites
Hello there,

about the glReadPixels i came to this conclusion. With the format parameter i specify wich components (r,g,b and a) i wanna copy in my array. With the type parameter i say to opengl how many bits i want for each pixel. i.e: If in the framebuffer there are 16 bit for red and i want a 4 bit red i might lose some definition since i can have "less kinds of red". The array i define to store the image has to be coerent with the format and the type parameter. Can u say me if i am right?

But i still can't understand why that array has 3 components. If someone can help would be great.

<have a nice day
Bro

Edit: why is there a skull on the left of my thread?^^

Share this post


Link to post
Share on other sites
It doesn't have to be three dimensional. In fact, my image data is usually one dimensional! :)
Width and height only specify how many pixels an image has. A 256*256 pixel resolution picture has 65536 pixels. Now you would assume that your array should be data[256][256]. You can, however also make it one dimensional: data[256*256]. You will save all pixels aswell (and I find one dimensional arrays easier for allocating etc).

However, if you attempted to fill this array now, you would get an error because it's too small. That's because each pixel itself is not the size of a single byte usually, but bigger. For example you may have 8 bit red, green, blue and alpha which is 32 bits together, or 4 bytes. So you end up with an array of data[256*256*4] or, if you want, data[256][256][4].

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement