Currently I'm using Direct2D for rendering 2D frames, but I realized that it's not supported in Windows XP (or anywhere with DirectX < 10), and now I'm looking for a way to support DirectX 9.
My scenario is not a simple one, and to cut to the chase my problem is that I do not have a HWND which I can use to initialize direct3d, however I do have an HDC.
This is what I'm doing with direct2d:
ID2D1DCRenderTarget *renderTarget = NULL;
HRESULT hr = FACTORY->CreateDCRenderTarget(&RENDER_TARGET_PROPERTIES, &renderTarget);
renderTarget->BindDC(this->hdc, &this->viewport);
renderTarget->BeginDraw();
...
I'm looking for an equivalent thing that will work with DirectX 9 and that allows to use HDC and not HWND.
I've searched a lot, and found other question regarding this issue, but I can't find a satisfying solution, the only thing I managed to find is offscreen rendering, but I couldn't find any good source for examples or explanations about that, what I did find included the use of an HWND to initiate d3d9.
Any ideas on how I can manage to render 2D frame (with transparency) on XP?
Thanks.
Edit
WindowFromDC returns null for the HDC I pass it.
Here's my code:
HWND hwnd = WindowFromDC(hdc);
LPDIRECT3D9 d3d = Direct3DCreate9(D3D_SDK_VERSION);
LPDIRECT3DDEVICE9 d3ddev;
D3DPRESENT_PARAMETERS d3dpp;
LPD3DXSPRITE sprite;
LPDIRECT3DTEXTURE9 texture;
D3DXVECTOR3 imagepos(0, 0, 0);
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = False;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
if (SUCCEEDED(d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev))) {
....
}
The hwnd is null and so the call to d3d->CreateDevice fails (I think that's the reason).
As for the HDC, it exists and when I use it with direct2d it works fine.
Any ideas how to bypass this problem?
2nd Edit
Thanks to #RogerRowland I've discovered that the HDC that I get is a memory HDC (OBJ_MEMDC).
I guess that it's what the browser/firebreath is giving me, but it works well when I use it with Direct2D (like in the code from my first posting) and also when I try regular Win32 rendering (with BitBlt and all).
I can't seem to find a way to use Direct3D 9 with only the HDC I get, and so I'm currently working on a workaround which creates a new hidden window in which I'll do the rendering and then will copy the result to the HDC I have (BitBlting probably).
Even if this solution works I still don't like it very much so if anyone has another approach for dealing with this problem I'd love to know.
Related
Reading about GetDC/ReleaseDC I should it appears always do the latter, and that CS_OWNDC on a window is considered evil:
https://blogs.msdn.microsoft.com/oldnewthing/20060601-06/?p=31003
Looking through my code I see I'm holding onto a DC retrieved from GetDC, which I've sent into wglCreateContextAttribARB. I'm presuming the context is created on that DC so it would be bad manners to subsequently release it from under the driver. Is my assumption correct? At the moment I'm calling ReleaseDC when I destroy my other OpenGL resources.
Additionally, elsewhere in my libraries I'm calling GetDC to instantiate a GDI+ Graphics object, then releasing it again when I've finished drawing. I'm thinking it would be nice to persist the DC and Graphics object between draw calls for performance reasons, only recreating it on WM_DISPLAYCHANGE etc.
So, is there a definitive guide to best practice in this area? The way I diligently release the GDI+ DC but persist the OpenGL DC seems somewhat inconsistent.
OpenGL and GDI+ behave differently.
In OpenGL you need a context, which is attached with a DC. This means that the DC must exist while the context exists. Thus, you do need CS_OWNDC style for the window where OpenGL draws.
Call ReleaseDC after you have deleted the context.
GDI+ is used in MS Windows like any common DC: retrieve a DC, draw to it, release that DC. In this scenary the use of CS_OWNDC can be evil, as pointed out in the link you posted.
The way MS GDI+ uses the graphics hardware (i.e. creating a context or whatever) is irrelevant for you.
EDIT due to Chris Becke's comment:
The CS_OWNDC usage is not required
Quoting https://msdn.microsoft.com/es-es/library/windows/desktop/dd374387(v=vs.85).aspx:
The hdc parameter must refer to a drawing surface supported by OpenGL.
It need not be the same hdc that was passed to wglCreateContext when
hglrc was created, but it must be on the same device and have the same
pixel format.
The CS_OWNDC usage is recommended.
In the old days of Windows 9x acquiring and releasing a device context was expensive and slow. Having a fixed dc was much more efficent. Using the CS_OWNDC flag at window registration was the way to have a fixed dc.
The CS_OWNDC usage provides a private device context (see https://msdn.microsoft.com/en-us/library/windows/desktop/ms633574(v=vs.85).aspx#class_styles).
Quoting from MS docs (https://msdn.microsoft.com/en-us/library/windows/desktop/dd162872(v=vs.85).aspx):
Although a private device context is convenient to use, it is
memory-intensive in terms of system resources, requiring 800 or more
bytes to store. Private device contexts are recommended when
performance considerations outweigh storage costs.
You must be aware that you must avoid ReleaseDC with a private device context:
An application can retrieve a handle to the private device context by
using the GetDC function any time after the window is created. The
application must retrieve the handle only once. Thereafter, it can
keep and use the handle any number of times. Because a private device
context is not part of the display device context cache, an
application need never release the device context by using the
ReleaseDC function.
In the common scenary where you draw to an unique window by retriving a DC, setting the curent context, drawing, swapping buffers and releasing the DC the usage of CS_OWNDC instead of GetDC&ReleaseDC is natural.
It can be also the case where wglGetCurrentDC() is used (e.g. by an extern library) regarless of your GetDC/ReleaseDC code. Normally no issues will happen. But if the current gl-context is NULL (as you would do right after ReleaseDC) then wglGetCurrentDC() will fail.
Code without CS_OWNDC
used in two windows with the same pixel format would look like this:
myGLContext = wglCreateContext(...)
//Draw to window A
HDC hdcA = GetDC(hWndA)
wglMakeCurrent(hdcA, myGLContext)
... render...
SwapBuffers(hdcA)
ReleaseDC(hWndA, hdcA)
//Draw to window B
HDC hdcB = GetDC(hWndB)
wglMakeCurrent(hdcB, myGLContext)
... render...
SwapBuffers(hdcB)
ReleaseDC(hWndA, hdcA)
wglMakeCurrent(hdcB, NULL)
How can I get image bytes from hbitmap if I am given an HBITMAP pointer, and my application is console application.
I tryed using GetDIBits which require such parameter as HDC, which I can't get.
EDIT:
I load bitmap from file:
HBITMAP bm = 0;
BITMAP Bitmap;
bm = (HBITMAP)LoadImage (0, TEXT("C:\\img1.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
I pass the HBITMAP to the function and expect to get another HBITMAP of processed image:
HBITMAP out1 = func(bm);
Where func is:
HBITMAP func(HBITMAP im);
And the problem is how to get image bytes from HBITMAP.
The easiest way is not to use GetDIBits (nor GetBitmapBits). These functions suck because they copy the data.
If you want the data directly, just use (for a DDB bitmap)
BITMAP bitmap;
GetObject(hBitmap, sizeof(bitmap), (LPVOID)&bitmap);
For a DIB bitmap use
DIBSECTION dib;
GetObject(hBitmap, sizeof(dib), (LPVOID)&dib);
GetObject info, See:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144904%28v=vs.85%29.aspx
This will not involve any copying of data, thus avoids the complicated issues associated with GetDIBits, See:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144879%28v=vs.85%29.aspx
Esp. the comments at the bottom for an explanation of the difficulties with GetDIBits.
Note that you do not get the palette info, but since most bitmaps are 24 or 32 bits anyway this is hardly an issue most of the time.
Since you're using LoadImage to get the HBITMAP, then it is indeed a DIB (Device-Independent Bitmap) (they call it a DIBsection). However, you don't have the color information.
This MSDN HOWTO shows you how to select the DIBsection into a memory DC. They then go on to use GetDIBColorTable to get the palette. However, I believe from there, with that DC you can use GetDIBits to get the RGB bitmap information as you were trying to do.
Here's the general gist of it:
// Create a memory DC and select the DIBSection into it
hMemDC = CreateCompatibleDC( NULL );
(HBITMAP)SelectObject( hMemDC, hBitmap );
GetDIBits(hMemDC, hBitmap, ...);
You'll note in their code that SelectObject returns a handle to the what was in the DC. They then restore that before calling DeleteDC. I'm not sure its entirely necessary, but they do it. I left it out here for clarity.
What worked for us is this: call GetDIBits while the correct palette (if indexed colour) is still selected into the device context. (Without the palette selected, the colours got garbled.)
But in our use case, it turned out that DIB sections performed a lot better, so check those out as well and benchmark. However, there are some gotchas. Windows wouldn't use the palette, we had to call SetDIBColorTable before use. But the device context still needed a one entry (black only) dummy palette selected and realised into the device context otherwise Windows would also ignore the palette set by SetDIBColorTable. Both SetDIBColorTable and RealizePalette needed to be present otherwise the colours would be garbled.
See new answer since question was edited...
You cannot do this without a handle to the device context (HDC). This is because GetDIBits expects an HBITMAP which is
A handle to the bitmap. This must be a compatible bitmap (DDB).
A DDB is a Device-Dependent Bitmap, (as opposed to a DIB, or Device-Independent Bitmap). That means:
Note that a DDB does not contain color values; instead, the colors are in a device-dependent format.
Which is why GetDIBits requires an HDC. Otherwise it cannot get the color information.
Perhaps a good question is, where did you get an HBITMAP without an accompanying HDC?
If you're trying to create this bitmap in memory, first you can call CreateCompatibleDC to create an in-memory DC compatible with some device, then CreateCompatibleBitmap with that DC. Then you have an HBITMAP and HDC to work with as you please. Otherwise, if you don't know what your HBITMAP is pointing to, you can't expect to do anything useful with it.
You can try GetBitmapBits API even from console. More here:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144850%28v=vs.85%29.aspx
Just pass HBITMAP handle and you'll get your bytes
When I convert an Enhanced Metafile (constructed via GDI+ in C#) into an old-style Windows Metafile, the results are very rough, apparently because coordinates are being rounded to the nearest screen pixel. I see this if I convert either via
GetWinMetaFileBits(emfh, bits_l, bits, MM_ANISOTROPIC, GetDC(0));
or using GDI+'s Metafile::EmfToWmfBits. The culprit is presumably the screen DC being used. This posting suggests using a printer DC, which works for me, but obviously will not work if the user has no printers installed. Is there a better way? I have considered creating a high-resolution in-memory DC for the purpose, but I can find no proper documentation for doing so, and I also worry about the RAM used.
The normal way is to create a much higher resolution memory DC, render to that and then save it however you want. Note that font sizes can get screwed up by this.
HDC memDC = CreateCompatibleDC ( hDC );
HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );
SelectObject ( memDC, memBM );
With nWidth , nHeight much larger.
The CreateCompatible bit should set all the dpi etc, but I have had problems where the fonts were drawn fixed pixel size rather than rescaled - so they ended up being only 10pixels high on a 10,000 pixel image
Ask Google for ENMETA.EXE
Description by Microsoft
Example in download included.
I am developing a Windows API application without using MFC.
I am using standard Windows libraries.
How do I draw a PNG image in a window?
Help me with some sample code.
I have tried some codes which are available on the Internet, but all are using MFC.
Take a look at this StackOverflow question. It offers several options which should meet your needs.
Adapted from MSDN:
#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
using namespace Gdiplus;
void draw()
{
// start up GDI+ -- only need to do this once per process at startup
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
Rect rect(20,20,50,50);
Graphics grpx(dc);
Image* image = new Image(L"SomePhoto.png");
grpx.DrawImage(Img,rect);
delete image;
// shut down - only once per process
GdiplusShutdown(gdiplusToken);
return;
}
Your choices are: GDI+, WIC(Windows Imaging Component) or libpng
You can use GDI+. See Loading and Displaying Bitmaps.
The below code worked for me. It's free of MFC and can be used straight away to draw PNG images in a window.
Gdiplus::Image image(L"C:\\Logo.png") ;
Gdiplus::Graphics* graphics = Gdiplus::Graphics::FromHDC(GetDC(hWnd));
RectF ImgRect(0,0,y3/10,y3/10) ;
Gdiplus::Status result = graphics->DrawImage(&image, ImgRect);
Thanks for all your support and quick response to solve my problem.
If you know PNG'coding,you can decoding it. So you can draw PNG in any way~
MSDN displays the following for CreatePatternBrush:
You can delete a pattern brush without
affecting the associated bitmap by
using the DeleteObject function.
Therefore, you can then use this
bitmap to create any number of pattern
brushes.
My question is the opposite. If the HBRUSH is long lived, can I delete the HBITMAP right after I create the brush? IE: does the HBRUSH store its own copy of the HBITMAP?
In this case, I'd like the HBRUSH to have object scope while the HBITMAP would have method scope (the method that creates the HBRUSH).
The HBRUSH and HBITMAP are entirely independent. The handles can be deleted entirely independent from each other, and, once created, no changes to either object will effect the other.
The brush does have its own copy of the bitmap. This is easily see by deleting the bitmap after creating the brush and then using the brush (works fine)
Using GetObject to fill a LOGBRUSH structure will return the original BITMAP handle in member lbhatch, though, and not the copy's handle, unfortunately. And using GetObject on the returned bitmap handle fails if the bitmap is deleted.
Anyone any idea how to get the original bitmap dimensions from the brush in this case? I wish to create a copy of the pattern brush even though the original bitmap is deleted. I can get a copy of the original bitmap simply by painting with the brush, but I don't know it's size. I tried using SetbrushorgEx (hdc, -1,-1), hoping the -1's would be reduced modulo its dimensions when brush selected into device context and get values when I retrieve with GetBrushOrgEx. Doesn't work.
I think the bitmap must outlive the brush: the brush just references the existing bitmap rather than copying it.
You could always try it and see what happened.
I doubt that the CreatePatternBrush() API copies the bitmap you give it, since an HBITMAP is:
a GDI handle, the maximum number of which is limited, and
potentially quite large.
Win32 and GDI tend to be conservative about creating internal copies of your data, if only because when most of their APIs were created (CreatePatternBrush() dates to Windows 95, and many functions are older still), memory and GDI handles were in much more limited supply than they are now. (For example, Windows 95 was required to run well on a system with only 4MB of RAM.)