{"id":26585321,"url":"https://github.com/xmaman/graphicengineexamples","last_synced_at":"2026-04-19T14:07:57.555Z","repository":{"id":282242017,"uuid":"947941609","full_name":"XMAMan/GraphicEngineExamples","owner":"XMAMan","description":"This project shows the usage of the XMAMan.GraphicEngine-NuGet","archived":false,"fork":false,"pushed_at":"2025-05-07T04:31:48.000Z","size":8458,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-07T05:27:06.719Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/XMAMan.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2025-03-13T13:46:26.000Z","updated_at":"2025-05-07T04:31:51.000Z","dependencies_parsed_at":"2025-05-07T05:33:14.058Z","dependency_job_id":null,"html_url":"https://github.com/XMAMan/GraphicEngineExamples","commit_stats":null,"previous_names":["xmaman/graphicengineexamples"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/XMAMan/GraphicEngineExamples","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XMAMan%2FGraphicEngineExamples","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XMAMan%2FGraphicEngineExamples/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XMAMan%2FGraphicEngineExamples/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XMAMan%2FGraphicEngineExamples/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/XMAMan","download_url":"https://codeload.github.com/XMAMan/GraphicEngineExamples/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XMAMan%2FGraphicEngineExamples/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32009243,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-03-23T10:36:21.379Z","updated_at":"2026-04-19T14:07:57.520Z","avatar_url":"https://github.com/XMAMan.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# How to use the GraphicEngine\n------------------------------\nThis project shows how to use the NuGets XMAMan.GraphicEngine and XMAMan.GraphicEngine2D. There is support for WinForm and WPF. Outputmethods are 2D, 3D and Raytracing. \n\nIf you want to use 2D and 3D-output, then you should use XMAMan.GraphicEngine\nIf you only want to use 2D-output, then XMAMan.GraphicEngine2D is better because its smaler.\n\nNote: DirectX mode only runs under WinForms, and DirectX must be installed first. To do so, copy the files from here: https://github.com/XMAMan/GraphicEngineExamples/blob/master/DirectXSetup.zip to a local directory and use DXSETUP.exe\n\n## Examples for the XMAMan.GraphicEngine-NuGet\n\n### Usage of the Raytracer\n-------------------------\n#### Step 1: Create your scene with blender\nUse the Wavefront-Exporter and use the triangulate-checkbox for export.\n\n![Blender](./Images/Blender.JPG)\n\n#### Step 2: Create a WPF-Project\n\nYou need this in your csproj-File:\n\n```xml\n \u003cUseWindowsForms\u003etrue\u003c/UseWindowsForms\u003e\n```\n\nAdd this to your xaml-File to place the GraphicPanel\n\n```xml\n\u003cBorder BorderThickness=\"5\" BorderBrush=\"DarkBlue\" x:Name=\"graphicControlBorder\"/\u003e\n```\n\nFor you code-behind you need this\n```csharp\n var panel = new GraphicPanel3D() { Width = 100, Height = 100, Mode = Mode3D.OpenGL_Version_3_0 }; \n this.graphicControlBorder.Child = new GraphicControl(panel);\n\n this.DataContext = new ViewModel(panel);\n```\n\nNow you can use the GraphicPanel3D-Object in your ViewModel to send the drawing-commands to the view. In our case we want to use the raytracer to show a blender-file. \nTo do this we need to add at first the obj-file:\n\n```csharp\npanel.RemoveAllObjekts();\npanel.AddWaveFrontFileAndSplit(DataDirectory + \"3DScene.obj\", false, new ObjectPropertys() \n{ \n    SpecularHighlightPowExponent = 20, \n    NormalInterpolation = InterpolationMode.Flat, \n    Albedo = 0.5f \n});\n```\n\nAfter this we can start the raytracer asynchron with \n\n```csharp\nthis.panel.StartRaytracing(this.panel.Width, this.panel.Height, (result) =\u003e {}, (error) =\u003e {});\n```\n\nYou can show/update the raytracingresult on the graphicpanel with this line of code:\n\n```csharp\ngraphicPanel.UpdateProgressImage();\n```\n\nThis will produce this image.\n![Raytracer](./Images/Raytracer.jpg)\n\nSee the Raytracer-Demo-project for details.\n\n\n### 3D-Output via WPF\n--------------------\n\nYou start again like in the raytracer-project by creating a WPF-Project and add the GraphicPanel to the view and viewModel.\n\nIf you want to display a 3D-scene you load the data into the GraphicPanel one times with this method:\n\n```csharp\nprivate void Add3DObjects()\n{\n    panel.RemoveAllObjekts();\n\n    //Ground\n    int groundId = panel.AddSquareXY(1, 1, 1, new ObjectPropertys() \n    { \n        Position = new Vector3D(0, 0, 0), \n        Orientation = new Vector3D(-90, 0, 180), \n        Size = 80, \n        Color = new ColorFromTexture() \n        { \n            TextureFile = DataDirectory + \"Decal.bmp\", \n            TextureMatrix = Matrix3x3.Scale(6, 6) \n        }, \n        ShowFromTwoSides = true, \n        BrdfModel = BrdfModel.Diffus, \n        \n    });\n\n    //Use Parallax Mapping for the ground\n    var tex = this.panel.GetObjectById(groundId).Color.As\u003cColorFromTexture\u003e();\n    this.panel.GetObjectById(groundId).NormalSource = new NormalFromParallax() \n    { \n        ParallaxMap = tex.TextureFile, \n        TextureMatrix = tex.TextureMatrix, \n        ConvertNormalMapFromColor = true, \n        TexturHeightFactor = 0.04f, \n        IsParallaxEdgeCutoffEnabled = true \n    };\n\n\n    //Player\n    this.playerId = panel.AddCylinder(2, 1, 1, true, 10, new ObjectPropertys() \n    { \n        Position = new Vector3D(0, 2, 0), \n        Orientation = new Vector3D(0, 0, 0), \n        Color = new ColorFromRgb() { Rgb = new Vector3D(1, 0, 0) },\n        BrdfModel = BrdfModel.DiffuseAndMirror,\n        HasStencilShadow = true,\n    });\n\n    panel.AddRing(0.3f, 2, 5, 20, new ObjectPropertys() \n    { \n        Position = new Vector3D(0, 2, 0), \n        Orientation = new Vector3D(0, 0, 45), \n        Size = 1, \n        HasStencilShadow = true, \n        NormalInterpolation = InterpolationMode.Smooth, \n        TextureFile = \"#004400\", \n        SpecularHighlightPowExponent = 50, \n        ShowFromTwoSides = false \n    });\n\n    //LightSource\n    panel.AddSphere(0.1f, 10, 10, new ObjectPropertys() \n    {\n        Position = new Vector3D(0, 10, 3),\n        Orientation = new Vector3D(0, 0, 45),\n        Size = 1.0f,\n        TextureFile = \"#FFFFFF\",\n        ShowFromTwoSides = true,\n        RasterizerLightSource = new RasterizerLightSourceDescription() { SpotDirection = Vector3D.Normalize(new Vector3D(0, 30, 0) - new Vector3D(0, 75, 30)), SpotCutoff = 180.0f, SpotExponent = 1, ConstantAttenuation = 1.1f },\n        RaytracingLightSource = new DiffuseSphereLightDescription() { Emission = 2200}\n    });\n\n    panel.GlobalSettings.BackgroundImage = \"#FFFFFF\";\n    panel.GlobalSettings.ShadowsForRasterizer = RasterizerShadowMode.Shadowmap;\n    panel.GlobalSettings.Camera = new Camera(new Vector3D(0, 7, 10), new Vector3D(0, -0.5f, -1), 45.0f);\n}\n```\n\nIn the timer-tick-method you can now draw the 3D-Object and add also 2D-content at top:\n\n```csharp\nprivate void Draw()\n{\n    this.panel.DrawWithoutFlip();\n    this.panel.DrawString(10, 10, Color.Red, 15, \"Press W,A,S,D for moving the cylinder\");\n    this.panel.DrawString(10, 30, Color.Red, 15, \"Press 1,2,3 or 4 for switching mode. Current mode: \" + this.panel.Mode);\n    this.panel.FlipBuffer();\n}\n```\n\nThis will produce a 3D-scene where you can move the red cylinder:\n![Wpf3D](./Images/Wpf3D.JPG)\n\nSee the Wpf3D-Project for details.\n\n\n### 3D-Output via WinForm\n------------------------\nCreate a new WinForm-application in VisualStudio and add the GraphicEngine-NuGet. After this go the the toolbox and add the GraphicPanel3D-Panel to your MainWindow-Panel.\n\n![VisualStudioWinFormToolBox](./Images/VisualStudioWinFormToolBox.JPG)\n\n\nYou can now again add all 3D-objects one time at start (or durring runtime if you would add/remove an object).\n\n```csharp\n panel.RemoveAllObjekts();\n //LegoMan from Wavefront file\n this.legoIds = panel.AddWaveFrontFileAndSplit(DataDirectory + \"LegoMan.obj\", false, new ObjectPropertys()\n {\n     NormalInterpolation = InterpolationMode.Smooth,\n     SpecularHighlightPowExponent = 50,\n     Size = 0.1f,\n });\n ```\n \nIn the timer-tick-method you call again the DrawWithoutFlip- and FlipBuffer-Method.\n \n```csharp\nprivate void Draw()\n{\n    this.panel.DrawWithoutFlip();\n    this.panel.DrawString(10, 10, Color.Red, 15, \"Press 1,2,3 or 4 for switching mode. Current mode: \" + this.panel.Mode);\n    this.panel.FlipBuffer();\n}\n```\n\nThis will produce a legoman which is spinning.\n![WinForm3D](./Images/WinForm3D.JPG)\n\nSee the WinForm3D-Project for details.\n\n### 2D-Output via WinForm\n------------------------\nYou create a new WinForm- or WPF-Project and add the GraphicPanel like in the 3D-Examples. But instead of using the Add-Methods for adding some 3D-Objects you are using the draw-commands direct in the \nTimerTick-Method.\n\n```csharp\nprivate void Draw()\n{\n    this.panel.ClearScreen(Color.AliceBlue);\n\n    this.panel.DrawRectangle(new Pen(Color.Black, 2), 0, 0, this.panel.Width, this.panel.Height);\n\n    this.panel.DrawFillCircle(Color.Green, this.ballPosition, ballRadius);\n    this.panel.DrawCircle(Pens.Red, this.mousePosition, 10);\n\n    this.panel.DrawFillRectangle(DataDirectory + \"Face_04.png\", 10, 10, 300, 200, true, Color.White);\n\n    this.panel.DrawString(10, 10, Color.Black, 15, \"Left mouse click for placing red circle\");\n    this.panel.DrawString(10, 30, Color.Black, 15, \"Press 1,2,3 or 4 for switching mode. Current mode: \" + this.panel.Mode);\n\n\n    this.panel.FlipBuffer();\n}\n```\n\nThis will produce this image with a moving circle:\n![Rasterizer2D](./Images/Rasterizer2D.JPG)\n\nSee the WinForm2D/Wpf2D-Project for details.\n\n## Example for the XMAMan.GraphicEngine2D-NuGet\n\n\n### 2D-Output via WPF\n------------------------\nCreate a WPF-Project (by example with usage of .NET 8.0) und add the XMAMan.GraphicEngine2D-NuGet.\n\nYou need this in your csproj-File because GraphicPanel2D is a winForm-control.\n\n```xml\n \u003cUseWindowsForms\u003etrue\u003c/UseWindowsForms\u003e\n```\n\nAdd this to your xaml-File to place the GraphicPanel\n\n```xml\n\u003cBorder BorderThickness=\"5\" BorderBrush=\"DarkBlue\" x:Name=\"graphicControlBorder\"/\u003e\n```\n\nFor you code-behind you need this\n```csharp\n var panel = new GraphicPanel2D() { Width = 100, Height = 100, Mode = Mode3D.OpenGL_Version_3_0 }; \n this.graphicControlBorder.Child = new GraphicControl(panel);\n\n this.DataContext = new ViewModel(panel);\n```\n\nNow you can use the GraphicPanel2D-Object in your ViewModel to send the drawing-commands to the view.\n\n```csharp\nclass ViewModel\n{\n    private GraphicPanel2D panel;\n\n    private System.Windows.Threading.DispatcherTimer timer;\n    private string DataDirectory = @\"..\\..\\..\\..\\..\\Data\\\";\n\n    private List\u003cVertex2D[]\u003e voronioPolygons = null;\n    private List\u003cPoint\u003e voronoiCellPoints = null;\n    private TextureData marioTexture = null;\n    private int spriteNr = 0;\n\n    public ViewModel(GraphicPanel2D panel)\n    {\n        this.panel = panel;\n\n        this.panel.Mode = Mode2D.OpenGL_Version_3_0;\n        this.panel.MouseClick += GraphicPanel2D_MouseClick;\n        this.panel.SizeChanged += GraphicPanel2D_SizeChanged;\n\n        this.timer = new System.Windows.Threading.DispatcherTimer();\n        this.timer.Interval = new TimeSpan(0, 0, 0, 0, 30);//30 ms\n        this.timer.Tick += Timer_Tick;\n        this.timer.Start();\n\n        CreateVoronoiPolygons();\n    }\n\n    private void GraphicPanel2D_MouseClick(object sender, MouseEventArgs e)\n    {\n        this.voronoiCellPoints = GraphicPanel2D.GetRandomPointList(10, this.panel.Width, this.panel.Height, new Random(0));\n        this.voronioPolygons = GraphicPanel2D.GetVoronoiPolygons(this.panel.Size, this.voronoiCellPoints);\n    }\n\n    private void GraphicPanel2D_SizeChanged(object sender, EventArgs e)\n    {\n        Draw(this.panel, DataDirectory, this.spriteNr, this.voronioPolygons, this.voronoiCellPoints, this.marioTexture, false, Matrix4x4.Ident());\n    }\n\n    private void Timer_Tick(object? sender, EventArgs e)\n    {\n        spriteNr++;\n        Draw(this.panel, DataDirectory, this.spriteNr, this.voronioPolygons, this.voronoiCellPoints, this.marioTexture, false, Matrix4x4.Ident());\n    }\n\n    //First, it creates a new texture bitmap by drawing into a framebuffer and then taking the data from it.This bitmap is then\n    //decomposed into polygons using Voronoi, and these polygons are then drawn using the polygon drawing function.\n    private void CreateVoronoiPolygons()\n    {\n        float yAngle = 10;\n\n        this.marioTexture = CreateMarioTexture(this.panel, DataDirectory + \"nes_super_mario_bros.png\", yAngle);\n        this.voronoiCellPoints = GraphicPanel2D.GetRandomPointList(10, marioTexture.Image.Width, marioTexture.Image.Height, new Random(0));\n        this.voronioPolygons = GraphicPanel2D.GetVoronoiPolygons(marioTexture.Image.Size, this.voronoiCellPoints);\n\n        this.voronioPolygons = this.voronioPolygons.Select(x =\u003e TransformPolygon(x, new Vector2D(340, 30))).ToList(); //Move to position (340, 30)\n    }\n\n\n    public class TextureData\n    {\n        public Bitmap Image;\n        public string TextureName;\n    }\n\n    //Creates a Mario texture in the currently selected 2D mode's texture memory in the GraphicsPanel2D.\n    //Return value: Name of the created texture.If the texture already exists, it will be updated.\n    public static TextureData CreateMarioTexture(GraphicPanel2D graphic, string texturFile, float yAngle)\n    {\n        int width = 80;\n        int height = 80;\n        int frameBufferId = graphic.CreateFramebuffer(width, height, true, false);\n        graphic.EnableRenderToFramebuffer(frameBufferId);\n        graphic.ClearScreen(Color.Transparent);\n        //Take only the section where Mario is visible from the large image and paint it into the framebuffer\n        graphic.DrawImage(texturFile, width / 2, height / 2, width, height, 243, 202, 283 - 243, 240 - 202, true, Color.FromArgb(255, 255, 255), 0, yAngle);\n        graphic.FlipBuffer();\n        int colorTextureId = graphic.GetColorTextureIdFromFramebuffer(frameBufferId);\n        Bitmap marioTexture = graphic.GetTextureData(colorTextureId);\n        graphic.DisableRenderToFramebuffer();\n        graphic.CreateOrUpdateNamedBitmapTexture(\"MarioBitmap\", marioTexture);\n\n        //marioTexture.Save(\"MarioTexture.bmp\");\n        //Color c = marioTexture.GetPixel(0, 0);\n\n        return new TextureData()\n        {\n            TextureName = \"MarioBitmap\",\n            Image = marioTexture\n        };\n    }\n\n    public static Vertex2D[] TransformPolygon(Vertex2D[] polygon, Vector2D position)\n    {\n        return polygon.Select(x =\u003e new Vertex2D(x.Position + position, x.Textcoord)).ToArray();\n    }\n\n    public void Draw(GraphicPanel2D graphic, string dataDirectory, int spriteNr, List\u003cVertex2D[]\u003e voronioPolygons, List\u003cPoint\u003e voronoiCellPoints, TextureData marioTex, bool showScreenAlpha, Matrix4x4 transform)\n    {\n         /*graphic.ClearScreen(Color.White);\n         foreach (var polygon in this.voronioPolygons)\n         {\n             graphic.DrawFillPolygon(dataDirectory + \"thumb_COLOURBOX5847554.jpg\", false, Color.FromArgb(255, 255, 255), polygon.ToList());\n             graphic.DrawPolygon(new Pen(Color.Black, 2), polygon.Select(x =\u003e x.Position).ToList());\n         }\n         foreach (var point in this.voronoiCellPoints)\n         {\n             graphic.DrawFillCircle(Color.Red, new Vector2D(point.X, point.Y), 2);\n         }\n\n         graphic.FlipBuffer();\n         return;*/\n\n        string text = graphic.Mode.ToString();\n        graphic.ClearScreen(dataDirectory + \"thumb_COLOURBOX5847554.jpg\");\n        graphic.MultTransformationMatrix(transform);\n        Size size = graphic.GetStringSize(20, text);\n\n        graphic.EnableScissorTesting(300, 20, 60, 25);\n        graphic.DrawImage(dataDirectory + \"nes_super_mario_bros.png\", 300, 20, 60, 50, 243, 202, 283 - 243, 240 - 202, true, Color.FromArgb(255, 255, 255));\n        graphic.DisableScissorTesting();\n        graphic.DrawImage(dataDirectory + \"nes_super_mario_bros.png\", 300, 100, 60, 50, 243, 202, 283 - 243, 240 - 202, true, Color.FromArgb(255, 255, 255), 0, 180);\n\n        graphic.DrawImage(\"MarioBitmap\", 420, 50, 40, 40, 0, 0, 80, 80, true, Color.FromArgb(0, 255, 0));\n\n        //Check that the alpha value of the Mario texture is correct\n        graphic.CreateOrUpdateNamedBitmapTexture(\"MarioBitmapAlpha\", BitmapHelp.GetAlphaChannel(marioTex.Image));\n        graphic.DrawFillRectangle(\"MarioBitmapAlpha\", 420, 90, 40, 40, false, Color.FromArgb(255, 255, 255));\n\n        foreach (var polygon in voronioPolygons)\n        {\n            graphic.DrawFillPolygon(\"MarioBitmap\", false, Color.FromArgb(255, 255, 255), polygon.ToList());\n            graphic.DrawPolygon(new Pen(Color.Black, 2), polygon.Select(x =\u003e x.Position).ToList());\n        }\n        foreach (var point in voronoiCellPoints)\n        {\n            graphic.DrawFillCircle(Color.Red, new Vector2D(point.X + 340, point.Y + 30), 2);\n        }\n\n        //graphic.DrawRectangle(new Pen(Color.Black, 3), 30, 30, size.Width, size.Height);\n        graphic.DrawFillRectangle(dataDirectory + \"Mario.png\", 10, 50, 40, 40, true, Color.FromArgb(spriteNr % 255, 255, 255, 255));\n        graphic.DrawString(30, 30, Color.Black, 10, text);\n        graphic.DrawLine(new Pen(Color.Black, 5), new Vector2D(0, 0), new Vector2D(graphic.Width, graphic.Height));\n        graphic.DrawPixel(new Vector2D(30, 30), Color.Green, 5);\n        graphic.DrawFillPolygon(dataDirectory + \"Decal.bmp\", new List\u003cVector2D\u003e() { new Vector2D(100, 100), new Vector2D(110, 110), new Vector2D(120, 70), new Vector2D(100, 50), new Vector2D(70, 90) }, false, Color.FromArgb(255, 255, 255));\n        graphic.DrawFillPolygon(dataDirectory + \"Decal.bmp\", new List\u003cVector2D\u003e() { new Vector2D(100 + 100, 100), new Vector2D(110 + 100, 110), new Vector2D(120 + 100, 70), new Vector2D(100 + 100, 50), new Vector2D(70 + 100, 90) }, false, Color.FromArgb(spriteNr % 255, 255, 255, 255));\n        graphic.DrawFillPolygon(Color.Red, new List\u003cVector2D\u003e() { new Vector2D(100, 100 + 70), new Vector2D(110, 110 + 70), new Vector2D(120, 70 + 70), new Vector2D(100, 50 + 70), new Vector2D(70, 90 + 70) });\n        graphic.DrawFillPolygon(Color.Green, new List\u003cVector2D\u003e() { new Vector2D(100 + 100, 100 + 70), new Vector2D(110 + 100, 110 + 70), new Vector2D(120 + 100, 70 + 70), new Vector2D(100 + 100, 50 + 70), new Vector2D(70 + 100, 90 + 70) });\n        graphic.DrawPolygon(new Pen(Color.BlueViolet, 3), new List\u003cVector2D\u003e() { new Vector2D(100, 100), new Vector2D(110, 110), new Vector2D(120, 70), new Vector2D(100, 50), new Vector2D(70, 90) });\n        graphic.DrawCircle(new Pen(Color.BurlyWood, 3), new Vector2D(40, 200), 35);\n        graphic.DrawFillCircle(Color.BurlyWood, new Vector2D(40, 250), 25);\n        graphic.DrawFillRectangle(dataDirectory + \"Tortoise.png\", 200, 200, 30, 20, true, Color.FromArgb(255, 255, 255));\n        graphic.DrawFillRectangle(dataDirectory + \"Tortoise.png\", 240, 240, 40, 30, true, Color.FromArgb(255, 255, 255), 30);\n        graphic.DrawFillRectangle(dataDirectory + \"Tortoise.png\", 280, 280, 40, 30, true, Color.FromArgb(255, 255, 255), 30, 50);\n        graphic.DrawFillRectangle(Color.FromArgb(200, 255, 0, 0), 200 + 70, 200, 30, 20);\n        graphic.DrawFillRectangle(Color.Green, 240 + 70, 240, 40, 30, 30);\n        graphic.DrawFillRectangle(Color.Blue, 280 + 70, 280, 40, 30, 30, 50);\n\n        //Here I'm testing the case of drawing a triangle with P0.X==P1.X\n        //Observation: OpenGL always seems to shift a line one pixel to the left. If I specify (3,3), it draws at (2,3)\n        //For a triangle, the top left corner is correct and the bottom right corner is shifted one pixel to the top left\n        graphic.DrawPolygon(new Pen(Color.Red, 1), new List\u003cVector2D\u003e() { new Vector2D(140, 200), new Vector2D(162, 200), new Vector2D(162, 211), new Vector2D(140, 211) });\n        graphic.DrawFillPolygon(Color.Green, new List\u003cVector2D\u003e() { new Vector2D(140, 200), new Vector2D(150, 200), new Vector2D(150, 210), new Vector2D(140, 210) });\n        graphic.DrawFillPolygon(Color.Blue, new List\u003cVector2D\u003e() { new Vector2D(151, 200), new Vector2D(161, 200), new Vector2D(161, 210), new Vector2D(151, 210) });\n\n        //Vertical lines with different widths\n        for (int i = 0; i \u003c 5; i++)\n        {\n            graphic.DrawLine(new Pen(Color.Red, 1 + i), new Vector2D(130 + i * 20, 240), new Vector2D(130 + i * 20, 270));\n            graphic.DrawPixel(new Vector2D(130 + i * 20, 235), Color.Green, i + 1);\n            graphic.DrawPixel(new Vector2D(130 + i * 20, 235), Color.Red, 1);\n\n            for (int j = 0; j \u003c= i; j++)\n            {\n                //One pixel is moved up by one\n                graphic.DrawPixel(new Vector2D(130 + i * 20 + j - (i + 1) / 2, 240 + j + 0.5f), Color.Yellow, 1);\n            }\n        }\n\n        //Horizontal lines of different widths\n        for (int i = 0; i \u003c 5; i++)\n        {\n            graphic.DrawLine(new Pen(Color.Red, 1 + i), new Vector2D(140, 300 + i * 10), new Vector2D(170, 300 + i * 10));\n            graphic.DrawPixel(new Vector2D(130, 300 + i * 10), Color.Green, i + 1);\n            graphic.DrawPixel(new Vector2D(130, 300 + i * 10), Color.Red, 1);\n\n            for (int j = 0; j \u003c= i; j++)\n            {\n                //One pixel is moved up by one\n                graphic.DrawPixel(new Vector2D(140 + j, 300 + i * 10 + j - (i + 0.5f) / 2), Color.Yellow, 1);\n            }\n        }\n\n\n        //int spriteNr = 0;\n        graphic.DrawSprite(dataDirectory + \"fire1.png\", 11, 11, spriteNr % 11, spriteNr / 11, 20, 180, 40, 40, 0.01f, true, Color.FromArgb(spriteNr % 255, 255, 255, 255));\n\n        //graphic.DrawLine(new Pen(Color.Blue, 5), new Vector2D(40, 200), new Vector2D(40, 250));\n        graphic.FlipBuffer();\n\n        if (showScreenAlpha)\n        {\n            //Prüfe ab, dass der Alpha-Wert der ScreenShoot-Funktion stimmt\n            Bitmap screenAlpha = BitmapHelp.GetAlphaChannel(graphic.GetScreenShoot());\n            graphic.CreateOrUpdateNamedBitmapTexture(\"ScreenAlpha\", screenAlpha);\n            graphic.DrawFillRectangle(\"ScreenAlpha\", 420, 130, 40, 40, false, Color.FromArgb(255, 255, 255));\n        }\n\n        //Check that the sprite display shows the correct sub-image (expected numbers from 1 to 6)\n        int spriteCounter = 0;\n        for (int x = 0; x \u003c 3; x++)\n            for (int y = 0; y \u003c 2; y++)\n            {\n                graphic.DrawSprite(dataDirectory + \"Numbers.png\", 3, 2, x, y, 325 + x * 20, 177 + y * 20, 20, 20, 0.01f, true, Color.White);\n                spriteCounter++;\n            }\n\n        //Since no DepthTesting is activated, the line is drawn over the turtle\n        graphic.DrawFillRectangle(dataDirectory + \"Tortoise.png\", 410, 210, 30, 20, true, Color.FromArgb(255, 255, 255));\n        graphic.DrawLine(new Pen(Color.Blue, 2), new Vector2D(404, 220), new Vector2D(450, 220));\n\n        //DepthTesting is activated\n        graphic.EnableDepthTesting();\n\n        //The Z-value of the turtle is smaller than the Z-value of the line. So the line is in front\n        graphic.ZValue2D = 1 - 5; //Rear\n        graphic.DrawFillRectangle(dataDirectory + \"Tortoise.png\", 410, 230, 30, 20, true, Color.FromArgb(255, 255, 255));\n        graphic.ZValue2D = 2 - 5; //Front\n        graphic.DrawLine(new Pen(Color.Blue, 2), new Vector2D(404, 240), new Vector2D(450, 240));\n\n        //The Z-value of the turtle is greater than the Z-value of the line. Therefore, the turtle is in front\n        graphic.ZValue2D = 2 - 5; //Front\n        graphic.DrawFillRectangle(dataDirectory + \"Tortoise.png\", 410, 250, 30, 20, true, Color.FromArgb(255, 255, 255));\n        graphic.ZValue2D = 1 - 5; //Rear\n        graphic.DrawLine(new Pen(Color.Blue, 2), new Vector2D(404, 260), new Vector2D(450, 260));\n\n        graphic.DisableDepthTesting();\n    }\n}\n```\n\nThis will produce this image with a moving fire-sprite:\n![wpf2d_example2](https://raw.githubusercontent.com/XMAMan/GraphicEngineExamples/refs/heads/master/Images/wpf2d_example2.JPG)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxmaman%2Fgraphicengineexamples","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxmaman%2Fgraphicengineexamples","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxmaman%2Fgraphicengineexamples/lists"}