How to use unsigned short in an opengl shader? - c

I'm trying to upload a texture with unsigned shorts in a shader but it's not working.
I have tried the following:
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, vbt[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 640, 480, 0, GL_RED, GL_UNSIGNED_SHORT, kinect_depth);
glUniform1i(ptexture1, 1);
GLenum ErrorCheckValue = glGetError();
I know I'm binding correctly the texture because I get some results by using
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, vbt[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 640, 480, 0,
GL_RG, GL_UNSIGNED_BYTE, kinect_depth);
glUniform1i(ptexture1, 1);
GLenum ErrorCheckValue = glGetError();
In particular, I get part of my values in the red channel. I would like to upload the texture as a unsigned byte or as a float. However I don't manage to get the glTexImage2D call correctly. Also, is it possible to something similar using a depth texture? I would like to do some operations on the depth information I get from a kinect and display it.

Your arguments to glTexImage2D are inconsistent. The 3rd argument (GL_RGB) suggests that you want a 3 component texture, the 7th (GL_RED) suggests a one-component texture. Then your other attempt uses GL_RG, which suggests 2 components.
You need to use an internal texture format that stores unsigned shorts, like GL_RGB16UI.
If you want one component, your call would look like this:
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 640, 480, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, kinect_depth);
If you want three components:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16UI, 640, 480, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, kinect_depth);
You also need to make sure that the types used in your shader for sampling the texture match the type of the data stored in the texture. In this example, since you use a 2D texture containing unsigned integer values, your sampler type should be usampler2D, and you want to store the result of the sampling operation (result of texture() call in the shader) in a variable of type uvec4. (paragraph added based on suggestion by Andon)
Some more background on the format/type arguments of glTexImage2D, since this is a source of fairly frequent misunderstandings:
The 3rd argument (internalFormat) is the format of the data that your OpenGL implementation will store in the texture (or at least the closest possible if the hardware does not support the exact format), and that will be used when you sample from the texture.
The last 3 arguments (format, type, data) belong together. format and type describe what is in data, i.e. they describe the data you pass into the glTexImage2D call.
It is mostly a good idea to keep the two formats matched. Like in this case, the data you pass in is GL_UNSIGNED_SHORT, and the internal format GL_R16UI contains unsigned short values. In OpenGL ES it is required for the internal format to match format/type. Full OpenGL does conversion if necessary, which is undesirable for performance reasons, and also frequently not what you want because the precision of the data in the texture won't be the same as the precision of your original data.

Related

glTexImage2D, in random and occasional ways, expends 800 times more in executing

