流体类游戏实现

16号,又囤了一批水饺,不是假牛肉馅了,好吃一点.....
这是2D流体类游戏‘鳄鱼洗澡‘中使用的Smoothed Particle Hydrodynamics平滑粒子算法,主要用来模拟水体。3D版太卡暂时只做了2D版。

类似的还有款沙盒游戏powertoy可能用的简化版sph粒子。还有一款类似小游戏火之创造者。

这只是一个模拟,并没有什么玩法,可以刷墙壁,可以拖放云彩、喷头发射水滴,可以拖放风力排斥水滴,拖放黑洞湮没水滴等。

有一些没实现的想法:

//todo渲染效果:对于单独的粒子可以加上拖尾的效果,水体渲染可以使用 marchingcube2D抽取表面, 或渲染到rendertarget上后使用alphatest抽取表面。水体可以添加折射效果。
//todo联机功能:流体粒子太多无法网络同步,但可以划分若干大格子,同步每个格子的水量即可。
//todo可以加入水管元素,闯关目标等。

2D版sph:

//========================================================
//  @Date:     2016.05
//  @File:     Include/Render/FluidSys.h
//  @Brief:     FluidSys
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================

#pragma once

#ifndef  __FluidSys2D__H__
#define  __FluidSys2D__H__

#include "Math/MathLib.h"
#include "Render/Texture.h"

#define MaxNeighbor		80
#define MaxParticle		1024*16

#define INF 1E-12f 
#define BOUNDARY 0.001f 

class Cell;

class FluidParticle2D 
{ 
public: 
	//int id; 
	vec2 pos; 
	vec2 vel; 
	vec2 acc; 
	vec2 ev; 

	float  density;	    //密度
	float  pressure;	//压力

	float  surfNorm;    //表面抽取

	//float  gravity;     //重力系数
	//float  r,g,b,a;
	//float  rendSize;

	bool   active;

	float  curFrame;

	FluidParticle2D *next; 
	FluidParticle2D *inactiveNext;
	Cell* cell; 
}; 

class FluidDef2D
{
public:
	//	double Viscosity;
	//	double Density;
	//	double INTSTIFF;
	//	double STIFF;      //刚性 碰触障碍时伸入越大反弹越大
	//	double DAMP;       //阻尼 碰触障碍时速度越大反弹越大
	//	double ParticleSpeedLimit;
	//	double MaxFrac;
	//
	//public:
	//	vec2 m_poolMin ;
	//	vec2 m_poolMax ;
	int	 m_particleMaxNum;	

	//float m_fluidDisplayScale;
	//float m_particleDisplayScale;
};
class FluidSim2D;
//粒子控制器
class FluidOP2D
{
public:
	FluidOP2D();
	virtual ~FluidOP2D(){};
	bool IntersectPos(vec2&pos);
	bool LoadTexture(const char* filename);
	void Rend();
	void RendBox();

	vec2        m_pos;
	vec2        m_extend; //onsize 时无需重新计算:池子坐标系
	float       m_headRad;//朝向
	TexturePtr  m_texture;
	int         m_texFrameNum;
	float       m_curFrame;
	FluidSim2D* m_ownerSim;
	bool        m_active;
};
//粒子发射器
class FluidEmitter2D:public FluidOP2D
{
public:
	FluidEmitter2D();
	void Rend();
	void EmitParticles(float time);

	float m_emitSpeed;
	float m_angRad; //椎角范围
	float m_emittDensity;
	float m_toEmittParticleNum;

	int   m_emitShape;

	FluidEmitter2D* m_next;
};

class FluidReactor2D:public FluidOP2D
{
public:
	FluidReactor2D();
	virtual~FluidReactor2D()=0;
	virtual void Rend();
	virtual void AffectParticle(FluidParticle2D* pariticle,float force=-1){};

	float   m_force;
	FluidReactor2D* m_next;
};

//吸引器 force<0 则为排斥
class FluidSucker2D:public FluidReactor2D
{
public:
	virtual void Rend();
	virtual void AffectParticle(FluidParticle2D* pariticle,float time);
};

//湮没黑洞
class FluidVanish2D:public FluidReactor2D
{
public:
	virtual void AffectParticle(FluidParticle2D* pariticle,float time);
};

//==================^_^==================^_^==================^_^==================^_^

//地图格子类型
enum CellType
{
	Empty,   //空
	Barrier, //栅栏阻碍
	Wood,    //火烧
	Wind,    //风  吸 排
};

//用于粒子分区加速
class Cell
{
public:
	CellType cellType;    //? todo xihua
	Cell*    neighbor[9]; //fast
	FluidParticle2D* head;
};

//! Smoothed Particle Hydrodynamics 2d
class FluidSim2D 
{ 
public: 
	FluidSim2D(); 
	~FluidSim2D(); 
	void SetFluidDef(FluidDef2D* def);
	virtual void Render();	
	virtual void Update();
	virtual void Free();
	void Reset();

	FluidParticle2D* AddActiveParticle(const vec2& pos, const vec2& vel); 
	void AddInActiveParticle(FluidParticle2D* particle);

	void SetEnable(bool enable);

	void AddEmitter(FluidEmitter2D* emitter);
	void RemoveEmitter(FluidEmitter2D* emitter);
	void RemoveAllEmitter();

	void AddReactor(FluidReactor2D* reactor);
	void RemoveReactor(FluidReactor2D* reactor);
	void RemoveAllReactor();
	
	void MoveVolumeParticle(const vec2& min, const vec2& max, const vec2& move);
	//!添加正方水体
	void AddVolumeParticles(const vec2& min, const vec2& max, float spacing );
	virtual void EmitParticles(float time);	
	virtual void ReactorParticles(float time);	

	vec2 Screen2Pos(const vec2& screenPos); 
	vec2 Pos2Screen(const vec2& pos); 
	void SetCellType(const vec2& pos,CellType cellType);

private: 
	void comp_dens_pres();  //计算密度、压力
	void comp_force_adv();  //力,对流
	void advection();       //对流

private:
	void CreateCells();		
	void ParticlesToCell(FluidParticle2D *particle); 
	void ParticlesToCell(); 
	void RendCells();
	void RendWalls();
	vec2I Pos2Cell(const vec2& pos); 
	int   CellIndex(const vec2I& cell_pos); 

	void MapVertexBuffer();
	void MapTexVertexBuffer();
	void MapColorVertexBuffer();
	void GenFace();
	int  ComputeCollision(const vec2& pos,const vec2& newPos,vec2& resPos,vec2& resNormal);

public: 
	FluidParticle2D *m_particles; 
	FluidParticle2D *m_inactiveParticleHead;
	int m_particleMaxNum; 
	int m_particleNum; //当前使用的容量,包含inactive particle, 新建active list 意义不大? 所有粒子都active时无法加速
	int m_vertexNum;

	vec2 m_poolExtend;

	//!2个轴向拆分的cell数
	vec2I  m_cellNum; 
	int    m_cellTotalIndex; 
	vec2   m_cellExtend; 
	vec2   m_cellExtendDelta;
	//!每个cell保存的是粒子链表头粒子
	Cell* m_cells;

	float Kernel; //SpaceDist?
	float Mass; 

	vec2  Gravity; 
	float Wall_Damping; 
	float Rest_Density; 
	float Gas_Constant; 
	float Viscosity; 
	float SurfFoam; 
	float SurfFoam2; 
	float Surf_coe; 

	float Poly6_value; 
	float spiky_value; 
	float visco_value; 

	float grad_poly6; 
	float lplc_poly6; 

	float Kernel_2; 
	float Self_dens; 
	float Self_lplc_color; 


	int     m_emitterNum;
	FluidEmitter2D* m_emitters;

	int     m_reactorNum;
	FluidReactor2D*  m_reactors;

	vec3*   m_vertexBuffers;
	vec2*   m_texBuffers;
	vec4*   m_colorBuffers;
	float   m_particleDisplaySize;
	bool    m_enable;

