/// <summary> /// <see cref="ISceneRenderer.Render"/> /// </summary> public void Render(ICameraController cam, Dictionary <Node, List <Mesh> > visibleMeshesByNode, bool visibleSetChanged, bool texturesChanged, RenderFlags flags, Renderer renderer) { GL.Disable(EnableCap.Texture2D); GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); GL.Enable(EnableCap.DepthTest); if (flags.HasFlag(RenderFlags.Wireframe)) { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); } var tmp = InitposeMax.X - InitposeMin.X; tmp = Math.Max(InitposeMax.Y - InitposeMin.Y, tmp); tmp = Math.Max(InitposeMax.Z - InitposeMin.Z, tmp); int logScale = (int)Math.Truncate(Math.Log10(tmp * 10 / 50)); // Up to 50units max size = 50m: keep scale (for smaller scenes). float scale = 1; for (int i = 0; i < logScale; i++) { scale = scale / 10; } Owner.Scale = scale; if (cam != null) { // cam.SetPivot(Owner.Pivot * (float)scale); this does nothing (?) only makes controller dirty } var view = cam == null?Matrix4.LookAt(0, 10, 5, 0, 0, 0, 0, 1, 0) : cam.GetView(); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref view); GL.Scale(scale, scale, scale); Owner.MaterialMapper.BeginScene(renderer, flags.HasFlag(RenderFlags.UseSceneLights)); //here we switch on lights if (flags.HasFlag(RenderFlags.ShowLightDirection)) //switch off for video?? { var dir = new Vector3(1, 1, 0); var mat = renderer.LightRotation; Vector3.TransformNormal(ref dir, ref mat, out dir); OverlayLightSource.DrawLightSource(dir); } // If textures changed, we may need to upload some of them to VRAM. // it is important this happens here and not accidentially while // compiling a displist. if (texturesChanged) { UploadTextures(); } UploadDynamicTextures(); GL.PushMatrix(); // Build and cache Gl displaylists and update only when the scene changes. // when the scene is being animated, this changes each frame var animated = Owner.SceneAnimator.IsAnimationActive; if (visibleSetChanged || texturesChanged || flags != _lastFlags || (animated && (Owner.NewFrame) || wasAnimated)) { int startList = 4; //we update only 4 animation displists if (visibleSetChanged || texturesChanged || flags != _lastFlags) { startList = 0; } _lastFlags = flags; // handle opaque geometry for (int currDispList = startList; currDispList < _displayListCount; currDispList++) { if (_displayList[currDispList, 0] == 0) { _displayList[currDispList, 0] = GL.GenLists(1); } GL.NewList(_displayList[currDispList, 0], ListMode.Compile); var needAlpha = RecursiveRender(Owner.Raw.RootNode, visibleMeshesByNode, flags, animated, currDispList); if (flags.HasFlag(RenderFlags.ShowSkeleton)) { RecursiveRenderNoScale(Owner.Raw.RootNode, visibleMeshesByNode, flags, 1.0f / scale, animated, currDispList); } if (flags.HasFlag(RenderFlags.ShowNormals)) { RecursiveRenderNormals(Owner.Raw.RootNode, visibleMeshesByNode, flags, 1.0f / scale, animated, Matrix4.Identity, currDispList); } GL.EndList(); if (needAlpha) { // handle semi-transparent geometry if (_displayList[currDispList, 1] == 0) { _displayList[currDispList, 1] = GL.GenLists(1); } GL.NewList(_displayList[currDispList, 1], ListMode.Compile); RecursiveRenderWithAlpha(Owner.Raw.RootNode, visibleMeshesByNode, flags, animated, currDispList); GL.EndList(); } else if (_displayList[currDispList, 1] != 0) { GL.DeleteLists(_displayList[currDispList, 1], 1); _displayList[currDispList, 1] = 0; } } } Owner.NewFrame = false; wasAnimated = animated; /* display lists: * 0: Background; * 1: Else (always visible); * 2: Foreground; * 3: GreenScreen; * 4: BackgroundAnimated; * 5: ElseAnimated (always visible); * 6: ForegroundAnimated; * 7: GreenScreenAnimated; * Animated - list is refreshed each frame */ switch (cam.GetScenePartMode()) { case ScenePartMode.Background: if (_displayList[0, 0] != 0) { GL.CallList(_displayList[0, 0]); } if (_displayList[4, 0] != 0) { GL.CallList(_displayList[4, 0]); } if (_displayList[0, 1] != 0) { GL.CallList(_displayList[0, 1]); } if (_displayList[4, 1] != 0) { GL.CallList(_displayList[4, 1]); } break; case ScenePartMode.Foreground: if (_displayList[2, 0] != 0) { GL.CallList(_displayList[2, 0]); } if (_displayList[6, 0] != 0) { GL.CallList(_displayList[6, 0]); } if (_displayList[2, 1] != 0) { GL.CallList(_displayList[2, 1]); } if (_displayList[6, 1] != 0) { GL.CallList(_displayList[6, 1]); } break; case ScenePartMode.Others: if (_displayList[1, 0] != 0) { GL.CallList(_displayList[1, 0]); } if (_displayList[5, 0] != 0) { GL.CallList(_displayList[5, 0]); } if (_displayList[1, 1] != 0) { GL.CallList(_displayList[1, 1]); } if (_displayList[5, 1] != 0) { GL.CallList(_displayList[5, 1]); } break; case ScenePartMode.GreenScreen: if (_displayList[3, 0] != 0) { GL.CallList(_displayList[3, 0]); } if (_displayList[7, 0] != 0) { GL.CallList(_displayList[7, 0]); } if (_displayList[3, 1] != 0) { GL.CallList(_displayList[3, 1]); } if (_displayList[7, 1] != 0) { GL.CallList(_displayList[7, 1]); } break; case ScenePartMode.All: for (int currDispList = 0; currDispList < _displayListCount; currDispList++) { if (_displayList[currDispList, 0] != 0) { GL.CallList(_displayList[currDispList, 0]); } if (_displayList[currDispList, 1] != 0) { GL.CallList(_displayList[currDispList, 1]); } } break; default: break; //at other modes we do not render anything } GL.PopMatrix(); // always switch back to FILL Owner.MaterialMapper.EndScene(renderer); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); GL.Disable(EnableCap.DepthTest); #if TEST GL.Enable(EnableCap.ColorMaterial); // TEST CODE to visualize mid point (pivot) and origin GL.LoadMatrix(ref view); GL.Begin(BeginMode.Lines); GL.Vertex3((InitposeMin + InitposeMax) * 0.5f * (float)scale); GL.Color3(0.0f, 1.0f, 0.0f); GL.Vertex3(0, 0, 0); GL.Color3(0.0f, 1.0f, 0.0f); GL.Vertex3((InitposeMin + InitposeMax) * 0.5f * (float)scale); GL.Color3(0.0f, 1.0f, 0.0f); GL.Vertex3(10, 10, 10); GL.Color3(0.0f, 1.0f, 0.0f); GL.End(); #endif GL.Disable(EnableCap.Texture2D); }
/// <summary> /// <see cref="ISceneRenderer.Render"/> /// </summary> public void Render(ICameraController cam, Dictionary <Node, List <Mesh> > visibleMeshesByNode, bool visibleSetChanged, bool texturesChanged, RenderFlags flags, Renderer renderer) { GL.Disable(EnableCap.Texture2D); GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest); GL.Enable(EnableCap.DepthTest); // set fixed-function lighting parameters GL.ShadeModel(ShadingModel.Smooth); GL.LightModel(LightModelParameter.LightModelAmbient, new[] { 0.3f, 0.3f, 0.3f, 1 }); GL.Enable(EnableCap.Lighting); GL.Enable(EnableCap.Light0); if (flags.HasFlag(RenderFlags.Wireframe)) { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); } var tmp = InitposeMax.X - InitposeMin.X; tmp = Math.Max(InitposeMax.Y - InitposeMin.Y, tmp); tmp = Math.Max(InitposeMax.Z - InitposeMin.Z, tmp); var scale = 2.0f / tmp; // TODO: migrate general scale and this snippet to camcontroller code if (cam != null) { cam.SetPivot(Owner.Pivot * (float)scale); } var view = cam == null?Matrix4.LookAt(0, 10, 5, 0, 0, 0, 0, 1, 0) : cam.GetView(); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref view); // light direction var dir = new Vector3(1, 1, 0); var mat = renderer.LightRotation; Vector3.TransformNormal(ref dir, ref mat, out dir); GL.Light(LightName.Light0, LightParameter.Position, new float[] { dir.X, dir.Y, dir.Z, 0 }); // light color var col = new Vector3(1, 1, 1); col *= (0.25f + 1.5f * GraphicsSettings.Default.OutputBrightness / 100.0f) * 1.5f; GL.Light(LightName.Light0, LightParameter.Diffuse, new float[] { col.X, col.Y, col.Z, 1 }); GL.Light(LightName.Light0, LightParameter.Specular, new float[] { col.X, col.Y, col.Z, 1 }); if (flags.HasFlag(RenderFlags.Shaded)) { OverlayLightSource.DrawLightSource(dir); } GL.Scale(scale, scale, scale); // If textures changed, we may need to upload some of them to VRAM. // it is important this happens here and not accidentially while // compiling a displist. if (texturesChanged) { UploadTextures(); } GL.PushMatrix(); // Build and cache Gl displaylists and update only when the scene changes. // when the scene is being animated, this is bad because it changes every // frame anyway. In this case we don't use a displist. var animated = Owner.SceneAnimator.IsAnimationActive; if (_displayList == 0 || visibleSetChanged || texturesChanged || flags != _lastFlags || animated) { _lastFlags = flags; // handle opaque geometry if (!animated) { if (_displayList == 0) { _displayList = GL.GenLists(1); } GL.NewList(_displayList, ListMode.Compile); } var needAlpha = RecursiveRender(Owner.Raw.RootNode, visibleMeshesByNode, flags, animated); if (flags.HasFlag(RenderFlags.ShowSkeleton) || flags.HasFlag(RenderFlags.ShowNormals)) { RecursiveRenderNoScale(Owner.Raw.RootNode, visibleMeshesByNode, flags, 1.0f / scale, animated); } if (!animated) { GL.EndList(); } if (needAlpha) { // handle semi-transparent geometry if (!animated) { if (_displayListAlpha == 0) { _displayListAlpha = GL.GenLists(1); } GL.NewList(_displayListAlpha, ListMode.Compile); } RecursiveRenderWithAlpha(Owner.Raw.RootNode, visibleMeshesByNode, flags, animated); if (!animated) { GL.EndList(); } } else if (_displayListAlpha != 0) { GL.DeleteLists(_displayListAlpha, 1); _displayListAlpha = 0; } } if (!animated) { GL.CallList(_displayList); if (_displayListAlpha != 0) { GL.CallList(_displayListAlpha); } } GL.PopMatrix(); // always switch back to FILL GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); GL.Disable(EnableCap.DepthTest); #if TEST GL.Enable(EnableCap.ColorMaterial); // TEST CODE to visualize mid point (pivot) and origin GL.LoadMatrix(ref view); GL.Begin(BeginMode.Lines); GL.Vertex3((InitposeMin + InitposeMax) * 0.5f * (float)scale); GL.Color3(0.0f, 1.0f, 0.0f); GL.Vertex3(0, 0, 0); GL.Color3(0.0f, 1.0f, 0.0f); GL.Vertex3((InitposeMin + InitposeMax) * 0.5f * (float)scale); GL.Color3(0.0f, 1.0f, 0.0f); GL.Vertex3(10, 10, 10); GL.Color3(0.0f, 1.0f, 0.0f); GL.End(); #endif GL.Disable(EnableCap.Texture2D); GL.Disable(EnableCap.Lighting); }