• Welcome to Dark Bit Factory & Gravity.
 

Using Direct3D to Load Images

Started by Jim, December 23, 2007

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Jim

I knocked this code up today because I wanted to be able to load PNG images.  Since neither LoadImage nor OleLoadPicture can handle PNG, I had a go with Direct3D.  Here's the code

#include <windows.h>
#include "d3dx9tex.h"
#include <stdlib.h>
...
HRESULT err;
unsigned int *pix;
IDirect3D9 *d3d9;
IDirect3DDevice9 *d3ddev;
IDirect3DTexture9 *d3dtex;
D3DPRESENT_PARAMETERS d3dpp = {0};
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
d3dpp.Windowed = TRUE;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
err = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
assert(err == S_OK);
D3DXCreateTextureFromFileInMemory(d3ddev, img, size, &d3dtex);
D3DLOCKED_RECT lock;
D3DSURFACE_DESC d3ddesc;
d3dtex->GetLevelDesc(0, &d3ddesc);
pix = new unsigned int[d3ddesc.Width * d3ddesc.Height];
d3dtex->LockRect(0, &lock, NULL, D3DLOCK_READONLY);
unsigned int *dst, *src;
src = (unsigned int *)lock.pBits;
dst = pix;
for (unsigned int y = 0; y < d3ddesc.Height; y++)
{
memcpy(dst, src, d3ddesc.Width * sizeof(unsigned int));
dst += d3ddesc.Width;
src += lock.Pitch/sizeof(unsigned int);
}
d3dtex->UnlockRect(0);
d3dtex->Release();
d3ddev->Release();
d3d9->Release();

The inputs are
img - pointer to the PNG file in memory
size - size of the PNG file in memory
hWnd - handle to your window
The output is
pix - pointer to the RGB image in memory

You will need to add d3d9.lib and d3dx9.lib to the linker options.

As well as PNG, this routine will load bmp, .dds, .dib, .hdr, .jpg, .pfm, .ppm, and .tga

Jim
Challenge Trophies Won:

ninogenio

#1
very very cool jim! k+

and is this compatible to use this in an ogl app or gdi app or is it d3d only.

-edit i can see it should be compatible with ogl, cool ill need to try it out.
Challenge Trophies Won:

Jim

Quoteand is this compatible to use this in an ogl app
I think so, and that is how I'm using it.  There are dire warnings in the paperwork about mixing OpenGL and Direct3D calls, but I think that's to do with trying to draw using both APIs at the same time.

Jim
Challenge Trophies Won:

taj

Quote from: Jim on December 23, 2007
Quoteand is this compatible to use this in an ogl app
I think so, and that is how I'm using it.  There are dire warnings in the paperwork about mixing OpenGL and Direct3D calls, but I think that's to do with trying to draw using both APIs at the same time.

Jim
Thats true. I've been mixing DX and OGL for quite a while. Maths, image loading, curve paths, host raytracing, model subdivision can all be done much smaller with DX. I then use OGL for rendering which is slightly larger (slightly) but I feel more comfortable with it.

Taj
Challenge Trophies Won:

Jim

The way I figure it, the drivers MUST be able to handle multiple D3D and OpenGL contexts at the same time to work with a multithreaded OS, so there are some very basic minimum things it has to allow.  As long as it's not using thread/process id or window id as a unique identifier then it should be OK, though of course that's not rigourously defined anywhere.

Jim
Challenge Trophies Won:

energy

Dear Jim!

:goodpost:

But theres something i dont understand! (trying to convert to Purebasic!)

Quote
pix = new unsigned int[d3ddesc.Width * d3ddesc.Height];

is  this right or

*pic= allocatememory(d3ddesc.Width * d3ddesc.Height)

Thank yu!
coding: jwasm,masm
hobby: www.scd2003.de

ninogenio

#6
as long as you have declared your pic pointer as an unsigned int and allocatememory is as close as you can get to the new command in purebasic then that will be fine energy.

new is just a really good way in c++ of allocating memory.
Challenge Trophies Won:

energy

ok that means that in c yu mustnt use the allocmem.... there yu can use NEW

then its ok when i use allocatememory in Purebasic!
coding: jwasm,masm
hobby: www.scd2003.de

ninogenio

yeah in c++ new is the best option. in purebasic if new is not allowed allocatememory should be fine.
Challenge Trophies Won:

energy

coding: jwasm,masm
hobby: www.scd2003.de

Jim

*pic= allocatememory(d3ddesc.Width * d3ddesc.Height)

That would be too small, as each pixel is an integer (4 bytes) so you'd need to allocate 4x as much.
In C something like
unsigned int *pix = malloc(d3ddesc.Width * d3ddesc.Height * sizeof(unsigned int));
or better
unsigned int *pix = malloc(d3ddesc.Width * d3ddesc.Height * sizeof *pix);