I'm using glsl 2.0 for some GPGPU purposes (I know, not the best for GPGPU).
I have a reduction phase for matrix multiplication in which I have to constantly reduce the texture size (I'm using glTexImage2D). The pseudocode is something like this:
// Start reduction
for (int i = 1; i <= it; i++)
{
glViewport(0, 0, x, y);
glDrawArrays(GL_TRIANGLES, 0, 6);
x = resize(it);
if (i % 2 != 0)
{
glUniform1i(tex2_multiply_initialstep, 4);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
// Resize output texture
glActiveTexture(GL_TEXTURE5);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, x, y, 0, GL_RGBA, GL_FLOAT, NULL);
}
else
{
glUniform1i(tex2_multiply_initialstep, 5);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
// Resize output texture
glActiveTexture(GL_TEXTURE4);
// A LOT OF TIME!!!!!!!
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, x, y, 0, GL_RGBA, GL_FLOAT, NULL);
// A LOT OF TIME!!!!!!!
}
}
In some iterations the glTexImage2D of the else branch takes 800 times more time that in other ones. I make a test hardcoding x and y but surprisingly takes similar high times in the same iterations, so have nothing to do with x value.
What's wrong here? Alternatives to resizing without glTexImage2D?
Thanks.
EDIT:
I know that glsl 2.0 is a bad choice for GPGPU but its mandatory for my project. So that I'm not able to use functions like glTexStorage2D because they are not included in 2.0 subset.
I'm not sure if I understand exactly what you're trying to achieve, but glTexImage2D is reallocating memory each time you call it. You may want to call glTexStorage2D, and then call glTexSubImage2D.
You can check Khronos's Common Mistakes page about that. Relevant part is :
Better code would be to use texture storage functions (if you have
OpenGL 4.2 or ARB_texture_storage) to allocate the texture's storage,
then upload with glTexSubImage2D:
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
glTexSubImage2D(GL_TEXTURE_2D, 0​, 0, 0, width​, height​, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
This creates a texture with a single mipmap level, and sets all of the parameters appropriately. If you wanted to have multiple mipmaps, then you should change the 1 to the number of mipmaps you want. You will also need separate glTexSubImage2D calls to upload each mipmap.
If that is unavailable, you can get a similar effect from this code:
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
Again, if you use more than one mipmaps, you should change the GL_TEXTURE_MAX_LEVEL to state how many you will use (minus 1. The base/max level is a closed range), then perform a glTexImage2D (note the lack of "Sub") for each mipmap.

Texture do not rotate with OpenGL (C)

I am trying to rotate a texture extracted from a video frame (provided by ffmpeg), I have tried the following code :
glTexSubImage2D(GL_TEXTURE_2D,
0,
0,
0,
textureWidth,
textureHeight,
GL_RGBA,
GL_UNSIGNED_BYTE,
//s_pixels);
pFrameConverted->data[0]);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5,0.5,0.0);
glRotatef(90,0.0,0.0,1.0);
glTranslatef(-0.5,-0.5,0.0);
glMatrixMode(GL_MODELVIEW);
//glDrawTexiOES(-dPaddingX, -dPaddingY, 0, drawWidth + 2 * dPaddingX, drawHeight + 2 * dPaddingY);
glDrawTexiOES(0, 0, 0, drawWidth, drawHeight);
The image is not rotated, do you see the problem ?
From the GL_OES_draw_texture extension specification:
Note also that s, t, r, and q are computed for each fragment as part of DrawTex rendering. This implies that the texture matrix is ignored and has no effect on the rendered result.
You are trying to transform the texture coordinates using the fixed-function texture matrix, but like point sprites, those coordinates are generated per-fragment rather than per-vertex. Thus, that means that nothing you do to the texture matrix is ever going to affect the output of glDrawTexiOES (...).
Consider using a textured quad instead, those will pass through the traditional vertex processing pipeline.

Why is the third vertex of my first triangle always at the origin and the rest of my triangles not being drawn?