	vec2    m_worldDisplayScale;
	TexturePtr m_texWater;
	TexturePtr m_texWall;
	TexturePtr m_texBack;
	//!碰撞模型在pool中的部分才起作用,因为cell划分的原因,超出poo部分没有cell,计算出粒子密度为0。所以加了限定。
	FluidDef2D* m_def;

	//地图数据
	vec2I     m_gridNum;
	//Gride*    m_mapGrides;

	bool      m_drawPoint;
}; 

inline vec2I FluidSim2D::Pos2Cell(const vec2& p)
{
	vec2I cell(int(floor(p.x * m_cellExtendDelta.x)),
		int(floor(p.y * m_cellExtendDelta.y)));
	return cell;
}

inline int  FluidSim2D::CellIndex(const vec2I& cell)
{
	if(cell.x < 0 || cell.x >= m_cellNum.x || cell.y < 0 || cell.y >= m_cellNum.y)
	{
		return -1;
	}
	return ((int)(cell.y)) * m_cellNum.x + (int)(cell.x);
}

#endif


//========================================================
//  @Date:     2016.05
//  @File:     SourceLib/Render/FluidSys.cpp
//  @Brief:     FluidSys
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#define  GLUT_BUILDING_LIB
#include "General/General.h" 
#include "General/Smoother.h"
#include "General/Timer.h"
#include "Input/InputMgr.h"
#include "Math/MarchingCubes.h"
#include "Math/mathlib.h"
#include "Render/FluidSys2D.h"
#include "Render/RendDriver.h"
#include "Render/Shader.h"
#include "General/Pce.h" 
#include "General/Window.h"
#include <stdlib.h>
//#define DebugNotValidNum

FluidSim2D::FluidSim2D()
:m_particles(NULL)
,m_texBuffers(NULL)
,m_colorBuffers(NULL)
,m_vertexBuffers(NULL)
,m_cells(NULL)
,m_emitterNum(0)
,m_reactorNum(0)
,m_emitters(NULL)
,m_reactors(NULL)
,m_def(NULL)
,m_inactiveParticleHead(NULL)
{
	m_enable = false;//true;
	m_particleNum = 0; 
	m_particleMaxNum = 0; 
}

FluidSim2D::~FluidSim2D()
{
	Free();
}

void FluidSim2D::SetFluidDef(FluidDef2D *def)
{
	if(!m_enable)
	{
		return;
	}
	if(m_def)
	{
		return;
	}
	m_def = def;
	//Free();
	SafeDeleteArray(m_cells);

	//m_poolExtend.x = 1.28f;
	//m_poolExtend.y = 1.28f;
	m_poolExtend.x = 1.8f;
	m_poolExtend.y = 1.28f;

    m_particleMaxNum = 16000;
    m_particleNum = 0;

    Kernel = 0.04f;
    Mass = 0.02f;

    Gravity.x = 0.0f;
    Gravity.y = -1.8f;
    Wall_Damping = -0.5f;
    Rest_Density = 1000.0f;
    Gas_Constant = 1.0f;
    Viscosity = 6.5f;
    //
	SurfFoam = 10.0f; //动态调节表面 泡沫数量
	SurfFoam2 = 6.0f;

    Surf_coe = 0.2f;

    Poly6_value = 315.0f / (64.0f * _PI * pow(Kernel, 9));
    spiky_value = -45.0f / (_PI * pow(Kernel, 6));
    visco_value = 45.0f / (_PI * pow(Kernel, 6));

    grad_poly6 = -945 / (32 * _PI * pow(Kernel, 9));
    lplc_poly6 = -945 / (8 * _PI * pow(Kernel, 9));

    Kernel_2 = Kernel * Kernel;
    Self_dens = Mass * Poly6_value * pow(Kernel, 6);
    Self_lplc_color = lplc_poly6 * Mass * Kernel_2 * (0 - 3 / 4 * Kernel_2);

	//
	m_particleDisplaySize = Kernel*0.4f;

	m_worldDisplayScale.x = G_Window->m_iWidth/m_poolExtend.x;
	m_worldDisplayScale.y = G_Window->m_iHeight/m_poolExtend.y;

	m_inactiveParticleHead = NULL;
	//==================^_^
	if(m_particleMaxNum != def->m_particleMaxNum)
	{
		m_particleMaxNum = def->m_particleMaxNum;
		if( m_particles != NULL ) 
			delete [] ( m_particles );
		if( m_vertexBuffers != NULL ) 
			delete [] ( m_vertexBuffers );
		if( m_texBuffers != NULL ) 
			delete [] ( m_texBuffers );
		if (m_colorBuffers != NULL)
			delete [] (m_colorBuffers);

		m_particles = new FluidParticle2D[m_particleMaxNum];
		m_vertexBuffers = new vec3[m_particleMaxNum*9];
		m_texBuffers = new vec2[m_particleMaxNum*9];
		m_colorBuffers = new vec4[m_particleMaxNum*9];

		MapTexVertexBuffer();
	}

	CreateCells();
	ParticlesToCell();	

//	int voxelSize[3] = {m_cellNum.x*CubeCellScale,m_cellNum.y*CubeCellScale,m_cellNum.y*CubeCellScale};
//	m_marchingCubeSys2D->Init(voxelSize,m_poolExtend*m_fluidDisplayScale);

	G_TextureMgr->AddTexture(m_texWater,"data/minigame/fluid2d/fluid_w.png");
	G_TextureMgr->AddTexture(m_texWall,"data/minigame/fluid2d/wall.png");
	G_TextureMgr->AddTexture(m_texBack,"data/minigame/fluid2d/back.png");
	
    m_enable = true;

    //printf("Initialize SPH:\n");
    //printf("World Width : %f\n", world_size.x);
    //printf("World Height: %f\n", world_size.y);
    //printf("Cell Size  : %f\n", cell_size);
    //printf("Grid Width : %u\n", grid_size.x);
    //printf("Grid Height: %u\n", grid_size.y);
    //printf("Total Cell : %u\n", tot_cell);
    //printf("Poly6 Kernel: %f\n", poly6_value);
    //printf("Spiky Kernel: %f\n", spiky_value);
    //printf("Visco Kernel: %f\n", visco_value);
    //printf("Self Density: %f\n", self_dens);

	AddVolumeParticles(vec2(),m_poolExtend,Kernel * 0.45f);

	m_drawPoint = false;
}
void FluidSim2D::CreateCells ()
{
	m_cellExtend = vec2(Kernel,Kernel);
	m_cellNum.x = (int)ceil(m_poolExtend.x / m_cellExtend.x);
	m_cellNum.y = (int)ceil(m_poolExtend.y / m_cellExtend.y);
	//重新计算
	m_cellExtend.x = m_poolExtend.x/m_cellNum.x;
	m_cellExtend.y = m_poolExtend.y/m_cellNum.y;
	m_cellExtendDelta.x = m_cellNum.x/m_poolExtend.x;
	m_cellExtendDelta.y = m_cellNum.y/m_poolExtend.y;

	int cellTotalIndex = (int)(m_cellNum.x * m_cellNum.y);
	if (m_cells == NULL || m_cellTotalIndex < cellTotalIndex )
	{
		if( m_cells != NULL ) 
			delete [] ( m_cells );
		m_cellTotalIndex = cellTotalIndex;
		m_cells = new Cell[m_cellTotalIndex];
	}

	vec2I cell;
	vec2I nearCell;
	Cell* pCell = m_cells;
	for(int n=0; n < m_cellTotalIndex; n++,pCell++) 
	{
		pCell->cellType = Empty;
		pCell->head = NULL;

		cell = vec2I(n%m_cellNum.x,n/m_cellNum.x);
		int index = 0;
		for(int x = -1; x <= 1; x++)
		{
			for(int y = -1; y <= 1; y++)
			{
				nearCell.x = cell.x + x;
				nearCell.y = cell.y + y;
				int hash = CellIndex(nearCell);

				if(hash != -1)
				{
					pCell->neighbor[index] = &m_cells[hash];
				}
				else
				{
					pCell->neighbor[index] = NULL;
				}
				index++;
			}
		}
	}
}


