Hello All, Ive been working a little(among other things) on getting Magic Particles to render to a texture that we can texture to a 3D object, like a plain... to make the particles 3d..
I succeeded, and while I havent done much testing... the changes required were of the most simplistic nature.
Basically 1 function had to be changed and 2 gdk functions added...
The "RenderParticles" function I changed, so that i switches to the new image render target before rendering the particles, then switch bak to the original target at the end...
The other 2 commands were 1 to create a box to render the image to and the crucial :
dbMakeImageUsage(2000, 512, 512, 1);
The particles wont render to any kind of image other than one created like above.... I dont know why and I havent tested much so I may be wrong lol....
anyway, here are 2 screenies :
Alpha Level 255 :
Alpha level 25 :
3 GDK Objects with 3 Seperate sets of emitters : (0-8 matrix particles-centre 9-14 fire-left 15-34 fireworks-right)
The attachment to this post is the complete Magic Particles GDK Wrapper, with the changes I made to it....
Here is the Main.cpp where the ONLY changes there were made, were made...
#include "DarkGDK.h"
#include "mp_wrap.h"
#include "win_data.h"
d3d d3d9;
MP_Manager* MP=NULL;
int cur=0;
int curA=9;
int curB=15;
// These 2 global vars are here global as it is cheaper to create them once globally and reuse them
// than it is to recreate and destroy them xx times persecond for the app's life :)
// Remember to release any memory these are holding when the app finishes
LPDIRECT3DSURFACE9 destSurface;
LPDIRECT3DSURFACE9 originalRenderTarget;
LPDIRECT3DDEVICE9 m_pDevice;
void PControl(int iCamera, float p_fMoveSpeed, float p_fMoveFastSpeed, float p_fTurnSpeed, float p_fPitchSpeed, float p_fTimeElapsedFloat);
// This function has been modified to render to an image rather than the main camera.
// you can also specify background colour and alpha levels for the render target
// you MUST use dbMakeImageUsage(int iId, int Width, int Height, DWORD dwUsage); to
// create the image and pass "1" as the dwUsage flag. This tells GDK that we are going
// to be using the image as a render target for DX data.
void RenderParticles(int iImgID, int ibkRed, int ibkGreen, int ibkBlue, int ibkAlpha, int iEmitFrom, int iEmitTo)
{
// check to make sure we have been passed valid arguments.
// return if the image doesnt exist - make sure it does
if(!dbImageExist(iImgID))
return;
// make sure colour values are in the proper range before we pass them
if(ibkRed > 255) ibkRed = 255; if(ibkRed < 0) ibkRed = 0;
if(ibkGreen > 255) ibkGreen = 255; if(ibkGreen < 0) ibkGreen = 0;
if(ibkBlue > 255) ibkBlue = 255; if(ibkBlue < 0) ibkBlue = 0;
if(ibkAlpha > 255) ibkAlpha = 255; if(ibkAlpha < 0) ibkAlpha = 0;
LPDIRECT3DDEVICE9 device_3d=d3d9.GetDevice3D();
// get the render surface of our image
dbGetImagePointer(iImgID)->GetSurfaceLevel(0, &destSurface);
// store the render surface of the current render target and set the image to the current render target
device_3d->GetRenderTarget(0, &originalRenderTarget);
device_3d->SetRenderTarget(0, destSurface);
// clear the device with the values passed to the function
device_3d->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE((float)ibkRed / 255.0f, (float)ibkGreen / 255.0f, (float)ibkBlue / 255.0f, (float)ibkAlpha / 255.0f), 1.0f, 0);
// setup directX device values for the particle render
device_3d->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP );
device_3d->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP );
device_3d->SetTextureStageState (0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
device_3d->SetTextureStageState (0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
device_3d->SetTextureStageState (0, D3DTSS_COLOROP, D3DTOP_MODULATE);
device_3d->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
device_3d->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
device_3d->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
device_3d->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device_3d->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
device_3d->SetRenderState(D3DRS_LIGHTING, FALSE);
// cycle through the MP emitters and render them
static int k_particles = iEmitFrom;
int k_emitter=MP->GetEmitterCount();
if(iEmitFrom < 0) iEmitFrom = 0; if(iEmitFrom > k_emitter) iEmitFrom = k_emitter;
if(iEmitTo < 0) iEmitTo = 0; if(iEmitTo > k_emitter) iEmitTo = k_emitter;
//for (int i=0;i<k_emitter;i++)
for (int i = iEmitFrom; i < iEmitTo; i++)
{
MP_Emitter* emitter=MP->GetEmitter(i);
k_particles+=emitter->Render();
}
// restore the original render target back to being primary.
device_3d->SetRenderTarget(0, originalRenderTarget);
}
// main entry point for program
void DarkGDK ( void )
{
dbSetWindowTitle("Magic Particles (www.astralax.com) wrapper for GDK");
// set sync rate
dbSyncOn ( );
dbSyncRate ( 0 );
dbBackdropOn ( ) ;
dbSetDisplayMode(1024, 768, 32);
dbSetWindowPosition(0, 0);
dbSetAmbientLight(100);
// Particles initialisation
// IMPORTANT - dbMakeImageUsage MUST BE USED TO CREATE THE TEXTURE.....
m_pDevice = dbGetDirect3DDevice();
int MatrixParticles = 2000;
int iFireA = 2001; int iFireB = 2002;
dbMakeImageUsage(MatrixParticles, 512, 512, 1);
dbGetImagePointer(MatrixParticles)->GetSurfaceLevel(0, &destSurface);
m_pDevice->GetRenderTarget(0, &originalRenderTarget);
m_pDevice->SetRenderTarget(0, destSurface);
m_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE((float)0 / 255.0f, (float)0 / 255.0f, (float)0 / 255.0f, (float)0 / 255.0f), 1.0f, 0);
m_pDevice->SetRenderTarget(0, originalRenderTarget);
dbMakeImageUsage(iFireA = 2001, 512, 512, 1);
dbGetImagePointer(iFireA)->GetSurfaceLevel(0, &destSurface);
m_pDevice->GetRenderTarget(0, &originalRenderTarget);
m_pDevice->SetRenderTarget(0, destSurface);
m_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE((float)0 / 255.0f, (float)0 / 255.0f, (float)0 / 255.0f, (float)10 / 255.0f), 1.0f, 0);
m_pDevice->SetRenderTarget(0, originalRenderTarget);
dbMakeImageUsage(iFireB = 2002, 512, 512, 1);
dbGetImagePointer(iFireB)->GetSurfaceLevel(0, &destSurface);
m_pDevice->GetRenderTarget(0, &originalRenderTarget);
m_pDevice->SetRenderTarget(0, destSurface);
m_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE((float)0 / 255.0f, (float)0 / 255.0f, (float)0 / 255.0f, (float)10 / 255.0f), 1.0f, 0);
m_pDevice->SetRenderTarget(0, originalRenderTarget);
// SET THE PARTICLE RENDERER SIZE TO THE IMAGE SIZE
int client_wi = 512;
int client_he = 512;
d3d9.Init();
MP=new MP_Manager;
const char* temp_folder=GetPathToTemp();
MP->Initialization(MAGIC_INTERPOLATION_ENABLE, MAGIC_NOLOOP, MAGIC_CHANGE_EMITTER_ONLY, temp_folder);
//const char* file=GetFirstFile();
//while (file)
//{
MP->LoadEmittersFromFile("matrix.ptc");
MP->LoadEmittersFromFile("fire.ptc");
//file=GetNextFile();
//}
const char* texture_folder=GetPathToTexture();
MP->LoadTextures(texture_folder,1024,1024,1,0.1f);
MP->CloseFiles();
MP->Stop();
MP_Emitter* emitter=MP->GetEmitter(cur);
emitter->SetState(MAGIC_STATE_UPDATE);
int k_emitter=MP->GetEmitterCount();
float cx=((float)client_wi)/2.f;
float cy=((float)client_he)/2.f;
for (int i=0;i<k_emitter;i++)
{
emitter=MP->GetEmitter(i);
MP_POSITION pos;
emitter->GetPosition(pos);
pos.x=pos.x+cx;
pos.y=pos.y+cy;
pos.z=50;
emitter->Move(pos);
}
// Make the object to be our render target image to be textured on and set its alpha value so we can
// see through it if we choose to in the render function
dbMakeObjectBox(1, 512, 512, 1);
dbPositionObject(1, 0, 0, 150);
dbTextureObject(1, MatrixParticles);
dbSetAlphaMappingOn(1, 100);
dbMakeObjectBox(2, 512, 512, 1);
dbPositionObject(2, 525, 0, 150);
dbTextureObject(2, iFireA);
dbSetAlphaMappingOn(2, 100);
dbMakeObjectBox(3, 512, 512, 1);
dbPositionObject(3, -525, 0, 150);
dbTextureObject(3, iFireB);
dbSetAlphaMappingOn(3, 100);
// main loop
while ( LoopGDK ( ) )
{
dbRotateObject(1, dbObjectAngleX(1)+0.1, dbObjectAngleY(1)+1.1, dbObjectAngleZ(1)+0.1);
dbRotateObject(2, dbObjectAngleX(2)+0.1, dbObjectAngleY(2)+1.1, dbObjectAngleZ(2)+0.1);
dbRotateObject(3, dbObjectAngleX(3)+0.1, dbObjectAngleY(3)+1.1, dbObjectAngleZ(3)+0.1);
// quit on escape key
if ( dbEscapeKey ( ) )
return;
// Magic Particles update
static unsigned long last_time=0;
double rate=0.01;
unsigned long new_time=GetTick();
if (new_time>last_time)
{
rate=new_time-last_time;
last_time=new_time;
if (rate>500)
rate=0.01;
}
MP->Update(rate);
MP_Emitter* emitter=MP->GetEmitter(cur);
if(emitter->GetState()==MAGIC_STATE_STOP)
{
cur++;
int k_emitter=8; //MP->GetEmitterCount();
if (cur>=k_emitter)
cur=0;
emitter=MP->GetEmitter(cur);
emitter->SetState(MAGIC_STATE_UPDATE);
}
emitter=MP->GetEmitter(curA);
if(emitter->GetState()==MAGIC_STATE_STOP)
{
curA++;
int k_emitter=14;//MP->GetEmitterCount();
if (cur>=k_emitter)
cur=9;
emitter=MP->GetEmitter(curA);
emitter->SetState(MAGIC_STATE_UPDATE);
}
emitter=MP->GetEmitter(curB);
if(emitter->GetState()==MAGIC_STATE_STOP)
{
curB++;
int k_emitter=34;//MP->GetEmitterCount();
if (curB>=k_emitter)
cur=15;
emitter=MP->GetEmitter(curB);
emitter->SetState(MAGIC_STATE_UPDATE);
}
// Render MATRIX PARTICLES to Object 1's Texture
RenderParticles(MatrixParticles, 0, 0, 0, 25, 0, 8);
// Render some Fire Particles to Object 2's Texture
RenderParticles(iFireA, 0, 0, 0, 10, 9, 14);
// Render some Fire Particles to Object 2's Texture
RenderParticles(iFireB, 0, 0, 0, 10, 15, 34); // Render Particles
PControl(0, 0.5, 1.0, 0.1, 0.1, 10);
dbPositionObject(1, 0, 0, 0);
dbSync ( );
}
// cleanup the directX stuff we created... gotta be tidy these days and release our memory lol
if(destSurface != NULL) { destSurface->Release(); destSurface = NULL; }
if(originalRenderTarget != NULL) { originalRenderTarget->Release(); originalRenderTarget = NULL; }
delete MP;
MP=NULL;
d3d9.Clear();
}
// cheap movement controls - FPS style, hold shift for move faster.. WSAD+Mouse to move
void PControl(int iCamera, float p_fMoveSpeed, float p_fMoveFastSpeed, float p_fTurnSpeed, float p_fPitchSpeed, float p_fTimeElapsedFloat)
{
float fMoveSpeed = p_fMoveSpeed * p_fTimeElapsedFloat;
float fMoveFastSpeed= p_fMoveFastSpeed * p_fTimeElapsedFloat;
float fTurnSpeed = p_fTurnSpeed * p_fTimeElapsedFloat;
float fPitchSpeed = p_fPitchSpeed * p_fTimeElapsedFloat;
int MX=dbMouseMoveX();
int MY=dbMouseMoveY();
int iCam = 0;
//if(dbCameraExist(iCamera) == 1)
//{
iCam = iCamera;
//}
dbRotateCamera(iCam, (dbCameraAngleX()+(MY*fPitchSpeed*0.1)), (dbCameraAngleY()+(MX*fTurnSpeed*0.1)), dbCameraAngleZ());
// forwards
if(dbKeyState(Key_W))
{ // fast speed
if(dbKeyState(Key_LShift))
{
dbMoveCamera(iCam, fMoveFastSpeed);
}
else // normal speed
{
dbMoveCamera(iCam, fMoveSpeed);
};
};
// backwards
if(dbKeyState(Key_S))
{
if(dbKeyState(Key_LShift))
{
dbMoveCamera(iCam, 0-fMoveFastSpeed);
}
else
{
dbMoveCamera(iCam, 0-fMoveSpeed);
};
};
// strafe left
if(dbKeyState(Key_A))
{
if(dbKeyState(Key_LShift))
{
dbMoveCameraLeft(iCam, fMoveFastSpeed);
}
else
{
dbMoveCameraLeft(iCam, fMoveSpeed);
};
};
//strafe right
if(dbKeyState(Key_D))
{
if(dbKeyState(Key_LShift))
{
dbMoveCameraRight(iCam, fMoveFastSpeed);
}
else
{
dbMoveCameraRight(iCam, fMoveSpeed);
};
};
if(dbKeyState(Key_Num8))
{ //fwd
dbMoveCamera(iCam, fMoveSpeed);
};
if(dbKeyState(Key_NumForwardSlash))
{//fwd fast
dbMoveCamera(iCam, fMoveFastSpeed);
};
if(dbKeyState(Key_Num2))
{//backward
dbMoveCamera(iCam, -fMoveSpeed);
};
if(dbKeyState(Key_Num0))
{//backward fast
dbMoveCamera(iCam, -fMoveFastSpeed);
};
if(dbKeyState(Key_Num4))
{//turn left
dbRotateCamera(iCam, dbCameraAngleX(iCam), dbWrapValue(dbCameraAngleY(iCam)-fTurnSpeed), dbCameraAngleZ(iCam));
};
if(dbKeyState(Key_Num6))
{//turn right
dbRotateCamera(iCam, dbCameraAngleX(iCam), dbWrapValue(dbCameraAngleY(iCam)+fTurnSpeed), dbCameraAngleZ(iCam));
};
if(dbKeyState(Key_NumLock))
{//Roll Left
dbRollCameraLeft(iCam, fTurnSpeed);
};
if(dbKeyState(Key_NumLock))
{//Roll Right
dbRollCameraRight(iCam, fTurnSpeed);
};
if(dbKeyState(Key_Num9))
{//Up
dbPitchCameraUp(iCam, 90);
dbMoveCamera(iCam, fMoveSpeed);
dbPitchCameraDown(iCam, 90);
};
if(dbKeyState(Key_NumStar))
{//Up Fast
dbPitchCameraUp(iCam, 90);
dbMoveCamera(iCam, fMoveFastSpeed);
dbPitchCameraDown(iCam, 90);
};
if(dbKeyState(Key_Num3))
{//Down
dbPitchCameraDown(iCam, 90);
dbMoveCamera(iCam, fMoveSpeed);
dbPitchCameraUp(iCam, 90);
};
if(dbKeyState(Key_NumPeriod))
{//Down Fast
dbPitchCameraDown(iCam, 90);
dbMoveCamera(iCam, fMoveFastSpeed);
dbPitchCameraUp(iCam, 90);
};
if(dbKeyState(Key_Num7))
{//Pitch down
dbRotateCamera(iCam, dbWrapValue(dbCameraAngleX(iCam)+fPitchSpeed),dbCameraAngleY(iCam), dbCameraAngleZ(iCam));
};
if(dbKeyState(Key_Num1))
{//Pitch Up
dbRotateCamera(iCam, dbWrapValue(dbCameraAngleX(iCam)-fPitchSpeed),dbCameraAngleY(iCam), dbCameraAngleZ(iCam));
};
if(dbKeyState(Key_NumLock))
{//Roll Left
dbRollCameraLeft(iCam, fPitchSpeed);
};
if(dbKeyState(Key_NumMinus))
{//Roll Right
dbRollCameraRight(iCam, fPitchSpeed);
};
if(dbKeyState(Key_Num5))
{// Resets the camera to 0, 0, 0 and looking straight ahead, good if you stuff up the look angles with rotation
dbRotateCamera(iCam, 0.0f, 0.0f, 0.0f);
};
};
If anybody wants to test it for me, I would appreciate some feedback as to if it works properly or not..... I only changed the render target quickly, so might have muffed something...
Hope this helps someone
PS. DEMO Exe in the attachment compiled with GDK 7.4 -- you will need at least GDK 7.3 to use this, I dont believe previous version had the appripriate image commands available....
Updated
I have made as many changes as I can to the setup of the wrapper. The render target function is now setup in a manner that allows you to render to multiple images if you choose, and also to specify the red, green, blue and alpha levels of the image. Combining that with GDK object's alpha mapping, making a see through 3d particle emitter is quite easy(for example fire doesnt have a black background in reality does it ? lol)
The RenderParticles Function is now setup to use be told which emmitter to render from and to... so you can render different sets of emitters to different images as I have no demonstrated in the demo attached to this post...
If anybody has any question please feel free to ask, I dont know much about Magic Particles itself, but I will help as I can in relation to using this.
If it ain't broke.... DONT FIX IT !!!