Archived

This topic is now archived and is closed to further replies.

Drawing to a texture or surface.

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

Ok, so here''s the deal. I want to be able to generate the texture that I''m going to lay over my terrain at run time, that way I won''t have to have every single texture premade and loaded into memory (there won''t be enough video memory). So what I want to be able to do is load a bunch of small textures and then ''blit'' them on to a larger texture that I will wrap over the current terrain. So how do I draw one texture on to another?

Share this post


Link to post
Share on other sites
IDirect3DDevice9 :: UpdateSurface(arg)

List of arguements
or

IDirect3DDevice8 :: CopyRects(arg)

uh, i dont use d3d8 so i cant help yah with this one, but i believe these are both SURFACE functions, so i think you said u were using a texture? im sure theres soem way u could use these...maybe...

Share this post


Link to post
Share on other sites
What kind of trouble are you having with UpdateSurface? Does it return some kind of error value? What does the debug spew say?

UpdateSurface is basically there to transfer a block of data from system memory to video memory. The source surface must be in D3DPOOL_SYSTEMMEM and the destination surface must be in D3DPOOL_DEFAULT. Also, no stretching is allowed. This is all from the DX9 docs

neneboricua

Share this post


Link to post
Share on other sites
quote:
Original post by neneboricua19
What kind of trouble are you having with UpdateSurface? Does it return some kind of error value? What does the debug spew say?

UpdateSurface is basically there to transfer a block of data from system memory to video memory. The source surface must be in D3DPOOL_SYSTEMMEM and the destination surface must be in D3DPOOL_DEFAULT. Also, no stretching is allowed. This is all from the DX9 docs

neneboricua


ohh, i guess i missed that part about where the surfaces must be located. Strange.

Thanks nene.

Share this post


Link to post
Share on other sites
D3DXLoadSurfaceFromSurface is more general utility for blitting, if you''re working in sys->sys memory.

UpdateSurface is indeed meant to be used primarily in agp uploads.

-Nik

Share this post


Link to post
Share on other sites
Ok, thanks Nik02, I got D3DXLoadSurfaceFromSurface to copy one surface on to another. But my next question is, how could I draw one surface on to another texture with an alhpa channel? I haven't yet tested using alpha values with D3DXLoadSurfaceFromSurface (because of my problem with DxTex), but I don't think it's going to work.

Any tips?

Thanks.


[edited by - SiliconMunky on December 2, 2003 12:18:58 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Nik02
I believe the alpha will be copied as well. I''m not at my own machine now, so I can''t verify this until tomorrow.

-Nik


K, thanks Nik02,

I''ll be trying to get it to work tonight when I get home from work. Hopefully I can get some sort of picture file with an alhpa channel without having to convert using DxTex, since mine isn''t working.

Share this post


Link to post
Share on other sites
I made a test file for you; get it here.
Consider it a christmas present

-Nik

EDIT:
You could also generate your own surface with alpha - just use some alpha-compatible pixel format when creating it (R8G8B8A8 recommended for smooth operation because of exactly 1 byte per color channel per pixel). Then lock it to get a pointer to the surface data, and write pixels with alpha to your heart's content
Do remember to unlock the surface to tell the gfx driver that the texture is again available for the device.

[edited by - Nik02 on December 2, 2003 6:35:37 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Nik02
I made a test file for you; get it here.
Consider it a christmas present

-Nik

EDIT:
You could also generate your own surface with alpha - just use some alpha-compatible pixel format when creating it (R8G8B8A8 recommended for smooth operation because of exactly 1 byte per color channel per pixel). Then lock it to get a pointer to the surface data, and write pixels with alpha to your heart''s content
Do remember to unlock the surface to tell the gfx driver that the texture is again available for the device.

[edited by - Nik02 on December 2, 2003 6:35:37 PM]


awesome, thanks nik! I''ll try it as soon as i get home. I''m still surprised that the d3dx functions can''t read in .tif files.

Thanks for the tips.

Share this post


Link to post
Share on other sites
SRI!!!!!! i messed up thinkin about my own update surface needs :-D

theres actually an UpdateTexture(arg) function!

heres a link...
ok, it doesnt seem to be in msdn, though ive found a few things arent, if you have msvc++ it should be a function of the device, if not, the texture...

i dont think i was imagining it....

Share this post


Link to post
Share on other sites
quote:
Original post by Ademan555
SRI!!!!!! i messed up thinkin about my own update surface needs :-D

theres actually an UpdateTexture(arg) function!

heres a link...
ok, it doesnt seem to be in msdn, though ive found a few things arent, if you have msvc++ it should be a function of the device, if not, the texture...

i dont think i was imagining it....


where''s the link?

Share this post


Link to post
Share on other sites
I wrote a simple implementation of copyrect for you during my coffee break.
It is in no means complete, but you can extend it's functionality as needed.
See the comments to determine the limitations
I didn't get to verify the d3d alpha copying issue yesterday, for various reasons :/ However, this code will copy the alpha pixels if present.

I wrote this in notepad w/o compiler, consider this as untested code!

Also, remember to set all the alpha blending renderstates (ALPHABLENDENABLE, SRCBLEND and DESTBLEND);


HRESULT CopyRectD3D9(IDirect3DSurface9 *pDest, IDirect3DSurface9 *pSrc, int x, int y, int w, int h)
{
/*
Copy rectangle function for dx9.
Copies the src rectangle to specific position on the dest.
-Use this code at your own responsibility.
I can't guarantee that it will work, although I'm confident that it does.
-It is assumed that src and dest surfaces are of the same format.
-Does not handle clipping. To fix that, check for the texture bounds in the copy loops.
-No filtering is necessary, because no stretching occurs.
-Also assumed that src can be read in by the driver, and dest can be written.
-D3D error checking omitted for clarity.
Don't take that for granted in production code!
Everything i've omitted is for clarity; that is, left as an excercise to the reader :)

-Nik
*/


D3DSURFACE_DESC srcDesc, destDesc;

pSrc->GetDesc(&srcDesc);
pDest->GetDesc(&destDesc);
if (srcDesc.Format != destDesc.Format) return E_FAIL; //if format does not match, bail out.

//check readability/writability and other possible issues here; omitted for clarity.


D3DLOCKED_RECT srcLR, destLR;
RECT destRect;
SetRect(&destRect, x,y,x+w,y+h);
pSrc->LockRect(&srcLR,0,0); //lock the whole src surface; -for clarity-

pDest->LockRect(&destLR,&destRect,0); //lock only the relevant part of dest


switch (srcDesc.Format) //common formats considered only, for clarity.

//for other formats, just consider the bitdepth and modify the code accordingly.

{
//32 bpp:

case D3DFMT_A8R8G8B8:
case D3DFMT_X8R8G8B8:
case D3DFMT_A8B8G8R8:
case D3DFMT_X8B8G8R8:

for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
(DWORD *)destLr.pBits[x] = (DWORD *)srcLr.pBits[x];
} // for x

srcLr.pBits += srcLr.Pitch;
destLr.pBits += destLr.Pitch;
} // for y

break;

16 bpp:
case D3DFMT_R5G6B5:
case D3DFMT_X1R5G5B5:
case D3DFMT_A1R5G5B5:
case D3DFMT_A4R4G4B4:

for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
(WORD *)destLr.pBits[x] = (WORD *)srcLr.pBits[x];
} // for x

srcLr.pBits += srcLr.Pitch;
destLr.pBits += destLr.Pitch;
} // for y


} // switch


