Sign in to follow this  

set and get a pixel in directx

This topic is 3585 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

Hello all! I'm a total beginner of directx so i hope that you can bear with my simple question. I'm certain that this question have arised before, but I can't seem to find any info about it when I try to search for it. I'm going to try to make a astronomy program and then I need the speed of my nvidia graphics card. But I have a little problem. I can't seem to figure out how to set and get a pixel in directx sdk. Can anyone point me in the right direction or can anyone share setpixel and getpixel code to me? I would be very thankful for all help you can give me on this subject. BR Jörgen Jönsson

Share this post


Link to post
Share on other sites
Setting or getting one pixel is an extremely expensive thing to do to a graphics card. The way to do it is to lock a texture or render target, read / write a value, and then unlock the texture / backbuffer.
Because of that, it's much better to lock the texture / backbuffer, draw all pixels, and then unlock it - even if it means having a copy of the pixel data in an array in memory.

Share this post


Link to post
Share on other sites
I'm relatively new myself, but I'm pretty sure that if you're using directx 8 or higher, you simply cannot. That was a feature of directdraw and directdraw has been removed. You will have to go through direct3d, which complicates things a little. I'm learning d3d10 at the moment and Microsoft's tutorial 3 for d3d10 should give you a good idea of how to use it for setting a pixel.

Share this post


Link to post
Share on other sites
Hello and thanks for your replies!

@Evil Steve
My idea was to have a copy of the pixels in an array in memory and update the screen from this buffer.


@kingdord
Could you give me a link to the tutorial that you are reading? is it on msdn?


@HellzGod
I have never used GDI/GDI+ either. Would that mean, that I need to learn both GDI/GDI+ and directx?

@all
If you have more suggestions, keep them coming... :)

BR
Jörgen Jönsson

Share this post


Link to post
Share on other sites
I'd stay away from D3D10 for something like this unless you really only want it to run obn Vista with a DX10 card (Unlike DX9, DX10 will only run with a DX10 card - e.g. a GeForce 8, and only on Vista).

GDI/GDI+ might be a possible option, but won't be as fast as using pure DirectX, although it is pretty easy to learn.

What exactly do you need to draw? Is it just individual points for stars? If so, the simplest way would be to render a series of points. If you need to render more than a few thousand points, or you need to render more complex shapes, then drawing directly to a texture or the backbuffer might be better.

Share this post


Link to post
Share on other sites
Quote:
Original post by jonssonj
I'm going to try to make a astronomy program and then I need the speed of my nvidia graphics card. But I have a little problem. I can't seem to figure out how to set and get a pixel in directx sdk.


An NVIDIA graphics card is very fast for certain kinds of operations. You cannot simply take an existing program, connect it to a graphics card, and expect it to run faster: you need to actually change your program so that it does the things that graphics cards are good at. Accessing individual pixels is not a good idea, while running a shader on all pixels at once is a good idea, for example.

Share this post


Link to post
Share on other sites
Quote:
Original post by jonssonj
@HellzGod
I have never used GDI/GDI+ either. Would that mean, that I need to learn both GDI/GDI+ and directx?
Jörgen Jönsson


Hi,
Like Steve says, GDI/GDI+ might be slower. But here is a code snippet for getting a pixel:


HBITMAP hBmp = (HBITMAP)LoadImage(NULL, "SomeImage.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HDC hdc = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hdc);
HBITMAP hBmpOld = (HBITMAP)SelectObject(hMemDC, hBmp);
....
COLORREF color = GetPixel(hMemDC, x, y);
BYTE r = GetRValue(color);
BYTE g = GetGValue(color);
BYTE b = GetBValue(color);
...
SelectObject( hMemDC,hBmpOld);



Lookup msdn/internet. It's very simple.
hth,
M

Share this post


Link to post
Share on other sites
Yes, that tutorial is on MSDN (full source can be installed with the dx SDK). I do agree with Evil Steve, dx10 is kind of a prohibitive platform at them moment, so if you don't have the hardware or want to redistribute the product, staying away is probably the best option for the time being.

Share this post


Link to post
Share on other sites
Hello all!

I now have this code, but I can't seem to get anything on the window. I guess that I'm doing things in the wrong order on in the wrong places. Can anyone help me to sort this code out.


// win32_test.cpp : Defines the entry point for the application.
//


#include "stdafx.h"
#include "win32_test.h"
#include <D3D9.h>

#define MAX_LOADSTRING 100



bool Init3D(HWND hWnd);
void render();

// Global Variables:
LPDIRECT3D9 g_pD3D;
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
LPDIRECT3DSURFACE9 g_Surface = NULL;
LPDIRECT3DSURFACE9 BackBuffer = NULL;

D3DPRESENT_PARAMETERS d3dpp;
D3DSURFACE_DESC surfaceDesc; // Get the surface description.
D3DLOCKED_RECT lockedRect; // Get a pointer to the surface pixel data.

HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name



// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32_TEST, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32_TEST));

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {


render(); // If there are no messages to process then render some DIRECTX stuff.


}
}

