{"id":17788694,"url":"https://github.com/devel0/netcore-opengl","last_synced_at":"2025-03-16T09:33:34.943Z","repository":{"id":40520095,"uuid":"284578803","full_name":"devel0/netcore-opengl","owner":"devel0","description":"net core opengl","archived":false,"fork":false,"pushed_at":"2025-01-06T16:45:51.000Z","size":27200,"stargazers_count":29,"open_issues_count":1,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-26T07:38:00.019Z","etag":null,"topics":["avalonia","control","framebuffer","multiplatform","netcore","opengl","silk-net"],"latest_commit_sha":null,"homepage":"https://devel0.github.io/netcore-opengl/api/SearchAThing.OpenGL.Core.html","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devel0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-03T01:53:24.000Z","updated_at":"2025-01-10T07:06:27.000Z","dependencies_parsed_at":"2024-07-12T22:29:46.098Z","dependency_job_id":null,"html_url":"https://github.com/devel0/netcore-opengl","commit_stats":{"total_commits":105,"total_committers":1,"mean_commits":105.0,"dds":0.0,"last_synced_commit":"05b6600ec32223d3447b217aa09de25c34a241de"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devel0%2Fnetcore-opengl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devel0%2Fnetcore-opengl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devel0%2Fnetcore-opengl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devel0%2Fnetcore-opengl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devel0","download_url":"https://codeload.github.com/devel0/netcore-opengl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243810586,"owners_count":20351552,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["avalonia","control","framebuffer","multiplatform","netcore","opengl","silk-net"],"created_at":"2024-10-27T10:20:51.905Z","updated_at":"2025-03-16T09:33:34.916Z","avatar_url":"https://github.com/devel0.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# netcore-opengl\n\n.NET core opengl\n\n- [API Documentation][api]\n- [Changelog][changelog]\n\n\u003chr/\u003e\n\n- [Introduction](#introduction)\n- [Requirements](#requirements)\n- [Quickstart](#quickstart)\n- [Build solution](#build-solution)\n- [Examples](#examples)\n  - [Running examples from console](#running-examples-from-console)\n  - [Running examples from vscode](#running-examples-from-vscode)\n  - [List of examples](#list-of-examples)\n- [Development key notes](#development-key-notes)\n  - [Coordinate spaces](#coordinate-spaces)\n  - [GL Dev inspect tool](#gl-dev-inspect-tool)\n  - [VsCode settings](#vscode-settings)\n  - [Primitives, figures interaction](#primitives-figures-interaction)\n    - [Selection and coord identify](#selection-and-coord-identify)\n    - [Removal](#removal)\n    - [SimpleCmd](#simplecmd)\n    - [Change rotation center](#change-rotation-center)\n  - [Send notification](#send-notification)\n  - [View invalidation model](#view-invalidation-model)\n  - [Opengl debugging tools](#opengl-debugging-tools)\n  - [Multiplatform](#multiplatform)\n  - [Docker (mesa)](#docker-mesa)\n  - [Software rendered (mesa)](#software-rendered-mesa)\n  - [C# global usings (full)](#c-global-usings-full)\n  - [Gestures](#gestures)\n    - [Mouse gestures](#mouse-gestures)\n    - [Keybindings](#keybindings)\n- [Unit tests](#unit-tests)\n- [How this project was built](#how-this-project-was-built)\n  - [Documentation (github pages)](#documentation-github-pages)\n    - [Build and view locally](#build-and-view-locally)\n    - [Build and commit into docs branch](#build-and-commit-into-docs-branch)\n- [References](#references)\n\n\u003chr/\u003e\n\n![](data/images/example-0006.gif)\n\n## Introduction\n\n**netcore-opengl** library provides a multiplatform framework for 3D rendering, visualization and interactions.\n\nThe library is composed by following modules:\n\n| module                               | framework        | dependencies                                                                                                           | description                                                       |\n| ------------------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |\n| **core** [![core-badge]][core]       | NET Standard 2.0 | [netcore-ext], [netcore-sci], [System.Drawing.Common], [Silk.NET], [Magick.NET], [SkiaSharp.HarfBuzz], [netdxf-devel0] | gl calculations, render abstraction over Silk.NET opengl library. |\n| **gui** [![gui-badge]][gui]          | NET Standard 2.0 | [core], [Avalonia], [netcore-desktop]                                                                                  | desktop gl widget                                                 |\n| **shapes** [![shapes-badge]][shapes] | NET Standard 2.0 | [core]                                                                                                                 | box, cone, sphere, arrow shapes                                   |\n| **nurbs** [![nurbs-badge]][nurbs]    | NET Standard 2.0 | [core], [G-Shark]                                                                                                      | nurbs figures                                                     |\n\n## Requirements\n\n```sh\napt install libglfw3\n```\n\n## Quickstart\n\n```sh\ndotnet new console --use-program-main -n sample\ncd sample\ndotnet add package netcore-opengl-gui\ndotnet add package netcore-opengl-shapes\ncode .\n# accept to install vscode required assets\n```\n\nedit [`Program.cs`](examples/example-9000/Program.cs) as follows ( consider to create a separate global [usings.cs](#c-global-usings-full) file ):\n\n```csharp\nnamespace sample;\n\n// quickstart\n\nusing Vector3 = System.Numerics.Vector3;\nusing Color = System.Drawing.Color;\nusing SearchAThing.OpenGL.Core;\nusing static SearchAThing.OpenGL.Core.Constants;\nusing SearchAThing.OpenGL.GUI;\nusing static SearchAThing.OpenGL.GUI.Toolkit;\nusing SearchAThing.OpenGL.Shapes;\n\nclass Program\n{\n    static void Main(string[] args)\n    {\n        // this must called for console application to enable Avalonia framework\n        // and must called before any other Avalonia control usage\n        InitAvalonia();\n\n        // create standalone Avalonia window for Silk.NET opengl rendering\n        var w = GLWindow.Create();\n\n        // define the GLModel build function\n        w.GLModel.BuildModel = (glCtl, isInitial) =\u003e\n        {\n            if (!isInitial) return;\n\n            var glModel = glCtl.GLModel;\n\n            // clear the model\n            glModel.Clear();\n\n            // place a point light at xyz=(2,2,2)\n            glModel.PointLights.Add(new GLPointLight(2, 2, 2));\n\n            // create and add a sphere centered at (0,0,0) with radius=1 and meshed as uvsphere with N=20 divisions\n            var sphere = new UVSphere(center: Vector3.Zero, radius: 1);\n            glModel.AddFigure(sphere.Figure(divisions: 20).SetColor(Color.Cyan));\n\n            // place a base box which receive sphere shadow centered like the sphere but 2*z lower ( out of sphere )\n            // with size xyz=(5, 5, .1f) larger than sphere but with small thickness\n            var basebox = new Box(cs: WCS.Move(sphere.Center - Vector3.UnitZ * 2), csSize: new Vector3(5, 5, .1f));\n            glModel.AddFigure(basebox.Sides);\n\n            glCtl.CameraView(CameraViewType.Right);\n        };\n\n        // show the gl window\n        w.ShowSync();\n    }\n}\n```\n\n```sh\ndotnet run # or hit F5 from vscode\n```\n\nresults ( control can manipulated with [gestures](#gestures) ):\n\n[![img][sample]][sample]\n\n[sample]: data/images/sample.png\n\n## Build solution\n\n```sh\ncd netcore-opengl\n# git submodule update --init\ndotnet build\n```\n\n## Examples\n\n### Running examples from console\n\n```sh\ncd netcore-opengl\ndotnet run --project examples/example-0000\n```\n\n### Running examples from vscode\n\n```sh\ncd netcore-opengl\ncode .\n```\n\nC-S-p -\u003e `NET: Generate Assets for Build and Debug`\n\nchoose an example.\n\nTip: to change startup example from bash `./set-startup-example xxxx` where xxxx is the nr of one of the examples provided.\n\nThis will update `.vscode/launch.json` then hit F5 to start.\n\n### List of examples\n\nClick on the `example code` link to open source code of the example, read top tour instructions contained in each example to test functions, for example following in the top comment of example 0000:\n\n```cs\n// example-0000\n// draw a triangle with 3 colors (one for each vertex)\n//\n// use gesture such as:\n// - 'w' to toggle wireframe\n// - ctrl right/left to change tilt\n// - mouse wheel to zoom\n// - 'z' to zoomfit\n// - ctrl + x to show bbox\n```\n\n\u003chr/\u003e\n\nCode: [0000][es0]\n\nDraw a triangle with 3 colors (one for each vertex).\n\n[![img][e0]][e0]\n\n\u003chr/\u003e\n\nCode: [0001][es1]\n\nRandom lines ( console program ).\n\n[![img][e1]][e1]\n\n\u003chr/\u003e\n\nCode: [0002][es2] (mvvm)\n\nRandom lines ( avalonia AXAML program ).\n\n[![img][e2]][e2]\n\n\u003chr/\u003e\n\nCode: [0003][es3]\n\nRender stl terrain map varying vertex colors by height ; presence of a point light makes shadows.\n\n[![img][e3]][e3]\n\n\u003chr/\u003e\n\nCode: [0004][es4]\n\nDraw text.\n\n[![img][e4]][e4]\n\n\u003chr/\u003e\n\nCode: [0005][es5]\n\nDraw box with keyboard face toggler.\n\n[![img][e5]][e5]\n\n\u003chr/\u003e\n\nCode: [0006][es6]\n\nDraw nurb surface with triangles normal and animation, layout loaded from saved file.\n\n[![img][e6]][e6]\n\n\u003chr/\u003e\n\nCode: [0007][es7]\n\nDraw nurb tube with triangle selection on click through raycast in perspective mode; generate gl split layout programmtically generated.\n\n[![img][e7]][e7]\n\n\u003chr/\u003e\n\nCode: [0008][es8] (mvvm)\n\nDraw nurb tube with lighting tunable from mvvm interface.\n\n[![img][e8]][e8]\n\n\u003chr/\u003e\n\nCode: [0009][es9]\n\nGenerate two captures of different sizes from the same scene.\n\n\u003chr/\u003e\n\nCode: [0010][es10]\n\nDraw 3d shapes on a textured cube face.\n\n[![img][e10]][e10]\n\n\u003chr/\u003e\n\nCode: [0011][es11]\n\nTexture, light and text transparency.\n\n[![img][e11]][e11]\n\n\u003chr/\u003e\n\nCode: [0012][es12]\n\nShow text alignment types with their bounding box.\n\n[![img][e12]][e12]\n\n\u003chr/\u003e\n\nCode: [0013][es13]\n\nMultiline text.\n\n[![img][e13]][e13]\n\n\u003chr/\u003e\n\nCode: [0014][es14]\n\nScalability benchmark for text.\n\n[![img][e14]][e14]\n\n\u003chr/\u003e\n\nCode: [0015][es15]\n\nRaycast in orthogonal mode for snapping test.\n\n[![img][e15]][e15]\n\n\u003chr/\u003e\n\nCode: [0016][es16] (mvvm)\n\nInvalidate control on vertex change.\n\n[![img][e16]][e16]\n\n\u003chr/\u003e\n\nCode: [0017][es17]\n\nFigure using screen coord.\n\n[![img][e17]][e17]\n\n\u003chr/\u003e\n\nCode: [0018][es18]\n\nIllusion of rotating base box model while its the camera that's rotating around. A small box rotates using object matrix in all scenes ; show camera frustum.\n\n[![img][e18]][e18]\n\n\u003chr/\u003e\n\nCode: [0019][es19] (mvvm)\n\nSphere vertex render and hittest scalability test.\n\n[![img][e19]][e19]\n\n\u003chr/\u003e\n\nCode: [0020][es20]\n\nCustomize key gesture.\n\n\u003chr/\u003e\n\nCode: [0021][es21]\n\nUse of raycast to pick vertexes and define a new ucs.\n\n[![img][e21]][e21]\n\n\u003chr/\u003e\n\nCode: [0022][es22]\n\nNurb surface join on two tubes.\n\n[![img][e22]][e22]\n\n\u003chr/\u003e\n\nCode: [0023][es23]\n\nShow 1-D fem element displacement using. Dependency: [BriefFiniteElement].\n\n[![img][e23]][e23]\n\n\u003chr/\u003e\n\nCode: [0024][es24]\n\nShow 3-D fem element displacement with countour and legend visible only in one of the split views using control and figure custom tag data. Dependency: [BriefFiniteElement]\n\n[![img][e24]][e24]\n\n\u003chr/\u003e\n\nCode: [0025][es25]\n\nNurb surface intersection generating nurb curves using [FeasibleTriIntersectionTests] extension method.\n\n[![img][e25]][e25]\n\n\u003chr/\u003e\n\nCode: [0026][es26]\n\nShows 2 triangle intersection and SimpleCmd management.\n\n[![img][e26]][e26]\n\n\u003chr/\u003e\n\nCode: [0027][es27]\n\nShows earth representation through a textured uv sphere.\n\n[![img][e27]][e27]\n\n## Development key notes\n\nMost of technical documentation is directly integrated with [API documentation](https://devel0.github.io/netcore-opengl/html/annotated.html).\n\n### Coordinate spaces\n\n![](data/notes/SpaceCoord.svg)\n\n- **Object**, **Model**, **View** and **Projection** matrixes are used by the gl pipeline at the [vertex shader set gl position].\n- **Clip**, **NDC** and finally **Screen** spaces are handled by the gl pipeline as further stages where size of render device was set by the [gl control render][set of gl viewport].\n- Forward and backward coordinate transform can be done through provided core helper functions; these methods exists to preview gl transformations done by the gpu on client side and are used forwardly by the zoomfit in [compute screen bbox] or in the backward case to detect local point from screen through [local ray cast].\n  - [forward transform](src/core/calc/ForwardTransform.cs)\n  - [backward transform](src/core/calc/BackwardTransform.cs)\n\n### GL Dev inspect tool\n\nHit `F1` gesture to open gl dev tool useful to understand how conversion translates between spaces; it provides some basic support such as:\n\n- show render count\n- show/edit GlView title\n- toggle control perspective, shadow, texture, wireframe, shade with edge, show normals\n- override light ambient, diffuse, specular strength\n- change fovdeg, show camera coordinates and frustum\n- toggle autoadjust near/far with near,far edit\n- show bbox size and model/view/projection matrixes\n- add, remove, set position, color of lights\n\n![](data/images/gldevtool.gif)\n\n### VsCode settings\n\nrelevant glsl settings\n\n```json\n{\n  \"[glsl]\": {\n      \"editor.defaultFormatter\": \"xaver.clang-format\"\n  },\n  \"glsllint.additionalStageAssociations\": {\n      \".fs\": \"frag\",\n      \".vs\": \"vert\",\n      \".gs\": \"geom\"\n  },\n  \"clang-format.language.glsl.style\": \"WebKit\",\n}\n```\n\n### Primitives, figures interaction\n\n#### Selection and coord identify\n\n| cursor                   | type      | hotkey | description                                   |\n| ------------------------ | --------- | ------ | --------------------------------------------- |\n| ![img][normal-cursor]    | normal    | `s`    | Normal pan/zoom/rotate [gestures](#gestures). |\n| ![img][primitive-cursor] | primitive | `s`    | Primitive selection toggler.                  |\n| ![img][figure-cursor]    | figure    | `s`    | Figure selection toggler.                     |\n| ![img][identify-cursor]  | identify  | `i`    | Identify coord.                               |\n\n#### Removal\n\nSelect a primitive/figures then hit `d` key to delete from the model.\n\n#### SimpleCmd\n\nEach primitive/figure selected can be copied to clipboard by the `ctrl+c` key and can be pasted within `ctrl+v`.\n\nActual implementation doesn't support color information but only geometric data:\n\n| Primitive | SimpleCmd                          |\n| --------- | ---------------------------------- |\n| point     | `p` x1,y1,z1;...                   |\n| line      | `l` x1,y1,z1,x2,y2,z2;...          |\n| triangle  | `t` x1,y1,z1,x2,y2,z2,x3,y3,z3;... |\n\nFor example a WCS object figure composed of 3 lines is expressed as follow SimpleCmd:\n\n```\nl 0,0,0,1,0,0;0,0,0,0,1,0;0,0,0,0,0,1\n```\n\n#### Change rotation center\n\n- select a primitive ( `s` to enable selection )\n- hit `ctrl+r`\n\n![](data/images/change-rotation.gif)\n\nTo return at default rotation center hit `ctrl+r` again that is with no selection.\n\n### Send notification\n\nUse gl model send notification to display a message with following properties:\n\n- _title_\n- _message_\n- _level_ : Information, Success, Warning, Error\n\n### View invalidation model\n\nThe view invalidation follow these rules:\n\n- View is refreshed automatically as a result of scale/rotate/pan predefined interactions.\n- Gl model changes doesn't imply an invalidation of the view and user have to request view update through gl model Invalidate method.\n\n### Opengl debugging tools\n\nTo implement some technical part of this library the [RenderDoc](https://renderdoc.org/) tool was a useful to investigate the content of the gl pipeline and to see the cube depth map generated to handle point light shadow rendering.\n\n### Multiplatform\n\n- The same binary compiled in a platform can run in others.\n- For example compile the solution then try to copy an example `bin` folder to other machine, then issue `dotnet bin/Debug/net7.0/example-xxxx.dll`.\n\n### Docker (mesa)\n\nUnit tests of this projects can run in docker ( see [this folder](src/test/docker) ).\n\nFor a simple program execution there is an example in the offscreen rendering [example-0009](examples/example-0009/docker-example/), to execute it:\n\n```sh\ncd examples/example-0009/docker-example\n./build.sh\n./run.sh\n```\n\nthat executes with follow output:\n\n```\nGL VERSION = 4.5 (Core Profile) Mesa 22.2.5\nfinished\nGenerated file:\ntotal 52K\ndrwxr-xr-x 2 devel0 devel0 4.0K Mar 29 13:46 .\ndrwxrwxr-x 3 devel0 devel0 4.0K Mar 29 13:06 ..\n-rw-r--r-- 1 devel0 devel0  21K Apr  3 10:33 example-0009-1024x768.png\n-rw-r--r-- 1 devel0 devel0  18K Apr  3 10:33 example-0009-640x480.png\n```\n\ngenerated files can be found in the `examples/example-0009/docker-example/output` generated folder.\n\n### Software rendered (mesa)\n\nFor example if you try to run the binary or sources from Windows guest in VirtualBox linux host you can receive follow error:\n\n```\nC:\\Users\\devel0\\Downloads\\bin\\Debug\\net7.0\u003edotnet example-0010.dll\nUnhandled exception. System.AggregateException: One or more errors occurred. (ApiUnavailable: WGL: The driver does not appear to support OpenGL)\n ---\u003e Silk.NET.GLFW.GlfwException: ApiUnavailable: WGL: The driver does not appear to support OpenGL\n   at Silk.NET.GLFW.Glfw.\u003c\u003ec.\u003c.cctor\u003eb__141_0(ErrorCode errorCode, String description)\n   at Silk.NET.GLFW.Glfw.CreateWindow(Int32 width, Int32 height, String title, Monitor* monitor, WindowHandle* share)\n   at Silk.NET.Windowing.Glfw.GlfwWindow.CoreInitialize(WindowOptions opts)\n   at Silk.NET.Windowing.Internals.WindowImplementationBase.CoreInitialize(ViewOptions opts)\n   at Silk.NET.Windowing.Internals.ViewImplementationBase.Initialize()\n   at SearchAThing.OpenGL.Core.GLContext..ctor() in /home/devel0/Documents/opensource/netcore-opengl/src/render/GLContext.cs:line 183\n```\n\nTo overcome the issue you can execute with software rendered mesa graphics driver.\n\nTo install:\n\n- Download [mesa library](https://fdossena.com/?p=mesa/index.frag).\n- Unpack `MesaForWindows-x64-20.1.8.7z` in a folder.\n- Set the environment variable `OPENGL_LIBRARY_PATH` to the path of the folder containing `opengl32.dll`.\n\n![](data/images/mesa-software-rendered.png)\n\n_Technical note:_\n\nMesa 20.1.8.7 doesn't expose glsl support for 4.6 regardless of that it contains effective implementation for that. To fix the problem `netcore-opengl` automatically set [two other environment variables](https://github.com/devel0/netcore-opengl/blob/37ad075f4bd983e9bfbeaa86d606fc25f3430eb5/src/render/GLContext.cs#L158-L159) when mesa is used.\n\n### C# global usings (full)\n\nFollowing is the list of global usings for app using gui and shapes modules.\nJust create a global.cs file and put into your solution to avoid `using` on each single .cs file.\n\n```cs\n// core\nglobal using System;\nglobal using System.Linq;\nglobal using System.Globalization;\nglobal using System.Collections;\nglobal using System.Collections.Generic;\nglobal using System.Collections.ObjectModel;\nglobal using System.Text;\nglobal using System.Text.RegularExpressions;\nglobal using System.IO;\nglobal using System.Diagnostics;\nglobal using System.Threading.Tasks;\nglobal using System.Numerics;\nglobal using System.ComponentModel;\nglobal using System.Runtime.CompilerServices;\nglobal using static System.Math;\nglobal using static System.FormattableString;\nglobal using Vector3 = System.Numerics.Vector3;\nglobal using Color = System.Drawing.Color;\nglobal using Size = System.Drawing.Size;\nglobal using ColorTranslator = System.Drawing.ColorTranslator;\nglobal using System.Reflection;\n\nglobal using Newtonsoft.Json;\nglobal using Newtonsoft.Json.Serialization;\nglobal using SkiaSharp;\n\nglobal using Silk.NET.OpenGL;\n\nglobal using SearchAThing.Ext;\nglobal using static SearchAThing.Ext.Toolkit;\n\nglobal using SearchAThing.Sci;\nglobal using static SearchAThing.Sci.Toolkit;\n\nglobal using SearchAThing.OpenGL.Core;\nglobal using static SearchAThing.OpenGL.Core.Toolkit;\nglobal using static SearchAThing.OpenGL.Core.Constants;\n\n// gui\nglobal using System.Threading;\nglobal using Avalonia;\nglobal using Avalonia.Input;\nglobal using Point = Avalonia.Point;\nglobal using Avalonia.Media;\nglobal using AColor = Avalonia.Media.Color;\nglobal using ABrush = Avalonia.Media.Brush;\nglobal using Avalonia.Data.Converters;\n\nglobal using SearchAThing.Desktop;\n\nglobal using SearchAThing.OpenGL.GUI;\nglobal using static SearchAThing.OpenGL.GUI.Toolkit;\nglobal using static SearchAThing.OpenGL.GUI.Constants;\n\n// shapes\nglobal using SearchAThing.OpenGL.Shapes;\nglobal using static SearchAThing.OpenGL.Shapes.Toolkit;\nglobal using static SearchAThing.OpenGL.Shapes.Constants;\n\n// nurbs\nglobal using SearchAThing.OpenGL.Nurbs;\nglobal using static SearchAThing.OpenGL.Nurbs.Toolkit;\n```\n\n### Gestures\n\n#### Mouse gestures\n\n| Key                 | Description                       |\n| ------------------- | --------------------------------- |\n| Left + Move         | Rotate the model over bbox middle |\n| Middle + Move       | Pan                               |\n| Middle double click | Zoom fit                          |\n\n#### Keybindings\n\nKey gesture can be overriden ( see [example-0020](https://github.com/devel0/netcore-opengl/blob/3943766b7cb98ae46149fbf14e54497f84ecf41f/examples/example-0020/Program.cs#L19-L23) ).\n\n| Key              | Description                                                |\n| ---------------- | ---------------------------------------------------------- |\n| o                | View bOttom                                                |\n| t                | View Top                                                   |\n| l                | View Left                                                  |\n| r                | View Right                                                 |\n| f                | View Front                                                 |\n| b                | View Back                                                  |\n| i                | Toggle Identify coord                                      |\n| s                | Toggle selection mode                                      |\n| Ctrl + r         | Change rotation center                                     |\n| Ctrl + ⬆         | Camera zoom in                                             |\n| Ctrl + ⬇         | Camera zoom out                                            |\n| Shift + ⬅        | Camera pan left                                            |\n| Shift + ➡        | Camera pan right                                           |\n| Shift + ⬆        | Camera pan up                                              |\n| Shift + ⬇        | Camera pan up                                              |\n| ⬅                | Model rotate left                                          |\n| ➡                | Model rotate right                                         |\n| ⬆                | Model rotate up                                            |\n| ⬇                | Model rotate down                                          |\n| Ctrl + ⬅         | Camera tilt left                                           |\n| Ctrl + ➡         | Camera tilt right                                          |\n| Alt + ⬅          | Camera rotate left                                         |\n| Alt + ➡          | Camera rotate right                                        |\n| Alt + ⬆          | Camera rotate up                                           |\n| Alt + ⬇          | Camera rotate down                                         |\n| h                | Split view horizontal                                      |\n| v                | Split view vertical                                        |\n| c                | Close current view                                         |\n| w                | Toggle wireframe                                           |\n| Ctrl + w         | Toggle (geom shader) shade with edges                      |\n| Alt + v          | Toggle (geom shader) vertex visibility                     |\n| n                | Toggle show normals                                        |\n| p                | Toggle perspective                                         |\n| x                | Toggle texture                                             |\n| Ctrl + s         | Toggle shadow                                              |\n| Ctrl + x         | Toggle model bbox                                          |\n| Ctrl + Shift + c | Toggle camera object                                       |\n| z                | Zoom fit                                                   |\n| Ctrl + c         | Copy selected primitives/figures to clipboard as SimpleCmd |\n| Ctrl + v         | Paste primitives/figures from clipboard SimpleCmd          |\n| Delete           | Delete selected primitives/figures                         |\n| Escape           | Cancel selection and back to view cursor mode              |\n| F1               | Open dev tool                                              |\n| F2               | Save current view                                          |\n| F3               | Restore last saved view                                    |\n| Shift + F2       | Save current view layout                                   |\n| Shift + F3       | Restore last saved view layout                             |\n| Ctrl + i         | Invalidate view                                            |\n\n## Unit tests\n\n- debugging unit tests\n  - from vscode click `debug test` on codelens button\n- executing all tests\n  - from solution root folder `dotnet test`\n- testing coverage\n  - from vscode run task ( ctrl+shift+p ) `Tasks: Run Task` then `test with coverage` or use provided script `./generate-coverage.sh`\n  - extensions required to watch coverage ( `Coverage Gutters` )\n\n![](data/images/unit-tests-coverage-gutters.png)\n\n## How this project was built\n\n```sh\nmkdir netcore-opengl\ncd netcore-opengl\n\nmkdir src examples\n\ncd src\ndotnet new classlib -n netcore-opengl-core\nmv netcore-opengl-core core\ncd ..\n\ncd examples\ndotnet new console --use-program-main -n example\nmv example/example.csproj example/example-0001.csproj\nmv example example-0001\n\ndotnet new --install Avalonia.Templates\ndotnet new avalonia.mvvm -n example\nmv example/example.csproj example/example-0002.csproj\nmv example example-0002\n\ndotnet new classlib -n example-figures\n\ndotnet new xunit -n test\ncd test\ndotnet add reference ../ext/netcore-ext.csproj\n# enable test coverage collector\n# to view in vscode ( \"Coverage Gutters\" ext ) run `./test-coverage` then `C-S-p` Coverage Gutters: Watch\ndotnet add package coverlet.collector\ndotnet add package coverlet.msbuild\ncd ..\n\ncd ..\n\ndotnet new sln\ndotnet sln add src/core src/test\ndotnet sln add examples/example-0001 examples/example-0002 examples/example-figures\ndotnet build\n```\n\n### Documentation (github pages)\n\nConfigured through Settings/Pages on Branch docs ( path /docs ).\n\n- while master branch exclude \"docs\" with .gitignore the docs branch doesn't\n\n#### Build and view locally\n\n```sh\n./doc build\n./doc serve\n./doc view\n```\n\n#### Build and commit into docs branch\n\n```sh\n./doc commit\n```\n\n## References\n\n- [OpenGL Transformation](http://www.songho.ca/opengl/gl_transform.html)\n- [The Perspective and Orthographic Projection Matrix](https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-GPU-rendering-pipeline-clipping.html)\n\n\u003c!-- LINKS --\u003e\n\n[api]: https://devel0.github.io/netcore-opengl/html/annotated.html\n[changelog]: https://github.com/devel0/netcore-opengl/commits/master\n[core-badge]: https://buildstats.info/nuget/netcore-opengl-core\n[gui-badge]: https://buildstats.info/nuget/netcore-opengl-gui\n[shapes-badge]: https://buildstats.info/nuget/netcore-opengl-shapes\n[nurbs-badge]: https://buildstats.info/nuget/netcore-opengl-nurbs\n[core]: https://www.nuget.org/packages/netcore-opengl-core\n[gui]: https://www.nuget.org/packages/netcore-opengl-gui\n[shapes]: https://www.nuget.org/packages/netcore-opengl-shapes\n[nurbs]: https://www.nuget.org/packages/netcore-opengl-nurbs\n[netcore-ext]: https://www.nuget.org/packages/netcore-ext\n[netcore-sci]: https://www.nuget.org/packages/netcore-sci\n[netdxf-devel0]: https://www.nuget.org/packages/netDxf-devel0\n[netcore-desktop]: https://www.nuget.org/packages/netcore-desktop\n[system.drawing.common]: https://www.nuget.org/packages/System.Drawing.Common\n[silk.net]: https://www.nuget.org/packages/Silk.NET\n[magick.net]: https://www.nuget.org/packages/Magick.NET-Q8-AnyCPU\n[skiasharp.harfbuzz]: https://www.nuget.org/packages/SkiaSharp.HarfBuzz\n[avalonia]: https://www.nuget.org/packages/Avalonia\n[g-shark]: https://www.nuget.org/packages/GShark\n[normal-cursor]: data/images/cursors/normal.png\n[primitive-cursor]: data/images/cursors/primitive.png\n[figure-cursor]: data/images/cursors/figure.png\n[identify-cursor]: data/images/cursors/identify.png\n[vertex shader set gl position]: https://github.com/devel0/netcore-opengl/blob/37ad075f4bd983e9bfbeaa86d606fc25f3430eb5/src/render/shaders/4.main.vs#L74\n[set of gl viewport]: https://github.com/devel0/netcore-opengl/blob/3dbf0e483007c9eea979d091547e5fa08a85e082/src/render/GLControl.cs#L855\n[local ray cast]: https://github.com/devel0/netcore-opengl/blob/37ad075f4bd983e9bfbeaa86d606fc25f3430eb5/src/core/calc/BackwardTransform.cs#L176\n[compute screen bbox]: https://github.com/devel0/netcore-opengl/blob/ca1237b9b3b16c1a7fc2c673c9bf2de87160f12b/src/core/calc/Util.cs#L17\n[brieffiniteelement]: https://github.com/BriefFiniteElementNet/BriefFiniteElement.Net\n[es0]: examples/example-0000/Program.cs\n[es1]: examples/example-0001/Program.cs\n[es2]: examples/example-0002/Views/MainWindow.axaml.cs\n[es3]: examples/example-0003/Program.cs\n[es4]: examples/example-0004/Program.cs\n[es5]: examples/example-0005/Program.cs\n[es6]: examples/example-0006/Program.cs\n[es7]: examples/example-0007/Program.cs\n[es8]: examples/example-0008/Views/MainWindow.axaml.cs\n[es9]: examples/example-0009/Program.cs\n[es10]: examples/example-0010/Program.cs\n[es11]: examples/example-0011/Program.cs\n[es12]: examples/example-0012/Program.cs\n[es13]: examples/example-0013/Program.cs\n[es14]: examples/example-0014/Program.cs\n[es15]: examples/example-0015/Program.cs\n[es16]: examples/example-0016/Views/MainWindow.axaml.cs\n[es17]: examples/example-0017/Program.cs\n[es18]: examples/example-0018/Program.cs\n[es19]: examples/example-0019/Views/MainWindow.axaml.cs\n[es20]: examples/example-0020/Program.cs\n[es21]: examples/example-0021/Views/MainWindow.axaml.cs\n[es22]: examples/example-0022/Program.cs\n[es23]: examples/example-0023/Program.cs\n[es24]: examples/example-0024/Program.cs\n[es25]: examples/example-0025/Program.cs\n[es26]: examples/example-0026/Views/MainWindow.axaml.cs\n[es27]: examples/example-0027/Program.cs\n\n[e0]: data/images/examples/0000.png\n[e1]: data/images/examples/0001.png\n[e2]: data/images/examples/0002.png\n[e3]: data/images/examples/0003.png\n[e4]: data/images/examples/0004.png\n[e5]: data/images/examples/0005.png\n[e6]: data/images/examples/0006.png\n[e7]: data/images/examples/0007.png\n[e8]: data/images/examples/0008.png\n[e9]: data/images/examples/0009.png\n[e10]: data/images/examples/0010.png\n[e11]: data/images/examples/0011.png\n[e12]: data/images/examples/0012.png\n[e13]: data/images/examples/0013.png\n[e14]: data/images/examples/0014.png\n[e15]: data/images/examples/0015.png\n[e16]: data/images/examples/0016.png\n[e17]: data/images/examples/0017.png\n[e18]: data/images/examples/0018.png\n[e19]: data/images/examples/0019.png\n[e21]: data/images/examples/0021.gif\n[e22]: data/images/examples/0022.png\n[e23]: data/images/examples/0023.png\n[e24]: data/images/examples/0024.png\n[e25]: data/images/examples/0025.png\n[e26]: data/images/examples/0026.png\n[e27]: data/images/examples/0027.png\n\n[FeasibleTriIntersectionTests]: https://github.com/devel0/netcore-opengl/blob/0ce534f6fcbb62279d814b0eca08f5be97ec8f98/src/core/primitive/IGLTriangle.cs#L113\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevel0%2Fnetcore-opengl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevel0%2Fnetcore-opengl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevel0%2Fnetcore-opengl/lists"}