I've checked the results of everything and I've tidied up multiple bugs in my draw function already, but I still can't find the reason for the behavior described in the question title. I'm using OpenGL 1.4, 3D textures, vertex arrays, texture coordinate arrays, and glDrawArrays to draw models (from my model API) with textures (from my texture API) to the screen. Through looking at the results of everything (printfs), I've concluded the problem has to be in the block of code that actually draws everything, and not my code that fills these arrays with post animating vertex data (so I'm only posting the former to save on bloating this post).
The current color is used to achieve a per current window brightness effect. The variable msindex is already set to the number of model draw specifications before the loop featured begins. Vertex data and texture coordinate data for every model being drawn are actually all stuffed into one segment, and as you can see below there are glVertexPointer and glTexCoordPointer calls on different parts of the start of it to register this data. The contents of this segment are tightly packed, with three floats for the position of a vertex first and then three floats following for its texture coordinates. There is multitexturing (up to two textures specified much earlier in the model), but both textures share the same texture coordinates (which is why both calls to glTexCoordPointer specify the same location in memory). The while loop is meant to draw each individual specified model according to information for the model draw specification in the miaptr segment. Start is, in my code, the starting 6 float wide index into the overall vertex data segment for the first vertex of the model to be drawn, and count is the number of vertices. In my example case these are just 0 for start and 6 for count (attempted to draw one model with two triangles). Type can be multiple things depending on the model, but in this case it is GL_TRIANGLES. I've tried this with other primitive types, but they all suffer from the same problem. Additionally, the texture being drawn is entirely opaque (and green), the brightness of the target window is always 1, and all the primitives are front facing.
The following is my broken source code:
/* Enable/set global things. */
jgl.Viewport(
(GLint) x, (GLint) y, (GLsizei) width, (GLsizei) height
);
fvals[0] = (jWindowsptr + jGetCurrentWindow())->brightness;
jgl.Color4f(
(GLfloat) fvals[0],
(GLfloat) fvals[0],
(GLfloat) fvals[0],
1
);
jgl.Enable(GL_ALPHA_TEST);
jgl.Enable(GL_CULL_FACE);
jgl.CullFace(GL_BACK);
jgl.Enable(GL_DEPTH_TEST);
jgl.Enable(GL_POINT_SPRITE_ARB);
jgl.EnableClientState(GL_VERTEX_ARRAY);
const GLvoid *vaptrc = vaptr;
jgl.VertexPointer(3, GL_FLOAT, 12, vaptrc);
/* Color clearing is in here so I could see better while testing. */
jgl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Enable/set per texture unit things. */
jgl.ActiveTexture(GL_TEXTURE0 + 1);
jgl.TexEnvi(
GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE
);
jgl.ClientActiveTexture(GL_TEXTURE0 + 1);
jgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
jgl.TexCoordPointer(3, GL_FLOAT, 12, (vaptrc + 3));
jgl.Enable(GL_TEXTURE_3D);
jgl.ActiveTexture(GL_TEXTURE0);
jgl.TexEnvi(
GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE
);
jgl.ClientActiveTexture(GL_TEXTURE0);
jgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
jgl.TexCoordPointer(3, GL_FLOAT, 12, (vaptrc + 3));
jgl.Enable(GL_TEXTURE_3D);
/* Pass #1. */
jgl.MatrixMode(GL_TEXTURE);
jgl.DepthFunc(GL_LESS);
jgl.AlphaFunc(GL_EQUAL, 1);
const GLfloat *tctm;
while (msindex > 0) {
msindex = msindex - 1;
jgl.ActiveTexture(GL_TEXTURE0);
jgl.BindTexture(
GL_TEXTURE_3D, (miaptr + msindex)->textureids[0]
);
if ((miaptr + msindex)->textureids[0] != 0) {
tctm
= (miaptr
+ msindex)->transformationmatrices[0];
jgl.LoadMatrixf(tctm);
}
jgl.ActiveTexture(GL_TEXTURE0 + 1);
jgl.BindTexture(
GL_TEXTURE_3D, (miaptr + msindex)->textureids[1]
);
if ((miaptr + msindex)->textureids[1] != 0) {
tctm
= (miaptr
+ msindex)->transformationmatrices[1];
jgl.LoadMatrixf(tctm);
}
jgl.DrawArrays(
(miaptr + msindex)->type,
(GLint) (miaptr + msindex)->start,
(GLsizei) (miaptr + msindex)->count
);
}
/* WIP */
/* Disable per texture unit things. */
jgl.ActiveTexture(GL_TEXTURE0 + 1);
jgl.ClientActiveTexture(GL_TEXTURE0 + 1);
jgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
jgl.Disable(GL_TEXTURE_3D);
jgl.ActiveTexture(GL_TEXTURE0);
jgl.ClientActiveTexture(GL_TEXTURE0);
jgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
jgl.Disable(GL_TEXTURE_3D);
/* WIP */
/* Disable global things. */
jgl.DisableClientState(GL_VERTEX_ARRAY);
jgl.Disable(GL_POINT_SPRITE_ARB);
jgl.Disable(GL_DEPTH_TEST);
jgl.Disable(GL_CULL_FACE);
jgl.Disable(GL_ALPHA_TEST);
Your description says that you have interleaved vertex attributes, with 3 floats for the position and 3 floats for the texture coordinates per vertex. This also matches the code you posted.
The values you pass as stride to the glVertexPointer() and glTexCoordPointer() does not match this, though. With 6 floats (3 for position + 3 for texture coordinate) per vertex, and a float being 4 bytes large, the stride should be 6 * 4 = 24. So all these calls need to use 24 for the stride:
jgl.VertexPointer(3, GL_FLOAT, 24, vaptrc);
jgl.TexCoordPointer(3, GL_FLOAT, 24, ...);

