void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ ) { GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_attachTexture_Cubemap, ColorI::RED ); AssertFatal(slot < MaxRenderSlotId, "GFXD3D11TextureTarget::attachTexture - out of range slot."); // Mark state as dirty so device can know to update. invalidateState(); // Release what we had, it's definitely going to change. SAFE_RELEASE(mTargetViews[slot]); SAFE_RELEASE(mTargets[slot]); SAFE_RELEASE(mTargetSRViews[slot]); mResolveTargets[slot] = NULL; // Cast the texture object to D3D... AssertFatal(!tex || static_cast<GFXD3D11Cubemap*>(tex), "GFXD3DTextureTarget::attachTexture - invalid cubemap object."); if(slot == Color0) { mTargetSize = Point2I::Zero; mTargetFormat = GFXFormatR8G8B8A8; } // Are we clearing? if(!tex) { // Yup - just exit, it'll stay NULL. return; } GFXD3D11Cubemap *cube = static_cast<GFXD3D11Cubemap*>(tex); mTargets[slot] = cube->get2DTex(); mTargets[slot]->AddRef(); mTargetViews[slot] = cube->getRTView(face); mTargetViews[slot]->AddRef(); mTargetSRViews[slot] = cube->getSRView(); mTargetSRViews[slot]->AddRef(); // Update surface size if(slot == Color0) { ID3D11Texture2D *surface = mTargets[Color0]; if ( surface ) { D3D11_TEXTURE2D_DESC sd; surface->GetDesc(&sd); mTargetSize = Point2I(sd.Width, sd.Height); S32 format = sd.Format; GFXREVERSE_LOOKUP( GFXD3D11TextureFormat, GFXFormat, format ); mTargetFormat = (GFXFormat)format; } } }
void GFXD3D11WindowTarget::resolveTo(GFXTextureObject *tex) { GFXDEBUGEVENT_SCOPE(GFXPCD3D11WindowTarget_resolveTo, ColorI::RED); D3D11_TEXTURE2D_DESC desc; ID3D11Texture2D* surf = ((GFXD3D11TextureObject*)(tex))->get2DTex(); surf->GetDesc(&desc); D3D11DEVICECONTEXT->ResolveSubresource(surf, 0, D3D11->mDeviceBackbuffer, 0, desc.Format); }
void GFXD3D11TextureTarget::resolveTo( GFXTextureObject *tex ) { GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_resolveTo, ColorI::RED ); if ( mTargets[Color0] == NULL ) return; D3D11_TEXTURE2D_DESC desc; mTargets[Color0]->GetDesc(&desc); D3D11DEVICECONTEXT->CopySubresourceRegion(((GFXD3D11TextureObject*)(tex))->get2DTex(), 0, 0, 0, 0, mTargets[Color0], 0, NULL); }
void SkyBox::_renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi ) { GFXDEBUGEVENT_SCOPE( SkyBox_RenderObject, ColorF::WHITE ); GFXTransformSaver saver; GFX->setVertexBuffer( mVB ); MatrixF worldMat = MatrixF::Identity; worldMat.setPosition( state->getCameraPosition() ); SceneData sgData; sgData.init( state ); sgData.objTrans = &worldMat; mMatrixSet->restoreSceneViewProjection(); mMatrixSet->setWorld( worldMat ); if ( state->isReflectPass() ) mMatrixSet->setProjection( state->getSceneManager()->getNonClipProjection() ); while ( mMatInstance->setupPass( state, sgData ) ) { mMatInstance->setTransforms( *mMatrixSet, state ); mMatInstance->setSceneInfo( state, sgData ); GFX->drawPrimitive( GFXTriangleList, 0, mPrimCount ); } // Draw render band. if ( mFogBandHeight > 0 && mFogBandMatInst ) { const FogData &fog = state->getSceneManager()->getFogData(); if ( mLastFogColor != fog.color ) { mLastFogColor = fog.color; _initRender(); } // Just need it to follow the camera... no rotation. MatrixF camPosMat( MatrixF::Identity ); camPosMat.setPosition( worldMat.getPosition() ); sgData.objTrans = &camPosMat; mMatrixSet->setWorld( *sgData.objTrans ); while ( mFogBandMatInst->setupPass( state, sgData ) ) { mFogBandMatInst->setTransforms( *mMatrixSet, state ); mFogBandMatInst->setSceneInfo( state, sgData ); GFX->setVertexBuffer( mFogBandVB ); GFX->drawPrimitive( GFXTriangleList, 0, 16 ); } } }
void GFXPCD3D9TextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ ) { GFXDEBUGEVENT_SCOPE( GFXPCD3D9TextureTarget_attachTexture_Cubemap, ColorI::RED ); AssertFatal(slot < MaxRenderSlotId, "GFXPCD3D9TextureTarget::attachTexture - out of range slot."); // Mark state as dirty so device can know to update. invalidateState(); // Release what we had, it's definitely going to change. mDevice->destroyD3DResource( mTargets[slot] ); // SAFE_RELEASE mTargets[slot] = NULL; mResolveTargets[slot] = NULL; // Cast the texture object to D3D... AssertFatal(!tex || dynamic_cast<GFXD3D9Cubemap*>(tex), "GFXD3DTextureTarget::attachTexture - invalid cubemap object."); GFXD3D9Cubemap *cube = static_cast<GFXD3D9Cubemap*>(tex); if(slot == Color0) { mTargetSize = Point2I::Zero; mTargetFormat = GFXFormatR8G8B8A8; } // Are we clearing? if(!tex) { // Yup - just exit, it'll stay NULL. return; } D3D9Assert(cube->mCubeTex->GetCubeMapSurface( (D3DCUBEMAP_FACES)face, mipLevel, &mTargets[slot] ), "GFXD3DTextureTarget::attachTexture - could not get surface level for the passed texture!"); // Update surface size if(slot == Color0) { IDirect3DSurface9 *surface = mTargets[Color0]; if ( surface ) { D3DSURFACE_DESC sd; surface->GetDesc(&sd); mTargetSize = Point2I(sd.Width, sd.Height); S32 format = sd.Format; GFXREVERSE_LOOKUP( GFXD3D9TextureFormat, GFXFormat, format ); mTargetFormat = (GFXFormat)format; } } }
void RenderImposterMgr::render( SceneState *state ) { PROFILE_SCOPE( RenderImposterMgr_Render ); if ( !mElementList.size() || ( !mDiffuseShaderState.mShader && !mDiffuseShaderState.init( "TSImposterShaderData", NULL ) ) ) return; GFXDEBUGEVENT_SCOPE( RenderImposterMgr_Render, ColorI::RED ); _innerRender( state, mDiffuseShaderState ); }
void GFXPCD3D9WindowTarget::resolveTo( GFXTextureObject *tex ) { GFXDEBUGEVENT_SCOPE( GFXPCD3D9WindowTarget_resolveTo, ColorI::RED ); IDirect3DSurface9 *surf; D3D9Assert( ((GFXD3D9TextureObject*)(tex))->get2DTex()->GetSurfaceLevel( 0, &surf ), "GFXPCD3D9WindowTarget::resolveTo() - GetSurfaceLevel failed!" ); D3D9Assert( mDevice->getDevice()->StretchRect( mBackbuffer, NULL, surf, NULL, D3DTEXF_NONE ), "GFXPCD3D9WindowTarget::resolveTo() - StretchRect failed!" ); surf->Release(); }
void CubeReflector::updateReflection( const ReflectParams ¶ms ) { GFXDEBUGEVENT_SCOPE( CubeReflector_UpdateReflection, ColorI::WHITE ); mIsRendering = true; // Setup textures and targets... S32 texDim = mDesc->texSize; texDim = getMax( texDim, 32 ); // Protect against the reflection texture being bigger // than the current game back buffer. texDim = getMin( texDim, params.viewportExtent.x ); texDim = getMin( texDim, params.viewportExtent.y ); bool texResize = ( texDim != mLastTexSize ); const GFXFormat reflectFormat = REFLECTMGR->getReflectFormat(); if ( texResize || cubemap.isNull() || cubemap->getFormat() != reflectFormat ) { cubemap = GFX->createCubemap(); cubemap->initDynamic( texDim, reflectFormat ); } GFXTexHandle depthBuff = LightShadowMap::_getDepthTarget( texDim, texDim ); if ( renderTarget.isNull() ) renderTarget = GFX->allocRenderToTextureTarget(); GFX->pushActiveRenderTarget(); renderTarget->attachTexture( GFXTextureTarget::DepthStencil, depthBuff ); F32 oldVisibleDist = gClientSceneGraph->getVisibleDistance(); gClientSceneGraph->setVisibleDistance( mDesc->farDist ); for ( U32 i = 0; i < 6; i++ ) updateFace( params, i ); GFX->popActiveRenderTarget(); gClientSceneGraph->setVisibleDistance(oldVisibleDist); mIsRendering = false; mLastTexSize = texDim; }
void RenderImposterMgr::_renderPrePass( const SceneState *state, RenderPrePassMgr *prePassBin, bool startPrePass ) { PROFILE_SCOPE( RenderImposterMgr_RenderPrePass ); if ( !mElementList.size() || !startPrePass || ( !mPrePassShaderState.mShader && !mPrePassShaderState.init( "TSImposterPrePassShaderData", &prePassBin->getOpaqueStenciWriteDesc() ) ) ) return; GFXDEBUGEVENT_SCOPE( RenderImposterMgr_RenderPrePass, ColorI::RED ); _innerRender( state, mPrePassShaderState ); }
void GFXPCD3D9WindowTarget::activate() { GFXDEBUGEVENT_SCOPE( GFXPCD3D9WindowTarget_activate, ColorI::RED ); LPDIRECT3DDEVICE9 d3dDevice = mDevice->getDevice(); // In debug lets do a complete test to be sure we don't // have a bad depth format for this display mode. #ifdef TORQUE_DEBUG if ( mDepthStencil && mBackbuffer ) { D3DSURFACE_DESC desc; D3D9Assert( mBackbuffer->GetDesc( &desc ), "GFXPCD3D9TextureTarget::activate() - Failed to get surface description!"); D3DFORMAT renderFormat = desc.Format; D3D9Assert( mDepthStencil->GetDesc( &desc ), "GFXPCD3D9TextureTarget::activate() - Failed to get surface description!"); D3DFORMAT depthFormat = desc.Format; HRESULT hr = mDevice->getD3D()->CheckDepthStencilMatch( mDevice->getAdaterIndex(), D3DDEVTYPE_HAL, mDevice->mDisplayMode.Format, renderFormat, depthFormat ); D3D9Assert( hr, "GFXPCD3D9WindowTarget::activate() - Bad depth format for this back buffer!" ); } #endif D3D9Assert( d3dDevice->SetRenderTarget( 0, mBackbuffer ), "GFXPCD3D9WindowTarget::activate() - Failed to set backbuffer target!" ); D3D9Assert( d3dDevice->SetDepthStencilSurface( mDepthStencil ), "GFXPCD3D9WindowTarget::activate() - Failed to set depthstencil target!" ); D3DPRESENT_PARAMETERS pp; mSwapChain->GetPresentParameters(&pp); // Update our video mode here, too. GFXVideoMode vm; vm = mWindow->getVideoMode(); vm.resolution.x = pp.BackBufferWidth; vm.resolution.y = pp.BackBufferHeight; vm.fullScreen = !pp.Windowed; mSize = vm.resolution; }
void GFXD3D11TextureTarget::resolve() { GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_resolve, ColorI::RED ); for (U32 i = 0; i < MaxRenderSlotId; i++) { // We use existance @ mResolveTargets as a flag that we need to copy // data from the rendertarget into the texture. if (mResolveTargets[i]) { D3D11_TEXTURE2D_DESC desc; mTargets[i]->GetDesc(&desc); D3D11DEVICECONTEXT->CopySubresourceRegion(mResolveTargets[i]->get2DTex(), 0, 0, 0, 0, mTargets[i], 0, NULL); } } }
void EditTSCtrl::renderMissionArea() { MissionArea* obj = MissionArea::getServerObject(); if ( !obj ) return; if ( !mRenderMissionArea && !obj->isSelected() ) return; GFXDEBUGEVENT_SCOPE( Editor_renderMissionArea, ColorI::WHITE ); F32 minHeight = 0.0f; F32 maxHeight = 0.0f; TerrainBlock* terrain = getActiveTerrain(); if ( terrain ) { terrain->getMinMaxHeight( &minHeight, &maxHeight ); Point3F pos = terrain->getPosition(); maxHeight += pos.z + mMissionAreaHeightAdjust; minHeight += pos.z - mMissionAreaHeightAdjust; } const RectI& area = obj->getArea(); Box3F areaBox( area.point.x, area.point.y, minHeight, area.point.x + area.extent.x, area.point.y + area.extent.y, maxHeight ); GFXDrawUtil* drawer = GFX->getDrawUtil(); GFXStateBlockDesc desc; desc.setCullMode( GFXCullNone ); desc.setBlend( true ); desc.setZReadWrite( false, false ); desc.setFillModeSolid(); drawer->drawCube( desc, areaBox, mMissionAreaFillColor ); desc.setFillModeWireframe(); drawer->drawCube( desc, areaBox, mMissionAreaFrameColor ); }
void MetaShapeRenderer::render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) { if ( overrideMat ) return; PROFILE_SCOPE(MetaShapeRenderer_Render); mPolyList.render(); if ( mVertexBuffer.isNull() ) return; // Set up a GFX debug event (this helps with debugging rendering events in external tools) GFXDEBUGEVENT_SCOPE( MetaShapeRenderer_Render, ColorI::RED ); // GFXTransformSaver is a handy helper class that restores // the current GFX matrices to their original values when // it goes out of scope at the end of the function GFXTransformSaver saver; // Calculate our object to world transform matrix MatrixF objectToWorld = getRenderTransform(); objectToWorld.scale( getScale() ); // Apply our object transform GFX->multWorld( objectToWorld ); // Deal with reflect pass otherwise // set the normal StateBlock if ( state->isReflectPass() ) GFX->setStateBlock( mReflectSB ); else GFX->setStateBlock( mNormalSB ); // Set up the "generic" shaders // These handle rendering on GFX layers that don't support // fixed function. Otherwise they disable shaders. GFX->setupGenericShaders( GFXDevice::GSModColorTexture ); // Set the vertex buffer GFX->setVertexBuffer( mVertexBuffer ); // Draw our triangles GFX->drawPrimitive( GFXTriangleList, 0, 12 ); }
void ForcedMaterialMeshMgr::render(SceneRenderState * state) { PROFILE_SCOPE(ForcedMaterialMeshMgr_render); if(!mOverrideInstance && mOverrideMaterial.isValid()) { mOverrideInstance = mOverrideMaterial->createMatInstance(); mOverrideInstance->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTBT>() ); } // Early out if nothing to draw. if(!mElementList.size() || !mOverrideInstance) return; GFXDEBUGEVENT_SCOPE(ForcedMaterialMeshMgr_Render, ColorI::RED); // Automagically save & restore our viewport and transforms. GFXTransformSaver saver; // init loop data SceneData sgData; sgData.init( state ); MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[0].inst); setupSGData( ri, sgData ); while (mOverrideInstance->setupPass(state, sgData)) { for( U32 j=0; j<mElementList.size(); j++) { MeshRenderInst* passRI = static_cast<MeshRenderInst*>(mElementList[j].inst); if(passRI->primBuff->getPointer()->mPrimitiveArray[passRI->primBuffIndex].numVertices < 1) continue; getRenderPass()->getMatrixSet().setWorld(*passRI->objectToWorld); getRenderPass()->getMatrixSet().setView(*passRI->worldToCamera); getRenderPass()->getMatrixSet().setProjection(*passRI->projection); mOverrideInstance->setTransforms(getRenderPass()->getMatrixSet(), state, sgData); mOverrideInstance->setBuffers(passRI->vertBuff, passRI->primBuff); GFX->drawPrimitive( passRI->primBuffIndex ); } } }
void GFXDrawUtil::_drawWirePolyhedron( const GFXStateBlockDesc &desc, const AnyPolyhedron &poly, const ColorI &color, const MatrixF *xfm ) { GFXDEBUGEVENT_SCOPE( GFXDrawUtil_DrawWirePolyhedron, ColorI::GREEN ); const U32 numEdges = poly.getNumEdges(); const Point3F* points = poly.getPoints(); const Polyhedron::Edge* edges = poly.getEdges(); // Allocate a temporary vertex buffer. GFXVertexBufferHandle< GFXVertexPC > verts( mDevice, numEdges * 2, GFXBufferTypeVolatile); // Fill it with the vertices for the edges. verts.lock(); for( U32 i = 0; i < numEdges; ++ i ) { const U32 nvert = i * 2; verts[ nvert + 0 ].point = points[ edges[ i ].vertex[ 0 ] ]; verts[ nvert + 0 ].color = color; verts[ nvert + 1 ].point = points[ edges[ i ].vertex[ 1 ] ]; verts[ nvert + 1 ].color = color; } if( xfm ) { for( U32 i = 0; i < numEdges; ++ i ) { xfm->mulP( verts[ i + 0 ].point ); xfm->mulP( verts[ i + 1 ].point ); } } verts.unlock(); // Render the line list. mDevice->setStateBlockByDesc( desc ); mDevice->setVertexBuffer( verts ); mDevice->setupGenericShaders(); mDevice->drawPrimitive( GFXLineList, 0, numEdges ); }
void ImposterCapture::_renderToTexture( GFXTexHandle texHandle, GBitmap *outBitmap, const ColorI &color ) { GFXDEBUGEVENT_SCOPE( ImposterCapture_RenderToTexture, ColorI::RED ); PROFILE_SCOPE( ImposterCapture_RenderToTexture ); mRenderTarget->attachTexture( GFXTextureTarget::Color0, texHandle ); mRenderTarget->attachTexture( GFXTextureTarget::DepthStencil, mDepthBuffer ); GFX->setActiveRenderTarget( mRenderTarget ); GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, color, 1.0f, 0 ); mShapeInstance->render( mRData, mDl, 1.0f ); mState->getRenderPass()->renderPass( mState ); mRenderTarget->resolve(); texHandle->copyToBmp( outBitmap ); }
void GFXD3D11WindowTarget::activate() { GFXDEBUGEVENT_SCOPE(GFXPCD3D11WindowTarget_activate, ColorI::RED); //clear ther rendertargets first ID3D11RenderTargetView* rtViews[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; D3D11DEVICECONTEXT->OMSetRenderTargets(8, rtViews, NULL); D3D11DEVICECONTEXT->OMSetRenderTargets(1, &D3D11->mDeviceBackBufferView, D3D11->mDeviceDepthStencilView); DXGI_SWAP_CHAIN_DESC pp; D3D11->mSwapChain->GetDesc(&pp); // Update our video mode here, too. GFXVideoMode vm; vm = mWindow->getVideoMode(); vm.resolution.x = pp.BufferDesc.Width; vm.resolution.y = pp.BufferDesc.Height; vm.fullScreen = !pp.Windowed; mSize = vm.resolution; }
void GFXPCD3D9TextureTarget::resolve() { GFXDEBUGEVENT_SCOPE( GFXPCD3D9TextureTarget_resolve, ColorI::RED ); for (U32 i = 0; i < MaxRenderSlotId; i++) { // We use existance @ mResolveTargets as a flag that we need to copy // data from the rendertarget into the texture. if (mResolveTargets[i]) { IDirect3DSurface9 *surf; D3D9Assert( mResolveTargets[i]->get2DTex()->GetSurfaceLevel( 0, &surf ), "GFXPCD3D9TextureTarget::resolve() - GetSurfaceLevel failed!" ); D3D9Assert( mDevice->getDevice()->StretchRect( mTargets[i], NULL, surf, NULL, D3DTEXF_NONE ), "GFXPCD3D9TextureTarget::resolve() - StretchRect failed!" ); surf->Release(); } } }
void GFXD3D11TextureTarget::activate() { GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_activate, ColorI::RED ); AssertFatal( mTargets[GFXTextureTarget::Color0], "GFXD3D11TextureTarget::activate() - You can never have a NULL primary render target!" ); // Clear the state indicator. stateApplied(); // Now set all the new surfaces into the appropriate slots. ID3D11RenderTargetView* rtViews[MaxRenderSlotId] = { NULL, NULL, NULL, NULL, NULL, NULL}; ID3D11DepthStencilView* dsView = (ID3D11DepthStencilView*)(mTargetViews[GFXTextureTarget::DepthStencil]); for (U32 i = 0; i < 4; i++) { rtViews[i] = (ID3D11RenderTargetView*)mTargetViews[GFXTextureTarget::Color0 + i]; } D3D11DEVICECONTEXT->OMSetRenderTargets(MaxRenderSlotId, rtViews, dsView); }
void GFXPCD3D9TextureTarget::activate() { GFXDEBUGEVENT_SCOPE( GFXPCD3D9TextureTarget_activate, ColorI::RED ); AssertFatal( mTargets[GFXTextureTarget::Color0], "GFXPCD3D9TextureTarget::activate() - You can never have a NULL primary render target!" ); const U32 NumRenderTargets = getMin( mDevice->getNumRenderTargets(), (U32)Color4 - Color0 ); LPDIRECT3DDEVICE9 d3dDevice = mDevice->getDevice(); // Clear the state indicator. stateApplied(); IDirect3DSurface9 *depth = mTargets[GFXTextureTarget::DepthStencil]; // In debug lets do a complete test to be sure we don't // have a bad depth format for this display mode. #ifdef TORQUE_DEBUG if ( depth && mTargets[GFXTextureTarget::Color0] ) { D3DSURFACE_DESC desc; D3D9Assert( mTargets[GFXTextureTarget::Color0]->GetDesc( &desc ), "GFXPCD3D9TextureTarget::activate() - Failed to get surface description!"); D3DFORMAT renderFormat = desc.Format; D3D9Assert( depth->GetDesc( &desc ), "GFXPCD3D9TextureTarget::activate() - Failed to get surface description!"); D3DFORMAT depthFormat = desc.Format; HRESULT hr = mDevice->getD3D()->CheckDepthStencilMatch( mDevice->getAdaterIndex(), D3DDEVTYPE_HAL, mDevice->mDisplayMode.Format, renderFormat, depthFormat ); D3D9Assert( hr, "GFXPCD3D9TextureTarget::activate() - Bad depth format for this target!" ); } #endif // First clear the non-primary targets to make the debug DX runtime happy. for(U32 i = 1; i < NumRenderTargets; i++) D3D9Assert(d3dDevice->SetRenderTarget( i, NULL ), avar("GFXPCD3D9TextureTarget::activate() - failed to clear texture target %d!", i) ); // Now set all the new surfaces into the appropriate slots. for(U32 i = 0; i < NumRenderTargets; i++) { IDirect3DSurface9 *target = mTargets[GFXTextureTarget::Color0 + i]; if ( target ) { D3D9Assert(d3dDevice->SetRenderTarget(i, target), avar("GFXPCD3D9TextureTarget::activate() - failed to set slot %d for texture target!", i) ); } } // TODO: This is often the same shared depth buffer used by most // render targets. Are we getting performance hit from setting it // multiple times... aside from the function call? D3D9Assert(d3dDevice->SetDepthStencilSurface( depth ), "GFXPCD3D9TextureTarget::activate() - failed to set depthstencil target!" ); }
//----------------------------------------------------------------------------- // render //----------------------------------------------------------------------------- void RenderMeshMgr::render(SceneRenderState * state) { PROFILE_SCOPE(RenderMeshMgr_render); // Early out if nothing to draw. if(!mElementList.size()) return; GFXDEBUGEVENT_SCOPE( RenderMeshMgr_Render, ColorI::GREEN ); // Automagically save & restore our viewport and transforms. GFXTransformSaver saver; // Restore transforms MatrixSet &matrixSet = getRenderPass()->getMatrixSet(); matrixSet.restoreSceneViewProjection(); // init loop data GFXTextureObject *lastLM = NULL; GFXCubemap *lastCubemap = NULL; GFXTextureObject *lastReflectTex = NULL; GFXTextureObject *lastMiscTex = NULL; SceneData sgData; sgData.init( state ); U32 binSize = mElementList.size(); for( U32 j=0; j<binSize; ) { MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[j].inst); setupSGData( ri, sgData ); BaseMatInstance *mat = ri->matInst; // If we have an override delegate then give it a // chance to swap the material with another. if ( mMatOverrideDelegate ) { mat = mMatOverrideDelegate( mat ); if ( !mat ) { j++; continue; } } if( !mat ) mat = MATMGR->getWarningMatInstance(); U32 matListEnd = j; lastMiscTex = sgData.miscTex; U32 a; while( mat && mat->setupPass(state, sgData ) ) { for( a=j; a<binSize; a++ ) { MeshRenderInst *passRI = static_cast<MeshRenderInst*>(mElementList[a].inst); // Check to see if we need to break this batch. if ( newPassNeeded( ri, passRI ) || lastMiscTex != passRI->miscTex ) { lastLM = NULL; break; } matrixSet.setWorld(*passRI->objectToWorld); matrixSet.setView(*passRI->worldToCamera); matrixSet.setProjection(*passRI->projection); mat->setTransforms(matrixSet, state); setupSGData( passRI, sgData ); mat->setSceneInfo( state, sgData ); // If we're instanced then don't render yet. if ( mat->isInstanced() ) { // Let the material increment the instance buffer, but // break the batch if it runs out of room for more. if ( !mat->stepInstance() ) { a++; break; } continue; } // TODO: This could proably be done in a cleaner way. // // This section of code is dangerous, it overwrites the // lightmap values in sgData. This could be a problem when multiple // render instances use the same multi-pass material. When // the first pass is done, setupPass() is called again on // the material, but the lightmap data has been changed in // sgData to the lightmaps in the last renderInstance rendered. // This section sets the lightmap data for the current batch. // For the first iteration, it sets the same lightmap data, // however the redundancy will be caught by GFXDevice and not // actually sent to the card. This is done for simplicity given // the possible condition mentioned above. Better to set always // than to get bogged down into special case detection. //------------------------------------- bool dirty = false; // set the lightmaps if different if( passRI->lightmap && passRI->lightmap != lastLM ) { sgData.lightmap = passRI->lightmap; lastLM = passRI->lightmap; dirty = true; } // set the cubemap if different. if ( passRI->cubemap != lastCubemap ) { sgData.cubemap = passRI->cubemap; lastCubemap = passRI->cubemap; dirty = true; } if ( passRI->reflectTex != lastReflectTex ) { sgData.reflectTex = passRI->reflectTex; lastReflectTex = passRI->reflectTex; dirty = true; } if ( dirty ) mat->setTextureStages( state, sgData ); // Setup the vertex and index buffers. mat->setBuffers( passRI->vertBuff, passRI->primBuff ); // Render this sucker. if ( passRI->prim ) GFX->drawPrimitive( *passRI->prim ); else GFX->drawPrimitive( passRI->primBuffIndex ); } // Draw the instanced batch. if ( mat->isInstanced() ) { // Sets the buffers including the instancing stream. mat->setBuffers( ri->vertBuff, ri->primBuff ); // Render the instanced stream. if ( ri->prim ) GFX->drawPrimitive( *ri->prim ); else GFX->drawPrimitive( ri->primBuffIndex ); } matListEnd = a; } // force increment if none happened, otherwise go to end of batch j = ( j == matListEnd ) ? j+1 : matListEnd; } }
void RenderGlowMgr::render( SceneRenderState *state ) { PROFILE_SCOPE( RenderGlowMgr_Render ); if ( !isGlowEnabled() ) return; const U32 binSize = mElementList.size(); // If this is a non-diffuse pass or we have no objects to // render then tell the effect to skip rendering. if ( !state->isDiffusePass() || binSize == 0 ) { getGlowEffect()->setSkip( true ); return; } GFXDEBUGEVENT_SCOPE( RenderGlowMgr_Render, ColorI::GREEN ); GFXTransformSaver saver; // Tell the superclass we're about to render, preserve contents const bool isRenderingToTarget = _onPreRender( state, true ); // Clear all the buffers to black. GFX->clear( GFXClearTarget, ColorI::BLACK, 1.0f, 0); // Restore transforms MatrixSet &matrixSet = getRenderPass()->getMatrixSet(); matrixSet.restoreSceneViewProjection(); // init loop data SceneData sgData; sgData.init( state, SceneData::GlowBin ); for( U32 j=0; j<binSize; ) { MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[j].inst); setupSGData( ri, sgData ); BaseMatInstance *mat = ri->matInst; GlowMaterialHook *hook = mat->getHook<GlowMaterialHook>(); if ( !hook ) { hook = new GlowMaterialHook( ri->matInst ); ri->matInst->addHook( hook ); } BaseMatInstance *glowMat = hook->getMatInstance(); U32 matListEnd = j; while( glowMat && glowMat->setupPass( state, sgData ) ) { U32 a; for( a=j; a<binSize; a++ ) { MeshRenderInst *passRI = static_cast<MeshRenderInst*>(mElementList[a].inst); if ( newPassNeeded( ri, passRI ) ) break; matrixSet.setWorld(*passRI->objectToWorld); matrixSet.setView(*passRI->worldToCamera); matrixSet.setProjection(*passRI->projection); glowMat->setTransforms(matrixSet, state); glowMat->setSceneInfo(state, sgData); glowMat->setBuffers(passRI->vertBuff, passRI->primBuff); if ( passRI->prim ) GFX->drawPrimitive( *passRI->prim ); else GFX->drawPrimitive( passRI->primBuffIndex ); } matListEnd = a; setupSGData( ri, sgData ); } // force increment if none happened, otherwise go to end of batch j = ( j == matListEnd ) ? j+1 : matListEnd; } // Finish up. if ( isRenderingToTarget ) _onPostRender(); // Make sure the effect is gonna render. getGlowEffect()->setSkip( false ); }
void GFXPCD3D9TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ ) { GFXDEBUGEVENT_SCOPE( GFXPCD3D9TextureTarget_attachTexture, ColorI::RED ); AssertFatal(slot < MaxRenderSlotId, "GFXPCD3D9TextureTarget::attachTexture - out of range slot."); // TODO: The way this is implemented... you can attach a texture // object multiple times and it will release and reset it. // // We should rework this to detect when no change has occured // and skip out early. // Mark state as dirty so device can know to update. invalidateState(); // Release what we had, it's definitely going to change. mDevice->destroyD3DResource( mTargets[slot] ); // SAFE_RELEASE mTargets[slot] = NULL; mResolveTargets[slot] = NULL; if(slot == Color0) { mTargetSize = Point2I::Zero; mTargetFormat = GFXFormatR8G8B8A8; } // Are we clearing? if(!tex) { // Yup - just exit, it'll stay NULL. return; } // Take care of default targets if( tex == GFXTextureTarget::sDefaultDepthStencil ) { mTargets[slot] = mDevice->mDeviceDepthStencil; mTargets[slot]->AddRef(); } else { // Cast the texture object to D3D... AssertFatal(dynamic_cast<GFXD3D9TextureObject*>(tex), "GFXPCD3D9TextureTarget::attachTexture - invalid texture object."); GFXD3D9TextureObject *d3dto = static_cast<GFXD3D9TextureObject*>(tex); // Grab the surface level. if( slot == DepthStencil ) { mTargets[slot] = d3dto->getSurface(); if ( mTargets[slot] ) mTargets[slot]->AddRef(); } else { // getSurface will almost always return NULL. It will only return non-NULL // if the surface that it needs to render to is different than the mip level // in the actual texture. This will happen with MSAA. if( d3dto->getSurface() == NULL ) { D3D9Assert(d3dto->get2DTex()->GetSurfaceLevel(mipLevel, &mTargets[slot]), "GFXPCD3D9TextureTarget::attachTexture - could not get surface level for the passed texture!"); } else { mTargets[slot] = d3dto->getSurface(); mTargets[slot]->AddRef(); // Only assign resolve target if d3dto has a surface to give us. // // That usually means there is an MSAA target involved, which is why // the resolve is needed to get the data out of the target. mResolveTargets[slot] = d3dto; if ( tex && slot == Color0 ) { mTargetSize.set( tex->getSize().x, tex->getSize().y ); mTargetFormat = tex->getFormat(); } } } // Update surface size if(slot == Color0) { IDirect3DSurface9 *surface = mTargets[Color0]; if ( surface ) { D3DSURFACE_DESC sd; surface->GetDesc(&sd); mTargetSize = Point2I(sd.Width, sd.Height); S32 format = sd.Format; GFXREVERSE_LOOKUP( GFXD3D9TextureFormat, GFXFormat, format ); mTargetFormat = (GFXFormat)format; } } } }
void RenderTranslucentMgr::render( SceneRenderState *state ) { PROFILE_SCOPE(RenderTranslucentMgr_render); // Early out if nothing to draw. if(!mElementList.size()) return; GFXDEBUGEVENT_SCOPE(RenderTranslucentMgr_Render, ColorI::BLUE); // Find the particle render manager (if we don't have it) if(mParticleRenderMgr == NULL) { RenderPassManager *rpm = state->getRenderPass(); for( U32 i = 0; i < rpm->getManagerCount(); i++ ) { RenderBinManager *bin = rpm->getManager(i); if( bin->getRenderInstType() == RenderParticleMgr::RIT_Particles ) { mParticleRenderMgr = reinterpret_cast<RenderParticleMgr *>(bin); break; } } } GFXTransformSaver saver; SceneData sgData; sgData.init( state ); GFXVertexBuffer * lastVB = NULL; GFXPrimitiveBuffer * lastPB = NULL; // Restore transforms MatrixSet &matrixSet = getRenderPass()->getMatrixSet(); matrixSet.restoreSceneViewProjection(); U32 binSize = mElementList.size(); for( U32 j=0; j<binSize; ) { RenderInst *baseRI = mElementList[j].inst; U32 matListEnd = j; // render these separately... if ( baseRI->type == RenderPassManager::RIT_ObjectTranslucent ) { ObjectRenderInst* objRI = static_cast<ObjectRenderInst*>(baseRI); objRI->renderDelegate( objRI, state, NULL ); lastVB = NULL; lastPB = NULL; j++; continue; } //Volumetric Fog Add else if (baseRI->type == RenderPassManager::RIT_VolumetricFog) { ObjectRenderInst* objRI = static_cast<ObjectRenderInst*>(baseRI); objRI->renderDelegate(objRI,state,NULL); lastVB = NULL; lastPB = NULL; j++; continue; } //Volumetric Fog Add else if ( baseRI->type == RenderPassManager::RIT_Particle ) { ParticleRenderInst *ri = static_cast<ParticleRenderInst*>(baseRI); // Tell Particle RM to draw the system. (This allows the particle render manager // to manage drawing offscreen particle systems, and allows the systems // to be composited back into the scene with proper translucent // sorting order) mParticleRenderMgr->renderInstance(ri, state); lastVB = NULL; // no longer valid, null it lastPB = NULL; // no longer valid, null it j++; continue; } else if ( baseRI->type == RenderPassManager::RIT_Translucent ) { MeshRenderInst* ri = static_cast<MeshRenderInst*>(baseRI); BaseMatInstance *mat = ri->matInst; setupSGData( ri, sgData ); while( mat->setupPass( state, sgData ) ) { U32 a; for( a=j; a<binSize; a++ ) { RenderInst* nextRI = mElementList[a].inst; if ( nextRI->type != RenderPassManager::RIT_Translucent ) break; MeshRenderInst *passRI = static_cast<MeshRenderInst*>(nextRI); // Check to see if we need to break this batch. if ( newPassNeeded( ri, passRI ) ) break; // Z sorting and stuff is still not working in this mgr... setupSGData( passRI, sgData ); mat->setSceneInfo(state, sgData); matrixSet.setWorld(*passRI->objectToWorld); matrixSet.setView(*passRI->worldToCamera); matrixSet.setProjection(*passRI->projection); mat->setTransforms(matrixSet, state); // If we're instanced then don't render yet. if ( mat->isInstanced() ) { // Let the material increment the instance buffer, but // break the batch if it runs out of room for more. if ( !mat->stepInstance() ) { a++; break; } continue; } // Setup the vertex and index buffers. mat->setBuffers( passRI->vertBuff, passRI->primBuff ); // Render this sucker. if ( passRI->prim ) GFX->drawPrimitive( *passRI->prim ); else GFX->drawPrimitive( passRI->primBuffIndex ); } // Draw the instanced batch. if ( mat->isInstanced() ) { // Sets the buffers including the instancing stream. mat->setBuffers( ri->vertBuff, ri->primBuff ); // Render the instanced stream. if ( ri->prim ) GFX->drawPrimitive( *ri->prim ); else GFX->drawPrimitive( ri->primBuffIndex ); } matListEnd = a; } // force increment if none happened, otherwise go to end of batch j = ( j == matListEnd ) ? j+1 : matListEnd; } } }
void ReflectionManager::update( F32 timeSlice, const Point2I &resolution, const CameraQuery &query ) { GFXDEBUGEVENT_SCOPE( UpdateReflections, ColorI::WHITE ); if ( mReflectors.empty() ) return; PROFILE_SCOPE( ReflectionManager_Update ); // Calculate our target time from the slice. U32 targetMs = timeSlice * smFrameReflectionMS; // Setup a culler for testing the // visibility of reflectors. Frustum culler; culler.set( false, query.fov, (F32)resolution.x / (F32)resolution.y, query.nearPlane, query.farPlane, query.cameraMatrix ); // Manipulate the frustum for tiled screenshots const bool screenShotMode = gScreenShot && gScreenShot->isPending(); if ( screenShotMode ) gScreenShot->tileFrustum( culler ); // We use the frame time and not real time // here as this may be called multiple times // within a frame. U32 startOfUpdateMs = Platform::getVirtualMilliseconds(); // Save this for interested parties. mLastUpdateMs = startOfUpdateMs; ReflectParams refparams; refparams.query = &query; refparams.viewportExtent = resolution; refparams.culler = culler; refparams.startOfUpdateMs = startOfUpdateMs; // Update the reflection score. ReflectorList::iterator reflectorIter = mReflectors.begin(); for ( ; reflectorIter != mReflectors.end(); reflectorIter++ ) (*reflectorIter)->calcScore( refparams ); // Sort them by the score. dQsort( mReflectors.address(), mReflectors.size(), sizeof(ReflectorBase*), compareReflectors ); // Update as many reflections as we can // within the target time limit. mTimer->getElapsedMs(); mTimer->reset(); U32 numUpdated = 0; reflectorIter = mReflectors.begin(); for ( ; reflectorIter != mReflectors.end(); reflectorIter++ ) { // We're sorted by score... so once we reach // a zero score we have nothing more to update. if ( (*reflectorIter)->score <= 0.0f && !screenShotMode ) break; (*reflectorIter)->updateReflection( refparams ); (*reflectorIter)->lastUpdateMs = startOfUpdateMs; numUpdated++; // If we run out of update time then stop. if ( mTimer->getElapsedMs() > targetMs && !screenShotMode && (*reflectorIter)->score < 1000.0f ) break; } // Set metric/debug related script variables... U32 numVisible = 0; U32 numOccluded = 0; reflectorIter = mReflectors.begin(); for ( ; reflectorIter != mReflectors.end(); reflectorIter++ ) { ReflectorBase *pReflector = (*reflectorIter); if ( pReflector->isOccluded() ) numOccluded++; else numVisible++; } #ifdef TORQUE_GATHER_METRICS U32 numEnabled = mReflectors.size(); U32 totalElapsed = mTimer->getElapsedMs(); const GFXTextureProfileStats &stats = ReflectRenderTargetProfile.getStats(); F32 mb = ( stats.activeBytes / 1024.0f ) / 1024.0f; char temp[256]; dSprintf( temp, 256, "%s %d %0.2f\n", ReflectRenderTargetProfile.getName().c_str(), stats.activeCount, mb ); Con::setVariable( "$Reflect::textureStats", temp ); Con::setIntVariable( "$Reflect::renderTargetsAllocated", stats.allocatedTextures ); Con::setIntVariable( "$Reflect::poolSize", stats.activeCount ); Con::setIntVariable( "$Reflect::numObjects", numEnabled ); Con::setIntVariable( "$Reflect::numVisible", numVisible ); Con::setIntVariable( "$Reflect::numOccluded", numOccluded ); Con::setIntVariable( "$Reflect::numUpdated", numUpdated ); Con::setIntVariable( "$Reflect::elapsed", totalElapsed ); #endif }
void EditTSCtrl::renderGrid() { if( !isOrthoDisplayType() ) return; GFXDEBUGEVENT_SCOPE( Editor_renderGrid, ColorI::WHITE ); // Calculate the displayed grid size based on view F32 drawnGridSize = mGridPlaneSize; F32 gridPixelSize = projectRadius(1.0f, mGridPlaneSize); if(gridPixelSize < mGridPlaneSizePixelBias) { U32 counter = 1; while(gridPixelSize < mGridPlaneSizePixelBias) { drawnGridSize = mGridPlaneSize * counter * 10.0f; gridPixelSize = projectRadius(1.0f, drawnGridSize); ++counter; // No infinite loops here if(counter > 1000) break; } } F32 minorTickSize = 0; F32 gridSize = drawnGridSize; U32 minorTickMax = mGridPlaneMinorTicks + 1; if(minorTickMax > 0) { minorTickSize = drawnGridSize; gridSize = drawnGridSize * minorTickMax; } // Build the view-based origin VectorF dir; smCamMatrix.getColumn( 1, &dir ); Point3F gridPlanePos = smCamPos + dir; Point2F size(mOrthoWidth + 2 * gridSize, mOrthoHeight + 2 * gridSize); GFXStateBlockDesc desc; desc.setBlend( true ); desc.setZReadWrite( true, false ); GFXDrawUtil::Plane plane = GFXDrawUtil::PlaneXY; switch( getDisplayType() ) { case DisplayTypeTop: case DisplayTypeBottom: plane = GFXDrawUtil::PlaneXY; break; case DisplayTypeLeft: case DisplayTypeRight: plane = GFXDrawUtil::PlaneYZ; break; case DisplayTypeFront: case DisplayTypeBack: plane = GFXDrawUtil::PlaneXZ; break; default: break; } GFX->getDrawUtil()->drawPlaneGrid( desc, gridPlanePos, size, Point2F( minorTickSize, minorTickSize ), mGridPlaneMinorTickColor, plane ); GFX->getDrawUtil()->drawPlaneGrid( desc, gridPlanePos, size, Point2F( gridSize, gridSize ), mGridPlaneColor, plane ); }
void AdvancedLightBinManager::render( SceneRenderState *state ) { PROFILE_SCOPE( AdvancedLightManager_Render ); // Take a look at the SceneRenderState and see if we should skip drawing the pre-pass if( state->disableAdvancedLightingBins() ) return; // Automagically save & restore our viewport and transforms. GFXTransformSaver saver; if( !mLightManager ) return; // Get the sunlight. If there's no sun, and no lights in the bins, no draw LightInfo *sunLight = mLightManager->getSpecialLight( LightManager::slSunLightType ); if( !sunLight && mLightBin.empty() ) return; GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render, ColorI::RED ); // Tell the superclass we're about to render if ( !_onPreRender( state ) ) return; // Clear as long as there isn't MRT population of light buffer with lightmap data if ( !MRTLightmapsDuringPrePass() ) GFX->clear(GFXClearTarget, ColorI(0, 0, 0, 0), 1.0f, 0); // Restore transforms MatrixSet &matrixSet = getRenderPass()->getMatrixSet(); matrixSet.restoreSceneViewProjection(); const MatrixF &worldToCameraXfm = matrixSet.getWorldToCamera(); // Set up the SG Data SceneData sgData; sgData.init( state ); // There are cases where shadow rendering is disabled. const bool disableShadows = state->isReflectPass() || ShadowMapPass::smDisableShadows; // Pick the right material for rendering the sunlight... we only // cast shadows when its enabled and we're not in a reflection. LightMaterialInfo *vectorMatInfo; if ( sunLight && sunLight->getCastShadows() && !disableShadows && sunLight->getExtended<ShadowMapParams>() ) vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM, false ); else vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None, false ); // Initialize and set the per-frame parameters after getting // the vector light material as we use lazy creation. _setupPerFrameParameters( state ); // Draw sunlight/ambient if ( sunLight && vectorMatInfo ) { GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Sunlight, ColorI::RED ); // Set up SG data setupSGData( sgData, state, sunLight ); vectorMatInfo->setLightParameters( sunLight, state, worldToCameraXfm ); // Set light holds the active shadow map. mShadowManager->setLightShadowMapForLight( sunLight ); // Set geometry GFX->setVertexBuffer( mFarFrustumQuadVerts ); GFX->setPrimitiveBuffer( NULL ); // Render the material passes while( vectorMatInfo->matInstance->setupPass( state, sgData ) ) { vectorMatInfo->matInstance->setSceneInfo( state, sgData ); vectorMatInfo->matInstance->setTransforms( matrixSet, state ); GFX->drawPrimitive( GFXTriangleFan, 0, 2 ); } } // Blend the lights in the bin to the light buffer for( LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++ ) { LightBinEntry& curEntry = *itr; LightInfo *curLightInfo = curEntry.lightInfo; LightMaterialInfo *curLightMat = curEntry.lightMaterial; const U32 numPrims = curEntry.numPrims; const U32 numVerts = curEntry.vertBuffer->mNumVerts; // Skip lights which won't affect the scene. if ( !curLightMat || curLightInfo->getBrightness() <= 0.001f ) continue; GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Light, ColorI::RED ); setupSGData( sgData, state, curLightInfo ); curLightMat->setLightParameters( curLightInfo, state, worldToCameraXfm ); mShadowManager->setLightShadowMap( curEntry.shadowMap ); // Let the shadow know we're about to render from it. if ( curEntry.shadowMap ) curEntry.shadowMap->preLightRender(); // Set geometry GFX->setVertexBuffer( curEntry.vertBuffer ); GFX->setPrimitiveBuffer( curEntry.primBuffer ); // Render the material passes while( curLightMat->matInstance->setupPass( state, sgData ) ) { // Set transforms matrixSet.setWorld(*sgData.objTrans); curLightMat->matInstance->setTransforms(matrixSet, state); curLightMat->matInstance->setSceneInfo(state, sgData); if(curEntry.primBuffer) GFX->drawIndexedPrimitive(GFXTriangleList, 0, 0, numVerts, 0, numPrims); else GFX->drawPrimitive(GFXTriangleList, 0, numPrims); } // Tell it we're done rendering. if ( curEntry.shadowMap ) curEntry.shadowMap->postLightRender(); } // Set NULL for active shadow map (so nothing gets confused) mShadowManager->setLightShadowMap(NULL); GFX->setVertexBuffer( NULL ); GFX->setPrimitiveBuffer( NULL ); // Fire off a signal to let others know that light-bin rendering is ending now getRenderSignal().trigger(state, this); // Finish up the rendering _onPostRender(); }
void SceneManager::_renderScene( SceneRenderState* state, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone ) { AssertFatal( this == gClientSceneGraph, "SceneManager::_buildSceneGraph - Only the client scenegraph can support this call!" ); PROFILE_SCOPE( SceneGraph_batchRenderImages ); // In the editor, override the type mask for diffuse passes. if( gEditingMission && state->isDiffusePass() ) objectMask = EDITOR_RENDER_TYPEMASK; // Update the zoning state and traverse zones. if( getZoneManager() ) { // Update. getZoneManager()->updateZoningState(); // If zone culling isn't disabled, traverse the // zones now. if( !state->getCullingState().disableZoneCulling() ) { // Find the start zone if we haven't already. if( !baseObject ) { getZoneManager()->findZone( state->getCameraPosition(), baseObject, baseZone ); AssertFatal( baseObject != NULL, "SceneManager::_renderScene - findZone() did not return an object" ); } // Traverse zones starting in base object. SceneTraversalState traversalState( &state->getCullingState() ); PROFILE_START( Scene_traverseZones ); baseObject->traverseZones( &traversalState, baseZone ); PROFILE_END(); // Set the scene render box to the area we have traversed. state->setRenderArea( traversalState.getTraversedArea() ); } } // Set the query box for the container query. Never // make it larger than the frustum's AABB. In the editor, // always query the full frustum as that gives objects // the opportunity to render editor visualizations even if // they are otherwise not in view. if( !state->getFrustum().getBounds().isOverlapped( state->getRenderArea() ) ) { // This handles fringe cases like flying backwards into a zone where you // end up pretty much standing on a zone border and looking directly into // its "walls". In that case the traversal area will be behind the frustum // (remember that the camera isn't where visibility starts, it's the near // distance). return; } Box3F queryBox = state->getFrustum().getBounds(); if( !gEditingMission ) { queryBox.minExtents.setMax( state->getRenderArea().minExtents ); queryBox.maxExtents.setMin( state->getRenderArea().maxExtents ); } PROFILE_START( Scene_cullObjects ); //TODO: We should split the codepaths here based on whether the outdoor zone has visible space. // If it has, we should use the container query-based path. // If it hasn't, we should fill the object list directly from the zone lists which will usually // include way fewer objects. // Gather all objects that intersect the scene render box. mBatchQueryList.clear(); getContainer()->findObjectList( queryBox, objectMask, &mBatchQueryList ); // Cull the list. U32 numRenderObjects = state->getCullingState().cullObjects( mBatchQueryList.address(), mBatchQueryList.size(), !state->isDiffusePass() ? SceneCullingState::CullEditorOverrides : 0 // Keep forced editor stuff out of non-diffuse passes. ); //HACK: If the control object is a Player and it is not in the render list, force // it into it. This really should be solved by collision bounds being separate from // object bounds; only because the Player class is using bounds not encompassing // the actual player object is it that we have this problem in the first place. // Note that we are forcing the player object into ALL passes here but such // is the power of proliferation of things done wrong. GameConnection* connection = GameConnection::getConnectionToServer(); if( connection ) { Player* player = dynamic_cast< Player* >( connection->getControlObject() ); if( player ) { mBatchQueryList.setSize( numRenderObjects ); if( !mBatchQueryList.contains( player ) ) { mBatchQueryList.push_back( player ); numRenderObjects ++; } } } PROFILE_END(); // Render the remaining objects. PROFILE_START( Scene_renderObjects ); state->renderObjects( mBatchQueryList.address(), numRenderObjects ); PROFILE_END(); // Render bounding boxes, if enabled. if( smRenderBoundingBoxes && state->isDiffusePass() ) { GFXDEBUGEVENT_SCOPE( Scene_renderBoundingBoxes, ColorI::WHITE ); GameBase* cameraObject = 0; if( connection ) cameraObject = connection->getCameraObject(); GFXStateBlockDesc desc; desc.setFillModeWireframe(); desc.setZReadWrite( true, false ); for( U32 i = 0; i < numRenderObjects; ++ i ) { SceneObject* object = mBatchQueryList[ i ]; // Skip global bounds object. if( object->isGlobalBounds() ) continue; // Skip camera object as we're viewing the scene from it. if( object == cameraObject ) continue; const Box3F& worldBox = object->getWorldBox(); GFX->getDrawUtil()->drawObjectBox( desc, Point3F( worldBox.len_x(), worldBox.len_y(), worldBox.len_z() ), worldBox.getCenter(), MatrixF::Identity, ColorI::WHITE ); } } }
void EditTSCtrl::renderCameraAxis() { GFXDEBUGEVENT_SCOPE( Editor_renderCameraAxis, ColorI::WHITE ); static MatrixF sRotMat(EulerF( (M_PI_F / -2.0f), 0.0f, 0.0f)); MatrixF camMat = mLastCameraQuery.cameraMatrix; camMat.mul(sRotMat); camMat.inverse(); MatrixF axis; axis.setColumn(0, Point3F(1, 0, 0)); axis.setColumn(1, Point3F(0, 0, 1)); axis.setColumn(2, Point3F(0, -1, 0)); axis.mul(camMat); Point3F forwardVec, upVec, rightVec; axis.getColumn( 2, &forwardVec ); axis.getColumn( 1, &upVec ); axis.getColumn( 0, &rightVec ); Point2I pos = getPosition(); F32 offsetx = pos.x + 20.0; F32 offsety = pos.y + getExtent().y - 42.0; // Take the status bar into account F32 scale = 15.0; // Generate correct drawing order ColorI c1(255,0,0); ColorI c2(0,255,0); ColorI c3(0,0,255); ColorI tc; Point3F *p1, *p2, *p3, *tp; p1 = &rightVec; p2 = &upVec; p3 = &forwardVec; if(p3->y > p2->y) { tp = p2; tc = c2; p2 = p3; c2 = c3; p3 = tp; c3 = tc; } if(p2->y > p1->y) { tp = p1; tc = c1; p1 = p2; c1 = c2; p2 = tp; c2 = tc; } PrimBuild::begin( GFXLineList, 6 ); //*** Axis 1 PrimBuild::color(c1); PrimBuild::vertex3f(offsetx, offsety, 0); PrimBuild::vertex3f(offsetx+p1->x*scale, offsety-p1->z*scale, 0); //*** Axis 2 PrimBuild::color(c2); PrimBuild::vertex3f(offsetx, offsety, 0); PrimBuild::vertex3f(offsetx+p2->x*scale, offsety-p2->z*scale, 0); //*** Axis 3 PrimBuild::color(c3); PrimBuild::vertex3f(offsetx, offsety, 0); PrimBuild::vertex3f(offsetx+p3->x*scale, offsety-p3->z*scale, 0); PrimBuild::end(); }
void TerrainBlock::_updateBaseTexture(bool writeToCache) { if ( !mBaseShader && !_initBaseShader() ) return; // This can sometimes occur outside a begin/end scene. const bool sceneBegun = GFX->canCurrentlyRender(); if ( !sceneBegun ) GFX->beginScene(); GFXDEBUGEVENT_SCOPE( TerrainBlock_UpdateBaseTexture, ColorI::GREEN ); PROFILE_SCOPE( TerrainBlock_UpdateBaseTexture ); GFXTransformSaver saver; const U32 maxTextureSize = GFX->getCardProfiler()->queryProfile( "maxTextureSize", 1024 ); U32 baseTexSize = getNextPow2( mBaseTexSize ); baseTexSize = getMin( maxTextureSize, baseTexSize ); Point2I destSize( baseTexSize, baseTexSize ); // Setup geometry GFXVertexBufferHandle<GFXVertexPT> vb; { F32 copyOffsetX = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.x; F32 copyOffsetY = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.y; GFXVertexPT points[4]; points[0].point = Point3F(1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0); points[0].texCoord = Point2F(1.0, 1.0f); points[1].point = Point3F(1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0); points[1].texCoord = Point2F(1.0, 0.0f); points[2].point = Point3F(-1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0); points[2].texCoord = Point2F(0.0, 1.0f); points[3].point = Point3F(-1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0); points[3].texCoord = Point2F(0.0, 0.0f); vb.set( GFX, 4, GFXBufferTypeVolatile ); GFXVertexPT *ptr = vb.lock(); if(ptr) { dMemcpy( ptr, points, sizeof(GFXVertexPT) * 4 ); vb.unlock(); } } GFXTexHandle blendTex; // If the base texture is already a valid render target then // use it to render to else we create one. if ( mBaseTex.isValid() && mBaseTex->isRenderTarget() && mBaseTex->getFormat() == GFXFormatR8G8B8A8 && mBaseTex->getWidth() == destSize.x && mBaseTex->getHeight() == destSize.y ) blendTex = mBaseTex; else blendTex.set( destSize.x, destSize.y, GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, "" ); GFX->pushActiveRenderTarget(); // Set our shader stuff GFX->setShader( mBaseShader ); GFX->setShaderConstBuffer( mBaseShaderConsts ); GFX->setStateBlock( mBaseShaderSB ); GFX->setVertexBuffer( vb ); mBaseTarget->attachTexture( GFXTextureTarget::Color0, blendTex ); GFX->setActiveRenderTarget( mBaseTarget ); GFX->clear( GFXClearTarget, ColorI(0,0,0,255), 1.0f, 0 ); GFX->setTexture( 0, mLayerTex ); mBaseShaderConsts->setSafe( mBaseLayerSizeConst, (F32)mLayerTex->getWidth() ); for ( U32 i=0; i < mBaseTextures.size(); i++ ) { GFXTextureObject *tex = mBaseTextures[i]; if ( !tex ) continue; GFX->setTexture( 1, tex ); F32 baseSize = mFile->mMaterials[i]->getDiffuseSize(); F32 scale = 1.0f; if ( !mIsZero( baseSize ) ) scale = getWorldBlockSize() / baseSize; // A mistake early in development means that texture // coords are not flipped correctly. To compensate // we flip the y scale here. mBaseShaderConsts->setSafe( mBaseTexScaleConst, Point2F( scale, -scale ) ); mBaseShaderConsts->setSafe( mBaseTexIdConst, (F32)i ); GFX->drawPrimitive( GFXTriangleStrip, 0, 2 ); } mBaseTarget->resolve(); GFX->setShader( NULL ); //GFX->setStateBlock( NULL ); // WHY NOT? GFX->setShaderConstBuffer( NULL ); GFX->setVertexBuffer( NULL ); GFX->popActiveRenderTarget(); // End it if we begun it... Yeehaw! if ( !sceneBegun ) GFX->endScene(); /// Do we cache this sucker? if (mBaseTexFormat == NONE || !writeToCache) { // We didn't cache the result, so set the base texture // to the render target we updated. This should be good // for realtime painting cases. mBaseTex = blendTex; } else if (mBaseTexFormat == DDS) { String cachePath = _getBaseTexCacheFileName(); FileStream fs; if ( fs.open( _getBaseTexCacheFileName(), Torque::FS::File::Write ) ) { // Read back the render target, dxt compress it, and write it to disk. GBitmap blendBmp( destSize.x, destSize.y, false, GFXFormatR8G8B8A8 ); blendTex.copyToBmp( &blendBmp ); /* // Test code for dumping uncompressed bitmap to disk. { FileStream fs; if ( fs.open( "./basetex.png", Torque::FS::File::Write ) ) { blendBmp.writeBitmap( "png", fs ); fs.close(); } } */ blendBmp.extrudeMipLevels(); DDSFile *blendDDS = DDSFile::createDDSFileFromGBitmap( &blendBmp ); DDSUtil::squishDDS( blendDDS, GFXFormatDXT1 ); // Write result to file stream blendDDS->write( fs ); delete blendDDS; } fs.close(); } else { FileStream stream; if (!stream.open(_getBaseTexCacheFileName(), Torque::FS::File::Write)) { mBaseTex = blendTex; return; } GBitmap bitmap(blendTex->getWidth(), blendTex->getHeight(), false, GFXFormatR8G8B8); blendTex->copyToBmp(&bitmap); bitmap.writeBitmap(formatToExtension(mBaseTexFormat), stream); } }