Dark Bit Factory & Gravity
PROGRAMMING => C / C++ /C# => Topic started by: Jim on December 23, 2007
-
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
-
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.
-
and 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
-
and 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
-
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
-
Dear Jim!
:goodpost:
But theres something i dont understand! (trying to convert to Purebasic!)
pix = new unsigned int[d3ddesc.Width * d3ddesc.Height];
is this right or
*pic= allocatememory(d3ddesc.Width * d3ddesc.Height)
Thank yu!
-
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.
-
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!
-
yeah in c++ new is the best option. in purebasic if new is not allowed allocatememory should be fine.
-
thank yu nino!
-
*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
-
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... :-*
-
It just crashes here and I can't see anything wrong with that code right now...doesn't mean it's right though :)
Jim
-
Crashing???
ATI CArd?
Here is a screenshot!
-
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:
For i=0 To (d3ddesc\Height-1)
CopyMemory(*src,*dst,d3ddesc\Width*4 )
*dst=*dst+d3ddesc\Width
*src=*src+(lock\Pitch/4)
to
*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
-
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
-
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
-
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
-
all fixed now....
added transparency!!
-
Added as Purbasic Userlib for download!
See:
http://dbfinteractive.com/index.php?topic=2946.msg40214#msg40214
Cheers eNeRGY
-
Nice one :)
-
Is it possible to load directly in RGBA insted of BRGA?
Cant find anything in DirectX Help.
The texture that gets created is the same format as the file that gets loaded, I think. Which means BMP will be BGRA and I don't know the others. You have to find out what format the texture is (GetSurfaceInfo or something like that) and if it's not what you want you'll have to swap the colour round when you do the memcpy out of the surface.
Jim
-
Thanx JIm...
Fixed it and added Transparency...
all included in the Userlib i posted!
Works very well now with OPENGL!
-
I already added this dx9 function to my OpenGL lib, and it works really great.
Take some more karma Jim ;D
-
yes for me too!
included loading from file too + transparency for all loadable formats.
Converted it to a static lib, for to use with other languages as purebasic, but i need some testers that can test in asm , c or c++ !
will upload the static lib as soon as i can!
-
MMmm..sounds nice, but how to really use this code? all I get is errors...I added all the .h files needed and thingsl like linker option, but it doesn't work :/ the problem in my case might, that I don't know where to put it (proper place).
I have this kind of code for my WIN32 window. It works fine and makes a window, but how I can use this directx code together with that.
//-----------------------------------------------------------------------------
// Filename: Win32Creation.cpp
// Description: Creates a simple Win32 window on screen
//-----------------------------------------------------------------------------
#define WIN32_LEAN_AND_MEAN
#include "Windows.h"
// Function declarations
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
// Globals
static char strAppname[]="ANAN JUTTUU";
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// Register the window class
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize=sizeof(WNDCLASSEX); // size of the window struct in bytes
wc.style=CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // window styles to use
wc.lpfnWndProc=MsgProc; // function name of event handler
wc.hInstance=hInstance; // handle to this apps instance
wc.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);// background colour of window
wc.hIcon= LoadIcon(NULL, IDI_APPLICATION); // icon for the app window
wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION); // icon when minimized to taskbar
wc.hCursor=LoadCursor(NULL, IDC_ARROW); // cursor to use for this window
wc.lpszClassName=strAppname; // name for this class
RegisterClassEx( &wc );
// Create the application's window
HWND hWnd = CreateWindow(strAppname, strAppname,
WS_OVERLAPPEDWINDOW |WS_BORDER | WS_MAXIMIZE, 0, 0, 1280, 960,
NULL, NULL, wc.hInstance, NULL );
// Show the window
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
// Enter the message loop
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while( msg.message!=WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
// no winmessages, idle code here
}
}
UnregisterClass( strAppname, wc.hInstance );
return 0;
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
HDC hDC;
PAINTSTRUCT PaintStruct;
switch( msg )
{
case WM_PAINT:
{
hDC=BeginPaint(hWnd, &PaintStruct); // Tell windows we want to update the window
// Do GDI drawing here
EndPaint(hWnd, &PaintStruct);
return 0;
}
case WM_DESTROY:
{
PostQuitMessage( 0 );
return 0;
}
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
}
------ Build started: Project: Win32creation, Configuration: Debug Win32 ------
Compiling...
png.cpp
d:\demo\win32creation\png.cpp(11) : error C2143: syntax error : missing ';' before '.'
d:\demo\win32creation\png.cpp(11) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(11) : error C2371: 'd3dpp' : redefinition; different basic types
d:\demo\win32creation\png.cpp(10) : see declaration of 'd3dpp'
d:\demo\win32creation\png.cpp(12) : error C2143: syntax error : missing ';' before '.'
d:\demo\win32creation\png.cpp(12) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(12) : error C2371: 'd3dpp' : redefinition; different basic types
d:\demo\win32creation\png.cpp(10) : see declaration of 'd3dpp'
d:\demo\win32creation\png.cpp(13) : error C2143: syntax error : missing ';' before '.'
d:\demo\win32creation\png.cpp(13) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(13) : error C2371: 'd3dpp' : redefinition; different basic types
d:\demo\win32creation\png.cpp(10) : see declaration of 'd3dpp'
d:\demo\win32creation\png.cpp(14) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(14) : error C2040: 'd3d9' : 'int' differs in levels of indirection from 'IDirect3D9 *'
d:\demo\win32creation\png.cpp(14) : error C2440: 'initializing' : cannot convert from 'IDirect3D9 *' to 'int'
There is no context in which this conversion is possible
d:\demo\win32creation\png.cpp(15) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(15) : error C2371: 'err' : redefinition; different basic types
d:\demo\win32creation\png.cpp(5) : see declaration of 'err'
d:\demo\win32creation\png.cpp(15) : error C2065: 'hWnd' : undeclared identifier
d:\demo\win32creation\png.cpp(16) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(17) : error C2065: 'img' : undeclared identifier
d:\demo\win32creation\png.cpp(17) : error C2065: 'size' : undeclared identifier
d:\demo\win32creation\png.cpp(17) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(17) : error C2365: 'D3DXCreateTextureFromFileInMemory' : redefinition; previous definition was 'function'
d:\demo\win32creation\d3dx9tex.h(1450) : see declaration of 'D3DXCreateTextureFromFileInMemory'
d:\demo\win32creation\png.cpp(17) : error C2078: too many initializers
d:\demo\win32creation\png.cpp(17) : error C2440: 'initializing' : cannot convert from 'IDirect3DTexture9 **__w64 ' to 'int'
There is no context in which this conversion is possible
d:\demo\win32creation\png.cpp(20) : error C2143: syntax error : missing ';' before '->'
d:\demo\win32creation\png.cpp(20) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(20) : error C2040: 'd3dtex' : 'int' differs in levels of indirection from 'IDirect3DTexture9 *'
d:\demo\win32creation\png.cpp(21) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(21) : error C2040: 'pix' : 'int' differs in levels of indirection from 'unsigned int *'
d:\demo\win32creation\png.cpp(21) : error C2440: 'initializing' : cannot convert from 'unsigned int *' to 'int'
There is no context in which this conversion is possible
d:\demo\win32creation\png.cpp(22) : error C2143: syntax error : missing ';' before '->'
d:\demo\win32creation\png.cpp(22) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(22) : error C2040: 'd3dtex' : 'int' differs in levels of indirection from 'IDirect3DTexture9 *'
d:\demo\win32creation\png.cpp(24) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(24) : error C2040: 'src' : 'int' differs in levels of indirection from 'unsigned int *'
d:\demo\win32creation\png.cpp(24) : error C2440: 'initializing' : cannot convert from 'unsigned int *' to 'int'
There is no context in which this conversion is possible
d:\demo\win32creation\png.cpp(25) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(25) : error C2040: 'dst' : 'int' differs in levels of indirection from 'unsigned int *'
d:\demo\win32creation\png.cpp(25) : error C2440: 'initializing' : cannot convert from 'unsigned int *' to 'int'
There is no context in which this conversion is possible
d:\demo\win32creation\png.cpp(26) : error C2059: syntax error : 'for'
d:\demo\win32creation\png.cpp(26) : error C2143: syntax error : missing ')' before ';'
d:\demo\win32creation\png.cpp(26) : error C2143: syntax error : missing ';' before '<'
d:\demo\win32creation\png.cpp(26) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(26) : error C2143: syntax error : missing ';' before '++'
d:\demo\win32creation\png.cpp(26) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(26) : error C2086: 'int y' : redefinition
d:\demo\win32creation\png.cpp(26) : see declaration of 'y'
d:\demo\win32creation\png.cpp(26) : error C2059: syntax error : ')'
d:\demo\win32creation\png.cpp(27) : error C2143: syntax error : missing ';' before '{'
d:\demo\win32creation\png.cpp(27) : error C2447: '{' : missing function header (old-style formal list?)
d:\demo\win32creation\png.cpp(32) : error C2143: syntax error : missing ';' before '->'
d:\demo\win32creation\png.cpp(32) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(32) : error C2040: 'd3dtex' : 'int' differs in levels of indirection from 'IDirect3DTexture9 *'
d:\demo\win32creation\png.cpp(33) : error C2143: syntax error : missing ';' before '->'
d:\demo\win32creation\png.cpp(33) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(33) : error C2040: 'd3dtex' : 'int' differs in levels of indirection from 'IDirect3DTexture9 *'
d:\demo\win32creation\png.cpp(34) : error C2143: syntax error : missing ';' before '->'
d:\demo\win32creation\png.cpp(34) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(34) : error C2040: 'd3ddev' : 'int' differs in levels of indirection from 'IDirect3DDevice9 *'
d:\demo\win32creation\png.cpp(35) : error C2143: syntax error : missing ';' before '->'
d:\demo\win32creation\png.cpp(35) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\demo\win32creation\png.cpp(35) : error C2040: 'd3d9' : 'int' differs in levels of indirection from 'IDirect3D9 *'
Build log was saved at "file://d:\demo\Win32creation\Debug\BuildLog.htm"
Win32creation - 59 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
-Kypho (forever beginner:))
-
The loader code is just a fragment - you need to wrap it in a function. In that file you need to include windows.h, d3d9.h and possibly a couple of others.
It looks like you've just bunged the loader code in a file and tried to build it?
Jim
-
Yes, that's what I tried :) Sorry so much to annoy you with my questions...I am trying to learn.
- Kypho
-
Your questions are not at all annoying - in fact they are very welcome because every time they are asked and answered this forum becomes a better resource. :)
So, somewhere you need to load the PNG file in to memory. I didn't write that bit because it can be done in lots of ways. Here's one:
long filelen;
void *buffer;
FILE *f;
f = fopen("pic.png", "rb");
fseek(f, 0, SEEK_END);
filelen = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = malloc(filelen);
fread(buffer, 1, filelen, f);
fclose(f);
You could make that in to a function called load_file(). len is the length of the file, and buffer points to it in memory.
Now you're in a position to use my code.
It needs to be in a function that looks like this
void load_png(void *img, DWORD len, HWND hWnd)
{
...
}
img is buffer from the load_file
len is filelen from the load_file
hWnd is the window handle from the sample windows code you're using.
At the end of the call, pix points to the graphic image in memory.
Jim
-
You can also use D3DXCreateTextureFromFile instead D3DXCreateTextureFromFileInMemory
Ex:
D3DXCreateTextureFromFile(d3ddev, "MyImage.png", &d3dtex);
And a example for a function would be:
void load_png(char *SrcFile, HWND hWnd)
{
...
D3DXCreateTextureFromFile(d3ddev, SrcFile, &d3dtex);
...
}
-
okay :) Thanks so much guys, I try that with my friend Ubbo. Good to know that I am not annoying, feel more like home here now ;D. peace
- Kypho
-
Hi!
If somebody noticed that there were problems with my last Intros (eg. c64 Orion Remake), i figured out that its this loader.
the problems were on some Vista and XP systems that they will get black screens.
I debugged down and saw that the problem is the "Getleveldesc()"
If found an article but havent time to test it out.
http://forums.indiegamer.com/showthread.php?t=13620
Cheers eNeRGy