Better way to ignore specific colour - Blit - c++

I am given a constantly changing/updated buffer and I need to blit this buffer's pixels to the screen.
For my test code, I read a bitmap and stored it into a buffer.
The thing is, I want to ignore a specific colour when blitting it to the screen using OpenGL.
Currently I use:
glPushMatrix();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
unsigned char* Data = (unsigned char*)Buffer;
for (int I = Bmp.Height(); I > 0; --I)
{
for (int J = 0; J < Bmp.Width(); ++J)
{
if (Data[0] != 0 && Data[1] != 0 && Data[2] != 0) //If the colour is black, we don't draw it..
{
glRasterPos2i(J, I);
glDrawPixels(1, 1, GL_BGR, GL_UNSIGNED_BYTE, Data);
}
Data += Bmp.Bits() == 32 ? 4 : 3;
if(Bmp.Bits() == 24)
Data += (-Bmp.Width() * 3) & 3;
}
}
glPopMatrix();
SwapBuffers(DC);
Sleep(1);
So in the above, what I have is some Buffer pointer called Data. I then loop through it given a height and width. If the colour is black, I don't draw it.. Otherwise I use glDrawPixels in combination with glRasterPos2i to draw it to the screen one pixel at a time. Is there a more efficient way I can make it draw all pixels except a specific colour? It is a buffer not a texture. I used Bmp as an example.

You can use the Stencil buffer. There are also some ways to do chroma key by using the pixel shader.

Related

How to draw an image from a 2d array in modern openGL

I want to draw points with openGL, I have a 32x32 screen size and I want to fill it with the color red, however I don't understand how the parameters of glVertex2f(-1, 0.5) are working
My first instinct was to do something like this:
glutInit(&argc, argv); // Initialize GLUT
glutCreateWindow("OpenGL Setup Test"); // Create a window with the given title
glutInitWindowSize(32, 32); // Set the window's initial width & height
glutDisplayFunc(displaySpectrogram); // Register display callback handler for window re-paint
glutMainLoop(); // Enter the event-processing loop
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer (background)
glBegin(GL_POINTS);
glColor3f(1.0f, 0.0f, 0.0f); // Red
for (int i = 0; i < 32; i++)
{
for (int j = 0; j < 32; j++)
{
glVertex2f(i,j);
}
}
glEnd();
glFlush(); // Render now
But glVertex2f() parameters range is -1 to 1 I think so I'm not sure how to achieve that.
There is another way with texture but I have no idea on how to use them and there are no tutorials for that online
I recommend to use an Orthographic projection. In Orthographic Projection, the view space coordinates are linearly mapped to the clip space coordinates and normalized device coordinates. The viewing volume is defined by 6 distances (left, right, bottom, top, near, far). The values for left, right, bottom, top, near and far define a cuboid (box).
With legacy OpenGL matrices you can use glOrtho to set an orthographic projection matrix:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 32, 0, 32, -1, 1);

OpenGL - object outline

