/////////////////////////////////////////////////////////////////////////////// // // ## ###### // ###### ### // ## ############### Shark 3D Engine (www.shark3d.com) // ########## # # # // ######## Copyright (c) 1996-2006 Spinor GmbH. // ######### # # # All rights reserved. // ## ########## // ## // /////////////////////////////////////////////////////////////////////////////// //@cpp #include "gtp_shader_envmap.h" #include "gtp_shader_opticsutil.h" #include "../../interf/eng_pos.h" #include "../../interf/eng_gfxvar.h" #include "../../interf/eng_gfxport.h" #include "../../util/eng_util_gfxutil.h" #include "../../util/eng_util_gfxbegin.h" #include "../../util/eng_util_gfxelemjobbegin.h" #include "../../util/eng_util_mathutil.h" #include "../../util/eng_util_shaderutil.h" #include "../../util/eng_util_shaderitemjob.h" #include "../../../drv/interf/drv_vartypes.h" #include "../../../drv/util/drv_util_varutil.h" #include "../../../drv/util/drv_util_gfxutil.h" #include "../../../util/math/util_geo_types.h" #include "../../../util/snk/util_snk_extractutil.h" /////////////////////////////////////////////////////////////////////////////// /*@{ @declare{shader.class}{gtp_shader.envmap}{} @}*/ /////////////////////////////////////////////////////////////////////////////// S3D_UTIL_RTTI_TABLE_DEFINE_BEGIN(gtp_Shader_EnvMap) S3D_UTIL_RTTI_TABLE_DEFINE_BASE(s3d_CEngShader) S3D_UTIL_RTTI_TABLE_DEFINE_BASE(s3d_CCompUtilUniqueBase) S3D_UTIL_RTTI_TABLE_DEFINE_BASE(s3d_CCompSetup) S3D_UTIL_RTTI_TABLE_DEFINE_END gtp_Shader_EnvMap::gtp_Shader_EnvMap() { } void gtp_Shader_EnvMap::SetupInit( s3d_CUtilMsgHandler *MsgHandler, s3d_CUtilStr_cr Info, s3d_CCompSuppl *FetchSuppl, s3d_CUtilSnkChunk *Param) { m_Data = S3D_SYS_NEW gtp_Shader_EnvMapData; s3d_CUtilSnkExtract SnkExtract; SnkExtract.Assign(MsgHandler, Param); m_Data->m_Info = SnkExtract.GetInfo(); /*@{ @declare{shader.param}{eng_shader_special.envmap.env}{$ [str]} @}*/ s3d_CUtilStr EnvIdent, EnvInfo; SnkExtract.ExtractStr(EnvInfo, EnvIdent, "env", true); m_ShaderEnv = s3d_CompSupplObjT( MsgHandler, EnvInfo, FetchSuppl, EnvIdent, S3D_GENERAL_INTEROP_INTERF); if(!m_ShaderEnv) return; /*@{ @declare{shader.param}{eng_shader_special.envmap.methods} {$ [str] .. [str]} @}*/ s3d_CUtilSnkExtractUtil::ExtractAtomSortedArray( m_Data->m_MethodArray, m_ShaderEnv->m_AtomMgr, SnkExtract, "methods", true); /*@{ @declare{shader.param}{eng_shader_special.envmap.rank}{$ [int]} See @ref{prog_man.shader.ranks}. @}*/ SnkExtract.ExtractInt( m_Data->m_RankInfo, m_Data->m_Rank, "rank", true); /*@{ @declare{shader.param}{eng_shader_special|envmap.proj_neg_z} {$ [float]} See @ident{comp}{kit_engbase.gfxport}. @}*/ m_Data->m_NegZ = SnkExtract.ExtractFloat("proj_neg_z", true); /*@{ @declare{shader.param}{eng_shader_special|envmap.proj_pos_z} {$ [float]} See @ident{comp}{kit_engbase.gfxport}. @}*/ m_Data->m_PosZ = SnkExtract.ExtractFloat("proj_pos_z", true); /*@{ @declare{shader.param}{eng_shader_special|envmap.max_ext}{$ [int]} Maximal texture width and heigth. @}*/ m_Data->m_MaxExt = SnkExtract.ExtractInt("max_ext", true); /*@{ @declare{shader.param}{eng_shader_special|envmap.ext_dist_scale} {$ [float]} Distance factor. At larger distance a smaller texture is used. If this factor is larger, a larger texture is used also at larger distances. Note that the texture is never larger than @ident{comp}{eng_shader_special|envmap.max_ext}. @}*/ m_Data->m_ExtDistScale = SnkExtract.ExtractFloat("ext_dist_scale", true); /*@{ @declare{shader.param}{eng_shader_special.envmap.max_recursion} {$ [int]} See @ident{comp}{eng_shader_special.opticsdirect.max_recursion}. @}*/ m_Data->m_MaxRecursion = SnkExtract.ExtractInt("max_recursion", true); /*@{ @declare{shader.param}{eng_shader_special.envmap.enum_trigger} {$ [str]} Trigger used for rendering the mirror image. @}*/ m_Data->m_EnumTrigger = s3d_CUtilSnkExtractUtil::ExtractAtom( m_ShaderEnv->m_AtomMgr, SnkExtract, "enum_trigger", true); /*@{ @declare{shader.param}{eng_shader_special.envmap.mesh_var}{$ [str]} @}*/ s3d_CUtilSnkExtractUtil::ExtractAtom( m_Data->m_MeshVarInfo, m_Data->m_MeshVarAtom, m_ShaderEnv->m_AtomMgr, SnkExtract, "mesh_var", true); m_Data->m_DestProp = 0; /*@{ @declare{shader.param} {eng_shader_special.envmap.destprop_antialias}{$ [bool]} Render the main rendering of @ident{comp}{eng_shader_special.envmap.dest_array} with antialiasing. @}*/ if(SnkExtract.ExtractBool("destprop_antialias", true)) m_Data->m_DestProp |= s3d_CDrvGfxEng::DestProp_Antialias; /*@{ @declare{shader.param}{eng_shader_special.envmap.dest_array} {$ [chunk]..[chunk]} See @ident{comp}{}. @}*/ s3d_CUtilSnkChunkArray DestChunkArray; SnkExtract.ExtractChunkArray(DestChunkArray, "dest_array", true); m_Data->m_UpdateAllFace = SnkExtract.ExtractBool("update_all_face", true, true); m_Data->m_WorldSpace = SnkExtract.ExtractBool("world_space", true, false); m_Data->m_UpdateInterval = SnkExtract.ExtractInt("update_interval", true, 1); m_Data->m_StartFrame = SnkExtract.ExtractInt("start_frame", true, 0); s3d_CUtilSnkExtractUtil::ExtractAtom( m_Data->m_LastCenterVarInfo, m_Data->m_LastCenterVarAtom, m_ShaderEnv->m_AtomMgr, SnkExtract, "last_center_var", true); SnkExtract.CheckForUnknown(); int ExtraTexProp = s3d_CDrvGfxEng::TexProp_Cube; int ExtraSampMode = 0; m_Data->m_Dest.Init(m_ShaderEnv, ExtraTexProp, ExtraSampMode, DestChunkArray); } void gtp_Shader_EnvMap::SetupDone() { } s3d_CUtilStr gtp_Shader_EnvMap::GetInfo() { return m_Data->m_Info; } void gtp_Shader_EnvMap::RegisterNotif(s3d_CUtilNotifRecip *Recip) { } s3d_CEngShaderGfxPtr gtp_Shader_EnvMap::FindShaderGfx( s3d_CUtilNotifGather *NotifGather, s3d_CEngGfxCtx *GfxCtx) { if(!m_ShaderEnv) return 0; gtp_Shader_EnvMapGfxPtr ShaderGfx; gtp_Shader_EnvMapGfxTree::CNode *Pos = s3d_UtilTreeSortedGetStart(m_ShaderGfxTree, GfxCtx); if(s3d_UtilTreeIsEqualAt(Pos, GfxCtx)) ShaderGfx = Pos->m_Data.m_Val; else { ShaderGfx = S3D_SYS_NEW gtp_Shader_EnvMapGfx( m_ShaderEnv, GfxCtx, m_Data); gtp_Shader_EnvMapGfxTree::CNode *Node = ShaderGfx->GetNode(); m_ShaderGfxTree.InsertBefore(Pos, Node); } return ShaderGfx.Get(); } /////////////////////////////////////////////////////////////////////////////// gtp_Shader_EnvMapGfx::gtp_Shader_EnvMapGfx( s3d_CEngShaderEnv *ShaderEnv, s3d_CEngGfxCtx *GfxCtx, gtp_Shader_EnvMapData *Data) { m_Node.m_Data.m_Key = GfxCtx; m_Node.m_Data.m_Val = this; m_ShaderEnv = ShaderEnv; m_Data = Data; m_DestGfx.Init(ShaderEnv, GfxCtx); } gtp_Shader_EnvMapGfxTree::CNode *gtp_Shader_EnvMapGfx::GetNode() { return &m_Node; } void gtp_Shader_EnvMapGfx::RegisterNotif( s3d_CUtilNotifRecip *Recip) { } void gtp_Shader_EnvMapGfx::ExtractGfx() { m_Node.Extract(); } bool gtp_Shader_EnvMapGfx::IsValid() { return true; } void gtp_Shader_EnvMapGfx::LinkCollect( s3d_CUtilAtomSet &VarAtomSet) { s3d_CDrvUtilVarUtil::LinkCollect( VarAtomSet, m_Data->m_MeshVarAtom); m_DestGfx.LinkCollect(VarAtomSet, m_Data->m_Dest); s3d_CDrvUtilVarUtil::LinkCollect( VarAtomSet, m_Data->m_LastCenterVarAtom); } void gtp_Shader_EnvMapGfx::LinkAppoint( s3d_CDrvVarDecl *VarDecl) { s3d_CDrvUtilVarUtil::LinkAppoint( m_MeshVarSlot.m_Val, VarDecl, m_Data->m_MeshVarAtom); m_DestGfx.LinkAppoint(VarDecl, m_Data->m_Dest); s3d_CDrvUtilVarUtil::LinkAppoint( m_LastCenterVarSlot.m_Val, VarDecl, m_Data->m_LastCenterVarAtom); } s3d_CEngShaderInstPtr gtp_Shader_EnvMapGfx::CreateShaderInst( s3d_CEngShaderHead *Head) { s3d_CEngGfxCtx *GfxCtx = m_Node.m_Data.m_Key; return S3D_SYS_NEW gtp_Shader_EnvMapInst( m_ShaderEnv, GfxCtx, Head, this); } /////////////////////////////////////////////////////////////////////////////// gtp_Shader_EnvMapInst::gtp_Shader_EnvMapInst( s3d_CEngShaderEnv *ShaderEnv, s3d_CEngGfxCtx *GfxCtx, s3d_CEngShaderHead *Head, gtp_Shader_EnvMapGfx *ShaderGfx) { m_FrameCount = 0; if(ShaderGfx->m_Data->m_UpdateInterval > 0) m_FrameCount = ShaderGfx->m_Data->m_StartFrame % ShaderGfx->m_Data->m_UpdateInterval; m_CurrentFace = 0; m_ShaderEnv = ShaderEnv; m_GfxCtx = GfxCtx; m_Head = Head; m_ShaderGfx = ShaderGfx; m_CanRenderColorAlphaTex = false; if(GfxCtx) { if(s3d_CDrvUtilGfxUtil::HasCap( GfxCtx->m_GfxEng, S3D_DRV_GFX_CAP_RENDER_TEX_COLORALPHA)) m_CanRenderColorAlphaTex = true; } } void gtp_Shader_EnvMapInst::RegisterNotif( s3d_CUtilNotifRecip *Recip) { } void gtp_Shader_EnvMapInst::SetShaderCtx( s3d_CEngShaderCtx *ShaderCtx) { } void gtp_Shader_EnvMapInst::SetGfxState( s3d_CEngGfxState *GfxState) { } void gtp_Shader_EnvMapInst::SetPos(s3d_CEngPos *Pos) { } void gtp_Shader_EnvMapInst::SetModel(s3d_CEngModel *Model) { } void gtp_Shader_EnvMapInst::ArrangeCollect( s3d_CUtilMemPool *MemPool, s3d_CEngShaderScopeArray &ScopeArray) { } void gtp_Shader_EnvMapInst::ArrangeInit( s3d_CUtilMemPool *MemPool, s3d_CEngShaderScopeArray_cr ScopeArray) { s3d_CSysIntps nScope = ScopeArray.GetCnt(); s3d_CSysIntps iScope; for(iScope = 0; iScope < nScope; iScope++) { s3d_CEngShaderScope *Scope = ScopeArray.GetAt(iScope); SetVars(MemPool, Scope); } } void gtp_Shader_EnvMapInst::ArrangePerform( s3d_CUtilMemPool *MemPool, s3d_CEngShaderScopeArray_cr ScopeArray) { } void gtp_Shader_EnvMapInst::ArrangeFeedback( s3d_CUtilMemPool *MemPool, s3d_CEngShaderScopeArray_cr ScopeArray) { } void gtp_Shader_EnvMapInst::ArrangeGather( s3d_CEngShaderExecArray &ExecArray) { gtp_Shader_EnvMapData *Data = m_ShaderGfx->m_Data; s3d_CEngUtilShaderUtil::ArrangeGather( ExecArray, Data->m_MethodArray, this); } void gtp_Shader_EnvMapInst::ShaderExecPerform( s3d_CEngShaderScope *Scope, s3d_CUtilAtom *Method, s3d_CEngGfxTaskArray &TaskArray) { gtp_Shader_EnvMapData *Data = m_ShaderGfx->m_Data; bool doRender = true; if(Data->m_UpdateInterval > 1) { if(m_FrameCount == Data->m_UpdateInterval) m_FrameCount = 0; m_FrameCount++; if(!(m_FrameCount % Data->m_UpdateInterval == 1)) doRender = false; } if(Data->m_UpdateInterval < 0) doRender = false; if(Data->m_UpdateInterval == 0) { Data->m_UpdateInterval = -1; Data->m_UpdateAllFace = true; } int Rank = Data->m_Rank; if(Rank == 0) doRender = false; if(doRender) { s3d_CEngGfxElemJob *GfxElemJob = new(m_ShaderEnv->m_MemPool) s3d_CEngUtilShaderItemJob( Scope, 0, this, >p_Shader_EnvMapInst::GfxElemJobExec); s3d_CEngGfxTaskOrder KeyOrder = 0; s3d_CEngUtilGfxUtil::AppendTask( m_ShaderEnv->m_MemPool, TaskArray, Rank, KeyOrder, GfxElemJob); } SetVars(m_ShaderEnv->m_MemPool, Scope); } void *gtp_Shader_EnvMapInst::GfxElemJobExec( s3d_CEngShaderScope *Scope, void *GfxMark) { gtp_Shader_EnvMapData *Data = m_ShaderGfx->m_Data; if(!Scope) return GfxMark; s3d_CEngGfxPortion *Portion = Scope->m_Portion; if(!Portion) return GfxMark; s3d_CUtilMemPool *MemPool = m_ShaderEnv->m_MemPool; s3d_CEngGfxVarMesh *MeshVar = s3d_EngGfxVarFetchWaryMesh( m_ShaderEnv->m_MsgHandler, Scope->m_Info, Scope->m_VarBlk, m_ShaderGfx->m_MeshVarSlot.m_Val); if(!MeshVar) return GfxMark; s3d_CUtilTranslQuatf ViewTransf = MeshVar->m_Val.m_ViewTransf; s3d_CUtilVec3f BoundCen = MeshVar->m_Val.m_MeshCompos.m_BoundCen; s3d_CUtilVec3f BoundExt = MeshVar->m_Val.m_MeshCompos.m_BoundExt; s3d_CEngUtilShaderDestJob *DestJob = 0; Calc(MemPool, Scope, ViewTransf, BoundCen, BoundExt, DestJob); s3d_CEngUtilShaderDestGfx *DestGfx = &m_ShaderGfx->m_DestGfx; DestGfx->FinishJob(m_ShaderEnv, Scope, Data->m_Dest, DestJob); return 0; } void gtp_Shader_EnvMapInst::Calc( s3d_CUtilMemPool *MemPool, s3d_CEngShaderScope *Scope, s3d_CUtilTranslQuatf_cr ViewTransf, s3d_CUtilVec3f_cr BoundCen, s3d_CUtilVec3f_cr BoundExt, s3d_CEngUtilShaderDestJob *&DestJob) { DestJob = 0; gtp_Shader_EnvMapData *Data = m_ShaderGfx->m_Data; s3d_CEngUtilShaderDestGfx *DestGfx = &m_ShaderGfx->m_DestGfx; s3d_CEngGfxPortion *Portion = Scope->m_Portion; if(!Portion) return; s3d_CEngGfxCycle *Cycle = Portion->m_Cycle; if(!Cycle) return; s3d_CEngGfxRun *Run = Cycle->m_Run; if(!Run) return; s3d_CDrvGfxEng *GfxEng = Run->m_GfxEng; if(!GfxEng) return; s3d_CEngGfxPort *Port = s3d_UtilRecogCastCheck( m_ShaderEnv->m_MsgHandler, Data->m_RankInfo, Portion->m_Port); if(!Port) return; if(!m_CanRenderColorAlphaTex) return; s3d_CEngGfxCam *Cam = &Portion->m_Cam; if(Data->m_WorldSpace) m_LastCenter = s3d_CUtilVec4f(Cam->m_Transf.ApplyToPoint( ViewTransf.ApplyToPoint(BoundCen)),1); else m_LastCenter = s3d_CUtilVec4f(ViewTransf.ApplyToPoint(BoundCen),1); // Check if rendering into texture is possible: if(!s3d_CEngUtilGfxUtil::VerifyGfxClosed( m_ShaderEnv->m_MsgHandler, Data->m_RankInfo.GetChars(), Portion->m_Cycle)) { Data->m_Rank = 0; // Avoid the error being reported each frame return; } // Check recursion level: if(Cam->m_Recursion >= Data->m_MaxRecursion) return; // Calculate texture size: float EffWidth = Cam->m_TotWidth * Cam->m_ViewPane.m_Scale.m_x; float EffHeight = Cam->m_TotHeight * Cam->m_ViewPane.m_Scale.m_y; float CamExt = s3d_SysMax(EffWidth, EffHeight); float Dist = ViewTransf.m_Transl.GetLen(); int RawTexExt = s3d_SysIntOfFloatNearest( Data->m_ExtDistScale * CamExt / Dist); int WantTexExt = gtp_ShaderOpticsUtil::RoundToPowerOfTwoUp( RawTexExt); if(WantTexExt > Data->m_MaxExt) WantTexExt = Data->m_MaxExt; int TexProp = 0; if(!DestGfx->GetSnapTexPropWidthHeight( m_ShaderEnv, Scope, Data->m_Dest, WantTexExt, WantTexExt, TexProp)) return; int TexWidth = WantTexExt; int TexHeight = WantTexExt; int TexDepth = 1; int TexSnap = s3d_CDrvGfxEng::TexSnap_PreferUp; GfxEng->SnapTexSize(TexWidth, TexHeight, TexDepth, TexProp, TexSnap); ///////////////// // Allocate texture: DestJob = DestGfx->CreateJob( m_ShaderEnv, Scope, Data->m_Dest, TexWidth, TexHeight); if(!DestJob) return; static const int CubeFaceMap[] = { s3d_CDrvGfxEng::TexPart_CubePosX, s3d_CDrvGfxEng::TexPart_CubeNegX, s3d_CDrvGfxEng::TexPart_CubePosY, s3d_CDrvGfxEng::TexPart_CubeNegY, s3d_CDrvGfxEng::TexPart_CubePosZ, s3d_CDrvGfxEng::TexPart_CubeNegZ, }; static const s3d_CUtilVec3f ViewDirMap[] = { s3d_CUtilVec3f( 1.f, 0.f, 0.f), s3d_CUtilVec3f(-1.f, 0.f, 0.f), s3d_CUtilVec3f( 0.f, 1.f, 0.f), s3d_CUtilVec3f( 0.f, -1.f, 0.f), s3d_CUtilVec3f( 0.f, 0.f, 1.f), s3d_CUtilVec3f( 0.f, 0.f, -1.f), }; static const s3d_CUtilVec3f AlsoFromMap[] = { s3d_CUtilVec3f( 1.f, 0.f, 0.f), s3d_CUtilVec3f( 1.f, 0.f, 0.f), s3d_CUtilVec3f( 0.f, 1.f, 0.f), s3d_CUtilVec3f( 0.f, 1.f, 0.f), s3d_CUtilVec3f( 1.f, 0.f, 0.f), s3d_CUtilVec3f( 1.f, 0.f, 0.f), }; static const s3d_CUtilVec3f AlsoToMap[] = { s3d_CUtilVec3f( 0.f, 0.f, -1.f), s3d_CUtilVec3f( 0.f, 0.f, 1.f), s3d_CUtilVec3f( 0.f, 0.f, -1.f), s3d_CUtilVec3f( 0.f, 0.f, 1.f), s3d_CUtilVec3f( 1.f, 0.f, 0.f), s3d_CUtilVec3f( -1.f, 0.f, 0.f), }; // Camera: s3d_CEngGfxCam ChildCam(*Cam); ChildCam.m_ViewPane = 1; ChildCam.m_ViewDepthStart = 0; ChildCam.m_ViewDepthEnd = 1; ChildCam.m_TotWidth = TexWidth; ChildCam.m_TotHeight = TexHeight; ChildCam.m_Proj = s3d_CEngUtilMathUtil::CalcProjStd( false, 1, -1, 0, 0, Data->m_NegZ, Data->m_PosZ); ChildCam.m_Reverse = true; ChildCam.m_Recursion = ChildCam.m_Recursion + 1; // Move record cam to object center s3d_CUtilTranslQuatf TranslQuat = Cam->m_Transf.Concat(ViewTransf); ChildCam.m_Transf.m_Transl = TranslQuat.m_Transl; ChildCam.m_BasePoint = ChildCam.m_Transf.m_Transl; ChildCam.m_VisibPoint = ChildCam.m_BasePoint; ChildCam.m_Exclude = m_Head; // Rendering: s3d_CDrvGfxDest *Dest = DestJob->m_DrvGfxDestArray.GetPtrRaw(); s3d_CSysIntps nDestTex = DestJob->m_DrvGfxDestArray.GetCnt(); s3d_CEngUtilGfxBeginTex *GfxBegin = new(m_ShaderEnv->m_MemPool) s3d_CEngUtilGfxBeginTex( GfxEng, TexWidth, TexHeight, nDestTex, Dest, 1); const s3d_CUtilVec3f CamDir(0, 0, 1); s3d_CUtilQuatf BaseQuat; if(!Data->m_WorldSpace) BaseQuat = Cam->m_Transf.m_Quat; else BaseQuat = s3d_CUtilQuatf(1,0,0,1); s3d_CEngGfxTaskArray ChildTaskArray; int iFace; //framecount++; //framecount = framecount % 6; //iFace = framecount; for(iFace = 0; iFace < 6; iFace++) { if(!Data->m_UpdateAllFace) { iFace = m_CurrentFace; m_CurrentFace = (++m_CurrentFace) % 6; } s3d_CSysIntps iDestTex = 0; for(iDestTex = 0; iDestTex < nDestTex; iDestTex++) Dest[iDestTex].m_Part = CubeFaceMap[iFace]; s3d_CUtilQuatf EffQuat; if(Data->m_WorldSpace) EffQuat = s3d_CUtilQuatf::ByPathAlso( CamDir, ViewDirMap[iFace], AlsoFromMap[iFace], AlsoToMap[iFace]); else EffQuat = BaseQuat * s3d_CUtilQuatf::ByPathAlso( CamDir, ViewDirMap[iFace], AlsoFromMap[iFace], AlsoToMap[iFace]); ChildCam.m_Transf.m_Quat = EffQuat; s3d_CEngGfxCycle *ChildCycle = Port->CollectNewCycle( Run, ChildCam, Data->m_EnumTrigger, ChildTaskArray); s3d_CEngUtilGfxElemJobBegin::AddGfxBegin( m_ShaderEnv->m_MsgHandler, Data->m_RankInfo.GetChars(), ChildCycle, Data->m_DestProp, ChildCam.m_ClearParam, ChildTaskArray, GfxBegin); s3d_CEngUtilGfxUtil::PerformChild( Cycle, ChildCycle, ChildTaskArray); s3d_CEngUtilGfxUtil::CloseGfxTex( m_ShaderEnv->m_MsgHandler, Data->m_RankInfo.GetChars(), Cycle, GfxBegin); ChildTaskArray.Clear(); if(!Data->m_UpdateAllFace) break; } ChildTaskArray.Reset(); } void gtp_Shader_EnvMapInst::SetVars( s3d_CUtilMemPool *MemPool, s3d_CEngShaderScope *Scope) { gtp_Shader_EnvMapData *Data = m_ShaderGfx->m_Data; s3d_CDrvVarSlot LastCenterVarSlot = m_ShaderGfx->m_LastCenterVarSlot; if(LastCenterVarSlot >= 0) { s3d_CDrvVarVec4f *ValVar = new(MemPool) s3d_CDrvVarVec4f; ValVar->m_Val = m_LastCenter; s3d_DrvVarSet(Scope->m_VarBlk, LastCenterVarSlot, ValVar); } } ///////////////////////////////////////////////////////////////////////////////