C++ | MFC(SDI) | opengl : black screen - c++

i want to draw some openGl in a simple MFC :
process:
i start a fresh project MFC/SDI
i link opengl32.lib/glu32.lib to my project , i include gl.h and glu.h too.
i implements the opengl's requierts methods (onCreate/precreate/PIXELFORMATDESCRIPTOR) (https://www.microsoft.com/msj/archive/S2085.aspx )
i can build without error
on my onDraw fonction, if i make nothing : nothing happend ! ( \o/)
when i start to write some opengl code => black screen ( i test this code before, in a valid mfc-opengl project , and it's works )
my onDraw() :
void CMFCopenGLtestView::OnDraw(CDC* pDC){
ValidateRect(NULL);
CRect rect;
GetClientRect(&rect);
pDC->SetTextColor(RGB(255, 0, 0));
wglMakeCurrent(m_hDC, m_hRC);
//://
// HERE i WANT TO DRAW SOME OPENGL
//://
SwapBuffers(m_hDC);
wglMakeCurrent(m_hDC, NULL);
pDC->DrawText(_T("test"), 16, &rect, 1);
}
onCreate()
int CMFCopenGLtestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
InitializeOpenGL();
return 0;
}
BOOL CMFCopenGLtestView::InitializeOpenGL()
{
m_pDC = new CClientDC(this);
if (NULL == m_pDC) // failure to get DC
{
return FALSE;
}
if (!SetupPixelFormat(NULL))
{
return FALSE;
}
if (0 == (m_hRC =
::wglCreateContext(m_pDC->GetSafeHdc())))
{
return FALSE;
}
if (FALSE ==
::wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC))
{
return FALSE;
}
// specify black as clear color
::glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// specify the back of the buffer as clear depth
::glClearDepth(1.0f);
// enable depth testing
::glEnable(GL_DEPTH_TEST);
return TRUE;
}
BOOL CMFCopenGLtestView::SetupPixelFormat(
PIXELFORMATDESCRIPTOR* pPFD)
{
// default pixel format for a single-buffered,
// OpenGL-supporting, hardware-accelerated,
// RGBA-mode format. Pass in a pointer to a different
// pixel format if you want something else
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),// size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL, // support OpenGL
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
16, // 16-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pixelformat;
PIXELFORMATDESCRIPTOR* pPFDtoUse;
// let the user override the default pixel format
pPFDtoUse = (0 == pPFD) ? &pfd : pPFD;
if (0 == (pixelformat =
::ChoosePixelFormat(m_pDC->GetSafeHdc(), pPFDtoUse)))
{
return FALSE;
}
if (FALSE == ::SetPixelFormat(m_pDC->GetSafeHdc(),
pixelformat, pPFDtoUse))
{
return FALSE;
}
return TRUE;
}
If you have an idea about what i'm doing wrong i'm taking all of them !

Related

Alternative way to SwapChain->Present to draw a frame on DX11

I need to hook DX11 on a game to draw some rectangle.
To do it I have tried some source code but actually the only one that work in my case is ImGui:
https://github.com/ocornut/imgui
theoretically I can use it, but because in my case I need to draw only some line I like to consider other altarnative.
For this reason I have tried this example:
http://www.directxtutorial.com/Lesson.aspx?lessonid=11-4-5
that work on a test desktop project but not in my dll that hook the game.
My dll crash in this line:
pChain->Present(0, 0);
becouse I have already hook with detour this method:
HRESULT __stdcall IDXGISwapChain_Present(IDXGISwapChain* pChain, UINT SyncInterval, UINT Flags)
{
// Get device and swapchain
if (!bGraphicsInitialised)
{
// Init Direct X
if (!InitDirectXAndInput(pChain)) return fnIDXGISwapChainPresent(pChain, SyncInterval, Flags);
// Init ImGui
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
// Setup rendering and IO
ImGui_ImplWin32_Init(hWindow);
ImGui_ImplDX11_Init(pDevice, pContext);
ImGui::GetIO().ImeWindowHandle = hWindow;
// Create render target view for rendering
ID3D11Texture2D* pBackBuffer;
pChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
HRESULT hr = pDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRenderTargetView);
if (FAILED(hr))
{
std::cerr << "Failed to create render target view" << std::endl;
return fnIDXGISwapChainPresent(pChain, SyncInterval, Flags);
}
pBackBuffer->Release();
bGraphicsInitialised = true;
}
LF::Log_Update("IDXGISwapChain_Present");
// Render ImGui
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
ImGui::ShowDemoWindowCustom(test);
ImGui::EndFrame();
ImGui::Render();
pContext->OMSetRenderTargets(1, &pRenderTargetView, NULL);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
return fnIDXGISwapChainPresent(pChain, SyncInterval, Flags);
}
with this code my dll (that use ImuGui) work perfectly and not need "swapChain->Present".
Here my dll without ImuGui:
HRESULT __stdcall IDXGISwapChain_Present(IDXGISwapChain* pChain, UINT SyncInterval, UINT Flags)
{
// Get device and swapchain
if (!bGraphicsInitialised)
{
// Init Direct X
if (!InitDirectXAndInput(pChain)) return fnIDXGISwapChainPresent(pChain, SyncInterval, Flags);
// Init ImGui
////ImGui::CreateContext();
////ImGuiIO& io = ImGui::GetIO(); (void)io;
////io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
////// Setup rendering and IO
////ImGui_ImplWin32_Init(hWindow);
////ImGui_ImplDX11_Init(pDevice, pContext);
////ImGui::GetIO().ImeWindowHandle = hWindow;
// set up and initialize Direct3D
InitD3D(hWindow, pDevice, pContext);
// Create render target view for rendering
ID3D11Texture2D* pBackBuffer;
pChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
HRESULT hr = pDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRenderTargetView);
if (FAILED(hr))
{
std::cerr << "Failed to create render target view" << std::endl;
return fnIDXGISwapChainPresent(pChain, SyncInterval, Flags);
}
pBackBuffer->Release();
bGraphicsInitialised = true;
}
RenderFrame();
pChain->Present(0, 0);
LF::Log_Update("pChain->Present(1, 0)");
return fnIDXGISwapChainPresent(pChain, SyncInterval, Flags);
}
and here my renderframe:
// this is the function used to render a single frame
void RenderFrame(void)
{
if (VectVertices.size() < 1)
return;
// Set transparent color
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
// clear the back buffer
devcon->ClearRenderTargetView(backbuffer, color);
// select which vertex buffer to display
UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);
// select which primtive type we are using
// draw the vertex buffer to the back buffer
devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
devcon->Draw(VectVertices.size(), 0);
// swapchain->Present(0, 0);
}
in short my code not work becouse shouldn't use swapchain->Present that is hooked.
The here the working rendering method of imuGUI:
// Render function
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
// Create and grow vertex/index buffers if needed
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
{
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
return;
}
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
{
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
return;
}
// Upload vertex/index data into a single contiguous GPU buffer
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
return;
if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
return;
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
ctx->Unmap(g_pVB, 0);
ctx->Unmap(g_pIB, 0);
// Setup orthographic projection matrix into our constant buffer
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
{
D3D11_MAPPED_SUBRESOURCE mapped_resource;
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
return;
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
};
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
ctx->Unmap(g_pVertexConstantBuffer, 0);
}
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
struct BACKUP_DX11_STATE
{
UINT ScissorRectsCount, ViewportsCount;
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D11RasterizerState* RS;
ID3D11BlendState* BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
UINT StencilRef;
ID3D11DepthStencilState* DepthStencilState;
ID3D11ShaderResourceView* PSShaderResource;
ID3D11SamplerState* PSSampler;
ID3D11PixelShader* PS;
ID3D11VertexShader* VS;
ID3D11GeometryShader* GS;
UINT PSInstancesCount, VSInstancesCount, GSInstancesCount;
ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
DXGI_FORMAT IndexBufferFormat;
ID3D11InputLayout* InputLayout;
};
BACKUP_DX11_STATE old;
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
ctx->RSGetState(&old.RS);
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
ctx->PSGetSamplers(0, 1, &old.PSSampler);
old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256;
ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount);
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
ctx->IAGetInputLayout(&old.InputLayout);
// Setup desired DX state
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_idx_offset = 0;
int global_vtx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Apply scissor/clipping rectangle
const D3D11_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw
ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->TextureId;
ctx->PSSetShaderResources(0, 1, &texture_srv);
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
// Restore modified DX state
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release();
for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
}
Can you please suggest me a way to avoid to use pChain->Present(0, 0) ?
Thank you !