OpenGL texture rendering

I'm having problem rendering a texture in OpenGL. I'm getting a white color instead of the texture image but my rectangle and the whole context is working fine. I'm using the stbi image loading library and OpenGL 3.3.
Before rendering:
glViewport(0, 0, ScreenWidth, ScreenHeight);
glClearColor(0.2f, 0.0f, 0.0f, 1.0f);
int Buffer;
glGenBuffers(1, &Buffer);
glBindBuffer(GL_ARRAY_BUFFER, Buffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
Loading the Texture:
unsigned char *ImageData = stbi_load(file_name, 1024, 1024, 0, 4); //not sure about the "0" parameter
int Texture;
glGenTextures(1, &Texture);
glBindTexture(GL_TEXTURE_2D, Texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, ImageData);
stbi_image_free(ImageData);
Rendering:
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 6 * 3); //a rectangle which is rendered fine
glDisableVertexAttribArray(0);
I am looking for a very minimalistic and simple solution.
First of all, take a second to look at the function declaration for stbi_load (...):
unsigned char *stbi_load (char const *filename,
int *x, // POINTER!!
int *y, // POINTER!!
int *comp, // POINTER!!
int req_comp)
Now, consider the arguments you have passed it:
file_name (presumably a pointer to a C string)
1024 (definitely NOT a pointer)
1024 (definitely NOT a pointer)
0 (definitely NOT a pointer)
The whole point of passing x, y and comp as pointers is so that stbi can update their values after it loads the image. This is the C equivalent of passing by reference in a language like C++ or Java, but you have opted instead to pass integer constants that the compiler then treats as addresses.
Because of the way you call this function, stbi attempts to store the width of the image at the address: 1024, the height of the image at address: 1024 and the number of components at address: 0. You are actually lucky that this does not cause an access violation or other bizarre behavior at run-time, storing things at arbitrary addresses is dangerous.
Instead, consider this:
GLuint ImageX,
ImageY,
ImageComponents;
GLubyte *ImageData = stbi_load(file_name, &ImageX, &ImageY, &ImageComponents, 4);
[...]
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
ImageX, ImageY, 0, GL_RGBA, GL_UNSIGNED_BYTE, ImageData);
// ~~~~ You are requesting 4 components per-pixel from stbi, so this is RGBA!
It's been a while since I've done OpenGL but aside from a few arbitrary calls, the main issue I'd guess is that you're not calling glEnable(GL_TEXTURE_2D);before you make the call to draw your function. Afterwards it is wise to call glDisable(GL_TEXTURE_2D);
as well to avoid potential future conflicts.

How to write out a greyscale cairo surface to PNG

I have a cairo_surface_t of format CAIRO_FORMAT_A8. I want to write out the surfe as a greyscale image, so every pixel has a single byte value of type uchar.
If I use cairo_surface_write_to_png directly on the CAIRO_FORMAT_A8 surface, all I get is an all-black image. I think this is how cairo internally treats the A8 surface - as alpha values, not as greyscale data. I want a single greyscale image, however.
I'd be enough if somebody count point out how to copy the A8 format to all 3 layers of an RGB24 image.
Any help appreciated!
Untested code below. The idea is to create an ARGB-surface and "copy" the A8 surface there via cairo_mask_surface(). If the colors are "swapped", swap the two cairo_set_source_rgb() calls.
cairo_surface_t *s = YOUR_A8_SURFACE;
cairo_t *cr = cairo_create(s);
cairo_push_group_with_content(cr, CAIRO_CONTENT_COLOR_ALPHA);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_mask_surface(cr, cairo_get_target(cr), 0, 0);
cairo_surface_write_to_png(cairo_get_group_target(cr), "/tmp/foo.png");
/* If you want to continue using the context:
cairo_pattern_destroy(cairo_pop_group(cr)); */
cairo_destroy(cr);

Resources