in C++
unsigned int *pix = new unsigned int [d3ddesc.Width * d3ddesc.Height];

Jim
Challenge Trophies Won:

energy

Hi Jim!

Small Error i cant find!
Hope yu can have an eye on it (Its Purebasic)
Result is in the exe!   (Displayed in OPENGL!)

Procedure.l DX_LoadTexture (*tex.Texture,*mem,PicSize.l)
  ;Texturloader orginally by Jim Shaw
 
  Protected *pix,*src, *dst, d3d9.IDirect3D9 , d3ddev.IDIRECT3DDEVICE9 , d3dtex.IDIRECT3DTEXTURE9, d3dpp.D3DPRESENT_PARAMETERS
  Protected lock.D3DLOCKED_RECT, d3ddesc.D3DSURFACE_DESC,i.l
  d3dpp\BackBufferFormat=#D3DFMT_UNKNOWN
  d3dpp\SwapEffect=#D3DSWAPEFFECT_FLIP
  d3dpp\Windowed=#True
  d3d9=Direct3DCreate9(#D3D_SDK_VERSION)
  d3d9\createdevice(#D3DADAPTER_DEFAULT,#D3DDEVTYPE_HAL,hwnd,#D3DCREATE_HARDWARE_VERTEXPROCESSING,@d3dpp,@d3ddev )
  D3DXCreateTextureFromFileInMemory(d3ddev,*mem,PicSize,@d3dtex)
  d3dtex\getleveldesc(0,@d3ddesc)
  *tex\Width= d3ddesc\Width
  *tex\Height= d3ddesc\Height
  *pix=AllocateMemory((d3ddesc\Width*d3ddesc\Height)*4)
  d3dtex\lockrect(0,@lock,#Null,#D3DLOCK_READONLY)
  *src=lock\pBits
  *dst=*pix
   For i=0 To (d3ddesc\Height-1)
    CopyMemory(*src,*dst,d3ddesc\Width*4 )
    *dst=*dst+d3ddesc\Width
    *src=*src+(lock\Pitch/4)
   Next
  d3dtex\unlockrect(0)
  d3dtex\release()
  d3ddev\release()
  d3d9\release()
  *tex\mem= *pix
EndProcedure


Thanx...  :-*
coding: jwasm,masm
hobby: www.scd2003.de

Jim

It just crashes here and I can't see anything wrong with that code right now...doesn't mean it's right though :)
Jim
Challenge Trophies Won:

energy

Crashing???
ATI CArd?

Here is a screenshot!
coding: jwasm,masm
hobby: www.scd2003.de

energy

hi Jim!

Fixed all for Purebasic... runs very well with OPENGL!!!    THANX A LOT FOR THIS LOADER!!!!!     :cheers:

One resent fix i made for me:
Quote
For i=0 To (d3ddesc\Height-1)
    CopyMemory(*src,*dst,d3ddesc\Width*4 )
    *dst=*dst+d3ddesc\Width
    *src=*src+(lock\Pitch/4)

to
Quote
*src=lock\pBits
*dst=*pix+((d3ddesc\Width*(d3ddesc\Height-1))*4)
For i=0 To (d3ddesc\Height-1)
   CopyMemory(*src,*dst,d3ddesc\Width*4 )
    *dst=*dst-(d3ddesc\Width*4)
    *src=*src+(lock\Pitch)
  Next

cause yu copy width*4 but calculating pointer for dest only for width

and for use in OPENGL i HAVE to turn the pic ... see *dst pointer!


Thanx
eNeRGy
coding: jwasm,masm
hobby: www.scd2003.de

energy

Hi Jim, Just one quick question:
Need to Have the Alpha-Value for the loaded Image!
Image is loaded in BGRA with this Routine...

But what value does this routine load for the Alpha-Value??

Thanx in Advance!
eNeRGy
coding: jwasm,masm
hobby: www.scd2003.de

Jim

If there's an alpha channel in the image it'll use that.  The only formats I've seen work reliably for that are PNG, TGA and the DirectX specific ones.  BMP and JPG are no good.  If there's no alpha channel it'll be set to 0xff.

Jim
Challenge Trophies Won:

energy

#17
Thanx Jim!
Is it possible to load directly in RGBA insted of BRGA?
Cant find anything in DirectX Help.

It was a Jpg i loaded with!
for the others with non Alpha valus ill change the routine and write manuell with a given Alpha-Value!

Cheers and best wishes....
eNeRGy
coding: jwasm,masm
hobby: www.scd2003.de

energy

all fixed now....
added transparency!!

coding: jwasm,masm
hobby: www.scd2003.de

energy

coding: jwasm,masm
hobby: www.scd2003.de