示例#1
0
void MBitmapR2::DrawEx(float tx1, float ty1, float tx2, float ty2, 
			float tx3, float ty3, float tx4, float ty4, DWORD dwColor, MDrawEffect effect)
{
	if (!m_pTexture) return;

	// 임시로 메모리에서 내린 상태라면 복구해준다
	if(m_bUnloadedTemporarily) {
		m_pTexture->OnRestore();
		m_bUnloadedTemporarily = false;
	}

	float ftw = (float)m_pTexture->GetWidth();
	float fth = (float)m_pTexture->GetHeight();

	float fuv[8] = {
		0.f,0.f,
		1.f,0.f,
		1.f,1.f,
		0.f,1.f
	};

	CheckDrawMode(fuv);

	CUSTOMVERTEX Sprite[4] = {
#define ADJUST_SIZE		0.5f
#define ADJUST_SIZE2	0.0f
		{tx1-ADJUST_SIZE,  ty1-ADJUST_SIZE,  0, 1.0f, dwColor, fuv[0], fuv[1]},
		{tx2-ADJUST_SIZE2, ty2-ADJUST_SIZE,  0, 1.0f, dwColor, fuv[2], fuv[3]},
		{tx4-ADJUST_SIZE2, ty4-ADJUST_SIZE2, 0, 1.0f, dwColor, fuv[4], fuv[5]},
		{tx3-ADJUST_SIZE,  ty3-ADJUST_SIZE2, 0, 1.0f, dwColor, fuv[6], fuv[7]},
	};
	m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
	m_pd3dDevice->SetPixelShader(NULL);

	m_pd3dDevice->SetTexture(0, m_pTexture->GetTexture());

	BeginState(effect);

	HRESULT hr = m_pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, Sprite, sizeof(CUSTOMVERTEX));
	_ASSERT(hr==D3D_OK);

	EndState();
}
示例#2
0
void MBitmapR2::Draw(float x, float y, float w, float h, float sx, float sy, float sw, float sh, 
					 DWORD dwColor, MDrawEffect effect)
{
	/*
	float ftw = (float)Floorer2PowerSize(m_Info.Width);
	float fth = (float)Floorer2PowerSize(m_Info.Height);
	*/
	float ftw = (float)m_pTexture->GetWidth();
	float fth = (float)m_pTexture->GetHeight();

	float fuv[8] = {
		(sx)/ftw	,(sy)/fth,
		(sx+sw)/ftw	,(sy)/fth,
		(sx+sw)/ftw	,(sy+sh)/fth,
		(sx)/ftw	,(sy+sh)/fth
	};

	CheckDrawMode(fuv);

	CUSTOMVERTEX Sprite[4] = {
#define ADJUST_SIZE		0.5f
#define ADJUST_SIZE2	0.0f
		{x-ADJUST_SIZE,    y-ADJUST_SIZE,    0, 1.0f, dwColor, fuv[0], fuv[1]},
		{x+w-ADJUST_SIZE2, y-ADJUST_SIZE,    0, 1.0f, dwColor, fuv[2], fuv[3]},
		{x+w-ADJUST_SIZE2, y+h-ADJUST_SIZE2, 0, 1.0f, dwColor, fuv[4], fuv[5]},
		{x-ADJUST_SIZE,    y+h-ADJUST_SIZE2, 0, 1.0f, dwColor, fuv[6], fuv[7]},
	};
	m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
	m_pd3dDevice->SetPixelShader(NULL);

	m_pd3dDevice->SetTexture(0, m_pTexture->GetTexture());

	BeginState(effect);

	m_pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, Sprite, sizeof(CUSTOMVERTEX));

	EndState();
}
SKILL_STATE cActiveSkillObject::Update()
{
	if( !GetOperator() )
	{
		mState = SKILL_STATE_DESTROY;
	}

	if( mState == SKILL_STATE_DESTROY )
	{
		return cSkillObject::Update();
	}

	switch( mState )
	{
	/// 시전중
	case SKILL_STATE_CASTING:
		{
			CastingState();
		}
		break;
	/// 발동중
	case SKILL_STATE_PROCESS:
		{
			ProcessState();
		}
		break;
	case SKILL_STATE_END:
		{
			EndState();
		}
		break;
	case SKILL_STATE_DESTROY:
		break;
	}

	return cSkillObject::Update();
}
bool ZEffectShadowList::Draw()
{
	if(!m_pVB) return false;

	if( empty() ) return true;

	BeginState();

	HRESULT		hr;

	DWORD	dwRemainNum = (DWORD)size();

	iterator itr=begin();

	while(dwRemainNum)
	{
		if(m_dwBase >= EFFECTBASE_DISCARD_COUNT)
			m_dwBase = 0;

		DWORD dwThisNum = min( dwRemainNum , BILLBOARD_FLUSH_COUNT );

		dwThisNum = min( dwThisNum , EFFECTBASE_DISCARD_COUNT - m_dwBase );	

		BYTE* pVertices;

		if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(ZEFFECTCUSTOMVERTEX) * 4, dwThisNum * sizeof(ZEFFECTCUSTOMVERTEX) * 4,
			(VOID**)&pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		BYTE *pInd;

		if( FAILED( hr = m_pIB->Lock( m_dwBase * sizeof(WORD) * 6, dwThisNum * sizeof(WORD) * 6,
			(VOID**)&pInd, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		for(DWORD j=0;j<dwThisNum;j++)
		{
			ZEFFECTSHADOWITEM *p = (ZEFFECTSHADOWITEM*)*itr;

			static ZEFFECTCUSTOMVERTEX v[] = {
				{-0.5f, -0.5f, 0.f, 0xFFFFFFFF, 0.f, 0.f},
				{ 0.5f, -0.5f, 0.f, 0xFFFFFFFF, 1.f, 0.f},
				{-0.5f,  0.5f, 0.f, 0xFFFFFFFF, 0.f, 1.f},
				{ 0.5f,  0.5f, 0.f, 0xFFFFFFFF, 1.f, 1.f},
			};

			static rvector sv[4] = { 
				rvector(-0.5f,-0.5f , 0.f) , 
				rvector( 0.5f,-0.5f , 0.f) , 
				rvector(-0.5f, 0.5f , 0.f) , 
				rvector( 0.5f, 0.5f , 0.f) ,
			};

			// 좋은코드는 아니지만 버텍스 카피를 줄이기위해 타입캐스팅했다.

			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[0].x,sv  ,&p->worldmat);
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[1].x,sv+1,&p->worldmat);
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[2].x,sv+2,&p->worldmat);
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[3].x,sv+3,&p->worldmat);

			v[0].color=v[1].color=v[2].color=v[3].color=p->dwColor;

			memcpy(pVertices,v,sizeof(ZEFFECTCUSTOMVERTEX)*4);

			pVertices+=sizeof(ZEFFECTCUSTOMVERTEX)*4;

			WORD inds[] = { 0,1,2,2,1,3 };

			for(int k=0;k<6;k++)
			{
				inds[k]+=(m_dwBase+j)*4;
			}

			memcpy(pInd,inds,sizeof(inds));

			pInd+=sizeof(inds);

			itr++;
		}

		m_pVB->Unlock();
		m_pIB->Unlock();

		if(FAILED( hr = RGetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,m_dwBase*4,dwThisNum*4,m_dwBase*6,dwThisNum*2) ))