L_LineRemoveBitmap returns an empty HRGN

I'm trying to use Leadtools Version 20 to automatically cleanup some images (black border removal, line removal, deskew, ...).
Since some of the APIs only work with black and white images, I create a copy of the image in memory and turn it black and white using L_ColorResBitmap. My plan is to use this black and white image to do the processing and then process the colored image manually. For example I use L_BorderRemoveBitmap to figure out the region that needs to be wiped out and then wipe the same region on the color image or use L_DeskewBitmap to figure out the angle that black and white image needs to be turned and then use L_RotateBitmap to turn the colored image. But when I use L_LineRemoveBitmap, it returns an empty region. I even tried to use the callback function, but inside the callback function region is always NULL.I have made sure the image that is being loaded has a vertical line in it and if I save the black and white version the line is removed, but the correct region is not handed back.Here is a snippet of what I'm doing:
FILEINFO fi;
L_INT PageCount;
L_INT i;
L_UINT uFlags;
BITMAPHANDLE tBmp;
BITMAPHANDLE bwBmp;
BORDERREMOVE br = {sizeof(BORDERREMOVE), BORDER_SINGLE_REGION, BORDER_ALL, 25, 4, 10, NULL, nullptr, sizeof(BITMAPHANDLE)};
RECT r;
LINEREMOVE lr = {sizeof(LINEREMOVE), LINE_SINGLE_REGION, 400, 12, 15, 10, 2, 0, LINEREMOVE_VERTICAL, NULL, nullptr, sizeof(BITMAPHANDLE)};
memset(&fi, 0, sizeof(FILEINFO));
fi.uStructSize = sizeof(FILEINFO);
plo->PageNumber = 0; // plo is a LOADFILEOPTION*
L_FileInfo(FileName, &fi, sizeof(FILEINFO), FILEINFO_TOTALPAGES, plo); // ok
PageCount = fi.TotalPages;
for(i = 0; i < PageCount; i++)
{
memset(&fi, 0, sizeof(FILEINFO));
fi.uStructSize = sizeof(FILEINFO);
plo->PageNumber = i + 1;
memset(&tBmp, 0, sizeof(BITMAPHANDLE));
FileInfo(FileName, &fi, sizeof(FILEINFO), 0, plo); // OK
if(tBmp.Flags.Allocated)
L_FreeBitmap(&tBmp);
L_LoadBitmap(FileName, &tBmp, sizeof(BITMAPHANDLE), fi.BitsPerPixel > 24 ? 24 : fi.BitsPerPixel, ORDER_RGBORGRAY, plo, &fi); // OK
if(tBmp.Flags.Allocated)
{
if (TOP_LEFT != tBmp.ViewPerspective)
L_ChangeBitmapViewPerspective(NULL, &tBmp, sizeof(BITMAPHANDLE), TOP_LEFT);
uFlags = DSKW_PROCESS | DSKW_FILL | DSKW_DOCUMENTANDPICTURE | DSKW_BICUBIC | DSKW_NORMALSPEEDROTATE;
if(1 != fi.BitsPerPixel)
uFlags |= (DSKW_DONT_PERFORM_PREPROCESSING | DSKW_NORMAL_DETECTION);
memset(&BitmapRegion, 0, sizeof(BITMAPHANDLE));
BitmapRegion.uStructSize = sizeof(BITMAPHANDLE);
if(bwBmp.Flags.Allocated)
L_FreeBitmap(&bwBmp);
memset(&bwBmp, 0, sizeof(BITMAPHANDLE));
bwBmp.uStructSize = sizeof(BITMAPHANDLE);
L_CopyBitmap(&bwBmp, &tBmp, bwBmp.uStructSize); // OK
if(1 != tBmp.BitsPerPixel)
L_ColorResBitmap(&bwBmp, &bwBmp, sizeof(BITMAPHANDLE), 1, CRF_FIXEDPALETTE, NULL, NULL, 0, NULL, NULL); // OK
L_BorderRemoveBitmap(&bwBmp, &br, nullptr, nullptr, 0) // OK
if(NULL != br.hRgn)
{
L_SetBitmapRgnHandle(&tBmp, nullptr, br.hRgn, L_RGN_SET); // OK
L_FillBitmap(&tBmp, bkColor); // OK bkColor is White
L_FreeBitmapRgn(&tBmp);
}
L_LineRemoveBitmap(&bwBmp, &lr, lrCB, NULL, 0) // returns OK
if(NULL != lr.hRgn) // not null but empty
{
::GetRgnBox(lr.hRgn, &r); // it is always {0, 0, 0, 0}
L_SetBitmapRgnHandle(&tBmp, nullptr, lr.hRgn, L_RGN_SET);
L_FillBitmap(&tBmp, bkColor); // OK but fills nothing
L_FreeBitmapRgn(&tBmp);
}
// do other stuff and save
}
}
L_INT EXT_CALLBACK lrCB(HRGN hRgn, L_INT iStartRow, L_INT iStartCol, L_INT iLength, L_VOID* pUserData)
{
UNREFERENCED_PARAMETER(pUserData);
if(NULL != hRgn) // always null
{
RECT rcRect;
GetRgnBox(hRgn, &rcRect);
DeleteObject(hRgn);
}
return SUCCESS_REMOVE;
}
Sam,
If you want the Callback to set a Windows region, you need to also set the LINE_CALLBACK_REGION uFlag when defining the LINEREMOVE structure:
LINEREMOVE lr = {
sizeof(LINEREMOVE), // uStructSize
LINE_CALLBACK_REGION| LINE_SINGLE_REGION, // uFlags
400, // Minimum Length
12, // Maximum Width
15, // Wall size
10, // Max percent of line that can be a wall
2, // Maximum Gap
0, // Maximum Line Variance
LINEREMOVE_VERTICAL, // horizontal or vertical
NULL, // hRgn
nullptr, // pBitmapRegion
sizeof(BITMAPHANDLE) // uBitmapStructSize
};
The flag is documented in this page.
After the function finishes processing, you can then take the lines region set in the lr.hRgn property and set it in the original color bitmap using the following code:
L_SetBitmapRgnHandle(&OriginalBitmap, NULL, lr.hRgn, L_RGN_SET);
In addition to the response here, I have sent you a small code snippet in a reply to the email you sent to our support address.

