#include "stdafx.h" #include "RTView.h" //#include "RCKRenderContext.h" #include "CKRasterizer.h" #define RENDERSCENE_GUID CKGUID(0x3f3c5b66,0x2ab81a45) //----------------------------------------------------------------------------- // Input parameters enum { PARAM_VIEW = 0, PARAM_RENDEROPTIONS, PARAM_BGCOLOR, PARAM_BGTEXTURE, PARAM_CAMERA, PARAM_FACEBYFACE, PARAM_UPDATESYSTEMMEMORY, PARAM_OVERIDINGMATERIAL, PARAM_ORIENTATIONREFERENTIAL, PARAM_OVERRIDETECHNIQUE, PARAM_TECHNIQUENAME }; //----------------------------------------------------------------------------- // Settings enum { PARAM_HOMOGENEOUSVIEW = 0, PARAM_RTCOUNT, PARAM_COUNT_PIXELS_USING_OCCLUSION_QUERY, }; //----------------------------------------------------------------------------- // Output parameters enum { PARAM_PIXELCOUNT = 0 }; #define MAXRT_COUNT 4 //----------------------------------------------------------------------------- void ConvertToFullSizeIfInvalid( RTView& rtview, CKRenderContext* rc=NULL, BOOL homogen=FALSE ); void ComputeViewRectFromCameraRatio( VxRect& oViewRect, CKCamera& iCam, VxRect& iWindowRect ); int GetCurrentRTCount( CKBehavior* beh ) { int viewCount=1; while( 1 ){ CKParameterIn* pin = beh->GetInputParameter( PARAM_VIEW + viewCount ); if( !pin || pin->GetGUID()!=CKPGUID_TEXTURE ) break; ++viewCount; } return viewCount; } static inline int AddSat(int lhs, int rhs) { if ((CKDWORD) lhs > 0x7ffffff) lhs = 0x7ffffff; if ((CKDWORD) rhs > 0x7ffffff) lhs = 0x7ffffff; return (rhs + lhs) < rhs ? 0x7fffffff : (rhs + lhs); } /***********************************************/ // MAIN /***********************************************/ int RenderScene(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; //--- Get Previous View Count int decal = GetCurrentRTCount( beh )-1; beh->ActivateInput(0, FALSE); beh->ActivateOutput(0); CKParameterIn* pin = beh->GetInputParameter( PARAM_VIEW ); if( !pin || !pin->GetRealSource() ) return CKBR_PARAMETERERROR; //--- Read Final RT View RTView rtview( pin->GetRealSource() ); // If no texture given, render in current backbuffer //--- Check if user want to see texture in system memory CKBOOL updateSystem = FALSE; beh->GetInputParameterValue(decal+PARAM_UPDATESYSTEMMEMORY, &updateSystem ); //--- Force upload to video memory CKRenderContext* rc = behcontext.CurrentRenderContext; if (rtview.tex) { rtview.tex->EnsureVideoMemory(rc); } int pixelCount = 0; CKBOOL countPixels = FALSE; // TMP TMP : for next version only //beh->GetLocalParameterValue(PARAM_COUNT_PIXELS_USING_OCCLUSION_QUERY, &countPixels); //--- View Rect is homogeneous ? BOOL homogen = FALSE; beh->GetLocalParameterValue( PARAM_HOMOGENEOUSVIEW, &homogen ); //--- Get Wanted Render Options CKDWORD prevropt = rc->GetCurrentRenderOptions(); CKDWORD ropt = prevropt; beh->GetInputParameterValue(decal+PARAM_RENDEROPTIONS, &ropt ); //--- Check Rect size CKCamera* oldCam = rc->GetAttachedCamera(); if( ropt&CK_RENDER_USECAMERARATIO ){ homogen = TRUE; VxRect texRect( 0, 0, 256, 256 ); if( rtview.tex ) { texRect.SetCorners( 0.0f, 0.0f, (float)rtview.tex->GetWidth(), (float)rtview.tex->GetHeight() ); } else { texRect.SetCorners( 0.0f, 0.0f, (float)rc->GetWidth(), (float)rc->GetHeight() ); } ComputeViewRectFromCameraRatio( rtview.rect, *oldCam, texRect ); } ConvertToFullSizeIfInvalid( rtview, rc, homogen ); //--- Remove present command ropt &= ~CK_RENDER_DOBACKTOFRONT; //--- Set Render Target and View Rect VxRect oldRect; rc->GetViewRect( oldRect ); VxMatrix oldViewMat; oldViewMat = rc->GetViewTransformationMatrix(); int currentRTCount = GetCurrentRTCount(beh); if (currentRTCount > 1) { // special case : OpenGL + multisampling + MRT -> slow downs on nVidia quadro FX, plus some output color are missed. // Can be solved by forcing an offscreen multisampled buffer, though. (not very elegant, but better than incorrect rendering) CKRST_RSTFAMILY driverFamily = rc->GetRasterizerContext()->m_Driver->m_2DCaps.Family; if (driverFamily == CKRST_OPENGL) { if (rc->GetRasterizerContext()->m_Antialias > 0) { behcontext.Context->GetVariableManager()->SetValue("CK2_3D/OffscreenMultiSampledBuffer", 1); } } } CKRenderContext* rrc = rc; CKTexture* leftEye = rtview.tex; CKTexture* rightEye = rtview.tex ? rrc->GetStereoTextureRightEye(rtview.tex) : NULL; CKBOOL stereo = (currentRTCount == 1 && leftEye && rightEye); if(!stereo && rtview.tex && !rtview.tex->IsCubeMap() ){ rc->SetRenderTarget( rtview.tex ); if(currentRTCount>1){ int rtIndex = 1; for(int i=PARAM_VIEW+1;iGetInputParameterObject(i); rc->SetRenderTarget(tex, rtIndex++); } } } rc->SetViewRect( rtview.rect ); //--- Get Desired camera CKCamera* cam = (CKCamera*)beh->GetInputParameterObject(decal+ PARAM_CAMERA ); if( !cam ){ if( oldCam ){ cam = oldCam; } else { rc->GetCKContext()->OutputToConsole("Render Scene In RTView BB: There is no camera attached to the Render Context"); return CKBR_GENERICERROR; } } DWORD prevCamFlag = cam->GetFlags(); //--- Prevent AttachViewpointToCamera() to override our nice ViewRect cam->SetFlags(prevCamFlag & ~CK_3DENTITY_CAMERAIGNOREASPECT); rc->AttachViewpointToCamera( cam ); cam->SetFlags(prevCamFlag); //--- Set Background Material's Texture And Color CKMaterial* bgMat = rc->GetBackgroundMaterial(); VxColor oldBgColor = bgMat->GetDiffuse(); VxColor bgColor(0,0,0,0); beh->GetInputParameterValue(decal+PARAM_BGCOLOR, &bgColor ); bgMat->SetDiffuse( bgColor ); CKTexture* oldBgTex = bgMat->GetTexture(); CKTexture* bgTex = (CKTexture*)beh->GetInputParameterObject(decal+PARAM_BGTEXTURE ); bgMat->SetTexture( bgTex ); //--- Get Overiding Material CKMaterial* overidingMaterial = (CKMaterial*)beh->GetInputParameterObject(decal+PARAM_OVERIDINGMATERIAL ); CKBOOL overrideTechnique = FALSE; beh->GetInputParameterValue(PARAM_OVERRIDETECHNIQUE, &overrideTechnique); if (overrideTechnique) { rc->SetOverriddenRendering( CK_OVERRIDE_TECHNIQUE, overidingMaterial, (const char*) beh->GetInputParameterReadDataPtr(PARAM_TECHNIQUENAME)); } else { if( overidingMaterial ) rc->SetOverriddenRendering( CK_OVERRIDE_MATERIAL, overidingMaterial ); } CK3dEntity* orientRef = (CK3dEntity*)beh->GetInputParameterObject( decal+PARAM_ORIENTATIONREFERENTIAL ); CK_RENDER_FLAGS oldRopt = (CK_RENDER_FLAGS) rc->GetCurrentRenderOptions(); rc->SetCurrentRenderOptions(ropt); //--- If Render Target is a Cube Map if(rtview.tex && rtview.tex->IsCubeMap() ){ //--- Compute the 6 Rotation Matrices VxMatrix Rotation[6]= {VxMatrix::Identity(),VxMatrix::Identity(),VxMatrix::Identity() ,VxMatrix::Identity(),VxMatrix::Identity(),VxMatrix::Identity() }; //----- Referential directed to X axis Rotation[0][0].Set(0.0f ,0.0f ,-1.0f ,0.0f); Rotation[0][2].Set(1.0f ,0.0f , 0.0f ,0.0f); //----- Referential directed to -X axis Rotation[1][0].Set(0.0f ,0.0f , 1.0f ,0.0f); Rotation[1][2].Set(-1.0f,0.0f , 0.0f ,0.0f); //----- Referential directed to Y axis Rotation[2][1].Set(0.0f ,0.0f ,-1.0f ,0.0f); Rotation[2][2].Set(0.0f, 1.0f , 0.0f ,0.0f); //----- Referential directed to -Y axis Rotation[3][1].Set(0.0f ,0.0f , 1.0f ,0.0f); Rotation[3][2].Set(0.0f,-1.0f , 0.0f ,0.0f); //----- Referential directed to Z axis //----- Referential directed to -Z axis Rotation[5][0].Set(-1.0f,0.0f , 0.0f ,0.0f); Rotation[5][2].Set( 0.0f,0.0f ,-1.0f ,0.0f); BOOL RenderFaceByFace = FALSE; beh->GetInputParameterValue(decal+PARAM_FACEBYFACE, &RenderFaceByFace ); //--- Storing Previous Camera Fov / Aspect Ratio / Target float oldFov = cam->GetFov(); int asx,asy; cam->GetAspectRatio( asx, asy ); CK3dEntity* oldTargetCam = cam->GetTarget(); //--- Setting Camera Fov / Aspect Ratio adapted for CubeMap generation cam->SetFov( PI/2.0f ); cam->SetAspectRatio( 1, 1 ); cam->SetTarget( NULL ); //--- Storing Previous Camera World Matrix VxMatrix OldCamMat = cam->GetWorldMatrix(); VxMatrix OrientRefMat; if (orientRef) OrientRefMat = orientRef->GetWorldMatrix(); VxVector Pos = OldCamMat[3]; // Special case : OpenGL + multisampling + Render into cubemap -> unsupported by FBO of some nVidia GPUs for that combination CKBOOL skipRender = FALSE; CKRST_RSTFAMILY driverFamily = rc->GetRasterizerContext()->m_Driver->m_2DCaps.Family; if (driverFamily == CKRST_OPENGL) { if (rc->GetRasterizerContext()->m_Antialias > 0) { behcontext.Context->GetVariableManager()->SetValue("CK2_3D/OffscreenMultiSampledBuffer", 1); // don't do the render right now (the device will be recreated) skipRender = TRUE; // don't want to trigger an error ... } } if (!skipRender) { //--- Render Face by Face ? if( RenderFaceByFace ){ int Current = rtview.tex->GetCurrentSlot(); //--- Set Camera's Orientation adapted for CubeMap if( orientRef ) Rotation[Current] = OrientRefMat * Rotation[Current]; Rotation[Current][3] = Pos; cam->SetWorldMatrix( Rotation[Current] ); if( rc->SetRenderTarget(rtview.tex,Current) ){ //--- Render scene and update to system memory if needed rc->Render((CK_RENDER_FLAGS)ropt); if( updateSystem ) rtview.tex->VideoToSystemMemory(); } //--- Increment CubeMap Slot rtview.tex->SetCurrentSlot((Current+1)%6); //--- Otherwise Render All Faces At Once } else { for( int a=0 ; a<6 ; ++a ){ //--- Set Camera's Orientation adapted for CubeMap if( orientRef ) Rotation[a] = OrientRefMat * Rotation[a]; Rotation[a][3] = Pos; cam->SetWorldMatrix( Rotation[a] ); if( rc->SetRenderTarget(rtview.tex,a) ) { if (countPixels) { rc->GetRasterizerContext()->BeginOcclusionQuery(); } //--- Render scene and update to system memory if needed rc->Render((CK_RENDER_FLAGS)ropt); if (countPixels) { pixelCount = AddSat(pixelCount, rc->GetRasterizerContext()->WaitOcclusionQueryResult()); } if( updateSystem ) rtview.tex->VideoToSystemMemory(); //--- Restore rendering to default rc->SetRenderTarget(NULL); } } } } //--- Restore Camera cam->SetWorldMatrix( OldCamMat ); cam->SetFov( oldFov ); cam->SetAspectRatio( asx, asy ); cam->SetTarget( oldTargetCam ); //--- If Render Target is not a Cube Map } else { //--- Render scene and update to system memory if needed if (countPixels) { rc->GetRasterizerContext()->BeginOcclusionQuery(); } //--- Render scene and update to system memory if needed CKBOOL rightEyeRendered = FALSE; if (stereo) { // it is a stereo texture -> render both eyes if (rc->GetRasterizerContext()->m_Driver->m_Stereo || behcontext.Context->WillRenderBothStereoEyes()) { rrc->_MatchStereoTextureRightToLeft(*leftEye, *rightEye); // render both eyes CKRenderContext::CK_STEREO_MODE oldStereoMode = rrc->GetStereoRenderMode(); rrc->SetRenderTarget(leftEye); rc->SetViewRect( rtview.rect ); rrc->SetStereoRenderMode(CKRenderContext::CK_STEREO_LEFT); rrc->Render( (CK_RENDER_FLAGS)ropt ); rrc->SetRenderTarget( NULL ); if (!rightEye->IsInVideoMemory()) { rightEye->EnsureVideoMemory(rc); } rrc->SetRenderTarget(rightEye); rc->SetViewRect( rtview.rect ); rrc->SetStereoRenderMode(CKRenderContext::CK_STEREO_RIGHT); rrc->Render( (CK_RENDER_FLAGS)ropt ); rrc->SetStereoRenderMode(oldStereoMode); rightEyeRendered = TRUE; } else { // use wanted eye rrc->SetRenderTarget(rrc->GetStereoRenderMode() == CKRenderContext::CK_STEREO_RIGHT ? rightEye : leftEye); rrc->Render( (CK_RENDER_FLAGS)ropt ); if (rrc->GetStereoRenderMode() == CKRenderContext::CK_STEREO_RIGHT) { rightEyeRendered = TRUE; } } } else { // bugfix : force non-stereo rendering for non stereo textures (always ...) // (unless we are rendering to the main frame buffer -> must retain current stereo settings in this case) CKRenderContext::CK_STEREO_MODE oldStereoMode = rrc->GetStereoRenderMode(); if (oldStereoMode != CKRenderContext::CK_STEREO_DEFAULT && rtview.tex != NULL) { rrc->SetStereoRenderMode(CKRenderContext::CK_STEREO_DEFAULT); rrc->Render( (CK_RENDER_FLAGS)ropt ); rrc->SetStereoRenderMode(oldStereoMode); } else { // simple render rrc->Render( (CK_RENDER_FLAGS)ropt ); } } if( rtview.tex && updateSystem ) { int oldSlot = rtview.tex->GetCurrentSlot(); if (stereo) { // Nicov : force use of slot 0 (slot 0 <- left, slot 1 <- right) rtview.tex->SetCurrentSlot(0); } rtview.tex->VideoToSystemMemory(); if (stereo) { rtview.tex->SetCurrentSlot(oldSlot); } } if (updateSystem && rightEyeRendered) { if (leftEye->GetWidth() > 0 && leftEye->GetHeight() > 0) { XASSERT(rightEye); if (leftEye->GetSlotCount() < 2) { leftEye->SetSlotCount(2); leftEye->CreateImage(leftEye->GetWidth(), leftEye->GetHeight(), 32, 1, NULL); } leftEye->VideoToSlotSystemMemory(*rightEye, 1); } } if (countPixels) { pixelCount = AddSat(pixelCount, rc->GetRasterizerContext()->WaitOcclusionQueryResult()); } } rc->SetCurrentRenderOptions(oldRopt); //--- Restore stuff if(overrideTechnique || overidingMaterial) { rc->SetOverriddenRendering( CK_OVERRIDE_NONE ); } if( oldCam ) rc->AttachViewpointToCamera( oldCam ); CKDWORD version = beh->GetVersion(); if (version >= 0x00020000) rc->SetViewTransformationMatrix(oldViewMat); rc->ForceCameraSettingsUpdate(); bgMat->SetDiffuse( oldBgColor ); bgMat->SetTexture( oldBgTex ); if (rtview.tex) { rc->SetRenderTarget( NULL ); if(currentRTCount>1){ int rtIndex = 0; /* for(int i=1;iSetRenderTarget(NULL,i); } */ for(int i=currentRTCount - 1;i>= 1;i--){ rc->SetRenderTarget(NULL,i); } } rc->SetViewRect( oldRect ); } // TMP TMP // For next version only //beh->SetOutputParameterValue(PARAM_PIXELCOUNT, &pixelCount); return CKBR_OK; } /*************************************************************************/ // Call Back /*************************************************************************/ CKERROR RenderSceneCallback(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; switch( behcontext.CallbackMessage ){ case CKM_BEHAVIORLOAD: { // TMP TMP : for next version /* if(!beh->GetOutputParameter(PARAM_PIXELCOUNT)) { beh->CreateOutputParameter("Pixel count", PARAM_PIXELCOUNT); int pixelCount = 0; beh->SetOutputParameterValue(PARAM_PIXELCOUNT, &pixelCount); } */ if(beh->GetOutputParameter(PARAM_PIXELCOUNT)) { // remove for safety, until next version beh->EnableOutputParameter(PARAM_PIXELCOUNT, FALSE); } // TMP TMP : for next version /* if(!beh->GetLocalParameter(PARAM_COUNT_PIXELS_USING_OCCLUSION_QUERY)) { beh->CreateLocalParameter("Count pixels using occlusion query", CKPGUID_BOOL); CKBOOL disabled = FALSE; beh->SetLocalParameterValue(PARAM_COUNT_PIXELS_USING_OCCLUSION_QUERY, &disabled); } */ if(!beh->GetInputParameter(PARAM_BGTEXTURE)) { beh->CreateInputParameter("Background Texture", CKPGUID_TEXTURE); } if(!beh->GetInputParameter(PARAM_CAMERA)) { beh->CreateInputParameter("Camera", CKPGUID_CAMERA); } if(!beh->GetInputParameter(PARAM_FACEBYFACE)) { beh->CreateInputParameter("(CubeMap) Render Face by Face", CKPGUID_BOOL); /*BOOL vFalse = FALSE; beh->SetInputParameterValue(PARAM_FACEBYFACE, &vFalse);*/ } if(!beh->GetInputParameter(PARAM_UPDATESYSTEMMEMORY)) { beh->CreateInputParameter("Update System Memory", CKPGUID_BOOL); /*BOOL vFalse = FALSE; beh->SetInputParameterValue(PARAM_UPDATESYSTEMMEMORY, &vFalse);*/ } if(!beh->GetInputParameter(PARAM_OVERIDINGMATERIAL)) { beh->CreateInputParameter("Overiding Material", CKPGUID_MATERIAL); } if(!beh->GetInputParameter(PARAM_ORIENTATIONREFERENTIAL)) { beh->CreateInputParameter("Orientation Referential", CKPGUID_3DENTITY); } if(!beh->GetLocalParameter(PARAM_HOMOGENEOUSVIEW)) { beh->CreateLocalParameter("Viewport is Homogeneous", CKPGUID_BOOL); } else { // old version : first setting was false if (strcmp(beh->GetLocalParameter(PARAM_HOMOGENEOUSVIEW)->GetName(), "Render Target Count") == 0) { CKParameterManager* pMgr = behcontext.Context->GetParameterManager(); if (pMgr) { beh->GetLocalParameter(PARAM_HOMOGENEOUSVIEW)->SetName("Viewport is Homogeneous"); beh->GetLocalParameter(PARAM_HOMOGENEOUSVIEW)->SetType(pMgr->ParameterGuidToType(CKPGUID_BOOL)); CKBOOL vFalse = FALSE; beh->GetLocalParameter(PARAM_HOMOGENEOUSVIEW)->SetValue(&vFalse); } } } if(!beh->GetLocalParameter(PARAM_RTCOUNT)) { beh->CreateLocalParameter("Render Target Count",CKPGUID_INT); int one = 1; beh->SetLocalParameterValue(PARAM_RTCOUNT,&one); } if(!beh->GetInputParameter(PARAM_OVERRIDETECHNIQUE)) { beh->CreateInputParameter("Override Shader Technique",CKPGUID_BOOL); //CKBOOL value = FALSE; //beh->SetLocalParameterValue(PARAM_RTCOUNT, &value); } if(!beh->GetInputParameter(PARAM_TECHNIQUENAME)) { beh->CreateInputParameter("Override Technique Name",CKPGUID_STRING); } } break; case CKM_BEHAVIORSETTINGSEDITED: { //--- Get Wanted View Count int wantedRTCount = 1; beh->GetLocalParameterValue( PARAM_RTCOUNT, &wantedRTCount ); //--- Get Previous View Count int currentRTCount = GetCurrentRTCount( beh ); if( currentRTCount != wantedRTCount ){ //--- Limit View Count if( wantedRTCount<1 ) wantedRTCount = 1; if( wantedRTCount>MAXRT_COUNT ) wantedRTCount = MAXRT_COUNT; beh->SetLocalParameterValue( PARAM_RTCOUNT, &wantedRTCount ); //--- Destroy pIns beyond "View Current" for(int i=1;iGetInputParameter(i); if(pin->GetGUID() == CKPGUID_TEXTURE) if(i>=wantedRTCount) CKDestroyObject( beh->RemoveInputParameter(i) ); else i++; else break; } //--- Create missing view pIns char pInName[8]; for( int a=currentRTCount ; aInsertInputParameter(PARAM_VIEW+a,behcontext.Context->CreateCKParameterIn(pInName, CKPGUID_TEXTURE)); } } } break; } return CKBR_OK; } /***********************************************/ // PROTO /***********************************************/ CKERROR CreateRenderSceneProto(CKBehaviorPrototype **pproto) { CKBehaviorPrototype *proto = CreateCKBehaviorPrototype("Render Scene In RT View"); if(!proto) return CKERR_OUTOFMEMORY; proto->DeclareInput("In"); proto->DeclareOutput("Out"); proto->DeclareInParameter("Target View", CKPGUID_RTVIEW); proto->DeclareInParameter("Render Options", CKPGUID_RENDEROPTIONS, "Background Sprites,Clear ZBuffer,Clear Stencil Buffer,Clear Back Buffer"); proto->DeclareInParameter("Background Color", CKPGUID_COLOR); proto->DeclareInParameter("Background Texture", CKPGUID_TEXTURE); proto->DeclareInParameter("Camera", CKPGUID_CAMERA ); proto->DeclareInParameter("(CubeMap) Render Face by Face",CKPGUID_BOOL,"FALSE"); proto->DeclareInParameter("Update System Memory",CKPGUID_BOOL,"FALSE"); proto->DeclareInParameter("Overiding Material",CKPGUID_MATERIAL); proto->DeclareInParameter("Orientation Referential",CKPGUID_3DENTITY); proto->DeclareInParameter("Override Shader Technique",CKPGUID_BOOL); proto->DeclareInParameter("Override Technique Name",CKPGUID_STRING); // TMP : for next version only // proto->DeclareOutParameter("Pixel count", CKPGUID_INT, "0"); proto->DeclareSetting("Viewport is Homogeneous",CKPGUID_BOOL, "FALSE"); proto->DeclareSetting("Render Target Count",CKPGUID_INT, "1"); // TMP : for next version only //proto->DeclareSetting("Count pixels using occlusion query", CKPGUID_BOOL, "FALSE"); proto->SetFlags(CK_BEHAVIORPROTOTYPE_NORMAL); proto->SetFunction(RenderScene); proto->SetBehaviorCallbackFct( RenderSceneCallback,CKCB_BEHAVIORLOAD | CKCB_BEHAVIORSETTINGSEDITED); *pproto = proto; return CK_OK; } /***********************************************/ // DECLARATION /***********************************************/ CKObjectDeclaration *FillBehaviorRenderScene() { CKObjectDeclaration *od = CreateCKObjectDeclaration("Render Scene In RT View"); od->SetDescription("Renders the scene into a RenderTarget View"); od->SetCategory("Shaders/Rendering"); od->SetType(CKDLL_BEHAVIORPROTOTYPE); od->SetGuid(RENDERSCENE_GUID); od->SetAuthorGuid(VIRTOOLS_GUID); od->SetAuthorName("Virtools"); od->SetVersion(0x00020000); od->SetCreationFunction(CreateRenderSceneProto); od->SetCompatibleClassId(CKCID_BEOBJECT); return od; }