Jump to content
  • Advertisement
Sign in to follow this  
nint22

Drawing per-pixel in DirectX

This topic is 3941 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I would never post here unless I could not find some kind of similar question and its answer. I have looked around (Web, forum and articles) and have not been able to find anything on this subject so any help is greatly appreciated. From what I understand, with DirectX 9 it is not possible to call any functions to draw per-pixel directly to the screen. By draw I mean any type of per-pixel function (something such as DrawLine() or DrawSquare(), etc). What I would like to do is access the screen's memory so that I can draw out manually in 2D. After a bit of research, I understand I have to create an off-screen texture (A DirectX surface object), access that memory, draw to it's memory manually and then call DirectX APIs to draw on-screen. Is this correct? All I am asking is in general how would one do it (draw per-pixel)? If its close to the above idea, are there any documents on this or should I look into the DirectX MSDN docs? Names of functions you recommend is very helpful, I would be glad to look anything up! Just drop off an idea. Thank you all for the great community and the help!

Share this post


Link to post
Share on other sites
Advertisement
It really depends why you want to do it. It's still possible to use DirectDraw for this sort of stuff, or you can lock the backbuffer, or you can create a texture and lock the top level surface of it.

Also, what language is this? C++?

Share this post


Link to post
Share on other sites
There are two ways, both are like what you described.

1) Create a dynamic texture. Get surface of that texture (Texture->GetSurfaceLevel). Then Get device context of that surface (Surface->GetDC). Then you can use your regular GDI functions with that DC, like Rectangle(), Ellipse(), MoveToEx()/LineTo(), BitBlt(), GetPixel(), SetPixel(), etc, etc. Don't forget to call Surface->ReleaseDC and Surface->Release when you are done drawing. After you are done with this, you just draw that texture on screen (manually by using a vertex buffer or with D3DXSprite)

2) Also start with Texture->GetSurfaceLevel, but then gain direct access to pixel data by using Surface->LockRect. Then you have to be really careful with your math to not access outside of Surface memory. When done, draw the texture on screen like in #1. The suggestion for improved performance is that you maintain a texture in D3DPOOL_SYSTEMMEM memory pool, draw your pixels on that, and then in the beginning of every frame, copy data from your in-memory texture to your in-videocard texture.

Share this post


Link to post
Share on other sites
Thank you all! This information helps greatly. Just to put it out there, yes, I am developing in Visual Studio 2005 in C++, for DirectX 9. I'd rather stay away from GDI/GDI+, so thats why I am asking on locking the low level per-pixel functionality.

Any other recommendations?

Share this post


Link to post
Share on other sites
Draw lines and squares using triangles is the other suggestion. It's a nice way to do sprites for instance since you get scaling and rotation for free.

Share this post


Link to post
Share on other sites
Well, a good example of what I am trying to do is something like the classic "Plasma-Demo". I have a function that generates the color per pixel-location and all I want to do is draw that on screen. I guess I will create a texture that is the screen's size, lock it, and walk through each pixel struct (data type) and fill it in with correct RGBA values.

Is this correct?

Also, quick side question: I can't seem to get DXUT to work for DirectX9 on Windows XP. Is there a trick to getting this lib working in 9 again?

EDIT:
I have looked into the details and I think I got it. We can access the surface that is being rendered to via IDirect3DDevice9::GetBackBuffer, right? So why not bit-blit another texture or surface directly to that backbuffer? I guess this is another method compared to creating a texture, locking it, and then drawing it with vertices's or other methods.

Is it recommended to use IDirect3DDevice9::GetBackBuffer() for direct screen-pixel access?

[Edited by - nint22 on October 31, 2007 3:04:55 PM]

Share this post


Link to post
Share on other sites
Alright, I have attempted an implementation and sadly it does not work. I have looked all over the web and still can not find good information on this. I am able to get an IDirect3DSurface9 pointer and I know that is correct, but I fail when I attempt to lock that surface. Any help please?

Also, this error is at run time, and the getDirect3DDevice() returns the Direct3DDevice object.


// Create a surface and set it to the backbuffer
IDirect3DSurface9 *backBuffer = NULL;
HRESULT error = parentWindow->getDirect3DDevice()->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);

// Continue with no error
if(error == S_OK)
{
// Get a description of the surface
D3DSURFACE_DESC description;
backBuffer->GetDesc(&description);

// Lock the surface
D3DLOCKED_RECT lockedRect;
RECT targetRect = {50, 50, 100, 100};
error = backBuffer->LockRect(&lockedRect, &targetRect, NULL);

// Continue with no error
if(error == S_OK)
{
// Draw onto the surface
/* Nothing to do here... */

// Unlock and release the texture
backBuffer->UnlockRect();
}

backBuffer->Release();
}

Share this post


Link to post
Share on other sites
The problem is you can't lock a default pool texture (which the back buffer always is unless you use D3DPRESENTFLAG_LOCKABLE_BACKBUFFER when creating the swap chain).

I'd recommend you create a new texture (probably in the managed pool) to lock, which you can then use to draw onto the back buffer with using say DrawPrimitiveUP() (or the ID3DXSprite interface). That allows you the flexibility to do more with your texture than just draw it flat on the background.

See http://msdn2.microsoft.com/en-us/library/bb172231.aspx for more info.

[Edited by - Adam_42 on November 1, 2007 9:19:55 AM]

Share this post


Link to post
Share on other sites
Thank you all! This greatly helps! And I see what you mean by performance issues. I was just afraid that creating a texture and displaying that would be slower, but it looks like you all were correct. I will experiment with this later and see what the results are.

Share this post


Link to post
Share on other sites
Drawing to an off-screen texture is the obvious and probably best solution.


I have an alternate suggestion.

If your goal is to display plasma, you can still render that using triangles.

I do a lot of procedural generation of geometry and have produced plasma-like results. You just take a grid like you would make for a terrain-patch with colored vertices, and update the vertex colors each frame.

One of the benefits of that is that your resulting shape can easily be rendered at any resolution and will scale very nicely with good blending between vertices. Another feature is that the grid can be deformed in three dimensions using a similar algorithm as you use for the plasma, and that can look very cool.

Obviously, it uses up quite a bit more memory for the vertex buffer, but that's how I would probably do it.


Here's a picture from a quad iteratively tessellated in a non-grid fashion I threw together yesterday.
http://claritydevjournal.blogspot.com/2007/10/need-vacation.html

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!