Why is an XImage's data pointer null when capturing using XShmGetImage?

I'm writing a program to rapidly capture images from one window, modify them, and output them to another window using Xlib with C++. I have this working via XGetImage:
#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
const int TEST_SIZE = 512;
int main()
{
// Open default display
Display *display = XOpenDisplay(nullptr);
int screen = DefaultScreen(display);
Window rootWin = RootWindow(display, screen);
GC graphicsContext = DefaultGC(display, screen);
// Create new window and subscribe to events
long blackPixel = BlackPixel(display, screen);
long whitePixel = WhitePixel(display, screen);
Window newWin = XCreateSimpleWindow(display, rootWin, 0, 0, TEST_SIZE, TEST_SIZE, 1, blackPixel, whitePixel);
XMapWindow(display, newWin);
XSelectInput(display, newWin, ExposureMask | KeyPressMask);
// Main event loop for new window
XImage *image;
XEvent event;
bool exposed = false;
bool killWindow = false;
while (!killWindow)
{
// Handle pending events
if (XPending(display) > 0)
{
XNextEvent(display, &event);
if (event.type == Expose)
{
exposed = true;
} else if (event.type == NoExpose)
{
exposed = false;
} else if (event.type == KeyPress)
{
killWindow = true;
}
}
// Capture the original image
image = XGetImage(display, rootWin, 0, 0, TEST_SIZE, TEST_SIZE, AllPlanes, ZPixmap);
// Modify the image
if (image->data != nullptr)
{
long pixel = 0;
for (int x = 0; x < image->width; x++)
{
for (int y = 0; y < image->height; y++)
{
// Invert the color of each pixel
pixel = XGetPixel(image, x, y);
XPutPixel(image, x, y, ~pixel);
}
}
}
// Output the modified image
if (exposed && killWindow == false)
{
XPutImage(display, newWin, graphicsContext, image, 0, 0, 0, 0, TEST_SIZE, TEST_SIZE);
}
XDestroyImage(image);
}
// Goodbye
XCloseDisplay(display);
}
It generates output like this: https://streamable.com/hovg9
I'm happy to have gotten this far, but from what I've read the performance isn't going to scale very well because it has to allocate space for a new image at every frame. In fact, without the call to XDestroyImage at the end of the loop this program fills up all 16GB of memory on my machine in a matter of seconds!
It seems the recommended approach here is to to set up a shared memory space where X can write the contents of each frame and my program can subsequently read and modify them without the need for any extra allocation. Since the call to XShmGetImage blocks and waits for IPC I believe this means I won't have to worry about any concurrency issues in the shared space.
I've attempted to implement the XShmGetImage approach with the following code:
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/Xutil.h>
const int TEST_SIZE = 512;
int main()
{
// Open default display
Display *display = XOpenDisplay(nullptr);
int screen = DefaultScreen(display);
Window rootWin = RootWindow(display, screen);
GC graphicsContext = DefaultGC(display, screen);
// Create new window and subscribe to events
long blackPixel = BlackPixel(display, screen);
long whitePixel = WhitePixel(display, screen);
Window newWin = XCreateSimpleWindow(display, rootWin, 0, 0, TEST_SIZE, TEST_SIZE, 1, blackPixel, whitePixel);
XMapWindow(display, newWin);
XSelectInput(display, newWin, ExposureMask | KeyPressMask);
// Allocate shared memory for image capturing
Visual *visual = DefaultVisual(display, 0);
XShmSegmentInfo shminfo;
int depth = DefaultDepth(display, screen);
XImage *image = XShmCreateImage(display, visual, depth, ZPixmap, nullptr, &shminfo, TEST_SIZE, TEST_SIZE);
shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height, IPC_CREAT | 0666);
shmat(shminfo.shmid, nullptr, 0);
shminfo.shmaddr = image->data;
shminfo.readOnly = False;
XShmAttach(display, &shminfo);
// Main event loop for new window
XEvent event;
bool exposed = false;
bool killWindow = false;
while (!killWindow)
{
// Handle pending events
if (XPending(display) > 0)
{
XNextEvent(display, &event);
if (event.type == Expose)
{
exposed = true;
} else if (event.type == NoExpose)
{
exposed = false;
} else if (event.type == KeyPress)
{
killWindow = true;
}
}
// Capture the original image
XShmGetImage(display, rootWin, image, 0, 0, AllPlanes);
// Modify the image
if (image->data != nullptr) // NEVER TRUE. DATA IS ALWAYS NULL!
{
long pixel = 0;
for (int x = 0; x < image->width; x++)
{
for (int y = 0; y < image->height; y++)
{
// Invert the color of each pixel
pixel = XGetPixel(image, x, y);
XPutPixel(image, x, y, ~pixel);
}
}
}
// Output the modified image
if (exposed && killWindow == false)
{
XShmPutImage(display, newWin, graphicsContext, image, 0, 0, 0, 0, 512, 512, false);
}
}
// Goodbye
XFree(image);
XCloseDisplay(display);
}
Somehow, the images are still being captured and sent to the new window, but the data pointer within the XImage is always null. I can't modify any of the contents and any usage of the XGetPixel and XPutPixel macros will fail. Notice in this video that none of the colors are being inverted like before: https://streamable.com/dckyv
This doesn't make any sense to me. Clearly the data is still being transferred between the windows, but where is it in the XImage structure? How can I access it via code?
It turns out I wasn't reading the signature for shmat correctly. It doesn't have a void return type, it returns a void pointer. This needs to be assigned directly to the XImage's data pointer in order for the data pointer to do anything.
In the call to XShmPutImage the shared memory location is referenced internally rather than the XImage's data pointer which is why this was still working even without utilizing the return value from shmat.
Here's the working code, along with a few other additions which I made for error handling and teardown:
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/Xutil.h>
const int TEST_SIZE = 512;
static int handleXError(Display *display, XErrorEvent *event)
{
printf("XErrorEvent triggered!\n");
printf("error_code: %d", event->error_code);
printf("minor_code: %d", event->minor_code);
printf("request_code: %d", event->request_code);
printf("resourceid: %lu", event->resourceid);
printf("serial: %d", event->error_code);
printf("type: %d", event->type);
return 0;
}
int main()
{
// Open default display
XSetErrorHandler(handleXError);
Display *display = XOpenDisplay(nullptr);
int screen = DefaultScreen(display);
Window rootWin = RootWindow(display, screen);
GC graphicsContext = DefaultGC(display, screen);
// Create new window and subscribe to events
long blackPixel = BlackPixel(display, screen);
long whitePixel = WhitePixel(display, screen);
Window newWin = XCreateSimpleWindow(display, rootWin, 0, 0, TEST_SIZE, TEST_SIZE, 1, blackPixel, whitePixel);
XMapWindow(display, newWin);
XSelectInput(display, newWin, ExposureMask | KeyPressMask);
// Allocate shared memory for image capturing
XShmSegmentInfo shminfo;
Visual *visual = DefaultVisual(display, screen);
int depth = DefaultDepth(display, screen);
XImage *image = XShmCreateImage(display, visual, depth, ZPixmap, nullptr, &shminfo, TEST_SIZE, TEST_SIZE);
shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height, IPC_CREAT | 0777);
image->data = (char*)shmat(shminfo.shmid, 0, 0);
shminfo.shmaddr = image->data;
shminfo.readOnly = False;
XShmAttach(display, &shminfo);
XSync(display, false);
shmctl(shminfo.shmid, IPC_RMID, 0);
// Main event loop for new window
XEvent event;
bool exposed = false;
bool killWindow = false;
while (!killWindow)
{
// Handle pending events
if (XPending(display) > 0)
{
XNextEvent(display, &event);
if (event.type == Expose)
{
exposed = true;
} else if (event.type == NoExpose)
{
exposed = false;
} else if (event.type == KeyPress)
{
killWindow = true;
}
}
// Capture the original image
XShmGetImage(display, rootWin, image, 0, 0, AllPlanes);
// Modify the image
if(image->data != nullptr) // NEVER TRUE. DATA IS ALWAYS NULL!
{
long pixel = 0;
for (int x = 0; x < image->width; x++)
{
for (int y = 0; y < image->height; y++)
{
// Invert the color of each pixel
pixel = XGetPixel(image, x, y);
XPutPixel(image, x, y, ~pixel);
}
}
}
// Output the modified image
if (exposed && killWindow == false)
{
XShmPutImage(display, newWin, graphicsContext, image, 0, 0, 0, 0, 512, 512, false);
}
}
// Goodbye
XShmDetach(display, &shminfo);
XDestroyImage(image);
shmdt(shminfo.shmaddr);
XCloseDisplay(display);
}