//		if(FAILED( hr = RGetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,0,m_dwBase*4,dwThisNum*4,m_dwBase*6,dwThisNum*2) ))
			return false;

		m_dwBase+=dwThisNum;
		dwRemainNum-=dwThisNum;

	}

	RGetDevice()->SetStreamSource( 0, NULL , 0,0 );	
	RGetDevice()->SetIndices(NULL);

	EndState();

	Clear();

	return true;	
}
bool ZEffectBillboardTexAniList::Draw()
{
	if(!m_pVB) return false;

	if( size()==0 ) return true;

	BeginState();

	RSetFog(FALSE);

	HRESULT	hr;

	DWORD	dwRemainNum = (DWORD)size();

	iterator itr = begin();

	while(dwRemainNum)
	{
		if(m_dwBase >= EFFECTBASE_DISCARD_COUNT)
			m_dwBase = 0;

		DWORD dwThisNum = min( dwRemainNum , BILLBOARD_FLUSH_COUNT );

		dwThisNum = min( dwThisNum , EFFECTBASE_DISCARD_COUNT - m_dwBase );	

		BYTE *pVertices;

		if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(ZEFFECTCUSTOMVERTEX) * 4, dwThisNum * sizeof(ZEFFECTCUSTOMVERTEX) * 4,
			(VOID**)&pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		BYTE *pInd;
		if( FAILED( hr = m_pIB->Lock( m_dwBase * sizeof(WORD) * 6, dwThisNum * sizeof(WORD) * 6,
			(VOID**)&pInd, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		int nRenderCnt = 0;

		ZCharacter* pChar = NULL;

		for(DWORD j=0;j<dwThisNum;j++)
		{
			ZEFFECTBILLBOARDTEXANIITEM *p = (ZEFFECTBILLBOARDTEXANIITEM*)*itr;

			if(p->fElapsedTime < p->fAddTime ) {
				itr++;
				continue;
			}

			pChar = ZGetCharacterManager()->Find(p->CharUID);

			if( pChar ) {
				if( pChar->m_pVMesh ) {
					if( pChar->m_pVMesh->m_bIsRender==false) {//부모가 안그려졌으면 skip...
						itr++;
						continue;
					}
				}
			}

			nRenderCnt++;

			// Transform
			rmatrix matTranslation;
			rmatrix matScaling;
			rmatrix matWorld;

			rvector dir = p->normal;

			rvector up=p->up;
			rvector right;

			if(IS_EQ(dir.z,1.f)) up=rvector(1,0,0);

			D3DXVec3Cross(&right, &up, &dir);
			D3DXVec3Normalize(&right, &right);

			D3DXVec3Cross(&up, &right, &dir);
			D3DXVec3Normalize(&up, &up);

			rmatrix mat;
			D3DXMatrixIdentity(&mat);
			mat._11=right.x;mat._12=right.y;mat._13=right.z;
			mat._21=up.x;mat._22=up.y;mat._23=up.z;
			mat._31=dir.x;mat._32=dir.y;mat._33=dir.z;

			rvector pos=p->position;

//			float fScale=p->fStartSize * p->fOpacity + p->fEndSize * (1.f - p->fOpacity);

			float fInt = min(1,max(0,(p->fLifeTime - p->fElapsedTime)/p->fLifeTime));
			float fScale=p->fStartSize * fInt + p->fEndSize * (1.f - fInt);

			D3DXMatrixScaling(&matScaling,fScale*m_Scale.x,fScale*m_Scale.y,fScale*m_Scale.z);
			D3DXMatrixTranslation(&matTranslation, pos.x, pos.y, pos.z);

			D3DXMatrixMultiply(&matWorld, &matScaling, &mat);
			D3DXMatrixMultiply(&matWorld, &matWorld, &matTranslation);

			DWORD color = ((DWORD)(p->fOpacity * 255))<<24 | p->dwColor;

			static ZEFFECTCUSTOMVERTEX v[] = {
				{-1, -1, 0, 0xFFFFFFFF, 1, 0},
				{-1,  1, 0, 0xFFFFFFFF, 1, 1},
				{ 1,  1, 0, 0xFFFFFFFF, 0, 1},
				{ 1, -1, 0, 0xFFFFFFFF, 0, 0},
			};

			static rvector sv[4] = { rvector(-1,-1,0) , rvector(-1,1,0) , rvector(1,1,0) , rvector(1,-1,0) };

			GetFrameUV( min( p->frame,m_nMaxFrame-1) );

			v[0].tu = m_fUV[0];
			v[0].tv = m_fUV[1];
			v[1].tu = m_fUV[2];
			v[1].tv = m_fUV[3];
			v[2].tu = m_fUV[4];
			v[2].tv = m_fUV[5];
			v[3].tu = m_fUV[6];
			v[3].tv = m_fUV[7];

			// 좋은코드는 아니지만 버텍스 카피를 줄이기위해 타입캐스팅했다.
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[0].x,sv+0,&matWorld);
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[1].x,sv+1,&matWorld);
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[2].x,sv+2,&matWorld);
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[3].x,sv+3,&matWorld);
			v[0].color=v[1].color=v[2].color=v[3].color=color;

			memcpy(pVertices,v,sizeof(ZEFFECTCUSTOMVERTEX)*4);
			pVertices+=sizeof(ZEFFECTCUSTOMVERTEX)*4;

			WORD inds[] = { 0,1,2,0,2,3 };
			for(int k=0;k<6;k++)
			{
				inds[k]+=(m_dwBase+j)*4;
			}
			memcpy(pInd,inds,sizeof(inds));
			pInd+=sizeof(inds);

			itr++;
		}

		m_pVB->Unlock();
		m_pIB->Unlock();

		if(FAILED( hr = RGetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,m_dwBase*4,nRenderCnt*4,m_dwBase*6,nRenderCnt*2) ))
			return false;

		m_dwBase+=dwThisNum;
		dwRemainNum-=dwThisNum;

	}

	RGetDevice()->SetStreamSource( 0, NULL , 0,0 );	
	RGetDevice()->SetIndices(NULL);

	if(ZGetWorld()) {
		ZGetWorld()->SetFog(true);// 게임 설정에 따라서
	}

	EndState();

	return true;
}
bool ZEffectBillboardList::Draw()
{
	if(!m_pVB) return false;

	if( size()==0 ) return true;

	BeginState();

	HRESULT		hr;

	DWORD		dwRemainNum = (DWORD)size();

	iterator itr=begin();

	while(dwRemainNum)
	{
		if(m_dwBase >= EFFECTBASE_DISCARD_COUNT)
			m_dwBase = 0;

		// 갯수가 BILLBOARD_FLUSH_COUNT 를 넘어가면 BILLBOARD_FLUSH_COUNT 씩 찍는다
		DWORD dwThisNum = min( dwRemainNum , BILLBOARD_FLUSH_COUNT );

		// 버퍼의 크기를 넘어가면 개수를 줄여서 크기만큼만 찍는다
		dwThisNum = min( dwThisNum , EFFECTBASE_DISCARD_COUNT - m_dwBase );	


		BYTE		*pVertices;
		if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(ZEFFECTCUSTOMVERTEX) * 4, dwThisNum * sizeof(ZEFFECTCUSTOMVERTEX) * 4,
			(VOID**)&pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		BYTE *pInd;
		if( FAILED( hr = m_pIB->Lock( m_dwBase * sizeof(WORD) * 6, dwThisNum * sizeof(WORD) * 6,
			(VOID**)&pInd, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		for(DWORD j=0;j<dwThisNum;j++)
		{
			ZEFFECTBILLBOARDITEM *p = (ZEFFECTBILLBOARDITEM*)*itr;

			// Transform
			rmatrix matTranslation;
			rmatrix matScaling;
			rmatrix matWorld;

			rvector dir = p->normal;

			rvector up=p->up;
			rvector right;

			if(IS_EQ(dir.z,1.f)) up=rvector(1,0,0);

			D3DXVec3Cross(&right, &up, &dir);
			D3DXVec3Normalize(&right, &right);

			D3DXVec3Cross(&up, &right, &dir);
			D3DXVec3Normalize(&up, &up);

			rmatrix mat;
			D3DXMatrixIdentity(&mat);
			mat._11=right.x;mat._12=right.y;mat._13=right.z;
			mat._21=up.x;mat._22=up.y;mat._23=up.z;
			mat._31=dir.x;mat._32=dir.y;mat._33=dir.z;

			rvector pos=p->position;

//			float fScale=p->fStartSize * p->fOpacity + p->fEndSize * (1.f - p->fOpacity);

			float fInt = min(1,max(0,(p->fLifeTime - p->fElapsedTime)/p->fLifeTime));

			float fScale=p->fStartSize * fInt + p->fEndSize * (1.f - fInt);

			if( p->bUseTrainSmoke ) {

				float fRatio = GetLifeRatio(p);
				float fAddScale = (p->fEndSize - p->fStartSize) / p->fLifeTime;

				if(fRatio < 0.1f ) {
					fAddScale *= 0.001f;
				}
				else if(fRatio < 0.4) {
					fAddScale *= 0.02f;
				}
				else {
					fAddScale *= 0.05f;
				}

				p->fCurScale += fAddScale;

				if(p->fCurScale > p->fEndSize)
					p->fCurScale = p->fEndSize;

				fScale = p->fCurScale;
			}

			D3DXMatrixScaling(&matScaling,fScale*m_Scale.x,fScale*m_Scale.y,fScale*m_Scale.z);
			D3DXMatrixTranslation(&matTranslation, pos.x, pos.y, pos.z);

			D3DXMatrixMultiply(&matWorld, &matScaling, &mat);
			D3DXMatrixMultiply(&matWorld, &matWorld, &matTranslation);
			//		D3DXMatrixMultiply(&matWorld, &mat, &matTranslation);

			DWORD color = ((DWORD)(p->fOpacity * 255))<<24 | p->dwColor;

			static ZEFFECTCUSTOMVERTEX v[] = {
				{-1, -1, 0, 0xFFFFFFFF, 1, 0},
				{-1,  1, 0, 0xFFFFFFFF, 1, 1},
				{ 1,  1, 0, 0xFFFFFFFF, 0, 1},
				{ 1, -1, 0, 0xFFFFFFFF, 0, 0},
			};

			static rvector sv[4] = { rvector(-1,-1,0) , rvector(-1,1,0) , rvector(1,1,0) , rvector(1,-1,0) };

			// 좋은코드는 아니지만 버텍스 카피를 줄이기위해 타입캐스팅했다.
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[0].x,sv+0,&matWorld);
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[1].x,sv+1,&matWorld);
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[2].x,sv+2,&matWorld);
			D3DXVec3TransformCoord((D3DXVECTOR3*)&v[3].x,sv+3,&matWorld);
			v[0].color=v[1].color=v[2].color=v[3].color=color;

			memcpy(pVertices,v,sizeof(ZEFFECTCUSTOMVERTEX)*4);
			pVertices+=sizeof(ZEFFECTCUSTOMVERTEX)*4;

			WORD inds[] = { 0,1,2,0,2,3 };
			for(int k=0;k<6;k++)
			{
				inds[k]+=(m_dwBase+j)*4;
			}
			memcpy(pInd,inds,sizeof(inds));
			pInd+=sizeof(inds);

			itr++;
		}

		m_pVB->Unlock();
		m_pIB->Unlock();

		if(FAILED( hr = RGetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,m_dwBase*4,dwThisNum*4,m_dwBase*6,dwThisNum*2) ))
			return false;

		m_dwBase+=dwThisNum;
		dwRemainNum-=dwThisNum;

	}

	RGetDevice()->SetStreamSource( 0, NULL , 0,0 );	
	RGetDevice()->SetIndices(NULL);

	EndState();

	return true;
}
示例#7
0
void MBitmapR2::Draw(float x, float y, float w, float h, float sx, float sy, float sw, float sh, 
					 DWORD dwColor, MDrawEffect effect, bool bMirrorX, bool bMirrorY)
{
	/*
	float ftw = (float)Floorer2PowerSize(m_Info.Width);
	float fth = (float)Floorer2PowerSize(m_Info.Height);
	*/
	if(m_pTexture==NULL) return;

	// 임시로 메모리에서 내린 상태라면 복구해준다
	if(m_bUnloadedTemporarily) {
		m_pTexture->OnRestore();
		m_bUnloadedTemporarily = false;
	}

	float ftw = (float)m_pTexture->GetWidth();
	float fth = (float)m_pTexture->GetHeight();

	// 인버스 작업
	float fuv[8];
	// X축 인버스
	if (!bMirrorX) {
		fuv[0] = (sx)/ftw;		
		fuv[2] = (sx+sw)/ftw;	
		fuv[4] = (sx+sw)/ftw;	
		fuv[6] = (sx)/ftw;		
	} else {

		fuv[2] = (sx)/ftw;		
		fuv[0] = (sx+sw)/ftw;	
		fuv[6] = (sx+sw)/ftw;	
		fuv[4] = (sx)/ftw;
	}

	// Y축 인버스
	if (!bMirrorY) {
		fuv[1] = (sy)/fth;
		fuv[3] = (sy)/fth;
		fuv[5] = (sy+sh)/fth;
		fuv[7] = (sy+sh)/fth;
	} else {
		fuv[7] = (sy)/fth;
		fuv[5] = (sy)/fth;
		fuv[3] = (sy+sh)/fth;
		fuv[1] = (sy+sh)/fth;
	}

	CheckDrawMode(fuv);

	CUSTOMVERTEX Sprite[4] = {
#define ADJUST_SIZE		0.5f
#define ADJUST_SIZE2	0.0f
		{x-ADJUST_SIZE,    y-ADJUST_SIZE,    0, 1.0f, dwColor, fuv[0], fuv[1]},
		{x+w-ADJUST_SIZE2, y-ADJUST_SIZE,    0, 1.0f, dwColor, fuv[2], fuv[3]},
		{x+w-ADJUST_SIZE2, y+h-ADJUST_SIZE2, 0, 1.0f, dwColor, fuv[4], fuv[5]},
		{x-ADJUST_SIZE,    y+h-ADJUST_SIZE2, 0, 1.0f, dwColor, fuv[6], fuv[7]},
	};
	m_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
	m_pd3dDevice->SetPixelShader(NULL);

	m_pd3dDevice->SetTexture(0, m_pTexture->GetTexture());

	BeginState(effect);

	HRESULT hr = m_pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, Sprite, sizeof(CUSTOMVERTEX));
	_ASSERT(hr==D3D_OK);

	EndState();
}
bool ZEffectBillboardTexAniList::Draw()
{
	if(!m_pVB) return false;

	if( size()==0 ) return true;

	BeginState();

	RSetFog(FALSE);

	HRESULT	hr;

	DWORD	dwRemainNum = (DWORD)size();

	iterator itr = begin();

	while(dwRemainNum)
	{
		if(m_dwBase >= EFFECTBASE_DISCARD_COUNT)
			m_dwBase = 0;

		DWORD dwThisNum = min( dwRemainNum , static_cast<DWORD>(BILLBOARD_FLUSH_COUNT) );

		dwThisNum = min( dwThisNum , EFFECTBASE_DISCARD_COUNT - m_dwBase );	

		BYTE *pVertices;

		if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(ZEFFECTCUSTOMVERTEX) * 4, dwThisNum * sizeof(ZEFFECTCUSTOMVERTEX) * 4,
			(VOID**)&pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		BYTE *pInd;
		if( FAILED( hr = m_pIB->Lock( m_dwBase * sizeof(WORD) * 6, dwThisNum * sizeof(WORD) * 6,
			(VOID**)&pInd, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		int nRenderCnt = 0;

		ZCharacter* pChar = NULL;

		for(DWORD j=0;j<dwThisNum;j++)
		{
			ZEFFECTBILLBOARDTEXANIITEM *p = (ZEFFECTBILLBOARDTEXANIITEM*)*itr;

			if(p->fElapsedTime < p->fAddTime ) {
				itr++;
				continue;
			}

			pChar = ZGetCharacterManager()->Find(p->CharUID);

			if( pChar ) {
				if( pChar->m_pVMesh ) {
					if( pChar->m_pVMesh->m_bIsRender==false) {
						itr++;
						continue;
					}
				}
			}

			nRenderCnt++;

			// Transform
			rmatrix matTranslation;
			rmatrix matScaling;
			rmatrix matWorld;

			rvector dir = p->normal;

			rvector up = p->up;
			rvector right;

			if (IS_EQ(dir.z, 1.f)) up = rvector(1, 0, 0);

			right = Normalized(CrossProduct(up, dir));
			up = Normalized(CrossProduct(right, dir));

			rmatrix mat;
			GetIdentityMatrix(mat);
			mat._11 = right.x; mat._12 = right.y; mat._13 = right.z;
			mat._21 = up.x; mat._22 = up.y; mat._23 = up.z;
			mat._31 = dir.x; mat._32 = dir.y; mat._33 = dir.z;

			rvector pos = p->position;

			float fInt = min(1.f, max(0.f, (p->fLifeTime - p->fElapsedTime) / p->fLifeTime));
			float fScale=p->fStartSize * fInt + p->fEndSize * (1.f - fInt);

			matScaling = ScalingMatrix(fScale * m_Scale);
			matTranslation = TranslationMatrix(pos);

			matWorld = matScaling * mat;
			matWorld *= matTranslation;

			DWORD color = ((DWORD)(p->fOpacity * 255))<<24 | p->dwColor;

			static ZEFFECTCUSTOMVERTEX v[] = {
				{{-1, -1, 0}, 0xFFFFFFFF, 1, 0 },
				{{-1,  1, 0}, 0xFFFFFFFF, 1, 1},
				{{ 1,  1, 0}, 0xFFFFFFFF, 0, 1},
				{{ 1, -1, 0}, 0xFFFFFFFF, 0, 0},
			};

			static rvector sv[4] = { rvector(-1,-1,0) , rvector(-1,1,0) , rvector(1,1,0) , rvector(1,-1,0) };

			GetFrameUV( min( p->frame,m_nMaxFrame-1) );

			v[0].tu = m_fUV[0];
			v[0].tv = m_fUV[1];
			v[1].tu = m_fUV[2];
			v[1].tv = m_fUV[3];
			v[2].tu = m_fUV[4];
			v[2].tv = m_fUV[5];
			v[3].tu = m_fUV[6];
			v[3].tv = m_fUV[7];

			for (size_t i{}; i < 4; ++i)
				v[i].pos = TransformCoord(sv[i], matWorld);

			v[0].color=v[1].color=v[2].color=v[3].color=color;

			memcpy(pVertices,v,sizeof(ZEFFECTCUSTOMVERTEX)*4);
			pVertices+=sizeof(ZEFFECTCUSTOMVERTEX)*4;

			WORD inds[] = { 0,1,2,0,2,3 };
			for(int k=0;k<6;k++)
			{
				inds[k]+=(m_dwBase+j)*4;
			}
			memcpy(pInd,inds,sizeof(inds));
			pInd+=sizeof(inds);

			itr++;
		}

		m_pVB->Unlock();
		m_pIB->Unlock();

		if(FAILED( hr = RGetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,m_dwBase*4,nRenderCnt*4,m_dwBase*6,nRenderCnt*2) ))
			return false;

		m_dwBase+=dwThisNum;
		dwRemainNum-=dwThisNum;

	}

	RGetDevice()->SetStreamSource( 0, NULL , 0,0 );	
	RGetDevice()->SetIndices(NULL);

	if(ZGetWorld()) {
		ZGetWorld()->SetFog(true);
	}

	EndState();

	return true;
}
bool ZEffectBillboardList::Draw()
{
	if(!m_pVB) return false;

	if( size()==0 ) return true;

	BeginState();

	HRESULT		hr;

	DWORD		dwRemainNum = (DWORD)size();

	iterator itr=begin();

	while(dwRemainNum)
	{
		if(m_dwBase >= EFFECTBASE_DISCARD_COUNT)
			m_dwBase = 0;

		DWORD dwThisNum = min( dwRemainNum , static_cast<DWORD>(BILLBOARD_FLUSH_COUNT) );

		dwThisNum = min( dwThisNum , EFFECTBASE_DISCARD_COUNT - m_dwBase );	


		BYTE		*pVertices;
		if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(ZEFFECTCUSTOMVERTEX) * 4, dwThisNum * sizeof(ZEFFECTCUSTOMVERTEX) * 4,
			(VOID**)&pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		BYTE *pInd;
		if( FAILED( hr = m_pIB->Lock( m_dwBase * sizeof(WORD) * 6, dwThisNum * sizeof(WORD) * 6,
			(VOID**)&pInd, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
		{
			return false;
		}

		for(DWORD j=0;j<dwThisNum;j++)
		{
			ZEFFECTBILLBOARDITEM *p = (ZEFFECTBILLBOARDITEM*)*itr;

			// Transform
			rmatrix matTranslation;
			rmatrix matScaling;
			rmatrix matWorld;

			rvector dir = p->normal;

			rvector up=p->up;
			rvector right;

			if(IS_EQ(dir.z,1.f)) up=rvector(1,0,0);

			right = Normalized(CrossProduct(up, dir));
			up = Normalized(CrossProduct(right, dir));

			rmatrix mat;
			GetIdentityMatrix(mat);
			mat._11=right.x;mat._12=right.y;mat._13=right.z;
			mat._21=up.x;mat._22=up.y;mat._23=up.z;
			mat._31=dir.x;mat._32=dir.y;mat._33=dir.z;

			rvector pos=p->position;

			float fInt = min(1.f, max(0.f, (p->fLifeTime - p->fElapsedTime) / p->fLifeTime));

			float fScale=p->fStartSize * fInt + p->fEndSize * (1.f - fInt);

			if( p->bUseTrainSmoke ) {

				float fRatio = GetLifeRatio(p);
				float fAddScale = (p->fEndSize - p->fStartSize) / p->fLifeTime;

				if(fRatio < 0.1f ) {
					fAddScale *= 0.001f;
				}
				else if(fRatio < 0.4) {
					fAddScale *= 0.02f;
				}
				else {
					fAddScale *= 0.05f;
				}

				p->fCurScale += fAddScale;

				if(p->fCurScale > p->fEndSize)
					p->fCurScale = p->fEndSize;

				fScale = p->fCurScale;
			}

			matScaling = ScalingMatrix(fScale * m_Scale);
			matTranslation = TranslationMatrix(pos);

			matWorld = matScaling * mat;
			matWorld *= matTranslation;

			DWORD color = ((DWORD)(p->fOpacity * 255))<<24 | p->dwColor;

			static ZEFFECTCUSTOMVERTEX v[] = {
				{{-1, -1, 0}, 0xFFFFFFFF, 1, 0 },
				{{-1,  1, 0}, 0xFFFFFFFF, 1, 1 },
				{{ 1,  1, 0 }, 0xFFFFFFFF, 0, 1},
				{ { 1, -1, 0}, 0xFFFFFFFF, 0, 0 },
			};

			static const rvector sv[4] = { rvector(-1,-1,0) , rvector(-1,1,0) , rvector(1,1,0) , rvector(1,-1,0) };

			for (size_t i{}; i < 4; ++i)
				v[i].pos = TransformCoord(sv[i], matWorld);

			v[0].color=v[1].color=v[2].color=v[3].color=color;

			memcpy(pVertices,v,sizeof(ZEFFECTCUSTOMVERTEX)*4);
			pVertices+=sizeof(ZEFFECTCUSTOMVERTEX)*4;

			WORD inds[] = { 0,1,2,0,2,3 };
			for(int k=0;k<6;k++)
			{
				inds[k]+=(m_dwBase+j)*4;
			}
			memcpy(pInd,inds,sizeof(inds));
			pInd+=sizeof(inds);

			itr++;
		}

		m_pVB->Unlock();
		m_pIB->Unlock();

		if(FAILED( hr = RGetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,m_dwBase*4,dwThisNum*4,m_dwBase*6,dwThisNum*2) ))
			return false;

		m_dwBase+=dwThisNum;
		dwRemainNum-=dwThisNum;

	}

	RGetDevice()->SetStreamSource( 0, NULL , 0,0 );	
	RGetDevice()->SetIndices(NULL);

	EndState();

	return true;
}