示例#1
0
文件: D3DUtils.cpp 项目: galek/xray
void CDrawUtilities::DrawEntity(u32 clr, ref_shader s)
{
	// fill VB
	_VertexStream*	Stream	= &RCache.Vertex;
	u32			vBase;
	FVF::L*	pv	 	= (FVF::L*)Stream->Lock(5,vs_L->vb_stride,vBase);
    pv->set			(0.f,0.f,0.f,clr); pv++;
    pv->set			(0.f,1.f,0.f,clr); pv++;
    pv->set			(0.f,1.f,.5f,clr); pv++;
    pv->set			(0.f,.5f,.5f,clr); pv++;
    pv->set			(0.f,.5f,0.f,clr); pv++;
	Stream->Unlock	(5,vs_L->vb_stride);
	// render flagshtok
	DU_DRAW_SH		(dxRenderDeviceRender::Instance().m_WireShader);
    DU_DRAW_DP		(D3DPT_LINESTRIP,vs_L,vBase,4);

    if (s) DU_DRAW_SH(s);
    {
        // fill VB
        FVF::LIT*	pv	 = (FVF::LIT*)Stream->Lock(6,vs_LIT->vb_stride,vBase);
        pv->set		(0.f,1.f,0.f,clr,0.f,0.f);	pv++;
        pv->set		(0.f,1.f,.5f,clr,1.f,0.f);	pv++;
        pv->set		(0.f,.5f,.5f,clr,1.f,1.f);	pv++;
        pv->set		(0.f,.5f,0.f,clr,0.f,1.f);	pv++;
        pv->set		(0.f,.5f,.5f,clr,1.f,1.f);	pv++;
        pv->set		(0.f,1.f,.5f,clr,1.f,0.f);	pv++;
        Stream->Unlock	(6,vs_LIT->vb_stride);
        // and Render it as line list
        DU_DRAW_DP		(D3DPT_TRIANGLEFAN,vs_LIT,vBase,4);
    }
}
示例#2
0
文件: D3DUtils.cpp 项目: galek/xray
void CDrawUtilities::DrawPrimitiveLIT(D3DPRIMITIVETYPE pt, u32 pc, FVF::LIT* vertices, int vc, BOOL bCull, BOOL bCycle)
{
	// fill VB
	_VertexStream*	Stream	= &RCache.Vertex;
	u32			vBase, dwNeed=(bCycle)?vc+1:vc;
	FVF::LIT* 	pv	= (FVF::LIT*)Stream->Lock(dwNeed,vs_LIT->vb_stride,vBase);
    for(int k=0; k<vc; k++,pv++)
    	pv->set		(vertices[k]);
    if (bCycle)		pv->set(*(pv-vc));
	Stream->Unlock(dwNeed,vs_LIT->vb_stride);

    if (!bCull) DU_DRAW_RS(D3DRS_CULLMODE,D3DCULL_NONE);
    DU_DRAW_DP		(pt,vs_LIT,vBase,pc);
    if (!bCull) DU_DRAW_RS(D3DRS_CULLMODE,D3DCULL_CCW);
}
示例#3
0
void CActor::RenderIndicator			(Fvector dpos, float r1, float r2, ref_shader IndShader)
{
	if (!g_Alive()) return;

	u32			dwOffset = 0,dwCount = 0;
	FVF::LIT* pv_start				= (FVF::LIT*)RCache.Vertex.Lock(4,hFriendlyIndicator->vb_stride,dwOffset);
	FVF::LIT* pv					= pv_start;
	// base rect

	CBoneInstance& BI = smart_cast<CKinematics*>(Visual())->LL_GetBoneInstance(u16(m_head));
	Fmatrix M;
	smart_cast<CKinematics*>(Visual())->CalculateBones	();
	M.mul						(XFORM(),BI.mTransform);

	Fvector pos = M.c; pos.add(dpos);
	const Fvector& T        = Device.vCameraTop;
	const Fvector& R        = Device.vCameraRight;
	Fvector Vr, Vt;
	Vr.x            = R.x*r1;
	Vr.y            = R.y*r1;
	Vr.z            = R.z*r1;
	Vt.x            = T.x*r2;
	Vt.y            = T.y*r2;
	Vt.z            = T.z*r2;

	Fvector         a,b,c,d;
	a.sub           (Vt,Vr);
	b.add           (Vt,Vr);
	c.invert        (a);
	d.invert        (b);
	pv->set         (d.x+pos.x,d.y+pos.y,d.z+pos.z, 0xffffffff, 0.f,1.f);        pv++;
	pv->set         (a.x+pos.x,a.y+pos.y,a.z+pos.z, 0xffffffff, 0.f,0.f);        pv++;
	pv->set         (c.x+pos.x,c.y+pos.y,c.z+pos.z, 0xffffffff, 1.f,1.f);        pv++;
	pv->set         (b.x+pos.x,b.y+pos.y,b.z+pos.z, 0xffffffff, 1.f,0.f);        pv++;
	// render	
	dwCount 				= u32(pv-pv_start);
	RCache.Vertex.Unlock	(dwCount,hFriendlyIndicator->vb_stride);

	RCache.set_xform_world		(Fidentity);
	RCache.set_Shader			(IndShader);
	RCache.set_Geometry			(hFriendlyIndicator);
	RCache.Render	   			(D3DPT_TRIANGLESTRIP,dwOffset,0, dwCount, 0, 2);
};
示例#4
0
void ESceneAIMapTool::OnRender(int priority, bool strictB2F)
{
	if (m_Flags.is(flHideNodes) || !ai_map_shown) return;
    if (1==priority){
        if (false==strictB2F){
            RCache.set_xform_world(Fidentity);
			if (OBJCLASS_AIMAP==LTools->CurrentClassID()){
	            u32 clr = 0xffffc000;
	            Device.SetShader	(Device.m_WireShader);
    	        DU_impl.DrawSelectionBox	(m_AIBBox,&clr);
            }
            if (Valid()){
                // render nodes
                Device.SetShader	(m_Shader);
                Device.SetRS		(D3DRS_CULLMODE,		D3DCULL_NONE);
                Irect rect;
                HashRect			(Device.m_Camera.GetPosition(),m_VisRadius,rect);

                u32 vBase;
                _VertexStream* Stream= &RCache.Vertex;
                FVF::LIT* pv		= (FVF::LIT*)Stream->Lock(block_size,m_RGeom->vb_stride,vBase);
                u32	cnt				= 0;
//				Device.Statistic.TEST0.Begin();
//				Device.Statistic.TEST2.Begin();
                for (int x=rect.x1; x<=rect.x2; x++){
                    for (int z=rect.y1; z<=rect.y2; z++){
                        AINodeVec* nodes	= HashMap(x,z);
                        if (nodes){
                            const Fvector	DUP={0,1,0};
                            const float st 	= (m_Params.fPatchSize*0.9f)*0.5f;
                            for (AINodeIt it=nodes->begin(); it!=nodes->end(); it++){
                                SAINode& N 	= **it;

								Fvector v;	v.set(N.Pos.x-st,N.Pos.y,N.Pos.z-st);
                                float p_denom 	= N.Plane.n.dotproduct(DUP);
                                float b			= (_abs(p_denom)<EPS_S)?m_Params.fPatchSize:_abs(N.Plane.classify(v) / p_denom);
							
                                if (Render->ViewBase.testSphere_dirty(N.Pos,_max(b,st))){
                                    u32 clr;
                                    if (N.flags.is(SAINode::flSelected))clr = 0xffffffff;
                                    else 								clr = N.flags.is(SAINode::flHLSelected)?0xff909090:0xff606060;
                                    int k = 0;
                                    if (N.n1) k |= 1<<0;
                                    if (N.n2) k |= 1<<1;
                                    if (N.n3) k |= 1<<2;
                                    if (N.n4) k |= 1<<3;
                                    Fvector		v;
                                    FVF::LIT	v1,v2,v3,v4;
                                    float tt	= 0.01f;
                                    v.set(N.Pos.x-st,N.Pos.y,N.Pos.z-st);	N.Plane.intersectRayPoint(v,DUP,v1.p);	v1.p.mad(v1.p,N.Plane.n,tt); v1.t.set(node_tc[k][0]); v1.color=clr;	// minX,minZ
                                    v.set(N.Pos.x+st,N.Pos.y,N.Pos.z-st);	N.Plane.intersectRayPoint(v,DUP,v2.p);	v2.p.mad(v2.p,N.Plane.n,tt); v2.t.set(node_tc[k][1]); v2.color=clr;	// maxX,minZ
                                    v.set(N.Pos.x+st,N.Pos.y,N.Pos.z+st);	N.Plane.intersectRayPoint(v,DUP,v3.p);	v3.p.mad(v3.p,N.Plane.n,tt); v3.t.set(node_tc[k][2]); v3.color=clr;	// maxX,maxZ
                                    v.set(N.Pos.x-st,N.Pos.y,N.Pos.z+st);	N.Plane.intersectRayPoint(v,DUP,v4.p);	v4.p.mad(v4.p,N.Plane.n,tt); v4.t.set(node_tc[k][3]); v4.color=clr;	// minX,maxZ
                                    pv->set(v3); pv++;
                                    pv->set(v2); pv++;
                                    pv->set(v1); pv++;
                                    pv->set(v1); pv++;
                                    pv->set(v4); pv++;
                                    pv->set(v3); pv++;
                                    cnt+=6;
                                    if (cnt>=block_size-6){
                                        Stream->Unlock	(cnt,m_RGeom->vb_stride);
                                        Device.DP		(D3DPT_TRIANGLELIST,m_RGeom,vBase,cnt/3);
                                        pv 				= (FVF::LIT*)Stream->Lock(block_size,m_RGeom->vb_stride,vBase);
                                        cnt				= 0;
                                    }	
                                }
                            }
                        }
                    }
                }
//                Device.Statistic.TEST2.End();
//                Device.Statistic.TEST0.End();
				Stream->Unlock		(cnt,m_RGeom->vb_stride);
                if (cnt) Device.DP	(D3DPT_TRIANGLELIST,m_RGeom,vBase,cnt/3);
                Device.SetRS		(D3DRS_CULLMODE,		D3DCULL_CCW);
            }
        }else{
/*            // render snap
            if (m_Flags.is(flDrawSnapObjects))
                for(ObjectIt _F=m_SnapObjects.begin();_F!=m_SnapObjects.end();_F++) 
                    if((*_F)->Visible()) ((CSceneObject*)(*_F))->RenderSelection(0x4046B646);
*/        }
    }
}
示例#5
0
void dxThunderboltRender::Render(CEffect_Thunderbolt &owner)
{
	VERIFY	(owner.current);

	// lightning model
	float dv			= owner.lightning_phase*0.5f;
	dv					= (owner.lightning_phase>0.5f)?Random.randI(2)*0.5f:dv;

	RCache.set_CullMode	(CULL_NONE);
	u32					v_offset,i_offset;
	
	dxThunderboltDescRender *pThRen = (dxThunderboltDescRender*)&*owner.current->m_pRender;

	u32					vCount_Lock		= pThRen->l_model->number_vertices;
	u32					iCount_Lock		= pThRen->l_model->number_indices;
	IRender_DetailModel::fvfVertexOut* v_ptr= (IRender_DetailModel::fvfVertexOut*) 	RCache.Vertex.Lock	(vCount_Lock, hGeom_model->vb_stride, v_offset);
	u16*				i_ptr				=										RCache.Index.Lock	(iCount_Lock, i_offset);
	// XForm verts
	pThRen->l_model->transfer(owner.current_xform,v_ptr,0xffffffff,i_ptr,0,0.f,dv);
	// Flush if needed
	RCache.Vertex.Unlock(vCount_Lock,hGeom_model->vb_stride);
	RCache.Index.Unlock	(iCount_Lock);
	RCache.set_xform_world(Fidentity);
	RCache.set_Shader	(pThRen->l_model->shader);
	RCache.set_Geometry	(hGeom_model);
	RCache.Render		(D3DPT_TRIANGLELIST,v_offset,0,vCount_Lock,i_offset,iCount_Lock/3);
	RCache.set_CullMode	(CULL_CCW);

	// gradient
	Fvector				vecSx, vecSy;
	u32					VS_Offset;
	FVF::LIT *pv		= (FVF::LIT*) RCache.Vertex.Lock(8,hGeom_gradient.stride(),VS_Offset);
	// top
	{
		u32 c_val		= iFloor(owner.current->m_GradientTop->fOpacity*owner.lightning_phase*255.f);
		u32 c			= color_rgba(c_val,c_val,c_val,c_val);
		vecSx.mul		(Device.vCameraRight, 	owner.current->m_GradientTop->fRadius.x*owner.lightning_size);
		vecSy.mul		(Device.vCameraTop, 	-owner.current->m_GradientTop->fRadius.y*owner.lightning_size);
		pv->set			(owner.current_xform.c.x+vecSx.x-vecSy.x, owner.current_xform.c.y+vecSx.y-vecSy.y, owner.current_xform.c.z+vecSx.z-vecSy.z, c, 0, 0); pv++;
		pv->set			(owner.current_xform.c.x+vecSx.x+vecSy.x, owner.current_xform.c.y+vecSx.y+vecSy.y, owner.current_xform.c.z+vecSx.z+vecSy.z, c, 0, 1); pv++;
		pv->set			(owner.current_xform.c.x-vecSx.x-vecSy.x, owner.current_xform.c.y-vecSx.y-vecSy.y, owner.current_xform.c.z-vecSx.z-vecSy.z, c, 1, 0); pv++;
		pv->set			(owner.current_xform.c.x-vecSx.x+vecSy.x, owner.current_xform.c.y-vecSx.y+vecSy.y, owner.current_xform.c.z-vecSx.z+vecSy.z, c, 1, 1); pv++;
	}
	// center
	{
		u32 c_val		= iFloor(owner.current->m_GradientTop->fOpacity*owner.lightning_phase*255.f);
		u32 c			= color_rgba(c_val,c_val,c_val,c_val);
		vecSx.mul		(Device.vCameraRight, 	owner.current->m_GradientCenter->fRadius.x*owner.lightning_size);
		vecSy.mul		(Device.vCameraTop, 	-owner.current->m_GradientCenter->fRadius.y*owner.lightning_size);
		pv->set			(owner.lightning_center.x+vecSx.x-vecSy.x, owner.lightning_center.y+vecSx.y-vecSy.y, owner.lightning_center.z+vecSx.z-vecSy.z, c, 0, 0); pv++;
		pv->set			(owner.lightning_center.x+vecSx.x+vecSy.x, owner.lightning_center.y+vecSx.y+vecSy.y, owner.lightning_center.z+vecSx.z+vecSy.z, c, 0, 1); pv++;
		pv->set			(owner.lightning_center.x-vecSx.x-vecSy.x, owner.lightning_center.y-vecSx.y-vecSy.y, owner.lightning_center.z-vecSx.z-vecSy.z, c, 1, 0); pv++;
		pv->set			(owner.lightning_center.x-vecSx.x+vecSy.x, owner.lightning_center.y-vecSx.y+vecSy.y, owner.lightning_center.z-vecSx.z+vecSy.z, c, 1, 1); pv++;
	}
	RCache.Vertex.Unlock	(8,hGeom_gradient.stride());
	RCache.set_xform_world	(Fidentity);
	RCache.set_Geometry		(hGeom_gradient);
	RCache.set_Shader		(((dxFlareRender*)&*owner.current->m_GradientTop->m_pFlare)->hShader);

#ifdef	USE_DX10
	//	Hack. Since lightning gradient uses sun shader override z write settings manually
	RCache.set_Z(TRUE);
	RCache.set_ZFunc(D3DCMP_LESSEQUAL);
#endif	//	USE_DX10

#ifdef	USE_DX10
	//	Hack. Since lightning gradient uses sun shader override z write settings manually
	RCache.set_Z(TRUE);
	RCache.set_ZFunc(D3DCMP_LESSEQUAL);
#endif	//	USE_DX10
	RCache.Render			(D3DPT_TRIANGLELIST,VS_Offset, 0,4,0,2);
	RCache.set_Shader		(((dxFlareRender*)&*owner.current->m_GradientCenter->m_pFlare)->hShader);

#ifdef	USE_DX10
	//	Hack. Since lightning gradient uses sun shader override z write settings manually
	RCache.set_Z(TRUE);
	RCache.set_ZFunc(D3DCMP_LESSEQUAL);
#endif	//	USE_DX10

#ifdef	USE_DX10
	//	Hack. Since lightning gradient uses sun shader override z write settings manually
	RCache.set_Z(TRUE);
	RCache.set_ZFunc(D3DCMP_LESSEQUAL);
#endif	//	USE_DX10
	RCache.Render			(D3DPT_TRIANGLELIST,VS_Offset+4, 0,4,0,2);
}
示例#6
0
void CLensFlare::Render(BOOL bSun, BOOL bFlares, BOOL bGradient)
{
	if (!bRender)		return;
	if(!m_Current)		return;
	VERIFY				(m_Current);

	Fcolor				dwLight;
	Fcolor				color;
	Fvector				vec, vecSx, vecSy;
	Fvector				vecDx, vecDy;

	dwLight.set							( LightColor );
	svector<ref_shader,MAX_Flares>		_2render;

	u32									VS_Offset;
	FVF::LIT *pv						= (FVF::LIT*) RCache.Vertex.Lock(MAX_Flares*4,hGeom.stride(),VS_Offset);

	float 	fDistance		= FAR_DIST*0.75f;

	if (bSun){
    	if (m_Current->m_Flags.is(CLensFlareDescriptor::flSource)){
            vecSx.mul			(vecX, m_Current->m_Source.fRadius*fDistance);
            vecSy.mul			(vecY, m_Current->m_Source.fRadius*fDistance);
            if (m_Current->m_Source.ignore_color) 	color.set(1.f,1.f,1.f,1.f);
            else									color.set(dwLight);
	        color.a				*= m_StateBlend;
            u32 c				= color.get();
            pv->set				(vecLight.x+vecSx.x-vecSy.x, vecLight.y+vecSx.y-vecSy.y, vecLight.z+vecSx.z-vecSy.z, c, 0, 0); pv++;
            pv->set				(vecLight.x+vecSx.x+vecSy.x, vecLight.y+vecSx.y+vecSy.y, vecLight.z+vecSx.z+vecSy.z, c, 0, 1); pv++;
            pv->set				(vecLight.x-vecSx.x-vecSy.x, vecLight.y-vecSx.y-vecSy.y, vecLight.z-vecSx.z-vecSy.z, c, 1, 0); pv++;
            pv->set				(vecLight.x-vecSx.x+vecSy.x, vecLight.y-vecSx.y+vecSy.y, vecLight.z-vecSx.z+vecSy.z, c, 1, 1); pv++;
            _2render.push_back	(m_Current->m_Source.hShader);
        }
	}
	if (fBlend>=EPS_L)
	{
		if(bFlares){
			vecDx.normalize		(vecAxis);
			vecDy.crossproduct	(vecDx, vecDir);
	    	if (m_Current->m_Flags.is(CLensFlareDescriptor::flFlare)){
                for (CLensFlareDescriptor::FlareIt it=m_Current->m_Flares.begin(); it!=m_Current->m_Flares.end(); it++){
                    CLensFlareDescriptor::SFlare&	F = *it;
                    vec.mul				(vecAxis, F.fPosition);
                    vec.add				(vecCenter);
                    vecSx.mul			(vecDx, F.fRadius*fDistance);
                    vecSy.mul			(vecDy, F.fRadius*fDistance);
                    float    cl			= F.fOpacity * fBlend * m_StateBlend;
                    color.set			( dwLight );
                    color.mul_rgba		( cl );
                    u32 c				= color.get();
                    pv->set				(vec.x+vecSx.x-vecSy.x, vec.y+vecSx.y-vecSy.y, vec.z+vecSx.z-vecSy.z, c, 0, 0); pv++;
                    pv->set				(vec.x+vecSx.x+vecSy.x, vec.y+vecSx.y+vecSy.y, vec.z+vecSx.z+vecSy.z, c, 0, 1); pv++;
                    pv->set				(vec.x-vecSx.x-vecSy.x, vec.y-vecSx.y-vecSy.y, vec.z-vecSx.z-vecSy.z, c, 1, 0); pv++;
                    pv->set				(vec.x-vecSx.x+vecSy.x, vec.y-vecSx.y+vecSy.y, vec.z-vecSx.z+vecSy.z, c, 1, 1); pv++;
                    _2render.push_back	(it->hShader);
                }
            }
		}
		// gradient
		if (bGradient&&(fGradientValue>=EPS_L)){
            if (m_Current->m_Flags.is(CLensFlareDescriptor::flGradient)){
                vecSx.mul			(vecX, m_Current->m_Gradient.fRadius*fGradientValue*fDistance);
                vecSy.mul			(vecY, m_Current->m_Gradient.fRadius*fGradientValue*fDistance);

                color.set			( dwLight );
                color.mul_rgba		( fGradientValue*m_StateBlend );

                u32 c				= color.get	();
                pv->set				(vecLight.x+vecSx.x-vecSy.x, vecLight.y+vecSx.y-vecSy.y, vecLight.z+vecSx.z-vecSy.z, c, 0, 0); pv++;
                pv->set				(vecLight.x+vecSx.x+vecSy.x, vecLight.y+vecSx.y+vecSy.y, vecLight.z+vecSx.z+vecSy.z, c, 0, 1); pv++;
                pv->set				(vecLight.x-vecSx.x-vecSy.x, vecLight.y-vecSx.y-vecSy.y, vecLight.z-vecSx.z-vecSy.z, c, 1, 0); pv++;
                pv->set				(vecLight.x-vecSx.x+vecSy.x, vecLight.y-vecSx.y+vecSy.y, vecLight.z-vecSx.z+vecSy.z, c, 1, 1); pv++;
                _2render.push_back	(m_Current->m_Gradient.hShader);
            }
		}
	}
	RCache.Vertex.Unlock	(_2render.size()*4,hGeom.stride());

	RCache.set_xform_world	(Fidentity);
	RCache.set_Geometry		(hGeom);
	for (u32 i=0; i<_2render.size(); i++)
	{
    	if (_2render[i])
		{
			u32						vBase	= i*4+VS_Offset;
			RCache.set_Shader		(_2render[i]);
			RCache.Render			(D3DPT_TRIANGLELIST,vBase, 0,4,0,2);
	    }
	}
}
示例#7
0
void CLightShadows::render	()
{
	// Gain access to collision-DB
	CDB::MODEL*		DB		= g_pGameLevel->ObjectSpace.GetStaticModel();
	CDB::TRI*		TRIS	= DB->get_tris();
	Fvector*		VERTS	= DB->get_verts();

	int			slot_line	= S_rt_size/S_size;
	
	// Projection and xform
	float _43					=	Device.mProject._43;
	Device.mProject._43			-=	0.002f; 
	RCache.set_xform_world		(Fidentity);
	RCache.set_xform_project	(Device.mProject);
	Fvector	View				= Device.vCameraPosition;
	
	// Render shadows
	RCache.set_Shader			(sh_World);
	RCache.set_Geometry			(geom_World);
	int batch					= 0;
	u32 Offset					= 0;
	FVF::LIT* pv				= (FVF::LIT*) RCache.Vertex.Lock	(batch_size*3,geom_World->vb_stride,Offset);
	for (u32 s_it=0; s_it<shadows.size(); s_it++)
	{
		Device.Statistic->RenderDUMP_Srender.Begin	();
		shadow&		S			=	shadows[s_it];
		float		Le			=	S.L->color.intensity()*S.E;
		int			s_x			=	S.slot%slot_line;
		int			s_y			=	S.slot/slot_line;
		Fvector2	t_scale, t_offset;
		t_scale.set	(float(S_size)/float(S_rt_size),float(S_size)/float(S_rt_size));
		t_scale.mul (.5f);
		t_offset.set(float(s_x)/float(slot_line),float(s_y)/float(slot_line));
		t_offset.x	+= .5f/S_rt_size;
		t_offset.y	+= .5f/S_rt_size;
		
		// Search the cache
		cache_item*						CI		= 0; BOOL	bValid = FALSE;
		cache_item						CI_what; CI_what.O	= S.O; CI_what.L = S.L; CI_what.tris=0;
		xr_vector<cache_item>::iterator	CI_ptr	= std::lower_bound(cache.begin(),cache.end(),CI_what,cache_search);
		if (CI_ptr==cache.end())		
		{	// empty ?
			CI_ptr	= cache.insert		(CI_ptr,CI_what);
			CI		= &*CI_ptr;
			bValid	= FALSE;
		} else {
			if (CI_ptr->O != CI_what.O  || CI_ptr->L != CI_what.L)	
			{	// we found something different
				CI_ptr	= cache.insert		(CI_ptr,CI_what);
				CI		= &*CI_ptr;
				bValid	= FALSE;
			} else {
				// Everything, OK. Check if info is still relevant...
				CI		= &*CI_ptr;
				bValid	= TRUE;
				if (!CI->Op.similar(CI->O->renderable.xform.c))	bValid = FALSE;
				else if (!CI->Lp.similar(CI->L->position))		bValid = FALSE;
			}
		}
		CI->time				= Device.dwTimeGlobal;	// acess time

		if (!bValid)			{
			// Frustum
			CFrustum				F;
			F.CreateFromMatrix		(S.M,FRUSTUM_P_ALL);

			// Query
			xrc.frustum_options		(0);
			xrc.frustum_query		(DB,F);
			if (0==xrc.r_count())	continue;

			// Clip polys by frustum
			tess.clear				();
			for (CDB::RESULT* p = xrc.r_begin(); p!=xrc.r_end(); p++)
			{
				VERIFY((p->id>=0)&&(p->id<DB->get_tris_count()));
				// 
				CDB::TRI&	t		= TRIS[p->id];
				if (t.suppress_shadows) continue;
				sPoly		A,B;
				A.push_back			(VERTS[t.verts[0]]);
				A.push_back			(VERTS[t.verts[1]]);
				A.push_back			(VERTS[t.verts[2]]);

				// Calc plane, throw away degenerate tris and invisible to light polygons
				Fplane				P;	float mag = 0;
				Fvector				t1,t2,n;
				t1.sub				(A[0],A[1]);
				t2.sub				(A[0],A[2]);
				n.crossproduct		(t1,t2);
				mag	= n.square_magnitude();
				if (mag<EPS_S)						continue;
				n.mul				(1.f/_sqrt(mag));
				P.build_unit_normal	(A[0],n);
				float	DOT_Fade	= P.classify(S.L->position);
				if (DOT_Fade<0)		continue;

				// Clip polygon
				sPoly*		clip	= F.ClipPoly	(A,B);
				if (0==clip)		continue;

				// Triangulate poly 
				for (u32 v=2; v<clip->size(); v++)	{
					tess.push_back	(tess_tri());
					tess_tri& T		= tess.back();
					T.v[0]			= (*clip)[0];
					T.v[1]			= (*clip)[v-1];
					T.v[2]			= (*clip)[v];
					T.N				= P.n;
				}
			}

			// Remember params which builded cache item
			CI->O					= S.O;
			CI->Op					= CI->O->renderable.xform.c;
			CI->L					= S.L;
			CI->Lp					= CI->L->position;
			CI->tcnt				= tess.size();
			//Msg						("---free--- %x",u32(CI->tris));
			xr_free					(CI->tris);	VERIFY(0==CI->tris);	
			if (tess.size())		{
				CI->tris			= xr_alloc<tess_tri>(CI->tcnt);
				//Msg					("---alloc--- %x",u32(CI->tris));
				CopyMemory		(CI->tris,&*tess.begin(),CI->tcnt * sizeof(tess_tri));
			}
		}

		// Fill VB
		for (u32 tid=0; tid<CI->tcnt; tid++)	{
			tess_tri&	TT		= CI->tris[tid];
			Fvector* 	v		= TT.v;
			Fvector		T;
			Fplane		ttp;	ttp.build_unit_normal(v[0],TT.N);

			if (ttp.classify(View)<0)						continue;
			int	c0		= PLC_calc(v[0],TT.N,S.L,Le,S.C);
			int	c1		= PLC_calc(v[1],TT.N,S.L,Le,S.C);
			int	c2		= PLC_calc(v[2],TT.N,S.L,Le,S.C);
			if (c0>S_clip && c1>S_clip && c2>S_clip)		continue;	
			clamp		(c0,S_ambient,255);
			clamp		(c1,S_ambient,255);
			clamp		(c2,S_ambient,255);

			S.M.transform(T,v[0]); pv->set(v[0],CLS(c0),(T.x+1)*t_scale.x+t_offset.x,(1-T.y)*t_scale.y+t_offset.y); pv++;
			S.M.transform(T,v[1]); pv->set(v[1],CLS(c1),(T.x+1)*t_scale.x+t_offset.x,(1-T.y)*t_scale.y+t_offset.y); pv++;
			S.M.transform(T,v[2]); pv->set(v[2],CLS(c2),(T.x+1)*t_scale.x+t_offset.x,(1-T.y)*t_scale.y+t_offset.y); pv++;

			batch++;
			if (batch==batch_size)	{
				// Flush
				RCache.Vertex.Unlock	(batch*3,geom_World->vb_stride);
				RCache.Render			(D3DPT_TRIANGLELIST,Offset,batch);

				pv						= (FVF::LIT*) RCache.Vertex.Lock(batch_size*3,geom_World->vb_stride,Offset);
				batch					= 0;
			}
		}
		Device.Statistic->RenderDUMP_Srender.End	();
	}

	// Flush if nessesary
	RCache.Vertex.Unlock	(batch*3,geom_World->vb_stride);
	if (batch)				{
		RCache.Render			(D3DPT_TRIANGLELIST,Offset,batch);
	}
	
	// Clear all shadows and free old entries in the cache
	shadows.clear				();
	for (int cit=0; cit<int(cache.size()); cit++)	{
		cache_item&		ci		= cache[cit];
		u32				time	= Device.dwTimeGlobal - ci.time;
		if				(time > cache_old)	{
			//Msg			("---free--- %x",u32(ci.tris));
			xr_free		(ci.tris);	VERIFY(0==ci.tris);
			cache.erase (cache.begin()+cit);
			cit			--;
		}
	}

	// Projection
	Device.mProject._43			= _43;
	RCache.set_xform_project	(Device.mProject);
}