Even though non of you aided me in times of need, I found my way around the previous problem. Hurray! Spend ALL day on this one.
But now I have a new problem and this one is more Irrlicht related so maybe you will help me with this one. Thank you very much!
http://img116.imageshack.us/my.php?imag ... llywa9.jpg
This code from his sourcecode makes the game crash during startup.
//height = Terrain->getHeight(p.X, p.Z);
I'm not exactly sure why, but I tried someone elses suggestion from the 'grass node' post and switched with this:
f32 ay = TerrainHeightMap->getPixel(x1,z1).getBlue()* Terrain->getScale().Y;
f32 by = TerrainHeightMap->getPixel(x1+1,z1).getBlue()* Terrain->getScale().Y;
f32 cy = TerrainHeightMap->getPixel(x1,z1+1).getBlue()* Terrain->getScale().Y;
f32 dy = TerrainHeightMap->getPixel(x1+1,z1+1).getBlue()* Terrain->getScale().Y;
f32 u = xz.X - (f32)x1;
f32 v2 = xz.Z - (f32)z1;
height = ay*(1.0f-u)*(1.0f-v2) + by*u*(1.0f-v2) + cy*(1.0f-u)*v2 + dy*u*v2;
------------------------------------------------------
Seems to locate the 'Y' coordinate like it should, and I dont see why that has anything to do with the odd effect of grass gone wild. Why does the original code not work.
Another thing, I cannot switch render mode (this also makes the game crash) and even though I use his terrain the grass area is offset by a few hundred X, Y.
Come on guys, I need you on this one. I dont use paypal sorry
Oh yeah and the code (didnt want to include it because it just takes up alot of space but if it helps then why not):
main.cpp
Code: Select all
#include <irrlicht.h>
#include <iostream>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#include "CGrassPatchSceneNode.h"
//#include "CWindGenerator.h"
#include "RealisticWater.h"
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
core::array<video::E_MATERIAL_TYPE> modes;
video::ITexture *tex1;
video::ITexture *tex2;
scene::IWindGenerator *wind;
#define width 10
#define height 10
#define total width*height
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(scene::ISceneNode* terrain, scene::CGrassPatchSceneNode** grass)
{
// store pointer to terrain so we can change its drawing mode
Terrain = terrain;
Grass = &grass[0];
mode = 0;
tex = false;
}
bool OnEvent(SEvent event)
{
// check if user presses the key 'W' or 'D'
if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case irr::KEY_KEY_W: // switch wire frame mode
Terrain->setMaterialFlag(video::EMF_WIREFRAME, !Terrain->getMaterial(0).Wireframe);
return true;
case irr::KEY_KEY_D: // toggle detail map
Terrain->setMaterialType(
Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ?
video::EMT_DETAIL_MAP : video::EMT_SOLID);
return true;
case irr::KEY_KEY_Z: // change draw distance
for (int n=0; n<total; ++n)
{
if (Grass[n]->getDrawDistance() > GRASS_PATCH_SIZE + 50)
Grass[n]->setDrawDistance(Grass[n]->getDrawDistance()- 50.0f);
}
return true;
case irr::KEY_KEY_X: // change draw distance
for (int n=0; n<total; ++n)
{
Grass[n]->setDrawDistance(Grass[n]->getDrawDistance()+ 50.0f);
}
return true;
case irr::KEY_KEY_C: // change max density
for (int n=0; n<total; ++n)
{
if (Grass[n]->getMaxDensity() > 55 )
Grass[n]->setMaxDensity(Grass[n]->getMaxDensity()- 50);
}
return true;
case irr::KEY_KEY_V: // change max density
for (int n=0; n<total; ++n)
{
Grass[n]->setMaxDensity(Grass[n]->getMaxDensity()+ 50);
}
return true;
case irr::KEY_KEY_B: // change mode
if (mode > 0)
--mode;
for (int n=0; n<total; ++n)
{
Grass[n]->setMaterialType(modes[mode]);
}
return true;
case irr::KEY_KEY_N: // change mode
if (mode < modes.size())
++mode;
for (int n=0; n<total; ++n)
{
Grass[n]->setMaterialType(modes[mode]);
}
return true;
case irr::KEY_KEY_M: // change mode
tex = !tex;
for (int n=0; n<total; ++n)
{
Grass[n]->setMaterialTexture(0,tex ? tex1:tex2);
}
return true;
case irr::KEY_KEY_S: // switch terrain invisible
Terrain->setVisible( !Terrain->isVisible());
return true;
case irr::KEY_KEY_K: // less wind
if ( wind->getStrength() > 5 )
wind->setStrength( wind->getStrength() - 5 );
return true;
case irr::KEY_KEY_L: // more wind
if ( wind->getStrength() < 100 )
wind->setStrength( wind->getStrength() + 5 );
return true;
case irr::KEY_KEY_O: // blustery wind
if ( wind->getRegularity() > 1 )
wind->setRegularity( wind->getRegularity() - 1 );
return true;
case irr::KEY_KEY_P: // regular wind
if ( wind->getRegularity() < 20 )
wind->setRegularity( wind->getRegularity() + 1 );
return true;
case irr::KEY_KEY_U: // decrease wind resolution
if (Grass[0]->getWindRes() > 1)
{
for (int n=0; n<total; ++n)
{
Grass[n]->setWindRes(Grass[n]->getWindRes() - 1);
}
}
return true;
case irr::KEY_KEY_I: // decrease wind resolution
if (Grass[0]->getWindRes() < 20)
{
for (int n=0; n<total; ++n)
{
Grass[n]->setWindRes(Grass[n]->getWindRes() + 1);
}
}
return true;
case irr::KEY_KEY_T: // decrease refresh delay
if (Grass[0]->getRefreshDelay() > 4)
{
for (int n=0; n<total; ++n)
{
Grass[n]->setRefreshDelay(Grass[n]->getRefreshDelay() - 10);
}
}
return true;
case irr::KEY_KEY_Y: // increase refresh delay
if (Grass[0]->getRefreshDelay() < 500)
{
for (int n=0; n<total; ++n)
{
Grass[n]->setRefreshDelay(Grass[n]->getRefreshDelay() + 10);
}
}
return true;
}
}
return false;
}
private:
scene::ISceneNode* Terrain;
u32 mode;
bool tex;
scene::CGrassPatchSceneNode** Grass;
};
int main()
{
// ask if user would like shadows
char i;
printf("Please press 'y' if you want to use realtime shadows.\n");
std::cin >> i;
bool shadows = (i == 'y');
// ask user for driver
video::E_DRIVER_TYPE driverType;
printf("Please select the driver you want for this example:\n"\
" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
" (d) Software Renderer\n (e) Burning's Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");
std::cin >> i;
switch(i)
{
case 'a': driverType = video::EDT_DIRECT3D9;break;
case 'b': driverType = video::EDT_DIRECT3D8;break;
case 'c': driverType = video::EDT_OPENGL; break;
case 'd': driverType = video::EDT_SOFTWARE; break;
case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
case 'f': driverType = video::EDT_NULL; break;
default: return 1;
}
// create device and exit if creation failed
IrrlichtDevice *device =
createDevice(driverType, core::dimension2d<s32>(1000, 760),
32, false, shadows);
if (device == 0)
return 1; // could not create selected driver.
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment();
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
// add some help text
gui::IGUIStaticText* text = env->addStaticText(
L"Press 'S' to toggle terrain\nPress 'W' to toggle wireframe mode\nPress 'D' to toggle detail map\nZ and X for distance\nC and V for max density\nB and N to change render mode\nM to swap texture\nK and L to change wind strength\nO and P to change wind regularity\nU and I for wind resolution\nT and Y for buffer refresh rate",
core::rect<s32>(10,320,200,450), true, true, 0, -1, true);
//Object
scene::IAnimatedMesh* mesh = smgr->getMesh(
"3d/objects/milka.b3d");
//node->setAnimationSpeed(30);
IAnimatedMeshSceneNode* hero = smgr->addAnimatedMeshSceneNode( mesh );
//hero->setMaterialTexture( 0, driver->getTexture("256.gif") );
hero->setFrameLoop(1*50, 20*50);
hero->setAnimationSpeed (15 * 100);
hero->setScale(vector3df(10,10,10));
// add shadow
hero->addShadowVolumeSceneNode();
smgr->setShadowColor(video::SColor(150,0,0,0));
hero->setPosition(vector3df(1000,500,1000));
hero->setMaterialFlag(EMF_LIGHTING, true);
//node->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL);
//node->setMaterialFlag(EMF_BACK_FACE_CULLING, false);
//hero->setRotation(vector3df(270,0,0));
// create light
scene::ISceneNode* node = 0;
node = smgr->addLightSceneNode(0, core::vector3df(0,0,0),
video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 800.0f);
scene::ISceneNodeAnimator* anim = 0;
anim = smgr->createFlyCircleAnimator (core::vector3df(1000,650,1000),250.0f);
node->addAnimator(anim);
anim->drop();
// attach billboard to light
node = smgr->addBillboardSceneNode(node, core::dimension2d<f32>(50, 50));
node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
node->setMaterialTexture(0, driver->getTexture("particlewhite.bmp"));
//Camera
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
camera->setPosition(core::vector3df(550,550,1000));
// add terrain scene node
scene::ITerrainSceneNode* terrain2 = smgr->addTerrainSceneNode("media/terrain-heightmap.bmp");
video::IImage* heightMap = driver->createImageFromFile ("media/terrain-heightmap.bmp");
video::IImage* textureMap = driver->createImageFromFile ("media/terrain-grasscol.bmp");
video::IImage* grassMap = driver->createImageFromFile ("media/terrain-grassmap.png");
core::vector3df ts(40, 4.0f, 40);
terrain2->setScale(ts);
terrain2->setPosition( core::vector3df(0,0,0) );
terrain2->setMaterialFlag(video::EMF_LIGHTING, false);
terrain2->setMaterialTexture(0, driver->getTexture("media/terrain-texture.jpg"));
terrain2->setMaterialTexture(1, driver->getTexture("media/detailmap3.jpg"));
terrain2->setMaterialType(video::EMT_DETAIL_MAP);
terrain2->scaleTexture(1.0f, 20.0f);
/*
RealisticWaterSceneNode* pWater;
pWater = new RealisticWaterSceneNode(smgr, 2100.0f, 2100.0f, driver->getTexture("data/terrain-grassmap.png"),device->getTimer(),core::dimension2di(256,256));
pWater->setPosition(vector3df(1000,500,1000));
pWater->setMaterialFlag(video::EMF_LIGHTING, false);
*/
// create skybox
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
smgr->addSkyBoxSceneNode(
driver->getTexture("irrlicht2_up.jpg"),
driver->getTexture("irrlicht2_dn.jpg"),
driver->getTexture("irrlicht2_lf.jpg"),
driver->getTexture("irrlicht2_rt.jpg"),
driver->getTexture("irrlicht2_ft.jpg"),
driver->getTexture("irrlicht2_bk.jpg"));
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
// create triangle selector for the terrain
scene::ITriangleSelector* selector
= smgr->createTerrainTriangleSelector(terrain2, 0);
terrain2->setTriangleSelector(selector);
selector->drop();
// create collision response animator and attach it to the camera
scene::ISceneNodeAnimator* anim2 = smgr->createCollisionResponseAnimator(
selector, camera, core::vector3df(60,100,60),
core::vector3df(0,-3,0),
core::vector3df(0,50,0));
camera->addAnimator(anim2);
anim2->drop();
// create event receiver
scene::CGrassPatchSceneNode *grass[width*height];
MyEventReceiver receiver(terrain2,&grass[0]);
device->setEventReceiver(&receiver);
// create wind...
wind = scene::createWindGenerator( 30.0f, 3.0f );
int lastFPS = -1;
tex1 = driver->getTexture("media/grass.png");
tex2 = driver->getTexture("media/grass2.bmp");
driver->makeColorKeyTexture(tex2, core::position2d<s32>(0,0));
//now we add some grass nodes
for (int x=0; x<width; ++x)
for (int z=0; z<height; ++z)
{
// add a grass node
grass[x*width + z] = new scene::CGrassPatchSceneNode(terrain2, smgr, -1, core::vector3d<s32>(x,0,z), "grass", heightMap, textureMap, grassMap, wind);
grass[x*width + z]->setMaterialFlag(video::EMF_LIGHTING,false);
grass[x*width + z]->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL);
grass[x*width + z]->setMaterialTexture(0,tex1);
grass[x*width + z]->drop();
}
while(device->run())
if (device->isWindowActive())
{
driver->beginScene(true, true, SColor(255,100,101,140));
smgr->drawAll();
env->drawAll();
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Irrlicht Engine - SpecialFX example [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
device->drop();
return 0;
}
And CGrassPatchSceneNode.cpp
Code: Select all
// Grass node by Gaz Davidson 2006
// created from Irrlicht's particle system node by Nikolaus Gebhardt
#include "CGrassPatchSceneNode.h"
#include "CWindGenerator.h"
namespace irr
{
namespace scene
{
#pragma comment(lib, "Irrlicht.lib")
//! constructor
CGrassPatchSceneNode::CGrassPatchSceneNode(
ITerrainSceneNode* terrain, ISceneManager* mgr, s32 id, core::vector3d<s32> gridpos,
char *filepath, video::IImage* heightMap, video::IImage* colourMap,
video::IImage* grassMap, scene::IWindGenerator *windgen) :
ISceneNode((ITerrainSceneNode*)terrain, mgr, -1),
DrawDistanceSQ(GRASS_PATCH_SIZE*1.5*GRASS_PATCH_SIZE*1.5),
MaxDensity(800),
TerrainHeightMap(heightMap),
TerrainColourMap(colourMap),
TerrainGrassMap(grassMap),
Terrain(terrain),
WindGen(windgen),
lastwindtime(0),
lastdrawcount(0),
redrawnextloop(true),
fpsLock(30)
{
#ifdef _DEBUG
setDebugName("CGrassPatchSceneNode");
#endif
// set position
setPosition(core::vector3df((f32)(gridpos.X*GRASS_PATCH_SIZE),0 , (f32)(gridpos.Z*GRASS_PATCH_SIZE)));
setWindRes(5);
// set default image count
setImageCount(core::dimension2d<s32>(4,2));
// create grass
Create();
}
//! destructor
CGrassPatchSceneNode::~CGrassPatchSceneNode()
{
}
void CGrassPatchSceneNode::setWindRes(u32 newres)
{
// set size of wind grid
windGridRes = newres < 2 ? 2 : newres;
WindGrid.set_used((windGridRes+1)*(windGridRes+1));
/*for (u32 i=0; i < WindGrid.size(); ++i)
{
WindGrid[i] = core::vector2df(0,0);
}*/
}
u32 CGrassPatchSceneNode::getWindRes() { return windGridRes; }
video::SMaterial& CGrassPatchSceneNode::getMaterial(u32 i) { return Material; }
u32 CGrassPatchSceneNode::getMaterialCount() { return 1; }
core::dimension2d<s32> CGrassPatchSceneNode::getImageCount() { return imagecount; }
void CGrassPatchSceneNode::setImageCount(core::dimension2d<s32> ic)
{
imagecount = ic;
imagesize.Width= 1.0f / f32(imagecount.Width);
imagesize.Height=1.0f / f32(imagecount.Height);
v1.set_used(imagecount.Width * imagecount.Height);
v2.set_used(imagecount.Width * imagecount.Height);
v3.set_used(imagecount.Width * imagecount.Height);
v4.set_used(imagecount.Width * imagecount.Height);
for (int x=0;x<imagecount.Width; ++x)
for (int y=0;y<imagecount.Height; ++y)
{
v1[ (imagecount.Width*y)+x ] = imagesize.Width * x;
v2[ (imagecount.Width*y)+x ] = imagesize.Height * (y+1);
v3[ (imagecount.Width*y)+x ] = imagesize.Height * y;
v4[ (imagecount.Width*y)+x ] = imagesize.Width * (x+1);
}
}
void CGrassPatchSceneNode::setRefreshDelay(u32 ms) { fpsLock = ms; }
u32 CGrassPatchSceneNode::getRefreshDelay() { return fpsLock; }
void CGrassPatchSceneNode::setDrawDistance(f32 draw) { DrawDistanceSQ = draw*draw; }
f32 CGrassPatchSceneNode::getDrawDistance() { return (f32)sqrt(DrawDistanceSQ); }
void CGrassPatchSceneNode::setMaxDensity(u32 max) { MaxDensity = max; }
u32 CGrassPatchSceneNode::getMaxDensity() { return MaxDensity; }
// creates random grass,
bool CGrassPatchSceneNode::Create()
{
srand((100 * gridpos.X) + gridpos.Z);
// particle count
s32 count = 3000; // lots. we dont need them all
// create them
Particles.set_used(count);
Box.reset(0,0,0);
core::matrix4 m;
m.setRotationDegrees(Terrain->getRotation());
m.setTranslation(Terrain->getAbsolutePosition());
m.makeInverse();
for(s32 i=0; i<count; ++i)
{
// get random x and z axis
f32 x = (rand() % (GRASS_PATCH_SIZE*10) ) / 1.0f;
f32 z = (rand() % (GRASS_PATCH_SIZE*10) ) / 1.0f;
x -= GRASS_PATCH_SIZE/2.0f;
z -= GRASS_PATCH_SIZE/2.0f;
Particles[i].pos.X = x;
Particles[i].pos.Z = z;
Particles[i].sprite.Width = rand() % imagecount.Width;
if (i<30)
Particles[i].sprite.Height = 1 *(rand() % imagecount.Height); // usually grass, sometimes a flower
else
Particles[i].sprite.Height = 0;
m.transformVect(Particles[i].pos);
// patch position + particle position - terrain position = position in terrain
core::vector3df p = getPosition() + Particles[i].pos; // - Terrain->getPosition();
core::dimension2d<f32> size;
/* core::vector3df xz((p.X - Terrain->getPosition().X)/Terrain->getScale().X, 0.0f,
(p.Z - Terrain->getPosition().Z)/Terrain->getScale().Z);*/
core::vector3df xz(p.X/Terrain->getScale().X,0.0f,p.Z/Terrain->getScale().Z);
s32 x1 = (s32) floorf( xz.X );
s32 z1 = (s32) floorf( xz.Z );
f32 height;
// drop blades that are outside the terrain
if ( x1 < 1 ||
z1 < 1 ||
x1 > TerrainHeightMap->getDimension().Width - 1 ||
z1 > TerrainHeightMap->getDimension().Height - 1 )
{
--count; --i;
Particles.set_used(count);
continue;
}
// drop blades that aren't so dense
video::SColor cDensity = TerrainGrassMap->getPixel(x1,z1);
if ((u32)(rand() % 255) > cDensity.getAlpha() || cDensity.getAlpha() < 1 )
{
--count; --i;
Particles.set_used(count);
continue;
}
f32 ay = TerrainHeightMap->getPixel(x1,z1).getBlue()* Terrain->getScale().Y;
f32 by = TerrainHeightMap->getPixel(x1+1,z1).getBlue()* Terrain->getScale().Y;
f32 cy = TerrainHeightMap->getPixel(x1,z1+1).getBlue()* Terrain->getScale().Y;
f32 dy = TerrainHeightMap->getPixel(x1+1,z1+1).getBlue()* Terrain->getScale().Y;
f32 u = xz.X - (f32)x1;
f32 v2 = xz.Z - (f32)z1;
height = ay*(1.0f-u)*(1.0f-v2) + by*u*(1.0f-v2) + cy*(1.0f-u)*v2 + dy*u*v2;
//height = 1000;//Terrain->getHeight(p.X, p.Z);
size = core::dimension2d<f32> ((f32)(rand() % 50 + 20), 100.0f);
size.Height *= (f32)cDensity.getBlue()/200.0f;
Particles[i].flex = size.Height / 120.0f;
Particles[i].pos.Y = height + (size.Height*0.5f);
Particles[i].color = TerrainColourMap->getPixel(x1,z1);
Particles[i].startColor = TerrainColourMap->getPixel(x1,z1);
Box.addInternalPoint(Particles[i].pos);
f32 rotation = (rand() % 3600) / 10.0f;
core::matrix4 m2;
m2.setRotationDegrees(core::vector3df(0,rotation,0)) ; //rand() % 20,rotation,rand() % 20));
core::vector3df dimensions(0.5f * size.Width,
-0.5f * size.Height,0);
m2.rotateVect(dimensions);
core::vector3df h = core::vector3df(dimensions.X,0.0f,dimensions.Z);
core::vector3df v = core::vector3df(0.0f,dimensions.Y,0.0f);
Particles[i].points[0] = Particles[i].pos + core::vector3df(dimensions.X,dimensions.Y,dimensions.Z);
Particles[i].points[1] = Particles[i].pos + core::vector3df(dimensions.X,-dimensions.Y,dimensions.Z);
Particles[i].points[2] = Particles[i].pos - core::vector3df(dimensions.X,dimensions.Y,dimensions.Z);
Particles[i].points[3] = Particles[i].pos - core::vector3df(dimensions.X,-dimensions.Y,dimensions.Z);
/*
core::vector3d<f32> xz1(Particles[i].points[0].X/Terrain->getScale().X,0.0f,Particles[i].points[0].Z/Terrain->getScale().Z);
x1 = (s32) xz1.X;
z1 = (s32) xz1.Z;
video::SColor c1 = TerrainHeightMap->getPixel(x1, z1);
f32 height1 = c1.getBlue()* Terrain->getScale().Y;
core::vector3d<f32> xz2(Particles[i].points[3].X/Terrain->getScale().X,0.0f,Particles[i].points[3].Z/Terrain->getScale().Z);
x1 = (s32) xz2.X - 10;
z1 = (s32) xz2.Z - 10;
video::SColor c2 = TerrainHeightMap->getPixel(x1, z1);
f32 height2 = c2.getBlue()* Terrain->getScale().Y;
Particles[i].points[0].Y = Particles[i].pos.Y + height1;
Particles[i].points[3].Y = Particles[i].pos.Y + height2;
*/
// Particles[i].points[0].Y -= 30;
// Particles[i].points[3].Y -= 30;
// Particles[i].points[1].Y += 30;
// Particles[i].points[2].Y += 30;
}
return true;
}
//! pre render
void CGrassPatchSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
{
if (Particles.size() != 0)
{
core::vector3df campos = SceneManager->getActiveCamera()->getPosition();
if ( (Box.getCenter() + getPosition()).getDistanceFromSQ(campos) < DrawDistanceSQ*1.5 )
{
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
}
}
}
void CGrassPatchSceneNode::OnAnimate(u32 timeMs)
{
//only change the grass if so many ms have passed since the last time we did it
// at 0 = 140fps, at 30 = 320fps, at 3000 = 370fps. woot!
if (lastwindtime < timeMs - fpsLock)
{
lastwindtime = timeMs;
redrawnextloop = true;
// populate wind grid
f32 dist =(Box.getCenter() + getPosition()).getDistanceFromSQ(SceneManager->getActiveCamera()->getPosition()) + 1;
if ( WindGen && dist < DrawDistanceSQ*1.5)
for (u32 x=0; x<windGridRes+1; ++x)
for (u32 z=0; z<windGridRes+1; ++z)
WindGrid[x*windGridRes + z] = //core::vector2df(0,0);
WindGen->getWind(core::vector3df(
( (f32)(gridpos.X*GRASS_PATCH_SIZE) + (f32)x*((f32)GRASS_PATCH_SIZE/(f32)windGridRes) - (GRASS_PATCH_SIZE/2.0f) ),
0.0f,
( (f32)(gridpos.X*GRASS_PATCH_SIZE) + (f32)x*((f32)GRASS_PATCH_SIZE/(f32)windGridRes) - (GRASS_PATCH_SIZE/2.0f) )),
timeMs);
}
else
{
redrawnextloop = false;
}
ISceneNode::OnAnimate(timeMs);
}
//! render
void CGrassPatchSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
if (!redrawnextloop)
{
// just draw the old buffer
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->setMaterial(Material);
driver->drawIndexedTriangleList(Vertices.pointer(), lastdrawcount*4,
Indices.pointer(), lastdrawcount*4);
}
else
{
// reallocate arrays, if they are too small
reallocateBuffers();
core::vector3df campos = camera->getAbsolutePosition();
core::aabbox3d<f32> cbox = camera->getViewFrustum()->getBoundingBox();
core::vector3df pos = getPosition();
u32 drawcount=0;
u32 max = (Particles.size() < MaxDensity) ? Particles.size() : MaxDensity;
// in far boxes we dont loop so deep
// 175 to 255 fps
f32 d = getPosition().getDistanceFromSQ(campos) / (f32)(GRASS_PATCH_SIZE*GRASS_PATCH_SIZE);
if (d > 1.0)
{
//printf("max = %d, %d\n", max, (int)(max/d));
max = u32(f32(max)/d) ;
}
// i likes teh oldenpointer
f32 *v1p = &v1[0];
f32 *v2p = &v2[0];
f32 *v3p = &v3[0];
f32 *v4p = &v4[0];
// make the matrix outside the main loop
core::matrix4 m;
// create particle vertex data
for (u32 i=0; i< max; ++i)
{
s32 idx = drawcount*4;
SGrassParticle& particle = Particles[i];
core::vector3df gpos = particle.pos + pos;
// bounding box check: 150fps to 175fps
if ( !cbox.isPointInside(gpos) )
continue;
// distance checks: 145fps to 175fps
f32 dist = campos.getDistanceFromSQ(gpos);
if (dist > DrawDistanceSQ) // too far
{
continue;
}
else if (dist > DrawDistanceSQ * 0.5) // if we're fading in
{
f32 i1 = f32(i)/f32(max);
f32 i2 = (dist/DrawDistanceSQ)/2;
if (particle.sprite.Height) // first row is boring grass, the rest doesnt fade
{
//particle.color = video::SColor(255,255,255,255);
}
else
{
if ( i1 < i2)
{
continue;
}
else
{
// fade this particle
s32 c = s32(255.0f-f32(i2/i1)*255.0f);
}
}
}
else
{
// particle.color = video::SColor(255,255,255,255);
}
//
// wind
//
s32 igridsize = GRASS_PATCH_SIZE/(windGridRes-1);
s32 ihalfres = (windGridRes-1)/2;
// get wind modifier from wind grid
u32 xgrid = u32((particle.pos.X/(f32)igridsize) +(f32)ihalfres);
u32 zgrid = u32((particle.pos.Z/(f32)igridsize) +(f32)ihalfres);
// get fraction to next grid pos
f32 xnext = particle.pos.X/((f32)GRASS_PATCH_SIZE/(f32)windGridRes)+ (windGridRes/2.0f) - xgrid;
f32 znext = particle.pos.Z/((f32)GRASS_PATCH_SIZE/(f32)windGridRes)+ (windGridRes/2.0f) - zgrid;
// get wind positions
core::vector2df wind1 = WindGrid[ xgrid * windGridRes +zgrid];
core::vector2df wind2 = WindGrid[(xgrid+1)* windGridRes +zgrid];
core::vector2df wind3 = WindGrid[ xgrid *(windGridRes+1)+zgrid];
core::vector2df wind4 = WindGrid[(xgrid+1)*(windGridRes+1)+zgrid];
core::vector2df wind2d = wind1*(1.0f-xnext)*(1.0f-znext) +
wind2*xnext*(1.0f-znext) +
wind3*(1.0f-xnext)*znext +
wind4*xnext*znext;
// flexibility of this grass strand
wind2d *= particle.flex;
// convert to 3d vector
core::vector3df wind(wind2d.X,0.0f,wind2d.Y);
// blade colour change along Y axis
video::SColor gcol( particle.color.getAlpha(),
(s32) (particle.color.getRed() *0.8f),
(s32) (particle.color.getGreen()*0.8f),
(s32) (particle.color.getBlue() *0.8f) );
Vertices[0+idx].Pos = particle.points[0]; //particle.pos + core::vector3df(dimensions.X,dimensions.Y,dimensions.Z);
Vertices[0+idx].Color = gcol; // particle.color;
//Vertices[0+idx].Normal = ??
Vertices[1+idx].Pos = particle.points[1] + wind; //particle.pos + core::vector3df(dimensions.X,-dimensions.Y,dimensions.Z) + wind;
Vertices[1+idx].Color = particle.color;
//Vertices[1+idx].Normal = ??
Vertices[2+idx].Pos = particle.points[2] + wind; //particle.pos - core::vector3df(dimensions.X,dimensions.Y,dimensions.Z) + wind;
Vertices[2+idx].Color = particle.color;
//Vertices[2+idx].Normal = ??
Vertices[3+idx].Pos = particle.points[3]; //particle.pos - core::vector3df(dimensions.X,-dimensions.Y,dimensions.Z);
Vertices[3+idx].Color = gcol ; //particle.color;
//Vertices[3+idx].Normal = ??
//printf("%f, %f, %f, %f\n",v1p[particle.sprite.Width],v2p[particle.sprite.Height],v3p[particle.sprite.Height],v4p[particle.sprite.Width]);
s32 arrpos = (imagecount.Width*particle.sprite.Height)+particle.sprite.Width;
// set tcoords
Vertices[0+idx].TCoords.set(v1p[arrpos], v2p[arrpos] );
Vertices[1+idx].TCoords.set(v1p[arrpos], v3p[arrpos] );
Vertices[2+idx].TCoords.set(v4p[arrpos], v3p[arrpos] );
Vertices[3+idx].TCoords.set(v4p[arrpos], v2p[arrpos] );
drawcount++;
}
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->setMaterial(Material);
driver->drawIndexedTriangleList(Vertices.pointer(), drawcount*4,
Indices.pointer(), drawcount*4);
lastdrawcount = drawcount;
}
// for debug purposes only:
if (DebugDataVisible)
{
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(Box, video::SColor(0,255,255,255));
core::aabbox3d<f32> b2;
b2.reset(core::vector3df(0,0,0));
b2.addInternalPoint(Box.MaxEdge*0.01f);
driver->draw3DBox(b2, video::SColor(0,255,255,255));
}
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CGrassPatchSceneNode::getBoundingBox() const
{
return Box;
}
void CGrassPatchSceneNode::reallocateBuffers()
{
if (Particles.size() * 4 > Vertices.size() ||
Particles.size() * 6 > Indices.size())
{
s32 oldSize = Vertices.size();
Vertices.set_used(Particles.size() * 4);
u32 i;
// fill remaining vertices
for (i=oldSize; i<Vertices.size(); i+=4)
{
Vertices[0+i].Normal = core::vector3df(0,1,0);
Vertices[1+i].Normal = core::vector3df(0,1,0);
Vertices[2+i].Normal = core::vector3df(0,1,0);
Vertices[3+i].Normal = core::vector3df(0,1,0);
}
// fill remaining indices
s32 oldIdxSize = Indices.size();
s32 oldvertices = oldSize;
Indices.set_used(Particles.size() * 12);
for (i=oldIdxSize; i<Indices.size(); i+=12)
{
Indices[0+i] = 0+oldvertices;
Indices[1+i] = 2+oldvertices;
Indices[2+i] = 1+oldvertices;
Indices[3+i] = 0+oldvertices;
Indices[4+i] = 3+oldvertices;
Indices[5+i] = 2+oldvertices;
Indices[6+i] = 1+oldvertices;
Indices[7+i] = 2+oldvertices;
Indices[8+i] = 0+oldvertices;
Indices[9+i] = 2+oldvertices;
Indices[10+i] = 3+oldvertices;
Indices[11+i] = 0+oldvertices;
oldvertices += 4;
}
}
}
} // end namespace scene
} // end namespace irr