void FluidSim2D::Render()
{
	if(!m_enable)
	{
		return;
	}
	PROFILEFUN("FluidSys::Render();",0.0001f,ALWAYSHIDE);

	//绘制背景
	G_RendDriver->Color4f(1.0f,1.0f,1.0f,1.0f);
	G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,true);
	m_texBack->Bind();
	G_RendDriver->DrawTextureRect(RectF(0,0,G_Window->m_iWidth,G_Window->m_iHeight),RectF(0,0,8,6));

	//
	G_RendDriver->PushMatrix();
	G_RendDriver->Scalef(G_Window->m_iWidth / m_poolExtend.x, G_Window->m_iHeight/ m_poolExtend.y, 1);

	if (G_RendDriver->GetDriverType()==D3DDRIVER)
	{
		G_ShaderMgr->SetCurEffectEnable( false );
	}

#ifdef _DEBUG
	RendCells();
#endif

	//绘制粒子
	if(m_drawPoint)
	{
		G_RendDriver->SetPointSize(5.0f);
		G_RendDriver->RendBegin(RS_POINTS);
		for(int i = 0; i < m_particleNum; i++)
		{
			if(m_particles[i].surfNorm > SurfFoam)
			{
				//边沿粒子
				G_RendDriver->Color3f(1.0f, 0.0f, 0.0f);
			}
			else
			{
				G_RendDriver->Color3f(0.2f, 0.2f, 1.0f);
			}
			G_RendDriver->Vertex3f(m_particles[i].pos.x, m_particles[i].pos.y,0);
		}
		G_RendDriver->RendEnd();
	}
	else
	{
		//避免对粒子深度排序
		//需要最后画否则会被覆盖
		G_RendDriver->DepthMask(false);
		//防止黑边
		G_RendDriver->ColorMask(true,true,true,false);
		G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,true);
		G_RendDriver->SetRenderStateEnable(RS_FOG,false);
		G_RendDriver->SetRenderStateEnable(RS_LIGHTING,false);
		//G_RendDriver->SetRenderStateEnable(RS_NORMALIZE,true);
		G_RendDriver->Color4f(1.0f,1.0f,1.0f,1.0f);

		G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,true);
		G_RendDriver->SetRenderStateEnable(RS_BLEND,true);
		G_RendDriver->BlendFunc(RS_SRC_ALPHA,RS_ONE_MINUS_SRC_ALPHA);
		//G_RendDriver->BlendFunc(RS_ONE,RS_ONE);
		G_RendDriver->SetRenderStateEnable(RS_ALPHA_TEST,true);
		G_RendDriver->AlphaFunc(RS_GREATER,0.0f);

		if(m_texWater)
			m_texWater->Bind();
		G_RendDriver->RendTrigon(m_vertexNum/3/*m_particleNum*2*/,m_vertexBuffers,m_texBuffers,m_colorBuffers);

		//MarchingCube抽取表面  在比较近距离内两个粒子之间拉出融合效果

		逐个emitter
		//for (int i=0;i<m_emitterNum;i++)
		//{
		//	FluidEmitter2D_* fromEmitter = m_emitters[i];
		//	G_RendDriver->PushRenderTarget(SpareRenderTarget01);
		//	{
		//		G_RendDriver->RendClear(RS_COLOR_BUFFER_BIT/*|RS_DEPTH_BUFFER_BIT|RS_STENCIL_BUFFER_BIT*/,Color(0.0f, 0.0f, 0.0f, 0.0f));
		//		fromEmitter->m_texWater->Bind();
		//		G_RendDriver->SetRenderStateEnable(RS_BLEND,true);
		//		//G_RendDriver->BlendFunc(RS_ONE, RS_ONE);
		//		G_RendDriver->BlendFunc(RS_SRC_ALPHA, RS_ONE_MINUS_SRC_ALPHA);
		//		G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,false);
		//		G_RendDriver->SetRenderStateEnable(RS_ALPHA_TEST,false);

		//		//逐个粒子
		//		for(int p = 0; p<m_particleNum; p++) 
		//		{
		//			if(m_particles[p].fromEmitter == fromEmitter)
		//				m_particles[p].Render();
		//		}
		//	}
		//	G_RendDriver->PopRenderTarget();

		//	G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f);
		//	//用alphatest替代mataball截取表面
		//	G_RendDriver->GetRenderTarget(SpareRenderTarget01)->BindTexture();
		//	if (G_RendDriver->GetDriverType()==D3DDRIVER)
		//	{
		//		G_RendDriver->BlendFunc(RS_ONE, RS_ONE);
		//	}
		//	else
		//	{
		//		G_RendDriver->BlendFunc(RS_SRC_ALPHA, RS_ZERO/*RS_ONE_MINUS_SRC_ALPHA*/);
		//	}
		//	//G_RendDriver->BlendFunc(RS_SRC_ALPHA, RS_ONE_MINUS_SRC_ALPHA);
		//	G_RendDriver->SetRenderStateEnable(RS_ALPHA_TEST,true);
		//	G_RendDriver->AlphaFunc(RS_GREATER, 0.85f);
		//	G_RendDriver->DrawTextureRect(RectF(0,G_Window->m_iHeight,G_Window->m_iWidth,-G_Window->m_iHeight));
		//}

		绘制表面抽取
		//if(0)
		//{
		//	G_RendDriver->SetRenderStateEnable(RS_FOG,false);
		//	G_RendDriver->SetRenderStateEnable(RS_LIGHTING,true);

		//	G_RendDriver->PushMatrix();

		//	G_RendDriver->Translatef(m_fluidDisplayPos.x,m_fluidDisplayPos.y,0);
		//	G_RendDriver->Translatef(m_marchingCubeSys2D->m_halfGroundExtend.x,m_marchingCubeSys2D->m_halfGroundExtend.y,0);

		//	G_RendDriver->Scalef(m_poolExtend.x*m_fluidDisplayScale/m_marchingCubeSys2D->m_halfGroundExtend.x/2,
		//				  		 m_poolExtend.y*m_fluidDisplayScale/m_marchingCubeSys2D->m_halfGroundExtend.y/2,
		//						 1);

		//	float index = G_Timer->GetAccumTime();
		//	int i = index*20;
		//	i%=4;
		//	if(m_texWaters[i])
		//		m_texWaters[i]->Bind();
		//	m_marchingCubeSys2D->Render();
		//	G_RendDriver->PopMatrix();
		//}

		G_RendDriver->DepthMask(true);
		G_RendDriver->ColorMask(true,true,true,true);
	}

	//绘制墙
	if (0)
	{
		RendWalls();
	}
	
	G_RendDriver->PopMatrix();


	//使用了drawtext 不要放在 pushmatrix内 
	//绘制发射器
	FluidEmitter2D* emitter = m_emitters;
	while(emitter)
	{
		emitter->Rend();
		emitter = emitter->m_next;
	}

	//绘制
	FluidReactor2D* reactor = m_reactors;
	while(reactor)
	{
		reactor->Rend();
		reactor = reactor->m_next;
	}

	if (G_RendDriver->GetDriverType()==D3DDRIVER)
	{
		G_ShaderMgr->SetCurEffectEnable( false );
	}

}

void FluidSim2D::Update()
{
	//	/*[ALARM]:   InsertCellParticles(); time cost : 0.611808 ms
	//		[ALARM]:   ComputePressure(); time cost : 6.770403 ms
	//		[ALARM]:   ComputeForceNeighbor(); time cost : 0.509627 ms*/
	if(!m_enable)
	{
		return;
	}

	float time = G_Timer->GetStepTimeLimited();
	if (time > 0.04f)
	{
		time = 0.04f;
	}
	//MoveVolumeParticle();
	EmitParticles(time); 
	
    ParticlesToCell();
    comp_dens_pres();
    comp_force_adv();
    advection();

	ReactorParticles(time); 

	GenFace();
	MapVertexBuffer();
	MapColorVertexBuffer();
	MapTexVertexBuffer();
}