return (int) msg.wParam;
}



//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32_TEST));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32_TEST);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
return FALSE;
}

Init3D(hWnd); // Init directx
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);


return TRUE;
}

//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
HRESULT result = NULL;
DWORD *imageData = NULL;


switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);

// TODO: Add any drawing code here...

EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;

case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}

bool Init3D(HWND hWnd) {
HDC result_hdc = NULL;
UINT width = 0;
UINT height = 0;
RECT rect;
LPRECT lpRect = &rect;

GetWindowRect(hWnd,lpRect);
width = lpRect->right - lpRect->left;
height = lpRect->bottom - lpRect->top;

if( NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) {
return FALSE;
}

ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;

if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) ) {
return FALSE;
}


HRESULT result = NULL;

UINT availMem = g_pd3dDevice->GetAvailableTextureMem();

D3DCAPS9 caps;
D3DCAPS9 *pCaps = &caps;
ZeroMemory( pCaps, sizeof(D3DCAPS9));
result = g_pd3dDevice->GetDeviceCaps(pCaps); // Just for debugging purpose

D3DDISPLAYMODE mode;
D3DDISPLAYMODE *pMode = &mode;
ZeroMemory(pMode, sizeof(D3DDISPLAYMODE));
result = g_pd3dDevice->GetDisplayMode(0, pMode);

result = g_pd3dDevice->CreateOffscreenPlainSurface(width, height,pMode->Format,D3DPOOL_DEFAULT,&g_Surface,NULL);

return TRUE;

}

void render() {
HRESULT result = NULL;

// g_pd3dDevice->SetRenderTarget(1,g_Surface); // This one I don't know if it is needed

// Just for testing purpose, to see if something is happening at all, but there is'nt.
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,255,255), 1.0f, 0);

result = g_Surface->GetDesc(&surfaceDesc);
result = g_Surface->LockRect(&lockedRect, // pointer to receive locked data
0, // lock entire surface
0); // no lock flags specified

DWORD *imageData = (DWORD*)lockedRect.pBits;
imageData = (DWORD*)lockedRect.pBits;

// My thought here was to set a pixel to red at the position 200, 100 in my window.
imageData[(int) (200*lockedRect.Pitch / 4 + 100)] = 0xffff0000; // red

g_Surface->UnlockRect();


if(SUCCEEDED(g_pd3dDevice->BeginScene( ) ) ) {
g_pd3dDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO, &BackBuffer);
g_pd3dDevice->UpdateSurface(g_Surface, NULL, BackBuffer, NULL);
if(BackBuffer != NULL)
BackBuffer->Release();

g_pd3dDevice->EndScene();
}

g_pd3dDevice->Present(NULL,NULL,NULL,NULL);

}




Very thankful for all help that I can get to sort this code out.

BR
Jörgen Jönsson

Share this post


Link to post
Share on other sites
I have not looked at your code. But these are some common checks:

1. Have you defined the vertices in the proper order? Counter clockwise and clockwise are different.
2. Check your camera parameters.
3. If you have enabled lighting, then light direction may be wrong. Set colour to blue (for eg) while clearing your screen.
4. Use PIX or some other tool to see if there is some problem.

hth,
M

Share this post


Link to post
Share on other sites
Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes Debug Runtimes.
If you use the debug runtimes you'll see that UpdateSurface is failing because the source surface is in D3DPOOL_DEFAULT when it should be in D3DPOOL_SYSTEMMEM.

Also, some other points:

1.

// My thought here was to set a pixel to red at the position 200, 100 in my window.
imageData[(int) (200*lockedRect.Pitch / 4 + 100)] = 0xffff0000; // red



