//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Base rendering utilities for all views // // $NoKeywords: $ //===========================================================================// #include "stdafx.h" #include "MapDoc.h" #include #include "mathlib/vmatrix.h" #include "Render.h" #include "Camera.h" #include "Material.h" #include "materialsystem/imesh.h" #include "datacache\imdlcache.h" #include "hammer.h" #include "hammer_mathlib.h" #include "vgui_controls/Controls.h" #include "vgui/IScheme.h" #include "texturesystem.h" #include "IStudioRender.h" #include "builddisp.h" #include "mapview.h" #include "material.h" #include #include "materialsystem/IMaterialSystemHardwareConfig.h" #include "vphysics_interface.h" #include "materialsystem/MaterialSystem_Config.h" #include "VGuiWnd.h" #include "Box3D.h" #include "MapInstance.h" extern IMatSystemSurface *g_pMatSystemSurface; static float s_fOneUnitLength = 1; CRender::CRender(void) { m_pView = NULL; // returns a handle to the default (first loaded) scheme vgui::IScheme * pScheme = vgui::scheme()->GetIScheme( vgui::scheme()->GetDefaultScheme() ); if ( pScheme ) { m_DefaultFont = pScheme->GetFont( "Default" ); } else { m_DefaultFont = vgui::INVALID_FONT; static bool s_bOnce = false; if ( !s_bOnce ) { s_bOnce = true; MessageBox( NULL, "Failed to load the default scheme file. The map views may be missing some visual elements.", "Error", MB_OK | MB_ICONEXCLAMATION ); } } for (int i = 0; i < 2; ++i) { m_pFlat[i] = NULL; m_pWireframe[i] = NULL; m_pTranslucentFlat[i] = NULL; m_pLightmapGrid[i] = NULL; m_pSelectionOverlay[i] = NULL; m_pDotted[i] = NULL; m_pFlatNoZ[i] = NULL; m_pFlatNoCull[i] = NULL; } m_pCurrentMaterial = NULL; m_pBoundMaterial = NULL; m_nDecalMode = 0; m_bIsRendering = false; m_bIsClientSpace = false; m_bIsLocalTransform = false; m_bIsRenderingIntoVGUI = false; VMatrix IdentityMatrix; IdentityMatrix.Identity(); m_LocalMatrix.AddToHead( IdentityMatrix ); m_OrthoMatrix.Identity(); m_eCurrentRenderMode = m_eDefaultRenderMode = RENDER_MODE_FLAT; m_bInstanceRendering = false; m_nInstanceCount = 0; m_InstanceSelectionDepth = 0; PushInstanceData( NULL, Vector( 0.0f, 0.0f, 0.0f ), QAngle( 0.0f, 0.0f, 0.0f ) ); // always add a default state UpdateStudioRenderConfig( false, false ); } CRender::~CRender(void) { } //----------------------------------------------------------------------------- // Purpose: this function will push all of the instance data // Input : pInstanceClass - the func_instance entity // InstanceOrigin - the translation of the instance // InstanceAngles - the rotation of the instance // Output : none //----------------------------------------------------------------------------- void CRender::PushInstanceData( CMapInstance *pInstanceClass, Vector &InstanceOrigin, QAngle &InstanceAngles ) { TInstanceState InstanceState; matrix3x4_t Instance3x4Matrix; InstanceState.m_InstanceOrigin = InstanceOrigin; InstanceState.m_InstanceAngles = InstanceAngles; InstanceState.m_pInstanceClass = pInstanceClass; InstanceState.m_pTopInstanceClass = NULL; AngleMatrix( InstanceState.m_InstanceAngles, InstanceState.m_InstanceOrigin, Instance3x4Matrix ); InstanceState.m_InstanceMatrix.Init( Instance3x4Matrix ); Vector vecTransformedOrigin; TransformInstanceVector( InstanceState.m_InstanceOrigin, vecTransformedOrigin ); m_CurrentInstanceState.m_InstanceOrigin = vecTransformedOrigin; // RotateInstanceVector( ( Vector )InstanceState.m_InstanceAngles, m_CurrentInstanceState.m_InstanceAngles ); no one uses this right now make sure to store it in the same fashion as vecTransformedOrigin if ( m_InstanceState.Count() > 0 ) { // first push is just a default state m_bInstanceRendering = true; BeginLocalTransfrom( InstanceState.m_InstanceMatrix, true ); if ( m_CurrentInstanceState.m_pTopInstanceClass == NULL ) { if ( pInstanceClass->IsEditable() == false ) { InstanceState.m_pTopInstanceClass = pInstanceClass; } } else { InstanceState.m_pTopInstanceClass = m_CurrentInstanceState.m_pTopInstanceClass; } if ( pInstanceClass->IsSelected() || m_InstanceSelectionDepth ) { m_InstanceSelectionDepth++; } InstanceState.m_InstanceMatrix = m_CurrentInstanceState.m_InstanceMatrix * InstanceState.m_InstanceMatrix; InstanceState.m_bIsEditable = pInstanceClass->IsEditable(); } else { m_bInstanceRendering = false; InstanceState.m_bIsEditable = true; } InstanceState.m_InstanceRenderMatrix = m_LocalMatrix.Head(); m_InstanceState.AddToHead( InstanceState ); m_CurrentInstanceState = InstanceState; if ( !pInstanceClass ) { } else if ( m_InstanceSelectionDepth > 0 ) { PushInstanceRendering( INSTANCE_STACE_SELECTED ); } else if ( pInstanceClass->IsEditable() || CMapDoc::GetActiveMapDoc()->GetShowInstance() == INSTANCES_SHOW_NORMAL ) { PushInstanceRendering( INSTANCE_STATE_OFF ); } else { PushInstanceRendering( GetInstanceClass()->IsSelected() ? INSTANCE_STACE_SELECTED : INSTANCE_STATE_ON ); } } //----------------------------------------------------------------------------- // Purpose: this function will pop off the top most instance data //----------------------------------------------------------------------------- void CRender::PopInstanceData( void ) { if ( m_CurrentInstanceState.m_pInstanceClass ) { PopInstanceRendering(); } m_InstanceState.Remove( 0 ); m_CurrentInstanceState = m_InstanceState.Head(); if ( m_InstanceState.Count() > 1 ) { // first push is just a default state m_bInstanceRendering = true; } else { m_bInstanceRendering = false; } if ( m_InstanceSelectionDepth > 0 ) { m_InstanceSelectionDepth--; } EndLocalTransfrom(); // m_CurrentInstanceState.m_InstanceRenderMatrix = m_LocalMatrix.Head(); } //----------------------------------------------------------------------------- // Purpose: this function initializes the stencil buffer for instance rendering //----------------------------------------------------------------------------- void CRender::PrepareInstanceStencil( void ) { CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); #if STENCIL_AS_CALLS pRenderContext->SetStencilEnable( true ); pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS ); pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); pRenderContext->SetStencilWriteMask( 0xff ); pRenderContext->SetStencilTestMask( 0xff ); pRenderContext->SetStencilReferenceValue( 0x01 ); pRenderContext->SetStencilPassOperation( STENCILOPERATION_ZERO); #else m_ShaderStencilState.m_bEnable = true; m_ShaderStencilState.m_CompareFunc = SHADER_STENCILFUNC_ALWAYS; m_ShaderStencilState.m_FailOp = SHADER_STENCILOP_KEEP; m_ShaderStencilState.m_ZFailOp = SHADER_STENCILOP_KEEP; m_ShaderStencilState.m_nWriteMask = 0xff; m_ShaderStencilState.m_nTestMask = 0xff; m_ShaderStencilState.m_nReferenceValue = 0x01; m_ShaderStencilState.m_PassOp = SHADER_STENCILOP_ZERO; pRenderContext->SetStencilState( m_ShaderStencilState ); #endif // STENCIL_AS_CALLS } //----------------------------------------------------------------------------- // Purpose: this function will draw the various alpha color 2d rectangles for the instance states //----------------------------------------------------------------------------- void CRender::DrawInstanceStencil( void ) { CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); CCamera *pCamera = GetCamera(); if ( m_nNumInstancesRendered > 0 ) { #if STENCIL_AS_CALLS pRenderContext->SetStencilPassOperation( STENCILOPERATION_KEEP ); pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); #else m_ShaderStencilState.m_PassOp = SHADER_STENCILOP_KEEP; m_ShaderStencilState.m_CompareFunc = SHADER_STENCILFUNC_EQUAL; #endif // STENCIL_AS_CALLS Color InstanceColoring; int width, height; pCamera->GetViewPort( width, height ); PushRenderMode( RENDER_MODE_INSTANCE_OVERLAY ); BeginClientSpace(); InstanceColor( InstanceColoring, false ); #if STENCIL_AS_CALLS pRenderContext->SetStencilReferenceValue( 0x01 ); #else m_ShaderStencilState.m_nReferenceValue = 0x01; pRenderContext->SetStencilState( m_ShaderStencilState ); #endif // STENCIL_AS_CALLS DrawFilledRect( Vector2D( 0.0f, 0.0f ), Vector2D( width, height ), ( byte * )&InstanceColoring, false ); InstanceColor( InstanceColoring, true ); #if STENCIL_AS_CALLS pRenderContext->SetStencilTestMask( 0xff ); pRenderContext->SetStencilReferenceValue( 0x02 ); #else m_ShaderStencilState.m_nReferenceValue = 0x02; pRenderContext->SetStencilState( m_ShaderStencilState ); #endif // STENCIL_AS_CALLS DrawFilledRect( Vector2D( 0.0f, 0.0f ), Vector2D( width, height ), ( byte * )&InstanceColoring, false ); EndClientSpace(); PopRenderMode(); } #if STENCIL_AS_CALLS pRenderContext->SetStencilEnable( false ); #else m_ShaderStencilState.m_bEnable = false; pRenderContext->SetStencilState( m_ShaderStencilState ); #endif // STENCIL_AS_CALLS } //----------------------------------------------------------------------------- // Purpose: this function will push all of the instance data // Input : pInstanceClass - the func_instance entity // InstanceOrigin - the translation of the instance // InstanceAngles - the rotation of the instance // Output : none //----------------------------------------------------------------------------- void CRender::PushInstanceRendering( InstanceRenderingState_t State ) { SetInstanceRendering( State ); m_InstanceRenderingState.AddToHead( State ); if ( State != INSTANCE_STATE_OFF ) { m_nNumInstancesRendered++; } } //----------------------------------------------------------------------------- // Purpose: this function will pop off the top most instance data //----------------------------------------------------------------------------- void CRender::PopInstanceRendering( void ) { m_InstanceRenderingState.Remove( 0 ); if ( m_InstanceRenderingState.Count() > 0 ) { SetInstanceRendering( m_InstanceRenderingState.Head() ); } else { SetInstanceRendering( INSTANCE_STATE_OFF ); } } //----------------------------------------------------------------------------- // Purpose: Sets the instance rendering state for stencil buffer operations. // 0 in stencil buffer = normal drawing // 1 in stencil buffer = instance shaded pass // 2 in stencil buffer = instance selected shaded pass // Input : State - the state at which the next drawing operations should impact // the stencil buffer //----------------------------------------------------------------------------- void CRender::SetInstanceRendering( InstanceRenderingState_t State ) { CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); switch( State ) { case INSTANCE_STATE_OFF: #ifdef STENCIL_AS_CALLS pRenderContext->SetStencilPassOperation( STENCILOPERATION_ZERO ); #else m_ShaderStencilState.m_PassOp = SHADER_STENCILOP_ZERO; #endif // STENCIL_AS_CALLS break; case INSTANCE_STATE_ON: #if STENCIL_AS_CALLS pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); pRenderContext->SetStencilReferenceValue( 0x01 ); #else m_ShaderStencilState.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE; m_ShaderStencilState.m_nReferenceValue = 0x01; #endif // STENCIL_AS_CALLS break; case INSTANCE_STACE_SELECTED: #if STENCIL_AS_CALLS pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); pRenderContext->SetStencilReferenceValue( 0x02 ); #else m_ShaderStencilState.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE; m_ShaderStencilState.m_nReferenceValue = 0x02; #endif // STENCIL_AS_CALLS break; } #ifndef STENCIL_AS_CALLS pRenderContext->SetStencilState( m_ShaderStencilState ); #endif // STENCIL_AS_CALLS } //----------------------------------------------------------------------------- // Purpose: This function renders a text string at the given position, width, // height, and format // Input: text - the string to print // pos - the screen space position of the text (the is the top-left of // a screen space rect) // width - the width to render the text into // height - the height to render the text into // nFlags - define the text format -- see SetTextFormat //----------------------------------------------------------------------------- void CRender::DrawText( const char *text, int x, int y, int nFlags ) { wchar_t unicode[ 128 ]; mbstowcs( unicode, text, ARRAYSIZE(unicode) ); int len = min( 127, Q_strlen( text ) ); Assert( m_DefaultFont != vgui::INVALID_FONT ); bool bJustifyText = nFlags & ( TEXT_JUSTIFY_LEFT | TEXT_JUSTIFY_TOP | TEXT_JUSTIFY_HORZ_CENTER | TEXT_JUSTIFY_VERT_CENTER ); if ( bJustifyText && m_DefaultFont != vgui::INVALID_FONT ) { int wide,tall; g_pMatSystemSurface->GetTextSize( m_DefaultFont, unicode, wide, tall ); if ( nFlags & TEXT_JUSTIFY_LEFT ) x -= wide; if ( nFlags & TEXT_JUSTIFY_TOP ) y -= tall; if ( nFlags & TEXT_JUSTIFY_HORZ_CENTER ) x -= wide/2; if ( nFlags & TEXT_JUSTIFY_VERT_CENTER ) y -= tall/2; } PushRenderMode( RENDER_MODE_EXTERN ); bool bPopMode = BeginClientSpace(); g_pMatSystemSurface->DrawSetTextPos( x, y ); g_pMatSystemSurface->DrawPrintText( unicode, len ); if ( bPopMode ) EndClientSpace(); PopRenderMode(); } //----------------------------------------------------------------------------- // Uses "world" coordinates //----------------------------------------------------------------------------- void CRender::DrawText( const char *text, const Vector2D &vPos, int nOffsetX, int nOffsetY, int nFlags ) { Vector vecActualPos( vPos.x, vPos.y, 0.0f ); if ( IsInLocalTransformMode() ) { VMatrix matrix; GetLocalTranform( matrix ); Vector vWorld = vecActualPos; Vector3DMultiplyPosition( matrix, vWorld, vecActualPos ); } Vector2D pt; m_pView->WorldToClient( pt, vecActualPos ); DrawText( text, (int)pt.x + nOffsetX, (int)pt.y + nOffsetY, nFlags ); } //----------------------------------------------------------------------------- // Purpose: set the text and background (behind text) colors // Input: tR, tG, tB - text red, green, and blue values : [0...255] // bkR, bkG, bkB - background red, green, blue values : [0...255] //----------------------------------------------------------------------------- void CRender::SetTextColor( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) { m_TextColor.SetColor( r,g,b,a ); if ( m_bIsRenderingIntoVGUI ) { g_pMatSystemSurface->DrawSetTextColor( m_TextColor ); } } void CRender::SetHandleColor( unsigned char r, unsigned char g, unsigned char b ) { m_HandleColor.SetColor( r, g, b, 255 ); } void CRender::UpdateStudioRenderConfig( bool bFlat, bool bWireframe ) { StudioRenderConfig_t config; memset( &config, 0, sizeof( config ) ); config.fEyeShiftX = 0.0f; config.fEyeShiftY = 0.0f; config.fEyeShiftZ = 0.0f; config.fEyeSize = 0; config.drawEntities = 1; config.skin = 0; config.fullbright = MaterialSystemConfig().nFullbright; config.bEyeMove = true; config.bSoftwareSkin = bWireframe; config.bNoHardware = false; config.bNoSoftware = false; config.bTeeth = false; config.bEyes = true; config.bFlex = true; config.bSoftwareLighting = true; config.bWireframe = bWireframe; config.bDrawNormals = false; config.bShowEnvCubemapOnly = false; g_pStudioRender->UpdateConfig( config ); } void CRender::StartRenderFrame() { Assert( !m_bIsRendering ); m_nNumInstancesRendered = 0; m_bIsRenderingIntoVGUI = dynamic_cast( GetView() ); if ( m_bIsRenderingIntoVGUI ) { g_pMatSystemSurface->DrawSetTextFont( m_DefaultFont ); g_pMatSystemSurface->DrawSetTextColor( m_TextColor ); g_pMatSystemSurface->DrawSetColor( m_DrawColor ); } int width, height; VMatrix matrix; CCamera *pCamera = GetCamera(); CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); // build ortho matrix for client space mode pCamera->GetViewPort( width, height ); pRenderContext->MatrixMode(MATERIAL_PROJECTION); pRenderContext->LoadIdentity(); pRenderContext->Scale( 1, -1, 1 ); pRenderContext->Ortho(0, 0, width, height, -99999, 99999 ); pRenderContext->GetMatrix( MATERIAL_PROJECTION, &m_OrthoMatrix ); // setup world camera pCamera->GetProjMatrix(matrix); pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->LoadMatrix( matrix ); pCamera->GetViewMatrix(matrix); pRenderContext->MatrixMode( MATERIAL_VIEW ); pRenderContext->LoadMatrix( matrix ); pRenderContext->MatrixMode(MATERIAL_MODEL); pRenderContext->LoadIdentity(); pRenderContext->SetAmbientLight( 1.0, 1.0, 1.0 ); pCamera->GetViewMatrix( m_CurrentMatrix ); // Disable all the lights.. for( int i = 0; i < MaterialSystemHardwareConfig()->MaxNumLights(); ++i) { LightDesc_t desc; desc.m_Type = MATERIAL_LIGHT_DISABLE; pRenderContext->SetLight( i, desc ); } m_bIsClientSpace = false; // reset render mode m_RenderModeStack.Clear(); SetRenderMode( m_eDefaultRenderMode, true ); // reset colors m_DrawColor.SetColor( 255,255,255,255 ); m_TextColor.SetColor( 255,255,255,255 ); m_HandleColor.SetColor( 255,255,255,255 ); s_fOneUnitLength = 1/pCamera->GetZoom(); // tell studiorender that we've updated the camera. if( g_pStudioRender ) { g_pStudioRender->BeginFrame(); Vector viewOrigin, viewRight, viewUp, viewForward; pCamera->GetViewPoint( viewOrigin ); pCamera->GetViewRight( viewRight ); pCamera->GetViewUp( viewUp ); pCamera->GetViewForward( viewForward ); g_pStudioRender->SetViewState( viewOrigin, viewRight, viewUp, viewForward ); static Vector white[6] = { Vector( 1.0, 1.0, 1.0 ), Vector( 1.0, 1.0, 1.0 ), Vector( 1.0, 1.0, 1.0 ), Vector( 1.0, 1.0, 1.0 ), Vector( 1.0, 1.0, 1.0 ), Vector( 1.0, 1.0, 1.0 ), }; g_pStudioRender->SetAmbientLightColors( white ); } m_bIsRendering = true; } void CRender::EndRenderFrame() { Assert( m_bIsRendering ); Assert( !m_bIsClientSpace ); Assert( m_RenderModeStack.Count() == 0 ); Assert( !m_bIsLocalTransform ); if ( g_pStudioRender ) { g_pStudioRender->BeginFrame(); } // turn off lighting preview shader state CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); pRenderContext->SetIntRenderingParameter(INT_RENDERPARM_ENABLE_FIXED_LIGHTING,0); m_nFrameCount++; m_bIsRendering = false; m_bIsRenderingIntoVGUI = false; } void CRender::DrawLine( const Vector &vStart, const Vector &vEnd ) { float scale = VectorLength( vEnd-vStart ) / ( s_fOneUnitLength * 16 ); meshBuilder.Begin(m_pMesh, MATERIAL_LINES, 1); meshBuilder.Position3fv(vStart.Base()); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.TexCoord2f(0, 0, 0); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv(vEnd.Base()); meshBuilder.Color4ubv((byte*)&m_DrawColor); meshBuilder.TexCoord2f(0, scale, scale); meshBuilder.AdvanceVertex(); meshBuilder.End(); m_pMesh->Draw(); } void CRender::BeginLocalTransfrom( const VMatrix &matrix, bool MultiplyCurrent ) { Assert( !m_bIsClientSpace ); VMatrix LocalCopy = matrix; if ( MultiplyCurrent ) { LocalCopy = m_LocalMatrix.Head() * LocalCopy; } m_LocalMatrix.AddToHead( LocalCopy ); CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); pRenderContext->MatrixMode(MATERIAL_MODEL); pRenderContext->PushMatrix(); pRenderContext->LoadMatrix( m_LocalMatrix.Head() ); CCamera *pCamera = GetCamera(); pCamera->GetViewMatrix( m_CurrentMatrix ); m_CurrentMatrix = m_CurrentMatrix * LocalCopy; m_bIsLocalTransform = true; } void CRender::EndLocalTransfrom() { Assert( m_bIsLocalTransform ); Assert( !m_bIsClientSpace ); CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); pRenderContext->MatrixMode(MATERIAL_MODEL); pRenderContext->PopMatrix(); m_LocalMatrix.Remove( 0 ); CCamera *pCamera = GetCamera(); pCamera->GetViewMatrix( m_CurrentMatrix ); if ( m_LocalMatrix.Count() > 1 ) { m_CurrentMatrix = m_CurrentMatrix * m_LocalMatrix.Head(); m_bIsLocalTransform = true; } else { m_bIsLocalTransform = false; } } bool CRender::IsInLocalTransformMode() { return m_bIsLocalTransform; } void CRender::GetLocalTranform( VMatrix &matrix ) { matrix = m_LocalMatrix.Head(); } bool CRender::BeginClientSpace(void) { if ( m_bIsClientSpace ) return false; CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->PushMatrix(); pRenderContext->LoadMatrix( m_OrthoMatrix ); pRenderContext->MatrixMode(MATERIAL_VIEW); pRenderContext->PushMatrix(); pRenderContext->LoadIdentity(); if ( m_bIsLocalTransform ) { pRenderContext->MatrixMode(MATERIAL_MODEL); pRenderContext->PushMatrix(); pRenderContext->LoadIdentity(); } m_bIsClientSpace = true; return true; } void CRender::EndClientSpace(void) { Assert( m_bIsClientSpace ); CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); pRenderContext->MatrixMode(MATERIAL_VIEW); pRenderContext->PopMatrix(); pRenderContext->MatrixMode(MATERIAL_PROJECTION); pRenderContext->PopMatrix(); if ( m_bIsLocalTransform ) { pRenderContext->MatrixMode(MATERIAL_MODEL); pRenderContext->PopMatrix(); } m_bIsClientSpace = false; } void CRender::TransformPoint( Vector2D &vClient, const Vector& vWorld ) { Vector vecActualPos; if ( !m_bIsLocalTransform ) { vecActualPos = vWorld; } else { m_LocalMatrix.Head().V3Mul( vWorld, vecActualPos ); } m_pView->WorldToClient( vClient, vecActualPos ); } void CRender::TransformNormal( Vector2D &vClient, const Vector& vWorld ) { Vector2D originClient, normalClient; TransformPoint( originClient, vec3_origin ); TransformPoint( normalClient, vWorld ); vClient = normalClient- originClient; } void CRender::DrawCircle( const Vector &vCenter, const Vector &vNormal, float flRadius, int nSegments) { Vector vx,vy; if ( !BuildAxesFromNormal( vNormal, vx, vy ) ) return; vx *= flRadius; vy *= flRadius; meshBuilder.Begin( m_pMesh, MATERIAL_LINE_LOOP, nSegments ); float invDelta = 2.0f * M_PI / nSegments; for ( int i = 0; i < nSegments; ++i ) { float flRadians = i * invDelta; float ca = cos( flRadians ); float sa = sin( flRadians ); // Rotate it around the circle Vector vertex = vCenter + (ca*vx) + (sa*vy); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.Position3fv( &vertex.x ); meshBuilder.AdvanceVertex(); } meshBuilder.End(); m_pMesh->Draw(); } void CRender::DrawCircle( Vector2D &vCenter, float fRadius, int nSegments, unsigned char *pColor ) { meshBuilder.Begin( m_pMesh, MATERIAL_LINE_LOOP, nSegments ); float invDelta = 2.0f * M_PI / nSegments; for ( int i = 0; i < nSegments; ++i ) { float flRadians = i * invDelta; float ca = cos( flRadians ); float sa = sin( flRadians ); // Rotate it around the circle float x = vCenter.x + (fRadius * ca); float y = vCenter.y + (fRadius * sa); meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( x, y, 0 ); meshBuilder.AdvanceVertex(); } meshBuilder.End(); m_pMesh->Draw(); } void CRender::DrawCross( Vector2D& ul, Vector2D& lr, unsigned char *pColor ) { // just sizes meshBuilder.Begin( m_pMesh, MATERIAL_LINES, 2 ); meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( ul.x, ul.y, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( lr.x, lr.y, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( ul.x, lr.y-1, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( lr.x, ul.y-1, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.End(); m_pMesh->Draw(); } void CRender::DrawRect( Vector2D& ul, Vector2D& lr, unsigned char *pColor ) { Vector2D vScale = (lr-ul)/16; meshBuilder.Begin( m_pMesh, MATERIAL_LINE_LOOP, 4 ); Vector2D tex(0,0); meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( ul.x, ul.y, 0 ); meshBuilder.TexCoord2f(0, tex.x, tex.y ); meshBuilder.AdvanceVertex(); tex.x += vScale.x; tex.y += vScale.x; meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( lr.x, ul.y, 0 ); meshBuilder.TexCoord2f(0, tex.x, tex.y ); meshBuilder.AdvanceVertex(); tex.x += vScale.y; tex.y -= vScale.y; meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( lr.x, lr.y, 0 ); meshBuilder.TexCoord2f(0, tex.x, tex.y ); meshBuilder.AdvanceVertex(); tex.x -= vScale.x; tex.y -= vScale.x; meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( ul.x, lr.y, 0 ); meshBuilder.TexCoord2f(0, tex.x, tex.y ); meshBuilder.AdvanceVertex(); meshBuilder.End(); m_pMesh->Draw(); } void CRender::DrawPlane( const Vector &p0, const Vector &p1, const Vector &p2, const Vector &p3, bool bFill ) { if ( bFill ) { meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, 1 ); } else { meshBuilder.Begin( m_pMesh, MATERIAL_LINE_LOOP, 4 ); } meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.Position3fv( &p0.x ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.Position3fv( &p1.x ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.Position3fv( &p2.x ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.Position3fv( &p3.x ); meshBuilder.AdvanceVertex(); meshBuilder.End(); m_pMesh->Draw(); } void CRender::DrawFilledRect( Vector2D& ul, Vector2D& lr, unsigned char *pColor, bool bBorder ) { static Color black(0,0,0,255); meshBuilder.Begin( m_pMesh, MATERIAL_QUADS, bBorder?2:1 ); if ( bBorder ) { meshBuilder.Color4ubv( (byte*)&black ); meshBuilder.Position3f( ul.x, ul.y, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( (byte*)&black ); meshBuilder.Position3f( lr.x, ul.y, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( (byte*)&black ); meshBuilder.Position3f( lr.x, lr.y, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( (byte*)&black ); meshBuilder.Position3f( ul.x, lr.y, 0 ); meshBuilder.AdvanceVertex(); ul.x+=1; ul.y+=1; lr.x-=1; lr.y-=1; } meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( ul.x, ul.y, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( lr.x, ul.y, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( lr.x, lr.y, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv( pColor ); meshBuilder.Position3f( ul.x, lr.y, 0 ); meshBuilder.AdvanceVertex(); meshBuilder.End(); m_pMesh->Draw(); } void CRender::DrawHandle( const Vector &vCenter, const Vector2D *vOffset ) { if ( !m_CurrentInstanceState.m_bIsEditable ) { return; } int size = m_nHandleSize; bool bPopMode = BeginClientSpace(); Vector2D vCenter2D; TransformPoint( vCenter2D, vCenter ); if ( vOffset ) { vCenter2D += *vOffset; } RoundVector( vCenter2D ); if ( m_nHandleType == HANDLE_CROSS ) size--; Vector2D ul( vCenter2D.x-size, vCenter2D.y-size ); Vector2D lr( vCenter2D.x+size+1, vCenter2D.y+size+1 ); switch ( m_nHandleType ) { case HANDLE_SQUARE : DrawFilledRect( ul, lr, (byte*)&m_HandleColor, true );break; case HANDLE_CIRCLE : DrawCircle( vCenter2D, size, 16, (byte*)&m_HandleColor ); break; case HANDLE_DIAMOND : break; case HANDLE_CROSS : DrawCross( ul, lr, (byte*)&m_HandleColor );break; } if ( bPopMode ) EndClientSpace(); } CCamera *CRender::GetCamera() { return m_pView->GetCamera(); } bool CRender::SetView( CMapView * pView ) { Assert( pView ); m_pView = pView; // Store off the three materials we use most often... if ( !GetRequiredMaterial( "editor/wireframe", m_pWireframe[0] ) || !GetRequiredMaterial( "editor/flat", m_pFlat[0] ) || !GetRequiredMaterial( "editor/flatdecal", m_pFlat[1] ) || !GetRequiredMaterial( "editor/translucentflat", m_pTranslucentFlat[0] ) || !GetRequiredMaterial( "editor/translucentflatdecal", m_pTranslucentFlat[1] ) || !GetRequiredMaterial( "editor/lightmapgrid", m_pLightmapGrid[0] ) || !GetRequiredMaterial( "editor/lightmapgriddecal", m_pLightmapGrid[1] ) || !GetRequiredMaterial( "editor/selectionoverlay", m_pSelectionOverlay[0] ) || !GetRequiredMaterial( "editor/flatignorez", m_pFlatNoZ[0] ) || !GetRequiredMaterial( "editor/flatnocull", m_pFlatNoCull[0] ) || !GetRequiredMaterial( "editor/dotted", m_pDotted[0] ) ) { return false; } // Some materials don't have a separate decal version. m_pFlatNoZ[1] = m_pFlatNoZ[0]; m_pFlatNoCull[1] = m_pFlatNoCull[0]; m_pWireframe[1] = m_pWireframe[0]; m_pDotted[1] = m_pDotted[0]; m_pSelectionOverlay[1] = m_pSelectionOverlay[0]; return true; } bool CRender::IsActiveView() { return m_pView->IsActive(); } void CRender::SetDrawColor( const Color &color ) { m_DrawColor = color; if ( m_bIsRenderingIntoVGUI ) { g_pMatSystemSurface->DrawSetColor( m_DrawColor ); } } void CRender::GetDrawColor( Color &color ) { color = m_DrawColor; } void CRender::SetDrawColor( unsigned char r, unsigned char g, unsigned char b ) { // current draw color, keep the alpha value m_DrawColor.SetColor( r, g, b, m_DrawColor.a() ); if ( m_bIsRenderingIntoVGUI ) { g_pMatSystemSurface->DrawSetColor( m_DrawColor ); } } void CRender::SetHandleStyle( int size, int type ) { m_nHandleType = type; m_nHandleSize = size; } void CRender::DrawArrow( Vector const &vStart, Vector const &vEnd ) { Assert(0); } void CRender::DrawPolyLine( int nPoints, const Vector *Points ) { // Draw the box bottom, top, and one corner edge. meshBuilder.Begin( m_pMesh, MATERIAL_LINE_LOOP, nPoints ); for (int i= 0; iDraw(); } void CRender::DrawDisplacement( CCoreDispInfo *pMapDisp ) { int numVerts = pMapDisp->GetSize(); int numIndices = pMapDisp->GetRenderIndexCount(); bool bWireFrame = m_eCurrentRenderMode == RENDER_MODE_WIREFRAME; meshBuilder.Begin( m_pMesh, MATERIAL_TRIANGLES, numVerts, numIndices ); Color color = m_DrawColor; CoreDispVert_t *pVert = pMapDisp->GetDispVertList(); for (int i = 0; i < numVerts; ++i ) { if ( bWireFrame ) { meshBuilder.Position3fv( pVert[i].m_Vert.Base() ); meshBuilder.Color4ubv( (byte*)&color ); meshBuilder.TexCoord2fv( 0, pVert[i].m_TexCoord.Base() ); meshBuilder.TexCoord2fv( 1, pVert[i].m_LuxelCoords[0].Base() ); meshBuilder.AdvanceVertex(); } else { meshBuilder.Position3fv( pVert[i].m_Vert.Base() ); meshBuilder.Color4ub( color[0], color[1], color[2], 255 - ( unsigned char )( pVert[i].m_Alpha ) ); meshBuilder.Normal3fv( pVert[i].m_Normal.Base() ); meshBuilder.TangentS3fv( pVert[i].m_TangentS.Base() ); meshBuilder.TangentT3fv( pVert[i].m_TangentT.Base() ); meshBuilder.TexCoord2fv( 0, pVert[i].m_TexCoord.Base() ); meshBuilder.TexCoord2fv( 1, pVert[i].m_LuxelCoords[0].Base() ); meshBuilder.AdvanceVertex(); } } unsigned short *pIndex = pMapDisp->GetRenderIndexList(); for ( int i = 0; i < numIndices; ++i ) { meshBuilder.Index( pIndex[i] ); meshBuilder.AdvanceIndex(); } meshBuilder.End(); m_pMesh->Draw(); } void CRender::DrawModel( DrawModelInfo_t* pInfo, matrix3x4_t *pBoneToWorld, const Vector &vOrigin, float fAlpha, bool bWireFrame ) { UpdateStudioRenderConfig( true, bWireFrame ); g_pStudioRender->SetAlphaModulation( fAlpha ); Vector viewOrigin; GetCamera()->GetViewPoint( viewOrigin ); g_pStudioRender->SetEyeViewTarget( pInfo->m_pStudioHdr, pInfo->m_Body, viewOrigin ); g_pStudioRender->DrawModel( NULL, *pInfo, pBoneToWorld, NULL, NULL, vOrigin, STUDIORENDER_DRAW_ENTIRE_MODEL ); g_pStudioRender->SetAlphaModulation( 1.0f ); // force rendermode reset SetRenderMode( RENDER_MODE_CURRENT, true ); } void CRender::DrawCollisionModel( MDLHandle_t mdlHandle, const VMatrix &mViewMatrix ) { vcollide_t *pCollide =g_pMDLCache->GetVCollide( mdlHandle ); if ( !pCollide || pCollide->solidCount <= 0 ) return; Vector *outVerts; int vertCount = g_pPhysicsCollision->CreateDebugMesh( pCollide->solids[0], &outVerts ); if ( vertCount ) { PushRenderMode( RENDER_MODE_WIREFRAME ); meshBuilder.Begin( m_pMesh, MATERIAL_TRIANGLES, vertCount/3 ); for ( int j = 0; j < vertCount; j++ ) { Vector out; mViewMatrix.V3Mul( outVerts[j], out ); meshBuilder.Position3fv( out.Base() ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.TexCoord2f( 0, 0, 0 ); meshBuilder.AdvanceVertex(); } meshBuilder.End(); m_pMesh->Draw(); PopRenderMode(); } g_pPhysicsCollision->DestroyDebugMesh( vertCount, outVerts ); } void CRender::DrawSphere( const Vector &vCenter, int nRadius ) { Assert(0); } void CRender::DrawBoxExt( const Vector &vCenter, float extend, bool bFill) { Vector vExtent( extend, extend, extend ); Vector vMins = vCenter - vExtent; Vector vMax = vCenter + vExtent; DrawBox( vMins, vMax, bFill ); } void CRender::DrawHandles( int nPoints, const Vector *Points ) { Assert(0); } void CRender::DrawBox( const Vector &vMins, const Vector &vMaxs, bool bFill) { Vector points[8]; PointsFromBox( vMins, vMaxs, points ); if ( bFill ) { Assert(0); } else { // Draw the box bottom, top, and one corner edge. meshBuilder.Begin( m_pMesh, MATERIAL_LINE_STRIP, 9 ); meshBuilder.Position3fv( &points[0].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[1].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[3].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[2].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[6].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[7].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[5].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[4].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[0].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[2].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.End(); m_pMesh->Draw(); // Draw the three missing edges. meshBuilder.Begin( m_pMesh, MATERIAL_LINES, 3 ); meshBuilder.Position3fv( &points[4].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[6].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[1].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[5].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[3].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3fv( &points[7].x ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.End(); m_pMesh->Draw(); } } void CRender::DrawPoint( const Vector &vPoint ) { // HACK HACK, MATERIAL_POINTS doesnt work somehow meshBuilder.Begin( m_pMesh, MATERIAL_LINES, 1 ); meshBuilder.Position3f( vPoint.x, vPoint.y, vPoint.z ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3f( vPoint.x+1, vPoint.y+1, vPoint.z ); meshBuilder.Color4ubv( (byte*)&m_DrawColor ); meshBuilder.AdvanceVertex(); meshBuilder.End(); m_pMesh->Draw(); } //----------------------------------------------------------------------------- // Purpose: Binds a texture for rendering. If the texture has never been bound // to this rendering context, it is uploaded to the driver. // Input : pTexture - Pointer to the texture object being bound. //----------------------------------------------------------------------------- void CRender::BindTexture(IEditorTexture *pTexture) { // These textures must be CMaterials.... BindMaterial( pTexture->GetMaterial() ); } //----------------------------------------------------------------------------- // Purpose: Binds a material for rendering. If the material has never been bound // to this rendering context, it is uploaded to the driver. // Input : pMaterial - Pointer to the material object being bound. //----------------------------------------------------------------------------- void CRender::BindMaterial( IMaterial *pMaterial ) { if ( m_pBoundMaterial != pMaterial ) { m_pBoundMaterial = pMaterial; SetRenderMode( RENDER_MODE_CURRENT, true ); } } bool CRender::GetRequiredMaterial( const char *pName, IMaterial* &pMaterial ) { pMaterial = NULL; IEditorTexture *pTex = g_Textures.FindActiveTexture( pName ); if ( pTex ) pMaterial = pTex->GetMaterial(); if ( pMaterial ) { return true; } else { char str[512]; Q_snprintf( str, sizeof( str ), "Missing material '%s'. Go to Tools | Options | Game Configurations and verify that your game directory is correct.", pName ); MessageBox( NULL, str, "FATAL ERROR", MB_OK ); return false; } } //----------------------------------------------------------------------------- // Purpose: // Input : eRenderMode - //----------------------------------------------------------------------------- void CRender::SetRenderMode(EditorRenderMode_t eRenderMode, bool bForce) { if (eRenderMode == RENDER_MODE_DEFAULT) { eRenderMode = m_eDefaultRenderMode; } if ( eRenderMode == RENDER_MODE_CURRENT ) { eRenderMode = m_eCurrentRenderMode; } if (m_eCurrentRenderMode == eRenderMode && !bForce) return; // Bind the appropriate material based on our mode CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); switch(eRenderMode) { case RENDER_MODE_DOTTED: m_pCurrentMaterial = m_pDotted[m_nDecalMode]; break; case RENDER_MODE_FLAT: // Ensures we get red even for decals m_pCurrentMaterial = m_pFlat[m_nDecalMode]; break; case RENDER_MODE_TRANSLUCENT_FLAT: m_pCurrentMaterial = m_pTranslucentFlat[m_nDecalMode]; break; case RENDER_MODE_FLAT_NOZ: // flat mode but not depth check m_pCurrentMaterial = m_pFlatNoZ[m_nDecalMode]; break; case RENDER_MODE_FLAT_NOCULL: // flat mode but not depth check m_pCurrentMaterial = m_pFlatNoCull[m_nDecalMode]; break; case RENDER_MODE_WIREFRAME: m_pCurrentMaterial = m_pWireframe[m_nDecalMode]; break; case RENDER_MODE_SMOOTHING_GROUP: m_pCurrentMaterial = m_pFlat[m_nDecalMode]; break; case RENDER_MODE_LIGHTMAP_GRID: m_pCurrentMaterial = m_pLightmapGrid[m_nDecalMode]; break; case RENDER_MODE_SELECTION_OVERLAY: case RENDER_MODE_INSTANCE_OVERLAY: // Ensures we get red even for decals m_pCurrentMaterial = m_pSelectionOverlay[m_nDecalMode]; break; case RENDER_MODE_TEXTURED: case RENDER_MODE_TEXTURED_SHADED: case RENDER_MODE_LIGHT_PREVIEW2: case RENDER_MODE_LIGHT_PREVIEW_RAYTRACED: if (m_pBoundMaterial) { if( m_pBoundMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS ) ) { pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP ); } else { pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE ); } m_pCurrentMaterial = m_pBoundMaterial; } else { m_pCurrentMaterial = m_pFlat[m_nDecalMode]; } break; } Assert( m_pCurrentMaterial != NULL ); pRenderContext->Bind( m_pCurrentMaterial ); pRenderContext->SetIntRenderingParameter(INT_RENDERPARM_ENABLE_FIXED_LIGHTING,0); if (eRenderMode==RENDER_MODE_TEXTURED_SHADED) pRenderContext->SetIntRenderingParameter(INT_RENDERPARM_ENABLE_FIXED_LIGHTING,1); if ( (eRenderMode==RENDER_MODE_LIGHT_PREVIEW2) || (eRenderMode==RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) ) pRenderContext->SetIntRenderingParameter(INT_RENDERPARM_ENABLE_FIXED_LIGHTING,2); m_pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_pCurrentMaterial ); Assert( m_pMesh ); m_eCurrentRenderMode = eRenderMode; } //----------------------------------------------------------------------------- // Purpose: // Input : eRenderMode - //----------------------------------------------------------------------------- void CRender::SetDefaultRenderMode(EditorRenderMode_t eRenderMode) { Assert( eRenderMode != RENDER_MODE_DEFAULT ); m_eDefaultRenderMode = eRenderMode; } void CRender::PushRenderMode( EditorRenderMode_t eRenderMode ) { m_RenderModeStack.Push( m_eCurrentRenderMode ); SetRenderMode( eRenderMode ); } void CRender::PopRenderMode() { SetRenderMode( m_RenderModeStack.Top() ); m_RenderModeStack.Pop(); } #define CAMERA_RIGHT 0 #define CAMERA_UP 1 #define CAMERA_FORWARD 2 //----------------------------------------------------------------------------- // Purpose: Returns a vector indicating the camera's forward axis. //----------------------------------------------------------------------------- void CRender::GetViewForward( Vector &ViewForward ) const { ViewForward[ 0 ] = -m_CurrentMatrix[ CAMERA_FORWARD ][ 0 ]; ViewForward[ 1 ] = -m_CurrentMatrix[ CAMERA_FORWARD ][ 1 ]; ViewForward[ 2 ] = -m_CurrentMatrix[ CAMERA_FORWARD ][ 2 ]; } //----------------------------------------------------------------------------- // Purpose: Returns a vector indicating the camera's up axis. //----------------------------------------------------------------------------- void CRender::GetViewUp(Vector& ViewUp) const { ViewUp[ 0 ] = m_CurrentMatrix[ CAMERA_UP ][ 0 ]; ViewUp[ 1 ] = m_CurrentMatrix[ CAMERA_UP ][ 1 ]; ViewUp[ 2 ] = m_CurrentMatrix[ CAMERA_UP ][ 2 ]; } //----------------------------------------------------------------------------- // Purpose: Returns a vector indicating the camera's right axis. //----------------------------------------------------------------------------- void CRender::GetViewRight(Vector& ViewRight) const { ViewRight[ 0 ] = m_CurrentMatrix[ CAMERA_RIGHT ][ 0 ]; ViewRight[ 1 ] = m_CurrentMatrix[ CAMERA_RIGHT ][ 1 ]; ViewRight[ 2 ] = m_CurrentMatrix[ CAMERA_RIGHT ][ 2 ]; }