void FluidSim2D::Free()
{
	SafeDeleteArray(m_particles);
	SafeDeleteArray(m_vertexBuffers);
	SafeDeleteArray(m_texBuffers);
	SafeDeleteArray(m_colorBuffers);
	SafeDeleteArray(m_cells);

	RemoveAllEmitter();
	RemoveAllReactor();
	//m_marchingCubeSys2D->Free();
}

FluidParticle2D* FluidSim2D::AddActiveParticle(const vec2& pos, const vec2& vel)
{
    FluidParticle2D *particle;
    //可以添加
    if( m_particleNum <= m_particleMaxNum - 2 )
    {
        particle = m_particles + m_particleNum;
        m_particleNum++;
    }
    else
    {
        //随机取一个粒子 
		//优先选择非活动粒子
		if (m_inactiveParticleHead)
		{
			particle = m_inactiveParticleHead;
			m_inactiveParticleHead = m_inactiveParticleHead->inactiveNext;
		}
		else
		{
			int ndx =  Rand()%m_particleNum;
			particle = m_particles + ndx;
		}
    }

    //particle->id=m_particleNum;

	particle->active = true;
    particle->pos = pos;
    particle->vel = vel;

    particle->acc.x = 0.0f;
    particle->acc.y = 0.0f;
    particle->ev.x = 0.0f;
    particle->ev.y = 0.0f;

    particle->density = Rest_Density;
    particle->pressure = 0.0f;

	//frame 添加参差
	static float frame = 0;
	particle->curFrame = frame;
	frame += 23.123456f;
	if(frame>100000) frame = 0;

	ParticlesToCell(particle);

	return particle;
}
void FluidSim2D::AddInActiveParticle(FluidParticle2D* particle)
{
	if (particle->active==false)
	{
		//todo ParticleOutCell
		return;
	}
	particle->inactiveNext = m_inactiveParticleHead;
	m_inactiveParticleHead = particle;
	particle->active = false;
}
void FluidSim2D::ParticlesToCell(FluidParticle2D *particle)
{
	int hash = CellIndex(Pos2Cell(particle->pos));
	if (hash!=-1)
	{
		if(m_cells[hash].head == NULL)
		{
			particle->next = NULL;
			m_cells[hash].head = particle;
		}
		else
		{
			particle->next = m_cells[hash].head;
			m_cells[hash].head = particle;
		}
		particle->cell = &m_cells[hash];
	}
	else
	{
		particle->next = NULL;
		particle->cell = NULL;
	}
}

void FluidSim2D::ParticlesToCell()
{
	PROFILEFUN("ParticlesToCell();",0.000f,ALWAYSHIDE);
	Cell* pCell = m_cells;
    for(int i = 0; i < m_cellTotalIndex; i++,pCell++)
    {
        pCell->head = NULL;
    }

	FluidParticle2D *particle = m_particles;
	int hash;

    for(int i = 0; i < m_particleNum; i++,particle++)
    {
		if (particle->active==false)
		{
			continue;
		}
        hash = CellIndex(Pos2Cell(particle->pos));
		if (hash!=-1)
		{
			pCell = &m_cells[hash];
			if(pCell->head == NULL)
			{
				particle->next = NULL;
				pCell->head = particle;
			}
			else
			{
				particle->next = pCell->head;
				pCell->head = particle;
			}
			particle->cell = pCell;
		}
		else
		{
			particle->next = NULL;
			particle->cell = NULL;
		}
    }
}

void FluidSim2D::comp_dens_pres()
{
	PROFILEFUN("comp_dens_pres();",0.000f,ALWAYSHIDE);
    FluidParticle2D *particle = m_particles;
    FluidParticle2D *nearParticle;

    vec2I cell;
    //vec2I nearCell;
	Cell** pNCell;
    //int hash;

    vec2 posDif;
    float r2;

    for(int i = 0; i < m_particleNum; i++,particle++)
    {
        particle->density = 0.0f;
        particle->pressure = 0.0f;

		if(particle->cell)
		{
			pNCell = particle->cell->neighbor;
			for(int c = 0; c <9; c++,pNCell++)
			{
				if(*pNCell)
				{
					nearParticle = (*pNCell)->head;
					while(nearParticle != NULL)
					{
						posDif.x = nearParticle->pos.x - particle->pos.x;
						posDif.y = nearParticle->pos.y - particle->pos.y;
						r2 = posDif.x * posDif.x + posDif.y * posDif.y;

						if(r2 < INF || r2 >= Kernel_2)
						{
							nearParticle = nearParticle->next;
							continue;
						}

						particle->density = particle->density + Mass * Poly6_value * pow(Kernel_2 - r2, 3);

						nearParticle = nearParticle->next;
					}
				}
			}
		}


        particle->density = particle->density + Self_dens;
        particle->pressure = (pow(particle->density / Rest_Density, 7) - 1) * Gas_Constant;
    }
}

void FluidSim2D::comp_force_adv()
{
	PROFILEFUN("comp_force_adv();",0.000f,ALWAYSHIDE);
    FluidParticle2D *particle = m_particles;
    FluidParticle2D *nearParticle;

    vec2I cell;
    //vec2I nearCell;
	Cell** pNCell;
    //int hash;

    vec2 posDif;
    vec2 velDif;

    float r2;
    float r;
    float kernel_r;
    float V;

    float pres_kernel;
    float visc_kernel;
    float temp_force;

    vec2 grad_color;
    float lplc_color;

    for(int i = 0; i < m_particleNum; i++,particle++)
    {
        particle->acc.x = 0.0f;
        particle->acc.y = 0.0f;

        grad_color.x = 0.0f;
        grad_color.y = 0.0f;
        lplc_color = 0.0f;

		//遍历9个格子 这种写法超出边界 还可能找到有效邻居cell
		//cell = Pos2Cell(particle->pos);
        /*for(int x = -1; x <= 1; x++)
        {
            for(int y = -1; y <= 1; y++)
            {
                nearCell.x = cell.x + x;
                nearCell.y = cell.y + y;
                hash = CellIndex(nearCell);

                if(hash == 0xffffffff)
                {
                    continue;
                }

                nearParticle = m_cells[hash].head;
                while(nearParticle != NULL)
                {
                    posDif.x = particle->pos.x - nearParticle->pos.x;
                    posDif.y = particle->pos.y - nearParticle->pos.y;
                    r2 = posDif.x * posDif.x + posDif.y * posDif.y;

                    if(r2 < Kernel_2 && r2 > INF)
                    {
                        r = sqrt(r2);
                        V = Mass / nearParticle->density / 2;
                        kernel_r = Kernel - r;

                        pres_kernel = spiky_value * kernel_r * kernel_r;
                        temp_force = V * (particle->pressure + nearParticle->pressure) * pres_kernel;
                        particle->acc.x = particle->acc.x - posDif.x * temp_force / r;
                        particle->acc.y = particle->acc.y - posDif.y * temp_force / r;

                        velDif.x = nearParticle->ev.x - particle->ev.x;
                        velDif.y = nearParticle->ev.y - particle->ev.y;

                        visc_kernel = visco_value * (Kernel - r);
                        temp_force = V * Viscosity * visc_kernel;
                        particle->acc.x = particle->acc.x + velDif.x * temp_force;
                        particle->acc.y = particle->acc.y + velDif.y * temp_force;

                        float temp = (-1) * grad_poly6 * V * pow(Kernel_2 - r2, 2);
                        grad_color.x += temp * posDif.x;
                        grad_color.y += temp * posDif.y;
                        lplc_color += lplc_poly6 * V * (Kernel_2 - r2) * (r2 - 3 / 4 * (Kernel_2 - r2));
                    }

                    nearParticle = nearParticle->next;
                }
            }
        }*/

		if(particle->cell)
		{
			pNCell = particle->cell->neighbor;
			for(int c = 0; c <9; c++,pNCell++)
			{
				if((*pNCell) == NULL)
				{
					continue;
				}

				nearParticle = (*pNCell)->head;
				while(nearParticle != NULL)
				{
					posDif.x = particle->pos.x - nearParticle->pos.x;
					posDif.y = particle->pos.y - nearParticle->pos.y;
					r2 = posDif.x * posDif.x + posDif.y * posDif.y;

					if(r2 < Kernel_2 && r2 > INF)
					{
						r = sqrt(r2);
						V = Mass / nearParticle->density / 2;
						kernel_r = Kernel - r;

						pres_kernel = spiky_value * kernel_r * kernel_r;
						temp_force = V * (particle->pressure + nearParticle->pressure) * pres_kernel;
						particle->acc.x = particle->acc.x - posDif.x * temp_force / r;
						particle->acc.y = particle->acc.y - posDif.y * temp_force / r;

						velDif.x = nearParticle->ev.x - particle->ev.x;
						velDif.y = nearParticle->ev.y - particle->ev.y;

						visc_kernel = visco_value * (Kernel - r);
						temp_force = V * Viscosity * visc_kernel;
						particle->acc.x = particle->acc.x + velDif.x * temp_force;
						particle->acc.y = particle->acc.y + velDif.y * temp_force;

						float temp = (-1) * grad_poly6 * V * pow(Kernel_2 - r2, 2);
						grad_color.x += temp * posDif.x;
						grad_color.y += temp * posDif.y;
						lplc_color += lplc_poly6 * V * (Kernel_2 - r2) * (r2 - 3 / 4 * (Kernel_2 - r2));
					}

					nearParticle = nearParticle->next;
				}
			}
		}

        lplc_color += Self_lplc_color / particle->density;
        particle->surfNorm = sqrt(grad_color.x * grad_color.x + grad_color.y * grad_color.y);

        if(particle->surfNorm > SurfFoam)
        {
            particle->acc.x += Surf_coe * lplc_color * grad_color.x / particle->surfNorm;
            particle->acc.y += Surf_coe * lplc_color * grad_color.y / particle->surfNorm;
        }
    }
}

