// Created on: 2011-09-20 // Created by: Sergey ZERCHANINOV // Copyright (c) 2011-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Workspace,Standard_Transient) namespace { static const OpenGl_Vec4 THE_WHITE_COLOR (1.0f, 1.0f, 1.0f, 1.0f); static const OpenGl_Vec4 THE_BLACK_COLOR (0.0f, 0.0f, 0.0f, 1.0f); static const OpenGl_Matrix myDefaultMatrix = { {{ 1.0F, 0.0F, 0.0F, 0.0F }, { 0.0F, 1.0F, 0.0F, 0.0F }, { 0.0F, 0.0F, 1.0F, 0.0F }, { 0.0F, 0.0F, 0.0F, 1.0F }} }; } // ======================================================================= // function : Init // purpose : // ======================================================================= void OpenGl_Material::Init (const Graphic3d_MaterialAspect& theMat, const Quantity_Color& theInteriorColor) { const bool isPhysic = theMat.MaterialType (Graphic3d_MATERIAL_PHYSIC); ChangeShine() = 128.0f * theMat.Shininess(); ChangeTransparency() = theMat.Alpha(); // ambient component if (theMat.ReflectionMode (Graphic3d_TOR_AMBIENT)) { const OpenGl_Vec3& aSrcAmb = isPhysic ? theMat.AmbientColor() : theInteriorColor; Ambient = OpenGl_Vec4 (aSrcAmb * theMat.Ambient(), 1.0f); } else { Ambient = THE_BLACK_COLOR; } // diffusion component if (theMat.ReflectionMode (Graphic3d_TOR_DIFFUSE)) { const OpenGl_Vec3& aSrcDif = isPhysic ? theMat.DiffuseColor() : theInteriorColor; Diffuse = OpenGl_Vec4 (aSrcDif * theMat.Diffuse(), 1.0f); } else { Diffuse = THE_BLACK_COLOR; } // specular component if (theMat.ReflectionMode (Graphic3d_TOR_SPECULAR)) { const OpenGl_Vec3& aSrcSpe = isPhysic ? (const OpenGl_Vec3& )theMat.SpecularColor() : THE_WHITE_COLOR.rgb(); Specular = OpenGl_Vec4 (aSrcSpe * theMat.Specular(), 1.0f); } else { Specular = THE_BLACK_COLOR; } // emission component if (theMat.ReflectionMode (Graphic3d_TOR_EMISSION)) { const OpenGl_Vec3& aSrcEms = isPhysic ? theMat.EmissiveColor() : theInteriorColor; Emission = OpenGl_Vec4 (aSrcEms * theMat.Emissive(), 1.0f); } else { Emission = THE_BLACK_COLOR; } } // ======================================================================= // function : OpenGl_Workspace // purpose : // ======================================================================= OpenGl_Workspace::OpenGl_Workspace (OpenGl_View* theView, const Handle(OpenGl_Window)& theWindow) : myView (theView), myWindow (theWindow), myGlContext (!theWindow.IsNull() ? theWindow->GetGlContext() : NULL), myUseZBuffer (Standard_True), myUseDepthWrite (Standard_True), // myNbSkippedTranspElems (0), myRenderFilter (OpenGl_RenderFilter_Empty), // myAspectLineSet (&myDefaultAspectLine), myAspectFaceSet (&myDefaultAspectFace), myAspectMarkerSet (&myDefaultAspectMarker), myAspectTextSet (&myDefaultAspectText), // ViewMatrix_applied (&myDefaultMatrix), StructureMatrix_applied (&myDefaultMatrix), myToAllowFaceCulling (false), myModelViewMatrix (myDefaultMatrix) { if (!myGlContext.IsNull() && myGlContext->MakeCurrent()) { myGlContext->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1); // General initialization of the context #if !defined(GL_ES_VERSION_2_0) if (myGlContext->core11 != NULL) { // enable two-side lighting by default glLightModeli ((GLenum )GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glHint (GL_POINT_SMOOTH_HINT, GL_FASTEST); if (myGlContext->caps->ffpEnable) { glHint (GL_FOG_HINT, GL_FASTEST); } } glHint (GL_LINE_SMOOTH_HINT, GL_FASTEST); glHint (GL_POLYGON_SMOOTH_HINT, GL_FASTEST); #endif } myFontFaceAspect.Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Blend, 0.285f); myFontFaceAspect.Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT); myNoneCulling .Aspect()->SetSuppressBackFaces (false); myNoneCulling .Aspect()->SetDrawEdges (false); myNoneCulling .Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque); myFrontCulling.Aspect()->SetSuppressBackFaces (true); myFrontCulling.Aspect()->SetDrawEdges (false); myFrontCulling.Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque); } // ======================================================================= // function : Activate // purpose : // ======================================================================= Standard_Boolean OpenGl_Workspace::Activate() { if (myWindow.IsNull() || !myWindow->Activate()) { return Standard_False; } ViewMatrix_applied = &myDefaultMatrix; StructureMatrix_applied = &myDefaultMatrix; ResetAppliedAspect(); // reset state for safety myGlContext->BindProgram (Handle(OpenGl_ShaderProgram)()); if (myGlContext->core20fwd != NULL) { myGlContext->core20fwd->glUseProgram (OpenGl_ShaderProgram::NO_PROGRAM); } if (myGlContext->caps->ffpEnable) { myGlContext->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)()); } #if !defined(GL_ES_VERSION_2_0) // font GLSL program has embedded discard, while FFP needs alpha test myFontFaceAspect.Aspect()->SetAlphaMode ((!myGlContext->caps->ffpEnable && myGlContext->core11 != NULL) ? Graphic3d_AlphaMode_Blend : Graphic3d_AlphaMode_Mask, 0.285f); #endif return Standard_True; } //======================================================================= //function : ResetAppliedAspect //purpose : Sets default values of GL parameters in accordance with default aspects //======================================================================= void OpenGl_Workspace::ResetAppliedAspect() { myGlContext->BindDefaultVao(); myHighlightStyle.Nullify(); myToAllowFaceCulling = false; myAspectLineSet = &myDefaultAspectLine; myAspectFaceSet = &myDefaultAspectFace; myAspectFaceApplied.Nullify(); myAspectMarkerSet = &myDefaultAspectMarker; myAspectMarkerApplied.Nullify(); myAspectTextSet = &myDefaultAspectText; myGlContext->SetPolygonOffset (Graphic3d_PolygonOffset()); ApplyAspectLine(); ApplyAspectFace(); ApplyAspectMarker(); ApplyAspectText(); myGlContext->SetTypeOfLine (myDefaultAspectLine.Aspect()->Type()); myGlContext->SetLineWidth (myDefaultAspectLine.Aspect()->Width()); } // ======================================================================= // function : SetDefaultPolygonOffset // purpose : // ======================================================================= Graphic3d_PolygonOffset OpenGl_Workspace::SetDefaultPolygonOffset (const Graphic3d_PolygonOffset& theOffset) { Graphic3d_PolygonOffset aPrev = myDefaultAspectFace.Aspect()->PolygonOffset(); myDefaultAspectFace.Aspect()->SetPolygonOffset (theOffset); if (myAspectFaceApplied == myDefaultAspectFace.Aspect() || myAspectFaceApplied.IsNull() || (myAspectFaceApplied->PolygonOffset().Mode & Aspect_POM_None) == Aspect_POM_None) { myGlContext->SetPolygonOffset (theOffset); } return aPrev; } // ======================================================================= // function : SetAspectLine // purpose : // ======================================================================= const OpenGl_AspectLine* OpenGl_Workspace::SetAspectLine (const OpenGl_AspectLine* theAspect) { const OpenGl_AspectLine* aPrevAspectLine = myAspectLineSet; myAspectLineSet = theAspect; return aPrevAspectLine; } // ======================================================================= // function : SetAspectFace // purpose : // ======================================================================= const OpenGl_AspectFace * OpenGl_Workspace::SetAspectFace (const OpenGl_AspectFace* theAspect) { const OpenGl_AspectFace* aPrevAspectFace = myAspectFaceSet; myAspectFaceSet = theAspect; return aPrevAspectFace; } // ======================================================================= // function : SetAspectMarker // purpose : // ======================================================================= const OpenGl_AspectMarker* OpenGl_Workspace::SetAspectMarker (const OpenGl_AspectMarker* theAspect) { const OpenGl_AspectMarker* aPrevAspectMarker = myAspectMarkerSet; myAspectMarkerSet = theAspect; return aPrevAspectMarker; } // ======================================================================= // function : SetAspectText // purpose : // ======================================================================= const OpenGl_AspectText * OpenGl_Workspace::SetAspectText (const OpenGl_AspectText* theAspect) { const OpenGl_AspectText* aPrevAspectText = myAspectTextSet; myAspectTextSet = theAspect; return aPrevAspectText; } // ======================================================================= // function : ApplyAspectFace // purpose : // ======================================================================= const OpenGl_AspectFace* OpenGl_Workspace::ApplyAspectFace() { if (myView->BackfacingModel() == Graphic3d_TOBM_AUTOMATIC) { bool toSuppressBackFaces = myToAllowFaceCulling && myAspectFaceSet->Aspect()->ToSuppressBackFaces(); if (toSuppressBackFaces) { if (myAspectFaceSet->Aspect()->InteriorStyle() == Aspect_IS_HATCH || myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Blend || myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Mask || (myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_BlendAuto && myAspectFaceSet->Aspect()->FrontMaterial().Transparency() != 0.0f)) { // disable culling in case of translucent shading aspect toSuppressBackFaces = false; } } myGlContext->SetCullBackFaces (toSuppressBackFaces); } if (myAspectFaceSet->Aspect() == myAspectFaceApplied && myHighlightStyle == myAspectFaceAppliedWithHL) { return myAspectFaceSet; } myAspectFaceAppliedWithHL = myHighlightStyle; // Aspect_POM_None means: do not change current settings if ((myAspectFaceSet->Aspect()->PolygonOffset().Mode & Aspect_POM_None) != Aspect_POM_None) { myGlContext->SetPolygonOffset (myAspectFaceSet->Aspect()->PolygonOffset()); } const Aspect_InteriorStyle anIntstyle = myAspectFaceSet->Aspect()->InteriorStyle(); if (myAspectFaceApplied.IsNull() || myAspectFaceApplied->InteriorStyle() != anIntstyle) { #if !defined(GL_ES_VERSION_2_0) myGlContext->SetPolygonMode (anIntstyle == Aspect_IS_POINT ? GL_POINT : GL_FILL); myGlContext->SetPolygonHatchEnabled (anIntstyle == Aspect_IS_HATCH); #endif } #if !defined(GL_ES_VERSION_2_0) if (anIntstyle == Aspect_IS_HATCH) { myGlContext->SetPolygonHatchStyle (myAspectFaceSet->Aspect()->HatchStyle()); } #endif // Case of hidden line if (anIntstyle == Aspect_IS_HIDDENLINE) { // copy all values including line edge aspect *myAspectFaceHl.Aspect() = *myAspectFaceSet->Aspect(); myAspectFaceHl.SetAspectEdge (myAspectFaceSet->AspectEdge()); myAspectFaceHl.Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT); myAspectFaceHl.Aspect()->SetInteriorColor (myView->BackgroundColor().GetRGB()); myAspectFaceHl.Aspect()->SetDistinguish (false); myAspectFaceHl.SetNoLighting(); myAspectFaceSet = &myAspectFaceHl; } else { myGlContext->SetShadingMaterial (myAspectFaceSet, myHighlightStyle); } if (myAspectFaceSet->Aspect()->ToMapTexture()) { myGlContext->BindTextures (myAspectFaceSet->TextureSet (myGlContext)); } else { myGlContext->BindTextures (myEnvironmentTexture); } myAspectFaceApplied = myAspectFaceSet->Aspect(); return myAspectFaceSet; } // ======================================================================= // function : ApplyAspectMarker // purpose : // ======================================================================= const OpenGl_AspectMarker* OpenGl_Workspace::ApplyAspectMarker() { if (myAspectMarkerSet->Aspect() != myAspectMarkerApplied) { if (myAspectMarkerApplied.IsNull() || (myAspectMarkerSet->Aspect()->Scale() != myAspectMarkerApplied->Scale())) { #if !defined(GL_ES_VERSION_2_0) glPointSize (myAspectMarkerSet->Aspect()->Scale()); #endif } myAspectMarkerApplied = myAspectMarkerSet->Aspect(); } return myAspectMarkerSet; } // ======================================================================= // function : Width // purpose : // ======================================================================= Standard_Integer OpenGl_Workspace::Width() const { return !myView->GlWindow().IsNull() ? myView->GlWindow()->Width() : 0; } // ======================================================================= // function : Height // purpose : // ======================================================================= Standard_Integer OpenGl_Workspace::Height() const { return !myView->GlWindow().IsNull() ? myView->GlWindow()->Height() : 0; } // ======================================================================= // function : FBOCreate // purpose : // ======================================================================= Handle(OpenGl_FrameBuffer) OpenGl_Workspace::FBOCreate (const Standard_Integer theWidth, const Standard_Integer theHeight) { // activate OpenGL context if (!Activate()) return Handle(OpenGl_FrameBuffer)(); // create the FBO const Handle(OpenGl_Context)& aCtx = GetGlContext(); aCtx->BindTextures (Handle(OpenGl_TextureSet)()); Handle(OpenGl_FrameBuffer) aFrameBuffer = new OpenGl_FrameBuffer(); if (!aFrameBuffer->Init (aCtx, theWidth, theHeight, GL_RGBA8, GL_DEPTH24_STENCIL8, 0)) { aFrameBuffer->Release (aCtx.operator->()); return Handle(OpenGl_FrameBuffer)(); } return aFrameBuffer; } // ======================================================================= // function : FBORelease // purpose : // ======================================================================= void OpenGl_Workspace::FBORelease (Handle(OpenGl_FrameBuffer)& theFbo) { // activate OpenGL context if (!Activate() || theFbo.IsNull()) { return; } theFbo->Release (GetGlContext().operator->()); theFbo.Nullify(); } // ======================================================================= // function : BufferDump // purpose : // ======================================================================= Standard_Boolean OpenGl_Workspace::BufferDump (const Handle(OpenGl_FrameBuffer)& theFbo, Image_PixMap& theImage, const Graphic3d_BufferType& theBufferType) { return !theImage.IsEmpty() && Activate() && OpenGl_FrameBuffer::BufferDump (GetGlContext(), theFbo, theImage, theBufferType); } // ======================================================================= // function : ShouldRender // purpose : // ======================================================================= bool OpenGl_Workspace::ShouldRender (const OpenGl_Element* theElement) { // render only non-raytracable elements when RayTracing is enabled if ((myRenderFilter & OpenGl_RenderFilter_NonRaytraceableOnly) != 0) { if (OpenGl_Raytrace::IsRaytracedElement (theElement)) { return false; } } else if ((myRenderFilter & OpenGl_RenderFilter_FillModeOnly) != 0) { if (!theElement->IsFillDrawMode()) { return false; } } // handle opaque/transparency render passes if ((myRenderFilter & OpenGl_RenderFilter_OpaqueOnly) != 0) { if (!theElement->IsFillDrawMode()) { return true; } if (OpenGl_Context::CheckIsTransparent (myAspectFaceSet, myHighlightStyle)) { ++myNbSkippedTranspElems; return false; } } else if ((myRenderFilter & OpenGl_RenderFilter_TransparentOnly) != 0) { if (!theElement->IsFillDrawMode()) { if (dynamic_cast (theElement) == NULL) { return false; } } else if (!OpenGl_Context::CheckIsTransparent (myAspectFaceSet, myHighlightStyle)) { return false; } } return true; }