pDest->UnlockRect();
pSrc->UnlockRect();

return S_OK;
}


-Nik

EDIT: Minor bugs noticed after posting
EDIT2: Major bug noticed; skipped scanlines on multiples of bitdepths Fixed!

Not on my own machine yet


[edited by - Nik02 on December 3, 2003 4:54:15 PM]

Share this post


Link to post
Share on other sites
Thanks you very much for the help nik. I've got a question though.

I fail to see how your copy rect code will use the alpha channel to blend the two texels together.

This part is what I'm referring to.
			
for (int y = 0; y < h; y++);
{
for (int x = 0; x < w; ++x);
{
(DWORD *)destLr.pBits[x] = (DWORD *)srcLr.pBits[x];
} // for x

srcLr.pBits += srcLr.Pitch;
destLr.pBits += destLr.Pitch;
} // for y



Your code appears to just copy over the existing value. Wouldn't we need to multiply the color of the source by the source alpha, and multiple the destination color by the inverse of the source alpha, and then add them together? I beleive that is the only way to get the true color.

Thanks again.


Edit: just another thing.
nik you mentioned that D3DXLoadSurfaceFromSurface only works from sys to sys memory. I think I might have the textures in managed. Maybe I should try forcing them to sys memory to see what happens.

[edited by - SiliconMunky on December 3, 2003 12:29:14 PM]

Share this post


Link to post
Share on other sites
Ah, i understood your needs wrongly.
I thought you wanted to replace the dest alpha with src alpha, an operation which both my code and the d3dx will do happily, i tested both!

I can write a small blitter with alpha blending for you tomorrow, today I have some work to do (even at home, middle of the night :/)

Note that i don't usually have time to write free custom code, but I've been in a very happy mood lately (since business is going well), and I want to share my happiness with the members of GDNet

-Nik

PS. Do you need any other blendmodes, say for example additive, modulate or subtractive? Well, I'll comment the code so it'll be easy for you to extend it.

EDIT: Managed textures generally consist of a system-memory and video memory copy, so that when device is lost or sys copy is updated, the textures can automatically be re-uploaded (by d3d) to the graphics card when needed.
In effect, managed surface should behave exactly same as system memory surface. Only downside (but not very severe) is that managed textures will require double the memory than other surface types. However, modern games cache their textures anyway, so the downside may very possibly not affect you at all.


[edited by - Nik02 on December 3, 2003 4:43:28 PM]