void FluidSim2D::advection()
{
	PROFILEFUN("advection();",0.000f,ALWAYSHIDE);
    FluidParticle2D *particle = m_particles;
	vec2 newPos;
	vec2 resPos;
	vec2 normal;
    float time = 0.003f;
    for(int i = 0; i < m_particleNum; i++,particle++)
    {
		if (particle->active==false || particle->cell==NULL)
		{
			continue;
		}
        particle->vel.x +=  particle->acc.x * time / particle->density + Gravity.x * time;
        particle->vel.y +=  particle->acc.y * time / particle->density + Gravity.y * time;
						
        newPos.x = particle->pos.x + particle->vel.x * time;
        newPos.y = particle->pos.y + particle->vel.y * time;

		//res = ComputeCollision(particle->pos,newPos,resPos,normal);
		//if (res==1)
		//{
		//	newPos.x = resPos.x;
		//	newPos.y = resPos.y;
		//	particle->vel.x = particle->vel.x * Wall_Damping;
		//}
		//else if (res==2)
		//{
		//	newPos.x = resPos.x;
		//	newPos.y = resPos.y;
		//	particle->vel.y = particle->vel.y * Wall_Damping;
		//}

		switch(particle->cell->cellType)
		{
			//? tobo 避免穿墙而不是穿墙后蒸发
			//已经在墙里 且速度为0  比如刷墙时 把粒子刷到了墙里面
			case Wood:
			case Barrier:
				if(particle->vel.x<0.01f && particle->vel.x>-0.01f
					&&particle->vel.y<0.01f && particle->vel.y>-0.01f
					)
				{
					//标记非活动
					AddInActiveParticle(particle);
				}				
				break;
		}

		//判断pos在cell的哪个四分之一区域,并判断最近的邻cell,否则显示时可能穿墙=>墙体后绘制
		
		//res = ComputeCollision(particle->pos,newPos,resPos,normal);
		Cell* newCell = &m_cells[CellIndex(Pos2Cell(newPos))];
		switch(newCell->cellType)
		{
		case Wood:
		case Barrier:
			newPos.x = particle->pos.x;
			newPos.y = particle->pos.y;
			//todo 碰墙后法线计算
			particle->vel.x *= Wall_Damping;
			particle->vel.y *= Wall_Damping;
			break;
		case Wind:
			particle->vel.x *= 2;
			particle->vel.y *= 2;
			break;
		}

        if(newPos.x >= m_poolExtend.x)
        {
			if(particle->vel.x>0)
				particle->vel.x = particle->vel.x * Wall_Damping;
            newPos.x = m_poolExtend.x - BOUNDARY;
        }

        if(newPos.x < 0.0f)
        {
			if(particle->vel.x<0)
				particle->vel.x = particle->vel.x * Wall_Damping;
            newPos.x = 0.0f;
        }

        if(newPos.y >= m_poolExtend.y)
        {
			if(particle->vel.y>0)
				particle->vel.y = particle->vel.y * Wall_Damping;
            newPos.y = m_poolExtend.y - BOUNDARY;
        }

        if(newPos.y < 0.0f)
        {
			if(particle->vel.y<0)
				particle->vel.y = particle->vel.y * Wall_Damping;
            newPos.y = 0.0f;
        }

		particle->pos.x = newPos.x;
		particle->pos.y = newPos.y;
        particle->ev.x = (particle->ev.x + particle->vel.x) *0.5f;
        particle->ev.y = (particle->ev.y + particle->vel.y) *0.5f;
    }
}

//
//void FluidSim2D::FindCells( const vec2& p, float radius )
//{
//	vec2 smin;
//	smin.x = (int)((-radius + p.x - m_poolMin.x) * m_cellExtendDelta.x);
//	smin.y = (int)((-radius + p.y - m_poolMin.y) * m_cellExtendDelta.y);
//	//smin.x = (int)((p.x - m_poolMin.x) * m_cellExtendDelta.x);
//	//smin.y = (int)((p.y - m_poolMin.y) * m_cellExtendDelta.y);
//
//	if( smin.x < 0 ) 
//		smin.x = 0;
//	if( smin.y < 0 ) 
//		smin.y = 0;
//
//	int indexMe = (int)(smin.y*m_cellNum.x + smin.x);
//	m_neighborCells[0] = m_cells[indexMe];
//	m_neighborCells[1] = m_cells[indexMe + 1];//x轴
//
//	//if(m_neighborCells[0]==(Cell)0xabababab)
//	//{
//	//	Assert(0,"m_neighborCells[0]==(Cell)0xabababab");
//	//}
//
//	int indexY = (int)(indexMe + m_cellNum.x);
//	m_neighborCells[2] = m_cells[indexY];    //y轴
//	m_neighborCells[3] = m_cells[indexY + 1];
//
//
//	if( smin.x+1 >= m_cellNum.x ) 
//	{
//		m_neighborCells[1] = NULL;		
//		m_neighborCells[3] = NULL;		
//	}
//	if( smin.y+1 >= m_cellNum.y ) 
//	{
//		m_neighborCells[2] = NULL;		
//		m_neighborCells[3] = NULL;
//	}
//}



//
//static MarchingCubeSys2D* m_marchingCubeSys2D;
//
//FluidParticle2D* FluidSim2D::m_neighborParticles[MaxParticle][MaxNeighbor];	
//float FluidSim2D::m_neighborParticleDist[MaxParticle][MaxNeighbor];
//
//static float CubeCellScale = 4;//1;

void FluidSim2D::Reset()
{
	if(!m_enable)
	{
		return;
	}
	SetFluidDef(m_def);
}