OpenGL on a custom made win32 window, using cygwin compiler, doesn't work

I wrote a bit of code, based on NeHe's first tutorial, which creates a window and initializes gl context. this worked exactly as it should in vc++. Then I've tried to replicate the same code in eclipse c++ environment using cygwin compiler and the problems began.
The window compiles without any errors (A number of warnings but no errors), the exe opens a win32 window as it should, all of the functionality that I've coded into the window works too (e.g. full screen mode, change resolution) the only problem is that instead of refreshing the background of the window with red colour as it should I'm getting a black square and that's it.
To me this looks like an opengl initialization problem. Been trying to solve this problem for two days but I can't find any solution I hope somebody can see what I'm doing wrong.
Below are the code extracts.
Initial method
#include <iostream>
#include <windows.h>
#include <gl/glew.h>
#include <string>
#define GLEW_STATIC
using namespace std;
#include <glWindow.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG msg;
GLboolean Exit = FALSE;
glWindow screen("Dark Light", 640, 480, 16);
while(!Exit){
if (screen.LastError() == errNone && screen.WndState() != glExit){
// Is There A Message Waiting?
if (PeekMessage(&msg, screen.Handles().Window(), 0, 0, PM_REMOVE)){
// Have We Received A Quit Message?
if (msg.message == WM_QUIT){
screen.WndState() = glExit;
}
// If Not, Deal With Window Messages
else{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
// If There Are No Messages
else{
if (screen.WndState() == glActive){
if (screen.KeysState(VK_ESCAPE)){
screen.WndState() = glExit;
}
else{
// Draw The Scene
screen.Draw();
}
}
if (screen.KeysState(VK_F1)){
screen.KeysState(VK_F1) = FALSE;
screen.ToggleFullscreen();
}
if (screen.KeysState(VK_SPACE)){
screen.KeysState(VK_SPACE) = FALSE;
screen.SetResolution(800, 600);
}
}
}
else{
Exit = true;
}
}
// Shutdown
return 0;
}
glWindow.h
#ifndef GLWINDOW_H
#define GLWINDOW_H
#include <string>
using namespace std;
enum glWndState
{
glActive = 0, glPaused = 1, glExit = 2
};
enum glWndErrors
{
errNone = 0, errCreateWC = 1, errCreateWnd = 2, errCreateDC = 3, errMatchPixelFormat = 4,
errSetPixelFormat = 5, errCreateRC = 6, errActivateRC = 7, errInitGL = 8, errChangeRC = 9,
errReleaseRC = 10, errReleaseDC = 11, errDestroyWnd = 12, errDestroyWC = 13, errGoToFullscreen = 14,
errGoToWindowed = 15, errGetInstance = 16
};
class glWndSettings
{
private:
GLsizei _width;
GLsizei _height;
GLboolean _fullscreen;
GLint _bits;
PIXELFORMATDESCRIPTOR _pfd;
DEVMODE _screenSettings;
public:
glWndSettings(GLsizei width, GLsizei height, GLint bits);
glWndErrors glSetStyle(HWND hWnd);
glWndErrors glSetStyle(HWND hWnd, GLboolean fullscreen, GLboolean save = TRUE);
glWndErrors glSetResolution(HWND hWnd, GLsizei width, GLsizei height);
GLsizei& Width();
GLsizei& Height();
GLboolean& Fullscreen();
GLint& Bits();
PIXELFORMATDESCRIPTOR& PixelFormatDescription();
};
class glWndHandles
{
private:
string _className;
HINSTANCE _hInstance;
WNDCLASS _wc;
HWND _hWnd;
HDC _hDC;
HGLRC _hRC;
GLuint _pixelFormat;
public:
glWndHandles(HICON icon, string title, WNDPROC wndProc);
~glWndHandles();
glWndErrors glDefWindow(PIXELFORMATDESCRIPTOR pfd);
HINSTANCE& Instance();
WNDCLASS& WinClass();
HWND& Window();
HDC& DeviceContext();
HGLRC& RenderContext();
};
class glWndFPS
{
GLint _framesCounter;
GLint _fps;
public:
glWndFPS();
GLvoid NewFrame();
GLvoid ResetFrames();
GLint FPS();
};
class glWindow
{
glWndHandles _handles;
glWndSettings _settings;
glWndFPS _fps;
glWndErrors _error;
glWndState _state;
bool _keys[256];
string _title;
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
public:
glWindow(string title, int width, int height, int bits);
~glWindow();
int InitGL();
GLvoid Draw();
GLvoid DisplayFPS();
GLvoid SetTitle(string title);
GLvoid SetResolution(GLsizei width, GLsizei height);
GLvoid SetFullscreen(GLboolean fullscreen);
GLvoid ToggleFullscreen();
glWndHandles& Handles();
glWndSettings& Settings();
glWndFPS& fpsInfo();
glWndErrors& LastError();
glWndState& WndState();
bool& KeysState(int key);
GLvoid ReSizeGLScene(GLsizei width, GLsizei height);
};
#endif /* GLWINDOW_H_ */
glWindow.cpp
#include <stdio.h>
#include <windows.h>
#include <GL/glew.h>
#include <glm/gtc/matrix_transform.hpp>
using namespace std;
#include "glWindow.h"
glWndSettings::glWndSettings(GLsizei width, GLsizei height, GLint bits){
_fullscreen = FALSE;
_width = width;
_height = height;
_bits = bits;
_pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); // Size Of This Pixel Format Descriptor
_pfd.nVersion = 1; // Version Number
_pfd.dwFlags = PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER; // Must Support Double Buffering
_pfd.iPixelType = PFD_TYPE_RGBA; // Request An RGBA Format
_pfd.cColorBits = bits; // Select Our Color Depth
_pfd.cRedBits = 0; _pfd.cRedShift = 0;
_pfd.cGreenBits = 0; _pfd.cGreenShift = 0;
_pfd.cBlueBits = 0; _pfd.cBlueShift = 0; // Color Bits Ignored
_pfd.cAlphaBits = 0; _pfd.cAlphaShift = 0; // No Alpha Buffer
_pfd.cAccumBits = 0;
_pfd.cAccumRedBits = 0;
_pfd.cAccumGreenBits = 0;
_pfd.cAccumBlueBits = 0;
_pfd.cAccumAlphaBits = 0;
_pfd.cDepthBits = 16; // 16Bit Z-Buffer (Depth Buffer)
_pfd.cStencilBits = 0; // No Stencil Buffer
_pfd.cAuxBuffers = 0; // No Auxiliary Buffer
_pfd.iLayerType = PFD_MAIN_PLANE; // Main Drawing Layer
_pfd.bReserved = 0; // Reserved
_pfd.dwLayerMask = 0;
_pfd.dwVisibleMask = 0;
_pfd.dwDamageMask = 0; // Layer Masks Ignored
}
glWndErrors glWndSettings::glSetStyle(HWND hWnd){
GLboolean fullscreen = !_fullscreen;
return glSetStyle(hWnd, fullscreen);
}
glWndErrors glWndSettings::glSetStyle(HWND hWnd, GLboolean fullscreen, GLboolean save){
DWORD dwExStyle = 0;
DWORD dwStyle = 0;
if (save)
_fullscreen = fullscreen;
if (fullscreen){
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
memset(&_screenSettings, 0, sizeof(_screenSettings)); // Makes Sure Memory's Cleared
_screenSettings.dmSize = sizeof(_screenSettings); // Size Of The Devmode Structure
_screenSettings.dmPelsWidth = _width; // Selected Screen Width
_screenSettings.dmPelsHeight = _height; // Selected Screen Height
_screenSettings.dmBitsPerPel = _bits; // Selected Bits Per Pixel
_screenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if (ChangeDisplaySettings(&_screenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){
return errGoToFullscreen;
}
while(ShowCursor(FALSE) >= 0);
}
else{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
if (ChangeDisplaySettings(NULL, 0) != DISP_CHANGE_SUCCESSFUL){
return errGoToWindowed;
}
while(ShowCursor(TRUE) < 0);
}
RECT windowRect;
windowRect.left=(long)0; // Set Left Value To 0
windowRect.right=(long)_width; // Set Right Value To Requested Width
windowRect.top=(long)0; // Set Top Value To 0
windowRect.bottom=(long)_height; // Set Bottom Value To Requested Height
AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size
ShowWindow(hWnd, SW_HIDE);
DWORD oldExStyle = SetWindowLongPtr(hWnd, GWL_EXSTYLE, dwExStyle);
DWORD oldStyle = SetWindowLongPtr(hWnd, GWL_STYLE, dwStyle);
SetWindowPos(hWnd, HWND_TOP, 0, 0, windowRect.right, windowRect.bottom, SWP_NOZORDER);
ShowWindow(hWnd, SW_SHOW);
return errNone;
}
glWndErrors glWndSettings::glSetResolution(HWND hWnd, GLsizei width, GLsizei height){
_width = width; _height = height;
glSetStyle(hWnd, _fullscreen);
return errNone;
}
GLsizei& glWndSettings::Width(){
return _width;
}
GLsizei& glWndSettings::Height(){
return _height;
}
GLboolean& glWndSettings::Fullscreen(){
return _fullscreen;
}
GLint& glWndSettings::Bits(){
return _bits;
}
PIXELFORMATDESCRIPTOR& glWndSettings::PixelFormatDescription(){
return _pfd;
}
glWndHandles::glWndHandles(HICON icon, string title, WNDPROC wndProc){
_hInstance = NULL;
_hWnd = NULL;
_hDC = NULL;
_hRC = NULL;
_pixelFormat = NULL;
_className = title;
_wc.style = CS_HREDRAW | CS_VREDRAW | // Redraw On Size
CS_OWNDC; // Own DC For Window.
_wc.lpfnWndProc = wndProc; // WndProc Handles Messages
_wc.cbClsExtra = NULL; // No Extra Window Data
_wc.cbWndExtra = NULL; // No Extra Window Data
_wc.hInstance = NULL; // Set The Instance
_wc.hIcon = icon; // Load The Default Icon
_wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer
_wc.hbrBackground = NULL; // No Background Required For GL
_wc.lpszMenuName = NULL; // We Don't Want A Menu
_wc.lpszClassName = _className.c_str(); // Set The Class Name
}
glWndHandles::~glWndHandles(){
// Are We Able To Release The DC And RC Contexts?
if (_hRC){
if (!wglMakeCurrent(NULL, NULL))
MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
// Are We Able To Delete The RC?
if (!wglDeleteContext(_hRC))
MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
// Are We Able To Release The DC
if (_hDC && !ReleaseDC(_hWnd, _hDC))
MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
// Are We Able To Destroy The Window?
if (_hWnd && !DestroyWindow(_hWnd))
MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
// Are We Able To Unregister Class
if (!UnregisterClass(_className.c_str(), _hInstance))
MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
glWndErrors glWndHandles::glDefWindow(PIXELFORMATDESCRIPTOR pfd){
if ((_hInstance = GetModuleHandle(NULL))){
_wc.hInstance = _hInstance;
}
else{
MessageBox(NULL, "Failed To Get Window's Instance.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
return errGetInstance;
}
if (!RegisterClass(&_wc)){
MessageBox(NULL, "Failed To Register The Window Class.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
return errCreateWC;
}
if (!(_hWnd=CreateWindowEx( NULL, // Extended Style For The Window
_wc.lpszClassName, // Class Name
_className.c_str(), // Window Title
NULL, // Style For The Window
0, 0, 300, 300, // Window's Position and Size
NULL, // No Parent Window
NULL, // No Menu
_hInstance, // Instance
NULL))){
MessageBox(NULL, "Window Creation Error.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errCreateWnd;
}
//Get Window's Device Context
if (!(_hDC = GetDC(_hWnd))){
MessageBox(NULL, "Can't Create A GL Device Context.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errCreateDC;
}
// Did Windows Find A Matching Pixel Format?
if (!(_pixelFormat = ChoosePixelFormat(_hDC, &pfd))){
MessageBox(NULL, "Can't Find A Suitable PixelFormat.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errMatchPixelFormat;
}
// Are We Able To Set The Pixel Format?
if(!SetPixelFormat(_hDC, _pixelFormat, &pfd)){
MessageBox(NULL, "Can't Set The PixelFormat.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errSetPixelFormat;
}
if (!(_hRC=wglCreateContext(_hDC))){
MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errCreateRC;
}
if(!wglMakeCurrent(_hDC,_hRC)){
MessageBox(NULL, "Can't Activate The GL Rendering Context.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
return errActivateRC;
}
// GLenum err = glewInit();
//
// if (err != GLEW_OK){
// MessageBox(NULL, (char*)glewGetErrorString(err), "ERROR", MB_OK|MB_ICONEXCLAMATION);
// return errInitGL;
// }
return errNone;
}
HINSTANCE& glWndHandles::Instance(){
return _hInstance;
}
WNDCLASS& glWndHandles::WinClass(){
return _wc;
}
HDC& glWndHandles::DeviceContext(){
return _hDC;
}
HGLRC& glWndHandles::RenderContext(){
return _hRC;
}
HWND& glWndHandles::Window(){
return _hWnd;
}
glWndFPS::glWndFPS(){
_framesCounter = 0; _fps = 0;
}
GLvoid glWndFPS::NewFrame(){
_framesCounter++;
}
GLvoid glWndFPS::ResetFrames(){
_fps = _framesCounter; _framesCounter = 0;
}
GLint glWndFPS::FPS(){
return _fps;
}
glWindow* owner;
LRESULT CALLBACK glWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
// Check For Windows Messages
switch (uMsg){
// Watch For Window Activate Message
case WM_ACTIVATE:{
// Check Minimization State
if (!HIWORD(wParam)){
// Program Is Active
owner->_state = glActive;
}
else{
// Program Is No Longer Active
owner->_state = glPaused;
}
// Return To The Message Loop
return 0;
}
// Intercept System Commands
case WM_SYSCOMMAND:{
// Check System Calls
switch (wParam){
// Screensaver Trying To Start?
case SC_SCREENSAVE:
// Monitor Trying To Enter Powersave?
case SC_MONITORPOWER:
// Prevent From Happening
return 0;
}
break;
}
// Did We Receive A Close Message?
case WM_CLOSE:{
// Send A Quit Message
PostQuitMessage(0);
return 0;
}
// Is A Key Being Held Down?
case WM_KEYDOWN:{
// If So, Mark It As TRUE
owner->_keys[wParam] = TRUE;
return 0;
}
// Has A Key Been Released?
case WM_KEYUP:{
// If So, Mark It As FALSE
owner->_keys[wParam] = FALSE;
return 0;
}
// Resize The OpenGL Window
case WM_SIZE:{
if (owner->Settings().Fullscreen() && IsWindowVisible(hWnd)){
if (wParam == SIZE_MINIMIZED)
owner->Settings().glSetStyle(hWnd, FALSE, FALSE);
else if (wParam == SIZE_RESTORED)
owner->Settings().glSetStyle(hWnd, TRUE, FALSE);
}
// LoWord=Width, HiWord=Height
owner->ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));
return 0;
}
case WM_KILLFOCUS:{
if (IsWindowVisible(hWnd) && owner->Settings().Fullscreen())
ShowWindow(hWnd, SW_MINIMIZE);
return 0;
}
case WM_TIMER:{
if (wParam == 1)
owner->DisplayFPS();
return 0;
}
}
// Pass All Unhandled Messages To DefWindowProc
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
glWindow::glWindow(string title, int width, int height, int bits)
:_settings(width, height, bits), _handles(LoadIcon(NULL, IDI_WINLOGO), title, (WNDPROC)WndProc)
{
for (int i = 0; i < 256; i++){
_keys[i] = false;
}
_error = errNone; _state = glActive; owner = this;
_title = title;
if ((_error = _handles.glDefWindow(_settings.PixelFormatDescription())) != errNone){
return;
}
_settings.glSetStyle(_handles.Window(), false);
SetForegroundWindow(_handles.Window()); // Slightly Higher Priority
SetFocus(_handles.Window()); // Sets Keyboard Focus To The Window
// Initialize Our Newly Created GL Window
if (!InitGL()){
MessageBox(NULL, "Initialization Failed.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
_error = errInitGL;
return;
}
SetTimer(_handles.Window(), 1, 1000, NULL);
}
glWindow::~glWindow(void){
if (_settings.Fullscreen()){
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
}
int glWindow::InitGL(){
glShadeModel(GL_SMOOTH);
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
// Really Nice Perspective Calculations
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
return TRUE; // Initialization Went OK
}
GLvoid glWindow::Draw(){
//Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // Reset The Current Modelview Matrix
SwapBuffers(_handles.DeviceContext());
fpsInfo().NewFrame();
}
glWndErrors& glWindow::LastError(){
return _error;
}
glWndState& glWindow::WndState(){
return _state;
}
glWndHandles& glWindow::Handles(){
return _handles;
}
glWndSettings& glWindow::Settings(){
return _settings;
}
glWndFPS& glWindow::fpsInfo(){
return _fps;
}
bool& glWindow::KeysState(int key){
return _keys[key];
}
GLvoid glWindow::DisplayFPS(){
fpsInfo().ResetFrames();
char fps[100];
sprintf(fps, "%d", fpsInfo().FPS());
SetTitle(_title + " : ");
SetTimer(_handles.Window(), 1, 1000, NULL);
}
GLvoid glWindow::SetTitle(string title){
SetWindowText(_handles.Window(), title.c_str());
}
GLvoid glWindow::SetResolution(GLsizei width, GLsizei height){
_settings.glSetResolution(_handles.Window(), width, height);
}
GLvoid glWindow::SetFullscreen(GLboolean fullscreen){
_settings.glSetStyle(_handles.Window(), fullscreen);
}
GLvoid glWindow::ToggleFullscreen(){
_settings.glSetStyle(_handles.Window());
}
GLvoid glWindow::ReSizeGLScene(GLsizei width, GLsizei height){
if (height == 0 && width == 0){
return;
}
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
glm::perspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
Compiler output
g++ -ID:/DarkLight/hello/header -ID:/DarkLight/externals/include -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\glWindow.o" "..\\src\\glWindow.cpp"
g++ -ID:/DarkLight/hello/header -ID:/DarkLight/externals/include -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\hello.o" "..\\src\\hello.cpp"
g++ -mwindows -o hello.exe "src\\hello.o" "src\\glWindow.o" -lgl -lglew32 -lglu32 -lopengl32 -lgdi32
How did you compile the Cygwin build? Specifically which libraries did you link?
Cygwin can be compiled for the native GUI system (Win32) or to make use of X11. But OpenGL goes through two very different stacks between the two cases. In case of Win32 it goes through WGL and in case of X11 it goes through GLX. Now if you accidently linked the GLX based OpenGL API (-lGL) then all the OpenGL symbols are there, so things seem to work superficially, but there's no output. You have to link against opengl32.lib, i.e. -lopengl32 so that the WGL based bindings are used.

OpenGL Set Transparent Color for textures

My question-> How do i make color 255,200,255 transparent in OpenGL? (by transparent i mean removing the pixels color 255,200,255 or whatever works...)
my texture loading functions are from this tutorial-> http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=33
note that i don't have to use Alpha Channels, i have a set of pre-made images with custom color (255,200,255) which must be transparent/removed pixels..
some .tga loading functions of my program:
Texture AllTextures[1000];
typedef struct
{
GLubyte * imageData; // Image Data (Up To 32 Bits)
GLuint bpp; // Image Color Depth In Bits Per Pixel
GLuint width; // Image Width
GLuint height; // Image Height
GLuint texID; // Texture ID Used To Select A Texture
GLuint type; // Image Type (GL_RGB, GL_RGBA)
} Texture;
bool LoadUncompressedTGA(Texture * texture, char * filename, FILE * fTGA) // Load an uncompressed TGA (note, much of this code is based on NeHe's
{ // TGA Loading code nehe.gamedev.net)
if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0) // Read TGA header
{
MessageBox(NULL, "Could not read info header", "ERROR", MB_OK); // Display error
if(fTGA != NULL) // if file is still open
{
fclose(fTGA); // Close it
}
return false; // Return failular
}
texture->width = tga.header[1] * 256 + tga.header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
texture->height = tga.header[3] * 256 + tga.header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
texture->bpp = tga.header[4]; // Determine the bits per pixel
tga.Width = texture->width; // Copy width into local structure
tga.Height = texture->height; // Copy height into local structure
tga.Bpp = texture->bpp; // Copy BPP into local structure
if((texture->width <= 0) || (texture->height <= 0) || ((texture->bpp != 24) && (texture->bpp !=32))) // Make sure all information is valid
{
MessageBox(NULL, "Invalid texture information", "ERROR", MB_OK); // Display Error
if(fTGA != NULL) // Check if file is still open
{
fclose(fTGA); // If so, close it
}
return false; // Return failed
}
if(texture->bpp == 24) //If the BPP of the image is 24...
{
texture->type = GL_RGBA; // Set Image type to GL_RGB
}
else // Else if its 32 BPP
{
texture->type = GL_RGBA; // Set image type to GL_RGBA
}
tga.bytesPerPixel = (tga.Bpp / 8); // Compute the number of BYTES per pixel
tga.imageSize = (tga.bytesPerPixel * tga.Width * tga.Height); // Compute the total amout ofmemory needed to store data
texture->imageData = (GLubyte *)malloc(tga.imageSize); // Allocate that much memory
if(texture->imageData == NULL) // If no space was allocated
{
MessageBox(NULL, "Could not allocate memory for image", "ERROR", MB_OK); // Display Error
fclose(fTGA); // Close the file
return false; // Return failed
}
if(fread(texture->imageData, 1, tga.imageSize, fTGA) != tga.imageSize) // Attempt to read image data
{
MessageBox(NULL, "Could not read image data", "ERROR", MB_OK); // Display Error
if(texture->imageData != NULL) // If imagedata has data in it
{
free(texture->imageData); // Delete data from memory
}
fclose(fTGA); // Close file
return false; // Return failed
}
// Byte Swapping Optimized By Steve Thomas
for(GLuint cswap = 0; cswap < (int)tga.imageSize; cswap += tga.bytesPerPixel)
{
texture->imageData[cswap] ^= texture->imageData[cswap+2] ^=texture->imageData[cswap] ^= texture->imageData[cswap+2];
}
fclose(fTGA); // Close file
return true; // Return success
}
void LoadMyTextureTGA(int id,char* texturename)
{
//texturename ex: "Data/Uncompressed.tga"
if(LoadTGA(&AllTextures[id], texturename))
{
//success
glGenTextures(1, &AllTextures[id].texID); // Create The Texture ( CHANGE )
glBindTexture(GL_TEXTURE_2D, AllTextures[id].texID);
glTexImage2D(GL_TEXTURE_2D, 0, 3, AllTextures[id].width, AllTextures[id].height, 0, GL_RGB, GL_UNSIGNED_BYTE, AllTextures[id].imageData);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
if (AllTextures[id].imageData) // If Texture Image Exists ( CHANGE )
{
free(AllTextures[id].imageData); // Free The Texture Image Memory ( CHANGE )
}
}
else
{
MessageBoxA(0,"Textures Loading Fail! Game will close now","Game Problem",0);
exit(1);
}
}
if texture->bpp == 24 instead of 32 (which means there is no built-in alpha channel), you have to generate a 32-bit openGL texture, and set the alpha value of each texel to 255 iif the tga pixel is 255,200,255.
Well, if you're using textures, then I'm assuming you already have a fragment shader.
It's pretty easy actually.
First in the main program turn on alpha blending:
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Then in the fragment shader add this code:
vec3 chromaKeyColor = texture(myTextureSampler,UV.xy).xyz;
float alpha;
if ((chromaKeyColor.x <= 0.01) && (chromaKeyColor.y <= 0.01) && (chromaKeyColor.z <= 0.01)){
alpha = 0.;
}
else
{
alpha = 1.0;
}
color = vec4(texture(myTextureSampler,VertexOut.texCoord.xy).xyz,alpha);
The above code will set black as the chroma key. (within a threshold of 0.01) You can choose another colour by looking up its RGB value. If it's not the chroma key colour, then set the alpha to full (1.0).
OpenGL and color-keying can be a little tricky. Using 1-bit alpha is probably easier, but I've seen SDL used for color-keying like you describe. This thread might help you out.