I'm trying to implement a selection-outline feature. This is what I get up to now.
As you can see, the objects are selected correctly when the mouse hovers and a contour is drawn around the selected object.
What I would like to do now is to outline the visible edges of the object in this way
In the image on the left is what I have now, and in the right image is what I want to achieve.
This is the procedure I use now.
void paintGL()
{
/* ... */
int w = geometry().width();
int h = geometry().height();
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF);
setClearColor(Qt::GlobalColor::darkGray);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glStencilMask(0x00);
DrawGeometry();
if (HoveredSphere != RgbFromColorToString(Qt::GlobalColor::black))
{
glBindFramebuffer(GL_FRAMEBUFFER, addFBO(FBOIndex::OUTLINE));
{
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(0xFF);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
DrawOutline(HoveredSphere, 1.0f - 0.025f);
}
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
glBindFramebuffer(GL_READ_FRAMEBUFFER, addFBO(FBOIndex::OUTLINE));
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebufferObject());
{
// copy stencil buffer
GLbitfield mask = GL_STENCIL_BUFFER_BIT;
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, mask, GL_NEAREST);
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00);
glDepthFunc(GL_LEQUAL);
DrawOutline(HoveredSphere, 1.0f);
}
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
}
update();
}
Where DrawGeometry draws all the objects, and DrawOutline draws the selected object scaled by the factor passed as the second parameter.
Thanks for any suggestions.
By following the tips of #MichaelMahn, I found a solution.
First of all, I draw the silhouette of the visible parts of the selected object in a texture.
And then I use this texture to calculate the outline by checking the neighboring pixels to figure out whether or not I stand on the edge of the silhouette.
outline fragment shader
#version 450
uniform sampler2D silhouette;
in FragData
{
smooth vec2 coords;
} frag;
out vec4 PixelColor;
void main()
{
// if the pixel is black (we are on the silhouette)
if (texture(silhouette, frag.coords).xyz == vec3(0.0f))
{
vec2 size = 1.0f / textureSize(silhouette, 0);
for (int i = -1; i <= +1; i++)
{
for (int j = -1; j <= +1; j++)
{
if (i == 0 && j == 0)
{
continue;
}
vec2 offset = vec2(i, j) * size;
// and if one of the neighboring pixels is white (we are on the border)
if (texture(silhouette, frag.coords + offset).xyz == vec3(1.0f))
{
PixelColor = vec4(vec3(1.0f), 1.0f);
return;
}
}
}
}
discard;
}
paintgl
void paintGL()
{
int w = geometry().width();
int h = geometry().height();
setClearColor(Qt::GlobalColor::darkGray);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DrawGeometry();
// if we hover a sphere
if (HoveredSphere != RgbFromColorToString(Qt::GlobalColor::black))
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebufferObject());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, addFBO(FBOIndex::SILHOUETTE));
{
// copy depth buffer
GLbitfield mask = GL_DEPTH_BUFFER_BIT;
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, mask, GL_NEAREST);
// set clear color
setClearColor(Qt::GlobalColor::white);
// enable depth test
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
// clear color buffer
glClear(GL_COLOR_BUFFER_BIT);
// draw silhouette
DrawSilhouette(HoveredSphere);
}
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
// clear depth buffer
glClear(GL_DEPTH_BUFFER_BIT);
// draw outline
DrawOutline();
}
}
PROBLEM :: Now I'd like to parameterize the width of the contour, whose thickness is currently fixed at 1 pixel.
Thank you so much for any suggestion!
Thanks to the advice of #Andrea I found the following solution.
outline fragment shader
#version 450
uniform sampler2D silhouette;
in FragData
{
smooth vec2 coords;
} frag;
out vec4 PixelColor;
void main()
{
// outline thickness
int w = 3;
// if the pixel is black (we are on the silhouette)
if (texture(silhouette, frag.coords).xyz == vec3(0.0f))
{
vec2 size = 1.0f / textureSize(silhouette, 0);
for (int i = -w; i <= +w; i++)
{
for (int j = -w; j <= +w; j++)
{
if (i == 0 && j == 0)
{
continue;
}
vec2 offset = vec2(i, j) * size;
// and if one of the pixel-neighbor is white (we are on the border)
if (texture(silhouette, frag.coords + offset).xyz == vec3(1.0f))
{
PixelColor = vec4(vec3(1.0f), 1.0f);
return;
}
}
}
}
discard;
}
Now I still have a small problem when the selected object is at the edge of the window.
As you can see, the outline is cut sharply.
I tried to "play" with glTexParameter on the parameters GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T.
In the image above you can see the effect I get with
glTexParameters(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameters(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
while in the image below you can see the effect I get with
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, &(QVector4D (1.0f, 1.0f, 1.0f, 1.0f)[0]));
glTexParameters(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameters(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
I would like the outline to show up at the edge of the window, but only where necessary.
Thanks a lot!

Using GLUT to simply print text

For the entire night, I've been looking around the internet, both stackoverflow and elsewhere, to find something to say how to print text on GLUT. While I've found places that say how, none have explained it well, saying which parts of the function is neccessary, which parts aren't. I've also tried to copy in some of the code with the closest to a success is something that made my entire screen white except for some blue pixels. So I've given up, and I'm hoping this will clear up confusion for me and the many people who are confused, like me.
So, I have found this code:
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(1280, 720);
int len = menu.length();
for (int i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
and I have placed it in my code:
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-_cameraAngle, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -9.0f + zoom);
glTranslatef(0.0f, -1.0f, 0.0f);
string menu = "Hello!";
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(1280, 720);
int len = menu.length();
for (int i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
} /*if I need to post the rest of drawScene(), which is the function delegated
as the Display Func, tell me. I don't want to because it's long
What I want to know is what am I doing wrong, and what do future readers in my position need to do in order to get good results.
You don't say what's specifically wrong, but I'm suspecting that your text is not showing up. The reason is likely that the raster position is being clipped, and this is causing your text to not be rendered.
The raster position is the "anchor point" of where a bitmap will be drawn. Usually, this is the lower-left corner of the bitmap (the glBitmap can change that with by setting the x and y parameters to something other than zero, but assume you're not doing that). The raster position is transformed by the model-view matrix, just like a vertex in a geometric primitive. And just like a vertex, if the transformed raster position lies outside of the viewport, it's clipped, and nothing is rendered. What's important to know here is that any rendering of a bitmap - regardless of its size - is predicated on the raster position being inside of the viewport.
In your example, you don't show the viewport you're using, nor the projection transformation (the matrix on the GL_PROJECTION stack), but you set the raster position to (1280, 720), which may well be outside of the viewport.
Let's say you want to render your text in the lower-left corner of your window (and for the sake of argument, let's say your window is 1280 x 1024). When it's time to render your text, drop the following into your rendering routine:
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
gluOrtho2D( 0, 1280, 0, 1024 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glRasterPos2i( 10, 1014 ); // move in 10 pixels from the left and bottom edges
for ( int i = 0; i < len; ++i ) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
glPopMatrix();
glMatrixMode( GL_PROJECTION );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
Depending on which version of OpenGL you're using, you may be able to use a simpler routine glWindowPos2i() (the 2i can be replaced with other dimension-type pairs like other OpenGL functions), which bypasses transforming the raster position by the model-view and projection matrices, and works directly in window coordinates. In that case, you'd write the above code as:
glWindowPos2i( 10, 1014 ); // move in 10 pixels from the left and bottom edges
for ( int i = 0; i < len; ++i ) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}

Holding Vector of unique value set for color selection using C++ and OpenGL

I'm part of a project where I am handling the selection method for a 3D rendering of a pipe system. to be able to select the pipes, my research suggests that color picking would be the best method (due to the number of pipes, ray selection may be more difficult).
//define color for pipe
int lowc=0;
int highc=9;
float cB = (rand()%(highc-lowc+1)+lowc)/10.0;
float cG = (rand()%(highc-lowc+1)+lowc)/10.0;
float cR = (rand()%(highc-lowc+1)+lowc)/10.0;
//some way of confirming the complete color combination is unique.
// Create and insert new pipe in a new branch..
Pipe* new_p = new Pipe(new_n1, new_n2, d, wf,cB,cG,cR);
ElementList* new_branch = new ElementList();
new_branch->branch->Append(new_n1);
new_branch->branch->Append(new_p);
new_branch->branch->Append(new_n2);
At the moment I'm struggling to figure out the most efficient way to check whether the defined color already exists. Storing a vector of all 1000 current color combinations seems too time consuming, as does referencing all other existing nodes color values for each. Would there be any better solution for storing a vector of existing colors (eg <0.2, 0.6, 0.4>, <0.8, 0.1, 0.1>, etc) and comparing it with any other existing vectors?
I can give you an example for picking triangles of an object. You should change this example into rendering tube indices instead of face indices.
PickingModeBegin(); // see below
glBegin(GL_TRIANGLES);
for (FaceIndex fi = 0; fi < GetFacesSize(); fi++) {
const Face & face = faces[fi];
glColor3ub((fi >> 16) & 255, (fi >> 8) & 255, (fi & 255)); // color coded index
glVertex3fv(vertices[face.a].GetPointer());
glVertex3fv(vertices[face.b].GetPointer());
glVertex3fv(vertices[face.c].GetPointer());
}
glEnd();
PickingModeEnd(); // see below
glReadBuffer(GL_BACK);
GLint viewportInfo[4];
glGetIntegerv(GL_VIEWPORT, viewportInfo);
GLubyte pixel[3];
// read the color
glReadPixels(mousePosX, viewportInfo[3] - mousePosY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel);
// extract face index
int selectedFaceIdx = (pixel[0] << 16) + (pixel[1] << 8) + pixel[2];
void PickingModeBegin(void) {
glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
// turn off everything
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_FOG);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_1D);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_3D);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
void PickingModeEnd(void) {
glPopAttrib();
}
struct ColourValue
{
int red, blue, green;
ColourValue() : red(0), blue(0), green(0) {}
ColourValue(int red, int blue, int green) : red(red), blue(blue), green(green) {}
bool operator < (const ColourValue& other) const
{
// magic trick to sort in set
return pair<int, pair<int, int>>(this->red, pair<int, int>(this->blue, this->green))
< pair<int, pair<int, int>>(other.red, pair<int, int>(other.blue, other.green));
}
};
set<ColourValue> all_colours;

Missing some colors from PNG texture in DirectX during loading and saving?

I use standard DirectX functions (like CreateTexture2D, D3DX11SaveTextureToFile and D3DX11CreateShaderResourceViewFromFile) to load the PNG image, render it on new created texture and than save to file. All the textures are the power of two sizes.
But during it, I have noticed, that some colors from PNG are a little corrupted (similar but not the same as the colors from the source texture). The same with transparency (it works for 0 and 100% transparency parts, but not for e.g. 34%).
Are there some big color-approximations or I do something wrong? If so, how can I solve it?
Here are these two images (left is source: a little different colors and some gradient transparency on the bottom; right is image after loading first image and render it on the new texture, that was than saved to file):
I don't know what cause that behaviour, maybe the new texture's description:
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
I have tried to change it to DXGI_FORMAT_R32G32B32A32_FLOAT, but the effect was even stranger:
Here is the code for rendering source texture on the new texture:
context->OMSetRenderTargets(1, &renderTargetView, depthStencilView); //to render on new texture instead of the screen
float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f}; //red, green, blue, alpha
context->ClearRenderTargetView(renderTargetView, clearColor);
//clear the depth buffer to 1.0 (max depth)
context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
//rendering
turnZBufferOff();
shader->set(context);
object->render(shader, camera, textureManager, context, 0);
swapChain->Present(0, 0);
And in object->render():
UINT stride;
stride = sizeof(Vertex);
UINT offset = 0;
context->IASetVertexBuffers( 0, 1, &buffers->vertexBuffer, &stride, &offset ); //set vertex buffer
context->IASetIndexBuffer( buffers->indexBuffer, DXGI_FORMAT_R16_UINT, 0 ); //set index buffer
context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); //set primitive topology
if(textureID){
context->PSSetShaderResources( 0, 1, &textureManager->get(textureID)->texture);
}
ConstantBuffer2DStructure cbPerObj;
cbPerObj.positionAndScale = XMFLOAT4(center.getX(), center.getY(), halfSize.getX(), halfSize.getY());
cbPerObj.textureCoordinates = XMFLOAT4(textureRectToUse[0].getX(), textureRectToUse[0].getY(), textureRectToUse[1].getX(), textureRectToUse[1].getY());
context->UpdateSubresource(constantBuffer, 0, NULL, &cbPerObj, 0, 0);
context->VSSetConstantBuffers(0, 1, &constantBuffer);
context->PSSetConstantBuffers(0, 1, &constantBuffer);
context->DrawIndexed(6, 0, 0);
The shader is very simple:
VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD)
{
VS_OUTPUT output;
output.Pos.zw = float2(0.0f, 1.0f);
//inPos(x,y) = {-1,1}
output.Pos.xy = (inPos.xy * positionAndScale.zw) + positionAndScale.xy;
output.TexCoord.xy = inTexCoord.xy * (textureCoordinates.zw - textureCoordinates.xy) + textureCoordinates.xy;
return output;
}
float4 PS(VS_OUTPUT input) : SV_TARGET
{
return ObjTexture.Sample(ObjSamplerState, input.TexCoord);
}
For some optimalisation I parse the sprite's size as the shader's param (it works fine, the size of texture, borders etc. are right).
Did you set blend states around? Alpha will not work by default since default blend is no blend at all.
Here is a standard alpha blend state:
D3D11_BLEND_DESC desc;
desc.AlphaToCoverageEnable=false;
desc.IndependentBlendEnable = false;
for (int i =0; i < 8 ; i++)
{
desc.RenderTarget[i].BlendEnable = true;
desc.RenderTarget[i].BlendOp = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD;
desc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP::D3D11_BLEND_OP_ADD;
desc.RenderTarget[i].DestBlend = D3D11_BLEND::D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND::D3D11_BLEND_ONE;
desc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE::D3D11_COLOR_WRITE_ENABLE_ALL;
desc.RenderTarget[i].SrcBlend = D3D11_BLEND::D3D11_BLEND_SRC_ALPHA;
desc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND::D3D11_BLEND_ONE;
}
ID3D11BlendState* state;
device->CreateBlendState(&desc,&state);
return state;
Also I would use Clear with alpha component set to 1 instead of 0
I'm suggesting that your problems are stemming from importing a layered Fireworks PNG file. Fireworks layered PNGs retain their layers when imported into other softwares like Flash and Freehand. However, in order to have an exact replication of a layered Fireworks PNG in Photoshop, it's necessary to export that layered PNG as a flattened PNG. Thus, opening it in Photoshop and flattening it is not the solution; the solution lies in opening it and flattening it in Fireworks. (Note: PNGs can be 8, 24 or 32-bit...maybe that needs to be accounted for in your analysis.)