void FluidSim2D::MoveVolumeParticle(const vec2& min, const vec2& max, const vec2& move)
{
	FluidParticle2D* particle = m_particles;
	for( int i=0; i<m_particleNum; i++,particle++ ) 
	{	
		if( (particle->pos.x >= min.x) && (particle->pos.y >= min.y) 
			&&(particle->pos.x <= max.x) && (particle->pos.y <= max.y)) 
		{
			particle->pos.x += move.x;
			particle->pos.y += move.y;

			ParticlesToCell(particle);
		}	
	}
}


void FluidSim2D::GenFace()
{
	if(!m_enable)
	{
		return;
	}
	
//	m_marchingCubeSys2D->ClearEnergys();

	//vec2  cellExtendDelta = m_cellExtendDelta*CubeCellScale;
	//FluidParticle2D * particle = m_particles;
	//int cellIndex,cx, cy;
	//for(int particleIndex = 0; particleIndex < m_particleNum; particleIndex++,particle++) 
	//{
	//	cx = (int)( (particle->pos.x - m_poolMin.x) * cellExtendDelta.x);		
	//	cy = (int)( (particle->pos.y - m_poolMin.y) * cellExtendDelta.y);
	//	//xyz主序
	//	//cellIndex = (int)( (cz*m_cellNum.y + cy)*m_cellNum.x + cx);		
	//	//if( cellIndex >= 0 && cellIndex < m_cellTotalIndex*8 ) 
	//	{
	//		//m_marchingCubeSys2D->SetEnergy(1,cx,cy) ;
	//	}
	//}

	//m_marchingCubeSys2D->Update();
}

int  FluidSim2D::ComputeCollision(const vec2& pos,const vec2& newPos,vec2& resPos,vec2& resNormal)
{

	{
		if(newPos.x >= m_poolExtend.x)
		{
			resNormal.x = -1;
			resNormal.y = 0;
			resPos.x = m_poolExtend.x - BOUNDARY;
			return 1;
		}

		if(newPos.x < 0.0f)
		{
			resNormal.x = 1;
			resNormal.y = 0;
			resPos.x = 0.0f;
			return 1;
		}

		if(newPos.y >= m_poolExtend.y)
		{
			resNormal.x = 0;
			resNormal.y = -1;
			resPos.y = m_poolExtend.y - BOUNDARY;
			return 2;
		}

		if(newPos.y < 0.0f)
		{
			resNormal.x = 0;
			resNormal.y = 1;
			resPos.y = 0.0f;
			return 2;
		}
	}

	return 0;
}


void FluidSim2D::AddVolumeParticles( const vec2& min, const vec2& max, float spacing )
{
	FluidParticle2D* p;	

	vec2 pos,vel;
	for(float y = min.y; y <= max.y; y += spacing ) 
	{	
		for(float x = min.x; x <= max.x; x += spacing ) 
		{
			pos.x = x;
			pos.y = y;
			vel.x = 0;
			vel.y = 0;
			p = AddActiveParticle(pos,vel);
		}
	}	
}

void FluidSim2D::EmitParticles(float time)
{	
	FluidEmitter2D* it = m_emitters;
	while(it)
	{
		it->EmitParticles(time);
		it = it->m_next;
	}
}
void FluidSim2D::ReactorParticles(float time)
{	
	FluidReactor2D* it = m_reactors;
	while(it)
	{
		if(it->m_active)
		{
			FluidParticle2D* particle = m_particles;
			//多加一个链表 不再全部遍历?
			for(int i = 0; i<m_particleNum; i++,particle++) 
			{
				if (particle->active==false)
				{
					continue;
				}
				it->AffectParticle(particle,time);
			}
		}
		it = it->m_next;
	}
}



