drawing pixels ok this way?

Started by
12 comments, last by deadimp 18 years, 10 months ago
I didn't like using the Direct3D sprite device because I didn't really know what is going on. I like to know what I'm doing. So I thought, I'll write my own class. So I went through the articles and found an interesting one on writing directly into video memory with direct draw. This would give me a few extra advantages too. What I do is the following: 1. Create Direct3D Device 2. Get the Device's backbuffer (GetBackBuffer()) 3. Start loop 3.1 LockRect() 3.2 write into video memory 3.3 UnlockRect() 3.4 Present() Now my questions: 1. Is this a good way to do this? if not, how IS a good way? 2. Does pitch / 4 work on all video cards? because I saw somewhere saying that the pitch can be different on some video cards. Something about a few more bytes per line. Maybe this new pitch thing is to solve that problem. ow yeah, I'm using DirectX 9 SDK.
Advertisement
LockRect and UnlockRect tends to be bad (so ive heard) you can do that though I guess. Im not sure of a good way to do it but this will at least give you an idea. Perhaps surface offscreen rendering?
You can draw pixels directly to the backbuffer surface (or use surfaces directly), as you suggest, but you won't be doing much more than directdraw, (not as good either), there probably are uses for it (i'm trying to use surfaces myself at the moment to "concatenate" letters to save as words for my own text/font thing).

Try using quads instead, a quad is just two triangles togather, also use the rhw setting, this means the lighting etc, for the quad is taken care of.


struct Vertex
{
float x, y, z;
float rhw;
D3DCOLOR color; // The color
float tu, tv; //use to adjust the textures position on the quad/triangle
};

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)

//Globals
//You need most of the ordinary stuff including a texture;
LPDIRECT3DTEXTURE9 m_pTexture;
char *filename;


Vertex *vertices;


TuStart = 0.0f;//this gets whole texture to show properly
TuEnd = 1.0f;
TvStart = 0.0f;
TvEnd = 1.0f;

float x, y, cx, cy;//how ever big you want the quad

void InitVertices(TuStart,TuEnd,TvStart,TvEnd,x,y,cx,cy)
{
Vertices = new Vertex[4];
//top left
Vertices[2].x = x; //x start size/position onscreen
Vertices[2].y = y; //y start size/position onscreen
Vertices[2].z = 0.5f;
Vertices[2].rhw = 1.0f;
Vertices[2].color = D3DCOLOR_XRGB(250,250,250);
Vertices[2].tu = TuStart;
Vertices[2].tv = TvStart;

//bottom left
Vertices[0].x = x;
Vertices[0].y = y+cy; //y start size + endsize -how big its going to be.
Vertices[0].z = 0.5f;
Vertices[0].rhw = 1.0f;
Vertices[0].color = D3DCOLOR_XRGB(250,250,250);
Vertices[0].tu = TuStart;
Vertices[0].tv = TvEnd;

//bottom right
Vertices[1].x = x+cx;
Vertices[1].y = y+cy;
Vertices[1].z = 0.5f;
Vertices[1].rhw = 1.0f;
Vertices[1].color = D3DCOLOR_XRGB(250,250,250);
Vertices[1].tu = TuEnd;
Vertices[1].tv = TvEnd;

//top right
Vertices[3].x = x+cx;
Vertices[3].y = y;
Vertices[3].z = 0.5f;
Vertices[3].rhw = 1.0f;
Vertices[3].color = D3DCOLOR_XRGB(250,250,250);
Vertices[3].tu = TuEnd;
Vertices[3].tv = TvStart;

}


void LoadTexture(LPDIRECT3DDEVICE9 mp_d3dDevice, char *texturename)
{
filename = texturename;
p_d3dDevice = mp_d3dDevice;
D3DXCreateTextureFromFile( p_d3dDevice, filename, &m_pTexture );
}


void FillInTehVB()
{
p_d3dDevice->CreateVertexBuffer( 4*sizeof(Vertex),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &p_VertexBuffer, NULL );

VOID* pVertices;
p_VertexBuffer->Lock( 0, 4*sizeof(Vertex), (void**)&pVertices, 0 );

memcpy( pVertices, Vertices, 4*sizeof(Vertex));
p_VertexBuffer->Unlock();

}