You shouldn't be dividing by 4 here, the pitch is in bytes, so 200*pitch + 100 is the pixel at x=100, y=200 I.e. (100, 200).

2. You shouldn't be taking the desktop format when you create the surface, and then casting the lock to a DWORD* when you lock the surface. That assumes that the desktop format is 32-bit, and will fall over if it's not - since the created surface could be e.g. 16 bit, which means that a pixel is 2 bytes, not 4.

3. D3DSWAPEFFECT_DISCARD instead of D3DSWAPEFFECT_COPY is advisable, unless you need to contents of the backbuffer to persist from one frame to the next - which you don't here because you're clearing the backbuffer at the start of each frame anyway.

4. You're creating a window but not specifying a proper width and height for it. While that's not a problem, it's not advisable. What if the user's system settings make a window that's smaller than 200x100? You'll write to pixels that don't exist in the Lock() call and crash.

5. You should use GetClientRect() instead of GetWindowRect() for measuring the size of the window. GetWindowRect() returns the size of the window including borders, which you and D3D don't render to.

Share this post


Link to post
Share on other sites
Hello all and thanks for your input.

@HellzGod
Thanks for your input, but my code is not that complicated. I'm just in my beginning of learning directx and this code is just a test to see if something comes out on the screen.

@Evil Steve
I'm very thankful for your help. The code below was just a test. I'm not going to write a pixel at 200, 100 every time. I just wanted to see if something did come out on the screen, so I assumed 32 bits just for testing purposes.


// My thought here was to set a pixel to red at the position 200, 100 in my window.
imageData[(int) (200*lockedRect.Pitch / 4 + 100)] = 0xffff0000; // red



@all
Right now my code does not run the render function. How do a proper message loop look like, with a call to a render() function?

BR
Jörgen Jönsson

Share this post


Link to post
Share on other sites
Quote:
Original post by jonssonj
@Evil Steve
I'm very thankful for your help. The code below was just a test. I'm not going to write a pixel at 200, 100 every time. I just wanted to see if something did come out on the screen, so I assumed 32 bits just for testing purposes.
Maybe so, but the /4 is still not needed. That code is currently setting the pixel at (50, 100), because you divide X by 4. The pointer is already a DWORD, so +1 means +1 pixel, or +1 DWORD.

Quote:
Original post by jonssonj
@all
Right now my code does not run the render function. How do a proper message loop look like, with a call to a render() function?
What you have seems fine to me, render() is being called in the code you posted.

Share this post


Link to post
Share on other sites
Hello!


@Evil Steve
I just want you to know that I'm really appreciating your help.

I'm setting a breakpoint in the render() function, but when I run the program it never stops at the breakpoint. I have also tried to set a breakpoint at the call to the render function, in the message loop, but when I debug the program it never calls the render function.

I'm using Visual Studio 2005. What is it that I'm doing wrong here then?


One more thing, this row does not change my background color, is there anyone that knows why? What is wrong?

// Just for testing purpose, to see if something is happening at all, but there is'nt.
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,255,255), 1.0f, 0);





Thanks for all help!

Share this post


Link to post
Share on other sites
Hi,
I think it would be much easier if you take a working sample ( http://www.riemers.net/eng/Tutorials/DirectX/C++/series1.php ) and try running it first. If those samples don't work, then there might be hardware incompatibility. If it works, modify the program to suit your needs. Make sure you have MSDN open.

Cheers,
M

Share this post


Link to post
Share on other sites
Quote:
Original post by jonssonj
I'm setting a breakpoint in the render() function, but when I run the program it never stops at the breakpoint. I have also tried to set a breakpoint at the call to the render function, in the message loop, but when I debug the program it never calls the render function.
Ah, you should be using PeekMessage rather than GetMessage, since GetMessage blocks until a new message arrives.
Try this instead:

while(1) // Infinite loop
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT)
return msg.wParam;

if(!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
render();
}
}



Quote:
Original post by jonssonj
One more thing, this row does not change my background color, is there anyone that knows why? What is wrong?
My guess is that UpdateSurface() is overwriting whatever is in the backbuffer. If you comment out the UpdateSurface() line, does the backbuffer appear cyan?

Share this post


Link to post
Share on other sites

This topic is 3585 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this