void FluidSim2D::MapVertexBuffer()
{
	float size = m_particleDisplaySize;

	m_vertexNum = 0;
	register int index = 0;
	FluidParticle2D* particle = m_particles;
	vec3* vertex = m_vertexBuffers;
	for(int i=0;i<m_particleNum;i++,particle++ )
	{
		if (particle->active==false)
		{
			continue;
		}
		vertex->x =particle->pos.x-size;
		vertex->y =particle->pos.y-size;
		vertex->z = 0;
		vertex++;

		vertex->x =particle->pos.x+size;
		vertex->y =particle->pos.y-size;
		vertex->z = 0;
		vertex++;

		vertex->x =particle->pos.x+size;
		vertex->y =particle->pos.y+size;
		vertex->z = 0;
		vertex++;


		vertex->x =particle->pos.x-size;
		vertex->y =particle->pos.y-size;
		vertex->z = 0;
		vertex++;

		vertex->x =particle->pos.x+size;
		vertex->y =particle->pos.y+size;
		vertex->z = 0;
		vertex++;

		vertex->x =particle->pos.x-size;
		vertex->y =particle->pos.y+size;
		vertex->z = 0;
		vertex++;

		m_vertexNum += 6;
	}
}
void FluidSim2D::MapTexVertexBuffer()
{
	float TS[8]={1.0f,0.875f,0.75f,0.625f,0.5f,0.375f,0.25f,0.125f};
	float BS[8]={0.875f,0.75f,0.625f,0.5f,0.375f,0.25f,0.125f,0.0f};
	if (G_RendDriver->GetDriverType()==D3DDRIVER)
	{
		TS[0]=0;
		TS[1]=0.125f;
		TS[2]=0.25f;
		TS[3]=0.375f;
		TS[4]=0.5f;
		TS[5]=0.625f;
		TS[6]=0.75f;
		TS[7]=0.875f;


		BS[0]=0.125f;
		BS[1]=0.25f;
		BS[2]=0.375f;
		BS[3]=0.5f;
		BS[4]=0.625f;
		BS[5]=0.75f;
		BS[6]=0.875f;
		BS[7]=1.0f;
	}

	float T=1;
	float B=0;
	float L;
	float R;

	vec2* vertex = m_texBuffers;
	FluidParticle2D* particle = m_particles;
	int frame;
	for(int i=0;i<m_particleMaxNum;i++,particle++)
	{
		if (particle->active==false)
		{
			continue;
		}
		particle->curFrame += 0.1f;

		frame = ((int)particle->curFrame)%8;
		T = TS[frame];
		B = BS[frame];

		//if(particle->surfNorm > SurfFoam)
		if(particle->surfNorm > SurfFoam2)
		{
			L = 0.5f;
			R = 1.0f;
		}
		else
		{
			L = 0;
			R = 0.5f;
		}

		vertex->x = L;
		vertex->y = B;
		vertex++;
		vertex->x = R;
		vertex->y = B;
		vertex++;
		vertex->x = R;
		vertex->y = T;
		vertex++;

		vertex->x = L;
		vertex->y = B;
		vertex++;
		vertex->x = R;
		vertex->y = T;
		vertex++;
		vertex->x = L;
		vertex->y = T;
		vertex++;
	}
}
void FluidSim2D::MapColorVertexBuffer()
{
	register int index = 0;
	vec4* vertex = m_colorBuffers;
	FluidParticle2D* particle = m_particles;
#define EDGER 0.6f
#define EDGEG 0.6f
#define EDGEB 1
#define EDGEA 1
	for(int i=0;i<m_particleMaxNum;i++,particle++)
	{
		if (particle->active==false)
		{
			continue;
		}
		if(particle->surfNorm > SurfFoam)
		{
			vertex->x = EDGER;
			vertex->y = EDGEG;
			vertex->z = EDGEB;
			vertex->w = EDGEA;
			vertex++;
			vertex->x = EDGER;
			vertex->y = EDGEG;
			vertex->z = EDGEB;
			vertex->w = EDGEA;
			vertex++;
			vertex->x = EDGER;
			vertex->y = EDGEG;
			vertex->z = EDGEB;
			vertex->w = EDGEA;
			vertex++;

			vertex->x = EDGER;
			vertex->y = EDGEG;
			vertex->z = EDGEB;
			vertex->w = EDGEA;
			vertex++;
			vertex->x = EDGER;
			vertex->y = EDGEG;
			vertex->z = EDGEB;
			vertex->w = EDGEA;
			vertex++;
			vertex->x = EDGER;
			vertex->y = EDGEG;
			vertex->z = EDGEB;
			vertex->w = EDGEA;
			vertex++;
		}
		else
		{
			vertex->x = 0.2f;
			vertex->y = 0.2f;
			vertex->z = 1;
			vertex->w = 1;
			vertex++;
			vertex->x = 0.2f;
			vertex->y = 0.2f;
			vertex->z = 1;
			vertex->w = 1;
			vertex++;
			vertex->x = 0.2f;
			vertex->y = 0.2f;
			vertex->z = 1;
			vertex->w = 1;
			vertex++;

			vertex->x = 0.2f;
			vertex->y = 0.2f;
			vertex->z = 1;
			vertex->w = 1;
			vertex++;
			vertex->x = 0.2f;
			vertex->y = 0.2f;
			vertex->z = 1;
			vertex->w = 1;
			vertex++;
			vertex->x = 0.2f;
			vertex->y = 0.2f;
			vertex->z = 1;
			vertex->w = 1;
			vertex++;
		}
	}
}
void FluidSim2D::RendCells()
{
	PROFILEFUN("FluidSys::RendCells();",0.0005f,ALWAYSHIDE);

	G_RendDriver->SetRenderStateEnable(RS_FOG,false);
	G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,false);
	G_RendDriver->SetRenderStateEnable(RS_BLEND,true);
	G_RendDriver->RendBegin( RS_LINES );	

	G_RendDriver->Color4f( 1.0f, 0.7f, 0.7f ,0.1f);
	float x1, y1;
	for(int x = 0; x <= m_cellNum.x; x++ ) 
	{
		x1 = (x * m_cellExtend.x) + 0;		
		G_RendDriver->Vertex3f( x1, 0, 0);			
		G_RendDriver->Vertex3f( x1, m_poolExtend.y, 0);
	}
	for(int y = 0; y <= m_cellNum.y; y++ ) 
	{
		y1 = (y * m_cellExtend.y);
		G_RendDriver->Vertex3f( 0, y1,  0);			
		G_RendDriver->Vertex3f( m_poolExtend.x, y1,  0);
	}
	G_RendDriver->RendEnd();
}
void FluidSim2D::RendWalls()
{
	PROFILEFUN("FluidSys::RendWalls();",0.0005f,ALWAYSHIDE);

	G_RendDriver->SetRenderStateEnable(RS_BLEND,true);

	G_RendDriver->Color3f( 1.0f, 1.0f, 1.0f );
	G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,true);
	m_texWall->Bind();
	G_RendDriver->RendBegin(RS_QUADS);
	float x,y;
	const float l1 = 0;
	const float r1 = 0.125f;
	const float l2 = 0.125f;
	const float r2 = 0.25f;
	const float l3 = 0.25f;
	const float r3 = 0.375f;
	const float l4 = 0.5f;
	const float r4 = 0.625f;

	for(int i = 0; i<m_cellTotalIndex; i++) 
	{
		switch(m_cells[i].cellType)
		{
		case Barrier:
			x = (i%m_cellNum.x)*m_cellExtend.x;
			y = (i/m_cellNum.x)*m_cellExtend.y;

			G_RendDriver->TexCoord2f(l1,0.0f);
			G_RendDriver->Vertex3f(x,y,0);

			G_RendDriver->TexCoord2f(r1,0.0f);
			G_RendDriver->Vertex3f(x+m_cellExtend.x,y,0);

			G_RendDriver->TexCoord2f(r1,1.0f);
			G_RendDriver->Vertex3f(x+m_cellExtend.x,y+m_cellExtend.y,0);

			G_RendDriver->TexCoord2f(l1,1.0f);
			G_RendDriver->Vertex3f(x,y+m_cellExtend.y,0);
			break;
		case Wood:
			x = (i%m_cellNum.x)*m_cellExtend.x;
			y = (i/m_cellNum.x)*m_cellExtend.y;

			G_RendDriver->TexCoord2f(l2,0.0f);
			G_RendDriver->Vertex3f(x,y,0);

			G_RendDriver->TexCoord2f(r2,0.0f);
			G_RendDriver->Vertex3f(x+m_cellExtend.x,y,0);

			G_RendDriver->TexCoord2f(r2,1.0f);
			G_RendDriver->Vertex3f(x+m_cellExtend.x,y+m_cellExtend.y,0);

			G_RendDriver->TexCoord2f(l2,1.0f);
			G_RendDriver->Vertex3f(x,y+m_cellExtend.y,0);
			break;
		case Wind:
			x = (i%m_cellNum.x)*m_cellExtend.x;
			y = (i/m_cellNum.x)*m_cellExtend.y;

			G_RendDriver->TexCoord2f(l3,0.0f);
			G_RendDriver->Vertex3f(x,y,0);

			G_RendDriver->TexCoord2f(r3,0.0f);
			G_RendDriver->Vertex3f(x+m_cellExtend.x,y,0);

			G_RendDriver->TexCoord2f(r3,1.0f);
			G_RendDriver->Vertex3f(x+m_cellExtend.x,y+m_cellExtend.y,0);

			G_RendDriver->TexCoord2f(l3,1.0f);
			G_RendDriver->Vertex3f(x,y+m_cellExtend.y,0);
			break;
		}
	}
	G_RendDriver->RendEnd();
}


void FluidSim2D::SetEnable( bool enable )
{
	m_enable = enable;
}

void FluidSim2D::AddEmitter( FluidEmitter2D* emitter )
{
	emitter->m_next = m_emitters;
	m_emitters = emitter;
	emitter->m_ownerSim = this;

	if (emitter->m_pos.x > m_poolExtend.x-m_cellExtend.x)
		emitter->m_pos.x = m_poolExtend.x-m_cellExtend.x;
	if (emitter->m_pos.y > m_poolExtend.y-m_cellExtend.y)
		emitter->m_pos.y = m_poolExtend.y-m_cellExtend.y;

	if (emitter->m_pos.x < 0+m_cellExtend.x)
		emitter->m_pos.x = 0+m_cellExtend.x;
	if (emitter->m_pos.y < 0+m_cellExtend.y)
		emitter->m_pos.y = 0+m_cellExtend.y;

	m_emitterNum++;
}

void FluidSim2D::RemoveEmitter( FluidEmitter2D* emitter)
{
	FluidEmitter2D* prev = NULL;
	FluidEmitter2D* it = m_emitters;
	while(it)
	{
		if (it == emitter)
		{
			if (prev)
			{
				prev->m_next = it->m_next;
			}
			else
			{
				m_emitters = it->m_next;
			}
			delete it;
			m_emitterNum--;
			return;
		}
		prev = it;
		it = it->m_next;
	}
}

void FluidSim2D::RemoveAllEmitter()
{
	FluidEmitter2D* it = m_emitters;
	while(it)
	{
		FluidEmitter2D* old = it;
		it = it->m_next;
		delete old;
	}
	m_emitters = NULL;
	m_emitterNum = 0;
}


void FluidSim2D::AddReactor( FluidReactor2D* reactor )
{
	reactor->m_next = m_reactors;
	m_reactors = reactor;
	reactor->m_ownerSim = this;

	if (reactor->m_pos.x > m_poolExtend.x-m_cellExtend.x)
		reactor->m_pos.x = m_poolExtend.x-m_cellExtend.x;
	if (reactor->m_pos.y > m_poolExtend.y-m_cellExtend.y)
		reactor->m_pos.y = m_poolExtend.y-m_cellExtend.y;

	if (reactor->m_pos.x < 0+m_cellExtend.x)
		reactor->m_pos.x = 0+m_cellExtend.x;
	if (reactor->m_pos.y < 0+m_cellExtend.y)
		reactor->m_pos.y = 0+m_cellExtend.y;

	m_reactorNum++;
}