void SetSomeTextureStages()
{
p_d3dDevice->SetTextureStageState(0, D3DTSS_CONSTANT, D3DTEXF_LINEAR );
p_d3dDevice->SetTextureStageState(0, D3DTSS_CONSTANT, D3DTEXF_LINEAR );

)

void DrawVB
{

p_d3dDevice->SetTexture( 0, m_pTexture );

// Render the vertex buffer contents
p_d3dDevice->SetStreamSource( 0, p_VertexBuffer, 0, sizeof(Vertex) );
p_d3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
p_d3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2);

}

Most of this won't copy & paste, you have to set it up your self properly, but this is the idea, most of the functions would go before the game loop, (after InitD3D), then the DrawVB can be called during the Render loop.
(p_d3ddevice is the same as g_pd3dDevice, mine has just come from my own texture class, thats why its different.)
Quote:Original post by DevLiquidKnight
LockRect and UnlockRect tends to be bad (so ive heard) you can do that though I guess. Im not sure of a good way to do it but this will at least give you an idea. Perhaps surface offscreen rendering?


Right - locking textures at runtime is very, very bad. It is incredibly slow, because all of the data must be transferred over the AGP bus (and back again, if you are updating). If at all, you should only be doing it at loadtime.

If you want a slight idea of how ID3DXSprite works, check out Stevie's post. It *does not* lock the backbuffer and plot the pixels right onto it. Instead, it creates 2 triangles, forming a quad, and renders it. Actually, it's a bit more complicated than that, since ID3DXSprite batches all of the drawing calls to improve performance.

It is undoubetdly a great thing to understand how the underlying interfaces work. Not only does it increase your knowledge of graphics programming, but it also allows you to utilize the interfaces in questions at a higher level. However, this does not mean that you should be recreating the wheel. ID3DXSprite is a very efficient sprite renderer and does a lot more than simply push textured quads to the GPU. If you have the means, you should be using it.
Dustin Franklin ( circlesoft :: KBase :: Mystic GD :: ApolloNL )
Quote:It is undoubetdly a great thing to understand how the underlying interfaces work. Not only does it increase your knowledge of graphics programming, but it also allows you to utilize the interfaces in questions at a higher level.

I'll check it out.

Quote:Most of this won't copy & paste

I never copy, paste things I don't understand. ;)
Waaay to much trouble getting something to work that way, and definitly anoying not knowing what you're actually doing.

// Edit: checked it
I allready did this once. I thought it was nice for textures, but I also want to draw things like ovals and lines. For lines and circles I would need to draw 1 pixel, that's why I started the whole draw 1 pixel thing. Is creating a vertex that is 1 pixel high and 1 pixel wide still faster than locking and unlocking every time? Or is there a better way to draw circles and lines?

thx for hanging on with me here :)
It might be useful if you can say exactly what it is you need to do.
Sounds to me like you'd be better served with GDI than DirectX. Sure, it's slow, but not as slow as trying to plot each individual pixel.

Hi,
As long as you only lock and unlock the buffer once every frame, there shouldn't be any problems - where you "write into video memory" make sure you do everything you need, there should be no problems.

As for the vertical pitch of the screen, it all gets very complicated with bytes per pixel and, as you say, extra bytes on each row but if you're using Direct3D, it should take care of everything for you. If it doesn't, I think the information about the 'memory pitch' is in the Surface Description (SurfaceDesc), although I can't remember specifically how to get at it in Direct3D.

Have Fun!

-indirectX-
--------------------------------www.hughosborne.co.uk[email=hugh.osborne@googlemail.com]hugh.osborne@googlemail.com[/email]
Instead of just writing your own class with a new method I would have just done research to figure out what directX is doing. Maybe you wouldn't have a problem with it once you knew what the internals were up to. You never know what you might have learned along the way either. :)
--------------------------------------------------------------------------Michael Schuld
Quote:Original post by mikeschuld
Instead of just writing your own class with a new method I would have just done research to figure out what directX is doing. Maybe you wouldn't have a problem with it once you knew what the internals were up to. You never know what you might have learned along the way either. :)

Yeah I know, but DirectX doesn't have a way of drawing ovals or lines.

// edit: ok, it has lines, now I feel ashamed of myself :D, but still, how do I do ovals? Ovals aren't really necesary, but still ...
Maybe you could try getting the surface's graphic context (in managed languages) or hwnd (in native ones) and use GDI functions to draw ellipses. Horribly slow but is a way :D

This topic is closed to new replies.

Advertisement