Share this post


Link to post
Share on other sites
Hi again,

I whipped this up already
Note that you need much more cases for different pixel formats with this approach, because the alpha is located differently in every single d3d pixel format.

This is the copy logic in case of A8R8G8B8; other formats I leave as an excercise for the reader.

If you have questions, please fire away


//assuming 0xAARRGGBB:

//temps are for clarity, compiler will optimize them off when appropriate.

unsigned char sa, sr, sg, sb; //source temps

unsigned char da, dr, dg, db; //dest temps

unsigned char na, nr, ng, nb; //new temps

float fractA;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; ++x)
{
sa = (DWORD *)srcLr.pBits[x] & 0xff;
da = (DWORD *)destLr.pBits[x] & 0xff;
fractA = (float)sa / 255.0f; //more useful in lerping than char :)


//separate color components:

sr = ((DWORD *)srcLr.pBits[x] >> 8) & 0xff;
dr = ((DWORD *)destLr.pBits[x] >> 8) & 0xff;
sg = ((DWORD *)srcLr.pBits[x] >> 16) & 0xff;
dg = ((DWORD *)destLr.pBits[x] >> 16) & 0xff;
sb = ((DWORD *)srcLr.pBits[x] >> 24) & 0xff;
db = ((DWORD *)destLr.pBits[x] >> 24) & 0xff;

//interpolate color values:

nr = sr + fractA * ((float)dr-(float)sr);
ng = sg + fractA * ((float)dg-(float)sg);
nb = sb + fractA * ((float)db-(float)sb);
//note that you could also use any other formula instead of lerp,

//for example add dest and src values together for additive blending.


//leave dest alpha as is (change as needed):

na = da;

//combine new color values, write them to the dest pixel:

(DWORD *)destLr.pBits[x] = na | (nr << 8) | (ng << 16) | (nb << 24);

} // for x

srcLr.pBits += srcLr.Pitch;
destLr.pBits += destLr.Pitch;
} // for y



-Nik

EDIT: fixed potential overflow error.

[edited by - Nik02 on December 3, 2003 5:28:56 PM]

Share this post


Link to post
Share on other sites
nik, you rock!
If you ever need any help with anything give me a shout and I''ll try my best!

Yeah, I guess you misinterpreted what I was trying to say. But all is clear now. Thanks.

It seems really weird to me that there is no blitter with alpha blending available in d3dx. Whats the deal with that??

I''ll have a closer look at the code when I get home from work tonight. Thanks again.


Just curious, what business are you in nik?

Share this post


Link to post
Share on other sites
Glad that you got it working

D3D doesn''t include a sw alpha blitter because it encourages the use of hardware features to do that. In this case, though, you''d need to create a render target destination, and draw the src into it using a textured quad and d3d alpha blending capabilities - if you were to use a hw "blitter". A bit overkill in this particular situation?

---

I work as a general manager and an agent in a Finnish multimedia studio, which me and my friend found several years ago. Gamedev has been my favourite hobby for over 10 years!

-Nik

Share this post


Link to post
Share on other sites
Yeah I was thinking of the possibilities of rendering the view of some alpha blended quads to the texture, but yeah.. that''s definetly overkill I think.

I haven''t got it working yet, because I have to have a usable graphics engine done by the end of this month. So for now I''m going to stick with large pre-rendered textures, and then once things are together I''m going to come back and create the textures on load-up by alpha blending a bunch of tiles and modular parts together.

I was originally going make the textures for the entire terrain pre-rendered. But due to memory constraints we had to ditch that idea.

Share this post


Link to post
Share on other sites
Have you considered procedural texturing?
By modifying my blitter code to use some other formula than copying the src pixels, you could produce, for example, Perlin noise textures.

The d3dx has much more optimized texture filler for this purpose, though

Procedural textures are very memory-efficient, you can discard them anytime; when needed, just create them back. No need to load any files!

-Nik

Share this post


Link to post
Share on other sites
quote:
Original post by Nik02
Have you considered procedural texturing?



well the reason I wanted to stay away from more advanced ways of texturing the terrain is because I wanted to keep it as simple as possible for the artists to the create the terrain. Maybe once I''ve got shadows setup decently I''ll come back to making the terrain nicer. But I think this will do for now, as the camera is mostly top down and at a fixed altitude.

Sorry for the late response, i was sick all weekend.

Share this post


Link to post
Share on other sites
quote:
Original post by SiliconMunky
quote:
Original post by Nik02
Have you considered procedural texturing?



well the reason I wanted to stay away from more advanced ways of texturing the terrain is because I wanted to keep it as simple as possible for the artists to the create the terrain.



I''m an artist and a programmer myself, didn''t think about that aspect I understand your situation, though; artists don''t usually like tweaking with code.

quote:

Sorry for the late response, i was sick all weekend.


No prob - I had a little flu too, but fortunately for me, it passed away easily :D

-Nik

Share this post


Link to post
Share on other sites