void FluidSim2D::RemoveReactor( FluidReactor2D* reactor )
{
	FluidReactor2D* prev = NULL;
	FluidReactor2D* it = m_reactors;
	while(it)
	{
		if (it == reactor)
		{
			if (prev)
			{
				prev->m_next = it->m_next;
			}
			else
			{
				m_reactors = it->m_next;
			}
			delete it;
			m_reactorNum--;
			return;
		}
		prev = it;
		it = it->m_next;
	}
}

void FluidSim2D::RemoveAllReactor()
{
	FluidReactor2D* it = m_reactors;
	while(it)
	{
		FluidReactor2D* old = it;
		it = it->m_next;
		delete old;
	}
	m_reactors = NULL;
	m_reactorNum = 0;
}

void FluidSim2D::SetCellType(const vec2& pos,CellType cellType)
{
	int cell = CellIndex(Pos2Cell(pos));
	if (cell>=0)
	{
		m_cells[cell].cellType = cellType;
	}
}


vec2 FluidSim2D::Screen2Pos(const vec2& mousePos)
{
	return vec2(mousePos.x/m_worldDisplayScale.x,
		(G_Window->m_iHeight-mousePos.y)/m_worldDisplayScale.y);
}

vec2 FluidSim2D::Pos2Screen(const vec2& pos)
{
	return vec2(pos.x*m_worldDisplayScale.x,
		(G_Window->m_iHeight-pos.y*m_worldDisplayScale.y));
}

FluidOP2D::FluidOP2D()
:m_active(true)
,m_texture(NULL)
,m_curFrame(0)
,m_headRad(0)
{
}
void FluidOP2D::Rend()
{
	if (m_texture)
	{
		m_texture->Bind();
		vec2 pos = m_ownerSim->Pos2Screen(m_pos);

		if (m_active)
		{
			m_curFrame+=0.2f;
			//m_curFrame%=m_texFrameNum;
		}

		int frame = m_curFrame;
		frame%=m_texFrameNum;

		float w = m_extend.x*m_ownerSim->m_worldDisplayScale.x;
		float h = m_extend.y*m_ownerSim->m_worldDisplayScale.y;

		//窗口onsize时,池子大小没变,水滴变大小,触发器也要变大小
		G_RendDriver->DrawTextureRect(RectF(pos.x-w/2,pos.y-h/2,w,h),
			RectF(1.0f/m_texFrameNum*frame,0,1.0f/m_texFrameNum,1),
			vec2(w/2,h/2),
			m_headRad,ET_SCALE);
	}
}
void FluidOP2D::RendBox()
{
	G_RendDriver->DisableRendState(RS_TEXTURE_2D);

	mat3 mat;
	mat.FromRotateZ(m_headRad);
	vec2 pos = m_ownerSim->Pos2Screen(m_pos);

	float w = m_extend.x*m_ownerSim->m_worldDisplayScale.x;
	float h = m_extend.y*m_ownerSim->m_worldDisplayScale.y;

	G_RendDriver->Color4f(0,0,1.0f,0.5f);
	//窗口onsize时,池子大小没变,水滴变大小,触发器也要变大小
	G_RendDriver->DrawRect(RectF(pos.x-w/2,pos.y-h/2,w,h),
		vec2(w/2,h/2),
		mat);
	G_RendDriver->EnableRendState(RS_TEXTURE_2D);
	G_RendDriver->Color4f(1,1,1,1);
}

bool FluidOP2D::IntersectPos(vec2&pos)
{
	vec2 dif = m_pos-pos;
	if (fabs(dif.x)<m_extend.x/2 && fabs(dif.y)<m_extend.y/2 )
	{
		return true;
	}
	return false;
}

bool FluidOP2D::LoadTexture(const char* filename)
{
	//onsize 时无需重新计算
	G_TextureMgr->AddTexture(m_texture,filename);
	m_extend.x = m_texture->GetWidth()/m_ownerSim->m_worldDisplayScale.x/m_texFrameNum;
	m_extend.y = m_texture->GetHeight()/m_ownerSim->m_worldDisplayScale.y;
	return true;
}

FluidEmitter2D::FluidEmitter2D()
:m_toEmittParticleNum(0)
,m_emittDensity(0)
,m_next(NULL)
{
}

void FluidEmitter2D::EmitParticles(float time)
{
	if (m_active==false)
	{
		return;
	}
	m_toEmittParticleNum += m_emittDensity * m_ownerSim->m_particleMaxNum * time;
	//if (m_dumyMovie)
	//{
	//	m_emitPos = (m_dumyMovie)->GetCollideSys().m_center;
	//}
	
	mat4 mat;
	mat.FromRotateZ(m_headRad);
	vec3 dir3(0,-1,0);
	dir3 = mat*dir3;
	//dir.Normalize();
	vec2 dir(dir3.x,dir3.y);
	vec2 speed2(dir.x*m_emitSpeed,dir.y*m_emitSpeed);
	
	vec2 xdir(-dir.y,dir.x);

	FluidParticle2D* p;
	vec2 pos;
	int size = sqrt(m_toEmittParticleNum);
	while(m_toEmittParticleNum>=1)
	{
		pos = m_pos;
		switch(m_emitShape)
		{
		case 0:
			//水管 点状
			pos += dir*(m_extend.y/2);
			break;
		case 1:
			//云彩 线状
			pos += dir*(m_extend.y/2);
			pos += xdir*(RandRange(-m_extend.x/2,m_extend.x/2));
			break;
		case 2:
			//水库 块状
			pos += dir*(RandRange(-m_extend.y/2,m_extend.y/2));
			pos += xdir*(RandRange(-m_extend.x/2,m_extend.x/2));
			正方形排列,不能太挤 ? 非中心
			//pos.x += m_ownerSim->Kernel * (((int)m_toEmittParticleNum)/size);
			//pos.y += m_ownerSim->Kernel * (((int)m_toEmittParticleNum)%size);
			break;
		}
		p = m_ownerSim->AddActiveParticle(pos,speed2);
		m_toEmittParticleNum -= 1;
	}
}

void FluidEmitter2D::Rend()
{
	FluidOP2D::Rend();
}


FluidReactor2D::FluidReactor2D()
:m_force(-1)
{

}
FluidReactor2D::~FluidReactor2D()
{

}
void FluidReactor2D::Rend()
{
	FluidOP2D::Rend();
}

void FluidSucker2D::AffectParticle( FluidParticle2D* pariticle,float time)
{
	if (m_active==false)
	{
		return;
	}
	if (m_force>_EPSILON || m_force<-_EPSILON)
	{
		//float force = m_force*m_ownerSim->m_poolExtend.x/G_Window->m_iWidth;
		const float dx = pariticle->pos.x - m_pos.x;
		const float dy = pariticle->pos.y - m_pos.y;
		float dist = (dx * dx + dy * dy);
		if(dist > 0.000001f) 
		{
			dist = m_force/dist*time;
			pariticle->vel.x-= dx*dist;
			pariticle->vel.y-= dy*dist;
		}
	}
}

void FluidSucker2D::Rend()
{
	FluidOP2D::Rend();
}
void FluidVanish2D::AffectParticle( FluidParticle2D* pariticle,float time)
{
	if (m_active==false)
	{
		return;
	}
	if (m_force>_EPSILON || m_force<-_EPSILON)
	{
		const float dx = pariticle->pos.x - m_pos.x;
		const float dy = pariticle->pos.y - m_pos.y;
		float dist = (dx * dx + dy * dy);
		if (dist<0.001f/*m_ownerSim->Kernel*/)
		{
			m_ownerSim->AddInActiveParticle(pariticle);
		}
		else if(dist > 0.000001f) 
		{
			dist = m_force/dist*time;
			pariticle->vel.x-= dx*dist;
			pariticle->vel.y-= dy*dist;
		}
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值