reading the docs i see that the glGetTexImage2d() function has a 'type' parameter.
The docs say that the type parameter "specifies the data type of the pixel data" and gives some examples of types such as GL_INT, GL_BYTE, etc.
but what does it mean precisely when the image format is GL_RGBA and GL_INT ? is it an int for each channel? or an int for the whole color? and if it's an int for th whole color, then isn't that really the same as GL_BYTE ? since there's 4 bytes in an int which makes each channel a byte each
It's an int per channel. RGBA means each pixel has R, G, B and A ints (if you set it to int) in the data-array you're giving it. RBGA (if it exists, not sure of that) would also mean four ints, but ordered differently. RGB would mean just three (no alpha channel).
The type parameter specifies the effective type of the data inside the buffer you're sending to OpenGL.
The aim here is that OpenGL is going to walk in your buffer, and want to know how much elements are present ( width * height * internalformat ) and their size & interpretation (type).
For instance, if you are to provide an array of unsigned ints containing red/green/blue/alpha channels (in this order), you'll need to specify:
target: GL_TEXTURE_2D
level: 0 (except if you use mipmaps)
internalformat: 4 because you have red, green, blue and alpha
width: 640
height: 480
border: 0
internal format: GL_RGBA to tell opengl the order of our channels, and what they mean
type: GL_UNSIGNED_INT will let opengl know the type of elements inside our array
pixels: a pointer to your array
Related
I've a c++ function (wrapped in obj-c files in Xcode):
int64_t* findEdges(int64_t* pixels, int width, int height);
that I'd like to call from Swift 3 and pass in a buffer full of picture data. After hunting around I'm calling it with:
var ptr = (NSData(data: imageRep.tiffRepresentation!).bytes).bindMemory(to: Int64.self, capacity: 4 * height * width).pointee
let processor = findEdges(&ptr, width, height)
But after accessing around 30 or 40 addresses in the c++ file I get a EXC_BAD_ACCESS crash.
Is the problem that I'm passing unsafe pointers from Swift? What would be the correct call procedure?
Here are at least some of the problems with this approach. There may be more, since I don't know what exactly findEdges() input means and how that function finds the edges.
NSData's bytes property is a raw pointer not bound to any type. The call to bindMemory then indicates that the NSData's content is to be treated as a buffer of 4 * height * width of 8-byte integers, i.e. a buffer of 32 * height * width bytes. I haven't worked with the TIFF format lately, but I strongly suspect that a TIFF representation of an image of width x height size would contain a lot less bytes than that, so even if the buffer was successfully passed to findEdges, trying to treat it as much larger than it is would lead to an access violation.
The first 8 bytes of the image's TIFF representation are treated as an Int64 and copied to the ptr variable, the address of which is then passed to findEdges, which treats it as the address of a buffer of 4 * height * width Int64 values. However, only the 1st Int64 in the buffer has anything to do with the image (it contains the first 8 bytes of its TIFF representation). When findEdges accesses the 2nd Int64 in the pixels array, it accesses memory having nothing to do with the image. It may be lucky accessing a few more (garbage) Int64 values, but will eventually try to access something it can't.
Solution depends on whether pixels required by findEdges contains the exact same byte sequence as the image's TIFF representation, or some transformation is required. In other words, can we say that the first 8 bytes of the TIFF representation form the first element of the pixels Int64 array, the 2nd 8 bytes - the 2nd element etc.
Assuming the buffer can be passed to the C++ function as is, here is a brief simplified example, which you can adapt to your needs. Let's say the C++ function takes an array of shorts with its size and looks like this:
void processBuffer(int16_t * buf, int count) {
...
}
We want to pass the contents of a Data from Swift as a buffer. Here is how one might go about doing that:
var myData = ...
myData.withUnsafeMutableBytes({(p: UnsafeMutablePointer<Int16>) -> Void in
processBuffer(p, Int32(myData.count / 2))
})
Please note that the buffer can be modified, not just read, in the C++ code, and the changes will be reflected in myData.
Title itself explains the question.
The last parameter of glTexImage2D is the array of bytes (unsigned, signed depends).
Should rgb array contain padding bytes or not?
Should RGB array contain padding bytes or not?
That entirely depends on your needs. You can configure OpenGL to accept various data layouts. See the reference documentation of glPixelStore, the unpack parameters are what you should look at.
Padding bytes are normally found between between rows, to fill up to a certain alignment. The unpack alignment specifies the byte alignment of each row.
If your pixels are 8 bit per component, but packed into 4 bytes each with a padding byte, you can specify that, by declaring the data type to be GL_UNSIGNED_INT_8_8_8_8; if you use a type/internal type with less than 4 components the excessive bytes are ignored.
The short answer is no. I typically create an array of structures.
The structure would look like:
typedef struct
{
unsigned char red;
unsigned char green;
unsigned char blue;
unsigned char alpha;
} AlphaPixelBytes;
Then the array I create would look like:
AlphaPixelBytes bitmapData[NUMTEXTUREPOINTS];
You can then use bitmapData as the last argument to glTexImage2D when you create the texture or you can pass NULL as the last argument to create an empty texture you'll later populate with glTexSubImage2D.
This sort of array of structures is also useful as a data source for an NSBitmapImageRep for use (for example) in exporting a PNG file of your texture.
EDIT:
Sorry, I didn't notice you're dealing with RGB not RGBA data. The structure for RGB would look like:
typedef struct
{
unsigned char red;
unsigned char green;
unsigned char blue;
} PixelBytes;
And the array:
PixelBytes bitmapData[NUMTEXTUREPOINTS];
I'm just learning how to texture in OpenGL and am a bit confused by some of the results I'm getting.
I'm using stb_image to load the following checkerboard png image:
When I saved the png image I explicitly chose to save it as 32 bit. That would lead me to believe that each component (RGBA) would be stored as 8 bits for a total of 32 bits - the size of an unsigned int. However, using the following code:
unsigned char * texture_data =
stbi_load("resources/graphics-scene/tut/textures/checker.png", &w, &h, nullptr, 4);
// ...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0,
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture_data);
yields:
If I instead use GL_UNSIGNED_BYTE for the type parameter I get the proper results.
Also, just incase it helps, I also tried the following image:
which yields
GL_UNSIGNED_BYTE gives the correct result in this case as well.
I'm not sure if this is a case of me misunderstanding glTexImage2D or stb_image (does it convert loaded data to 8-bit? that would seem unlikely to me).
EDIT: I just finally found a related posted (had already searched some but had no luck). However the answer (https://stackoverflow.com/a/4191875/2507444) confuses me. If that is the case - that the type parameter specifies how many bytes per component - then what exactly do things like GL_UNSIGNED_BYTE_3_3_2 and GL_UNSIGNED_INT_8_8_8_8 mean???
If that is the case - that the type parameter specifies how many bytes per component - then what exactly do things like GL_UNSIGNED_BYTE_3_3_2 and GL_UNSIGNED_INT_8_8_8_8 mean???
It does both, depending on what the actual type is.
If the pixel transfer type is just a data type, then it specifies the data size per-component. If it has numbers in it, then the type specifies the size of the data per-pixel; the numbers specify the individual component sizes within that data type.
GL_UNSIGNED_INT_8_8_8_8 means that OpenGL will interpret each pixel as an unsigned integer. The first component will be the high 8 bits, the next will be the next 8 bits, and so forth.
However, where your problem is coming from is the fact that STB-image does not work with unsigned integers. Each pixel is written as 4 separate bytes, in RGBA order. Basically, it does this:
GLubyte arr[4] = {red, green, blue, alpha};
Now, that may sound like the same thing. But it isn't. The reason why has to do with endian issues.
When you do this in C/C++:
GLuint foo = 0;
foo |= (red << 24);
foo |= (green << 16);
foo |= (blue << 8);
foo |= (alpha << 0);
OpenGL's data types require GLuint to be an unsigned integer exactly 32-bits in size. And assuming that red, green, blue, and alpha are all GLubytes (8-bit unsigned integers), C/C++ says that this will pack the red bits into the high 8-bit byte, the green into the next one, and so on. The C and C++ standards require this to work.
However, the C and C++ standards do not require this to work:
GLubyte *ptr = (GLubyte*)&foo;
ptr[0] == ((foo >> 24) & 0xFF);
That is, the first byte of memory pointed to by foo does not have to be the red component.
In little endian byte ordering, the low byte of a 32-bit integer is stored first, not last.
When OpenGL sees GL_UNSIGNED_INT, that means it will interpret those four bytes exactly the way your CPU does. So GL_UNSIGNED_INT_8_8_8_8 will do the equivalent of foo above. The first byte of memory it sees will be interpreted, on a little endian machine, as the low byte, not the high byte.
STB-image does not output GL_UNSIGNED_INT_8_8_8_8. It treats each pixel as a 4-byte array, like arr above. Therefore, you must tell OpenGL that this is how your data is stored. So you say that each component is one byte. Which is what GL_UNSIGNED_BYTE does.
I know the height and width, as well as each pixel value (from x,y location) that I want a QImage to be. How can I build a QImage knowing these values?
The second argument to setPixel() is a 24bit RGB value in a single int you can use the QRgb macros to construct it or just (red<<16) + (green << 8) + blue
But unless it's a very small image it will take a long time to call setPixel().
If you have the data I would call Qimage::bits() to get an unsigned pointer to the QImage data and just set the R,G,B values directly for each pixel or use memcpy()
You simply create the object (eg, new QImage(640, 480);) and then use setPixel to change each pixel in the image to the value you want it to be.
i'm approaching c++ with some basic computer graphics.
pixels data is usually represented as :
unsigned char *pixels
and an unsigned char is good because is a value between 0 and 255 (256 = 2^8 because a char is 2 byte and 1 byte is 8 bit?). and this is good because in RGB color are represented with a number between 0 and 255.
but.. i understand this as a monchromatic image, in a normal image i have RGB, i would have 3 array of unsiged char, one for red, one for green, one for blue. something like:
unsigned char *pixels[3]
but i never found something similar for RGB pixels data
RGB images are usually stored in interleaved order (R1, G1, B1, R2, G2, B2, ...), so one pointer (to R1) is enough.
This makes it a bit harder to address individual pixels: pixel with index N is stored at pixels[3*N+0], pixels[3*N+1] and pixels[3*N+2] instead of just red[N], green[N], blue[N].
However, this has the advantage of allowing faster access: less pointers lead to easier programs, improving their speed; interleaved order also makes memory caching more effective.
unsigned char *pixels[3];
declares an array of three pointers to unsigned char. I'm not sure if that's what you wanted.
There are several different ways to represent pixels. The simplest is probably something like:
struct Pixel
{
unsigned char red;
unsigned char green;
unsigned char blue;
};
But you may have to (or want to) conform to some external format. Another frequent possibility is to put all three colors in a uint32_t. Also, in some graphic systems, there may be a fourth element, and alpha, representing transparency.
Really whenever you refer to a block of bytes, it's going to be of type unsigned char* because of the fact that unsigned char by the C-specification has no padding in the type itself (i.e., every bit is used for a value in the byte, and there are no padded bits that are not used), and pixel-data is going to be some block of X bytes with no padding (at least not internal padding ... there may be padding at the end of the buffer for alignment purposes). It will also most likely be allocated on the heap somewhere. So no matter if it's going to be monochrome, color-data, etc., you will often find that a pixel buffer will be pointed to via an unsigned char pointer, and you may then cast it to some struct like James mentioned in order to easily access the pixel information. Other times you may have to index into the buffer like anatolyg mentions. But in the end, a buffer of pixels is just a buffer of data, and a general buffer of data bytes should be accessed in C/C++ using type unsigned char*.
With *pixels[3] you've got separate arrays for the three colour components, whereas in files the three colour components for a single pixel are stored together. It also means you can use a single fread()/fwrite() for the whole block of image data,