C# OpenGL gränssnitt
för Windows operativsystem
Colin Fahey

CSGL12Control på en Form, visar en ”fraktal” Pixel Shader-program och GDI+ ritning kopieras till en textur

Två CSGL12Control fall på en Form visar Pixel Shader-program och texturer

En 3D-avatar att roams skrivbordet och kan flyttas med markören
1. Mjukvara
CSGL12_20090725.zip
CSGL12: C# OpenGL gränssnitt för Windows, version 12
4170499 bytes
MD5: 30781a6570441785ea636f2ae1cd16ef
2. Alla de C# dator koden i C# OpenGL gränssnitt (CSGL12) är ”allmän egendom”
Jag skrev alla de C# dator-nummer inom C# OpenGL gränssnitt (CSGL12).
Jag förklarar alla de C# dator-nummer inom C# OpenGL gränssnitt (CSGL12) att i det ”offentliga rummet.”
Därför datorn kod kan användas för något ändamål (kommersiella eller privata), utan betalning, utan begränsningar, utan förpliktelser, och utan att tacka för den ursprungliga författaren.
Koden kan ändras eller delar återanvändas utan restriktioner och utan förpliktelser, och utan att tacka för den ursprungliga författaren.
Exemplet program inkluderar en liten mängd datakod (specifikt ”shader datakod) skriven av andra människor.” Denna kod är inte gränssnittet i sig och kan trivially bort. Dessa nummer är enbart att visa att det är så enkelt att använda gränssnittet för att skapa och använda ”shader” program.
3. Inledning
”CSGL12” är en samling C# datakod filer som genomför ett gränssnitt mot den OpenGL grafik bibliotek (inklusive alla förlängningar av OpenGL fram till år 2007) för Windows operativsystem.
Den C# datakod filer i ”CSGL12” insamling gör det lätt att lägga OpenGL ritning till någon C# / .NET mjukvara med en ”Form” (en instans av ”System.Windows.Forms.Form”).
Den ”CSGL12” insamling av datakoder filer innehåller en fil med namnet ”CSGL12Control.cs” som definierar en klass som heter ”CSGL12Control”, härrör från ”System.Windows.Forms.Control”. Varje instans av ”CSGL12Control” är en oberoende OpenGL ritning område. Det är mycket enkelt att lägga till flera instanser av CSGL12Control till en Form (en instans av System.Windows.Forms.Form).
4. Egenskaper och krav för ”CSGL12”
Koden är endast för Windows operativsystem som stöder .NET 2.0 Framework (Windows 2000, Windows XP, Windows Vista, Windows 7)
Koden kan kompileras med hjälp ”Microsoft Visual C# 2008 Express Edition” (en fri kompilator), eller liknande C# kompilatorer.
Koden kräver att byggas med ”[X] Allow unsafe code” bygga alternativet väljas så att optimerade bilduppgifter kopiering funktioner kan användas. Om du är en expert C# programmerare kommer du att ha möjlighet att lätt identifiera de delar av C# nummer som kräver ”unsafe” alternativet och stänga av dem om så önskas eller krävs. Bild data kopiering är 10 gånger snabbare med ”unsafe” kod än alternativet, och det är varför en sådan kod används. Om du bygga ett DLL som innehåller alla de ”unsafe” nummer, sedan ett projekt som använder denna DLL inte kräver byggs med ”unsafe” alternativ och så att du kan dra slutsatsen att avsaknaden av ”unsafe” alternativ i ett projekt innebär inte några extra säkerhet (eftersom många DLL filer som används uttryckligen eller underförstått genom programmet innehålla ”farlig” kod).
Koden kan sammanställas och användas av något av följande:
Microsoft Visual C# 2008 Express Edition
Microsoft Visual Studio 2008
Microsoft .NET 3.5 SDK
SharpDevelop
Mono Project
Koden ger mest OpenGL förlängningar (genom året 2007), inklusive ”vertex shaders” och ”pixel shaders”.
Koden ger 1570 funktioner relaterade till OpenGL:
336 GL functions
51 GLU functions
19 WGL functions
1164 extensions
Koden ger några alternativa varianter av 1570 funktioner med olika parameter slag, för enkelhetens skull.
Koden anger mer än 3244 konstanterna för OpenGL.
Koden gör det möjligt att ha flera OpenGL ritning sammanhang, alla informationsinsatser självständigt, på någon ”Form”.
Om du klickar på en ”CSGL12Control” ger den ”input fokus,” vilket gör efterföljande tangentbord och mus hjulet ingång. Cursor klick och rörelser fick när markören inom rektangulärt område med en instans av ”CSGL12Control”.
Koden omfattar funktioner för att visa hur man gör vissa gemensamma OpenGL uppgifter i C# och .NET.
Den kodlistor alla OpenGL konstanter och funktioner i alfabetisk ordning i ”class GL” i ”GL.cs”, vilket gör det enkelt att avgöra om någon konstant eller en funktion saknas (vilket är osannolikt, med undantag för förlängningar antagits efter år 2007).
Exemplet program visa hur man gör GDI+ ritning till en Bitmap och sedan hur man kan kopiera den Bitmap till en OpenGL textur.
Detta gör att text och andra GDI+ ritning förmåga att bidra till en OpenGL scenen.
Den GDI+ Bitmap kan uppdateras och laddas upp till en OpenGL konsistens så ofta som en gång per OpenGL ram.
Exemplet program visar hur man väljer mellan flera olika ”pixel shader programs” medan programmet körs.
Exemplet program visar hur man skriver OpenGL buffertar till image-filer (JPG, BMP, GIF, PNG).
Press Shift + 0 (Shift-noll) för att skriva OpenGL buffert för bildfiler.
Exemplet kod visar hur sammanställningen ”GL.cs” i att en DLL filen och sedan lägga till att DLL filen till ett annat projekt, kan hindra Microsoft kod redigerare (t.ex. Microsoft Visual C# 2008 Express Edition, etc) med ”IntelliSense” (kontextrik känsliga kod avslutad) blir ofta och ihärdigt okänsliga (upprepade pauser för många sekunder, gör redaktören helt oanvändbara). Med filen ”GL.cs” direkt ingår i ett projekt som redigeras av en Microsoft kod editorn är inte praktiskt, om inte en person som är villig att stå ut med den långsamma redigeraren. Detta problem har påverkat Microsoft Visual Studio 2003, 2005, 2008, och sannolikt kommer att påverka 2010 version också.
Den exempelkod visar användning av flera instanser av ”CSGL12Control” på en ”Form”.
Exemplet kod innehåller kod för att göra en 3D ”avatar” att roams skrivbordet av Windows.
5. Exempel på program som ingår i ”CSGL12”
5.1 ”CSGL12DLL”
Projektet heter ”CSGL12DLL” producerar en DLL fil med namnet ”CSGL12DLL.dll” som innehåller ”class GL” (definierade i C# fil ”GL.cs”).
Putting ”class GL” in på en DLL filen och sedan använda denna DLL i andra projekt som använder ”class GL”, hjälper till att undvika en extrem problemet med alla Microsoft kod redigerare med IntelliSense funktionen. Använda C# fil GL.cs direkt i ett projekt skulle orsaka någon Microsoft kod redaktör med IntelliSense funktionen för att bli helt oförstående och oanvändbara nästan oavbrutet på grund av ineffektivitet i IntelliSense funktion (och det faktum att IntelliSense uppenbarligen block huvudprogrammet tråd av redaktören ).
Om du använder en C# nummer redaktör som inte är producerat av Microsoft (t.ex. ”SharpDevelop”, ”MonoDevelop”, osv), då kan du helt enkelt inkludera filen ”GL.cs” direkt i dina projekt och du knappast skulle få någon fördel av att använda ”CSGL12DLL.dll”.
5.2 ”CSGL12Control”
Projektet heter ”CSGL12Control” producerar en DLL fil med namnet ”CSGL12Control.dll” som innehåller ”class CSGL12Control” (definierade i C# fil ”CSGL12Control.cs”).
Putting ”class CSGL12Control” in på en DLL fil, gör att ”Control” (dvs en klass från ”System.Windows.Forms.Control”) skall läggas till ”Toolbox” av Microsoft Visual C# 2008 Express Edition (och liknande C# redaktörer). Med ”CSGL12Control” i ”Toolbox” gör det enkelt för en person att lägga till en instans av ”CSGL12Control” att en ”Form” i ”Designer” (t.ex. en person kan helt enkelt använda markören för att markera och dra ett exempel på ”CSGL12Control” från ”Toolbox” att en ”Form”).
Den ”CSGL12Control” objekt hanterar ett OpenGL ritning sammanhang. Flera fall av ”CSGL12Control” kan samexistera på ett ”Form”.
5.3 ”CSGL12Example1”
Projektet heter ”CSGL12Example1” producerar en körbar programfil (EXE) heter ”CSGL12Example1.exe”. Programmet använder ”CSGL12DLL.dll” och ”CSGL12Control.dll” att visa ett exempel på CSGL12Control och rita en kub med hjälp OpenGL.
Programmet visar att använda fyra olika ”pixel shaders” ”(fraktal, tegel, trä” och ”karikatyr).”
Programmet visar också användningen av ”GDI+”, en .NET ritning biblioteket, att göra text och andra former för ett ”Bitmap” objekt (en ”GDI+” objekt), och sedan kopiera bilden från den ”Bitmap” till en ”texture” i OpenGL, vilket gör att bilden dras av ”GDI+” ska visas i OpenGL ritningen. Denna förmåga är mycket användbart eftersom OpenGL saknar många av de 2D ritning funktioner som finns i ”GDI+” och liknande 2D ritning libaries.
5.4 ”CSGL12Example2”
Projektet heter ”CSGL12Example2” producerar en körbar programfil (EXE) heter ”CSGL12Example2.exe”. Programmet använder ”CSGL12DLL.dll” och ”CSGL12Control.dll” att visa två fall av CSGL12Control, som var och en drar en kub med hjälp OpenGL.
Programmet har en ”SplitContainer” ”Control” på ”Form”. Var och en av de två områden i ”SplitContainer” innehåller en instans av CSGL12Control. Alltså, en person kan justera positionen av den uppdelade mellan de två fallen av CSGL12Control. Detta visar på den flexibilitet på CSGL12Control.
Ett av de fall av CSGL12Control sänder evenemang till en rad omständigheter hanterarna i en instans av ”CSGL12Example2Handler1.cs”, som använder samma kod som ”CSGL12Example1Handler.cs” i ”CSGL12Example1” exempel projektet. Därför är ett av de fall CSGL12Control drar en kub med en vald ”pixel shader” bland fyra tillgängliga ”pixel shaders”.
Det andra fallet av CSGL12Control sänder evenemang till en rad omständigheter hanterarna i en instans av ”CSGL12Example2Handler2.cs”, som drar en kub med hjälp av en textur bild (eller en ”Checkerboard” mönster om en bildfil som heter ”image.jpg” inte finns).
5.5 ”CSGL12Avatar”
Projektet heter ”CSGL12Avatar” producerar en körbar programfil (EXE) heter ”CSGL12Avatar.exe”. Programmet använder ”CSGL12DLL.dll” och ”CSGL12Control.dll” att rita en kub med hjälp OpenGL på ”Form” utan gräns, med färg baserat insyn aktiverat för att dra en 3D ”avatar” att roams den Windows skrivbordet område.
Den rörliga avatar kan klickas och dras till en ny plats med hjälp av markören. Dubbelklicka på avatar gör det försvinna. Även om koden bara drar en kub, OpenGL kan användas för att göra andra saker.
Flera instanser av ”avatar” program kan startas. Alltså, många oberoende ”avatar” fall kan samtidigt roam den Windows skrivbordet. Det är lustigt. En expert C# programmerare kan njuta av att hitta sätt att samordna verksamheten i många sådana ”avatar” fall.
Tyvärr är den kurs till vilken Window objekt med insyn uppdateras på skärmen är mycket långsammare än den hastighet med vilken OpenGL kan dra. Den ”avatar” endast uppdateras 10 gånger per sekund. Jag vet inte om detta kan förbättras.
5.6 ”CSGL12BuiltExecutableExamplesForReference”
Katalogen heter ”CSGL12BuiltExecutableExamplesForReference” innehåller DLL filer och EXE filer som produceras av alla de exempel projekt. Dessa filer finns som referens, så att filerna kan testas omedelbart, även om en person inte har förmåga att sammanställa de olika projekten från förutsättning C# kod.
5.7 ”CSGL12UsefulCode”
Katalogen heter ”CSGL12UsefulCode” innehåller C# filer som kan vara till nytta för människor som vill göra vanliga ritning med OpenGL. Katalogen omfattar även DLL filer ”CSGL12DLL.dll” och ”CSGL12Control.dll” för enkelhetens skull.
Koden i den katalogen definieras olika class, t.ex. Color4f, Vector3f, Matrix4x4f, Triangle, Mesh, ImageData, Texture, ShaderProgram etc. Koden är någorlunda effektiv, men koden är endast avsedd att inspirera människor att utveckla sina egna tillämpningar.
6. CSGL12 filer
Den ”CSGL12” insamling av C# datakod filer innehåller de filer som visas i följande diagram:

Den ”CSGL12” insamling av C# datakod filer innehåller de filer som visas i detta diagram.
Den ”CSGL12” programvara ingår också projekt för att skapa två DLL filer (”CSGL12DLL.dll” och ”CSGL12Control.dll”) visas i diagrammet. Dessa två DLL filer kan skapas för att göra det enklare att skapa program som använder OpenGL, men det är också möjligt att skapa program med endast C# filer direkt.
7. ”namespace CSGL12” och ”class” typer
Den ”CSGL12” insamling av C# datakod filer definierar ”namespace CSGL12” och ”class” typer som visas i diagrammet nedan:

Den ”CSGL12” insamling av C# datakod filer definierar ”namespace CSGL12” och ”class” typer som visas i detta diagram.
Ett program som gör OpenGL ritning kan skapas med endast ”class GL” (med hjälp av C# fil GL.cs direkt, eller genom att använda DLL fil CSGL12DLL.dll som också innehåller ”class GL”). Men med hjälp ”class CSGL12Control” (med hjälp av C# fil CSGL12Control.cs direkt, eller genom att använda DLL fil CSGL12Control.dll som också innehåller ”class CSGL12Control”) gör tillägg OpenGL ritning till en Form (System.Windows.Forms.Form) enkelt och bekvämt.
Den C# klasser Color4f, CSGL12Support, ImageData, ..., längst ner i diagrammet erbjuds bara för enkelhetens skull. De klasser som gör det lättare att skapa program för att rita med hjälp OpenGL. Men du kanske redan har klasser att utöva verksamhet i dessa klasser, eller så kan du välja att skapa liknande klasser att utföra de operationer annorlunda eller effektivare. Dessa klasser erbjuds som exempel på ett särskilt nummer utformning och genomförande.
8. Använda en enda ”CSGL12Control” på System.Windows.Forms.Form
8.1 Program struktur
Följande diagram visar hur ett program med en System.Windows.Forms.Form kan använda en enda ”CSGL12Control” att göra ritning med OpenGL. Diagrammet visar de olika CSGL12 filer användas för att bygga upp programmet.

Ett program med en enda ”CSGL12Control” på en System.Windows.Forms.Form
8.2 Använda Microsoft Visual C# att skapa program
(1) Start Microsoft Visual C#.
(2) I menyn, välj ”File” -> ”New Project...”.
(3) I ”New Project” dialogrutan som visas väljer du ”Windows Forms Application” och välja ett namn på programmet och tryck ”OK”.
(4) Omedelbart spara ”Solution” genom att välja ”File” -> ”Save All”. En dialogruta med titeln ”Save Project” kommer att visas, så att du kan ställa in projektets namn, katalogplats och ”lösningen” namn för projektet. Kom ihåg katalogen plats så att du är redo för nästa instruktion. Tryck på ”Save” knappen för att rädda projektet.
(5) Kopiera alla filer från katalogen ”CSGL12UsefulCode” i ”CSGL12” programvara till den katalog som innehåller källkoden filer i det nya projektet (dvs. den katalog som innehåller de filer ”Form1.cs”, ”Form1.Designer.cs”, ”Program.cs”, etc), så att filerna ”CSGL12DLL.dll”, ”CSGL12Control.dll”, ”Color4f.cs” , ”CSGL12Support.cs”, etc, är vid sidan av det nya projektet filer ”Form1.cs” etc.
(6) I Microsoft Visual C# lägger ”CSGL12” C# filer till projektet. I menyn, välj ”Project” -> ”Add Existing Item...” och i ”Add Existing Item” dialogrutan välja alla de C# filer från CSGL12 programvara (”Color4f.cs”, ”CSGL12Support.cs”, ”ImageData.cs”, ...).
(7) I Microsoft Visual C#, lägga till ”referenser” till DLL filer ”CSGL12DLL.dll” och ”CSGL12Control.dll”. I menyn, välj ”Project” -> ”Add Reference...” och i ”Add Reference” dialogrutan välja ”Browse” fliken och välj de filer ”CSGL12DLL.dll” och ”CSGL12Control.dll” från projektet källfilen katalogen och tryck ”OK”.
(8) I Microsoft Visual C# lägger ”CSGL12Control” till ”Toolbox”. I menyn, välj ”Tools” -> ”Choose Toolbox Items...”. I ”Choose Toolbox Items” dialogrutan som visas, tryck på ”Browse...” knappen och gå till projektet katalogen med källkoden filer och välj ”CSGL12Control.dll”. Tryck på ”OK” knappen.
(9) I Microsoft Visual C# visa ”Toolbox”. I menyn, välj ”View” -> ”Toolbox”. I ”Toolbox”, gå direkt till det avsnitt som heter ”General” och lokalisera objektet heter ”CSGL12Control”. Använda markören klickar du på objektet som heter ”CSGL12Control” och dra den till ”Form” i ”Design” uppfattning.
(10) I Microsoft Visual C# i ”Form” ”Design” visa, flytta ”CSGL12Control” exempel på ”Form” och anpassa sin bredd och höjd. I ”Properties” panel in ”Anchor” värde att inkludera ”Top, Bottom, Left, Right” om du vill att kontrollen för att ändra storlek beroende på förändringar i programmet fönsterstorleken.
(11) I Microsoft Visual C#, ändra projektets egenskaper så att den kan använda ”unsafe” kod. I menyn, välj ”Project” -> ”[project] Properties...”. Välj dialogrutan som visas väljer du den flik som heter ”Build” och kontrollera kryssrutan som heter ”[X] Allow unsafe code”. Stäng Projektegenskaper dialogrutan.
(12) I Microsoft Visual C#, lägga till en ny C# filen till projektet. I menyn, välj ”Project” -> ”Add New Item...”. I dialogrutan som heter ”Add New Item”, välj den mall som heter ”Class” och välja ett namn för den nya klassen, t.ex. ”CSGL12MyHandler.cs” och tryck sedan på ”Add” knappen. Titta på exemplet projektet heter ”CSGL12Example1” på filen som heter ”CSGL12Example1Handler.cs”, som ett exempel på hur koden för ”CSGL12MyHandler.cs” ska skrivas.
(13) I Microsoft Visual C# i ”Solution Explorer”, klicka på ”Form1”. I menyn, välj ”View” -> ”Code” (eller tryck F7, eller högerklicka på ”Form1” och väljer ”View Code”. Koden i filen ”Form1.cs” kommer att visas i editorn. Ändra koden i filen ”Form1.cs” som liknar koden i filen ”CSGL12Example1Form.cs” i projektet ”CSGL12Example1” ingår i ”CSGL12” programvara. I synnerhet skapa en variabel för ett fall av din händelsehanterare klass (t.ex. ”CSGL12MyHandler”) och sedan lägga till de metoder för den klassen exempel så fall hanterar för de olika händelserna i fallet av ”CSGL12Control” på ”Form”.
(14) I Microsoft Visual C#, kompilera och köra programmet. Om du vill dela programmet måste du inkludera två DLL filer (”CSGL12DLL.dll” och ”CSGL12Control.dll”) med den körbara filen (*.exe).
Om du är en expert C# programmerare, kan du undvika att behöva distribuera DLL filer (”CSGL12DLL.dll” och ”CSGL12Control.dll”) med ditt körbara (*.exe).
Kopiera filerna ”GL.cs”, ”CSGL12Control.cs” och ”PrecisionTime.cs” från de projekt som heter ”CSGL12DLL” och ”CSGL12Control” i ”CSGL12” programvara till källan för din nuvarande projektet. Lägg filerna ”GL.cs”, ”CSGL12Control.cs” och ”PrecisionTime.cs” till ditt projekt så att de är byggda direkt till programmet. Vill inte ha hänvisningar till ”CSGL12DLL.dll” och ”CSGL12Control.dll” i projektet.
Titta på ”CSGL12Example1” projektet i ”CSGL12” programvara och titta på kod i filer som heter ”CSGL12Example1Form.cs” och ”CSGL12Example1Form.Designer.cs” att se vad koden krävs för att skapa och initiera en instans av ”CSGL12Control” om en ”Form”. Lägg liknande kod för att ”Form1.cs” och ”Form1.Designer.cs” att manuellt skapa och initiera en instans av ”CSGL12Control” på din ”Form”.
Detta förfarande är mycket pinsamt, och kräver kompetens och omsorg, men den körbara (*.exe) kommer inte att kräva ”CSGL12DLL.dll” eller ”CSGL12Control.dll”. Det är mycket trevligt att kunna dela din programvara i form av en enda körbar fil (*.exe) utan att kräva att andra filer.
8.3 Lägga ”hänvisningar” till CSGL12DLL.dll och CSGL12Control.dll
Detta avsnitt innehåller bilder för att använda Microsoft Visual C# 2008 Express Edition att lägga till ”referenser” till DLL filer CSGL12DLL.dll och CSGL12Control.dll till projektet.
I menyn, välj ”Project” -> ”Add Reference...”. Eller högerklicka på ”References” post i ”Solution Explorer” panelen och välj ”Add Reference...”, enligt nedanstående bild.

Sammanhangsberoende meny för ”References” posten i ”Solution Explorer”, visar ”Add Reference...” alternativ
Efter att ha valt ”Add Reference...” alternativ, en dialogruta som heter ”Add Reference” visas. I denna dialogruta väljer du det ”Browse” fliken och välj DLL filer ”CSGL12DLL.dll” och ”CSGL12Control.dll”, enligt nedanstående bild och tryck på knappen ”OK”.

Den ”Browse” fliken i ”Add Reference” dialogrutan med DLL filer ”CSGL12DLL.dll” och ”CSGL12Control.dll” båda utvalda
När du har tryckt på knappen ”OK”, det ”Add Reference” dialogruta kommer att försvinna, och DLL filer ”CSGL12DLL.dll” och ”CSGL12Control.dll” visas i ”References” filial i ”Solution Explorer”, som visas i följande diagram.

Den DLL filer ”CSGL12DLL.dll” och ”CSGL12Control.dll” i ”References” filial i ”Solution Explorer”
8.4 Lägga CSGL12Control till Toolbox i Microsoft Visual C# 2008 Express Edition
Detta avsnitt innehåller bilder för att använda Microsoft Visual C# 2008 Express Edition att lägga CSGL12Control till ”Toolbox” så att en person kan enkelt lägga till exempel på CSGL12Control till en ”Form” i ”Designer” (Shift+F7 som standard).
I menyn, välj ”View” -> ”Toolbox”. I ”Toolbox”, gå direkt till det avsnitt som heter ”General”, enligt nedanstående bild.

Den ”General” avsnitt av ”Toolbox”
Högerklicka någonstans i ”Toolbox”. Välj alternativet ”Choose Items...” i snabbmenyn som visas, enligt nedanstående bild.

Alternativet ”Choose Items...” i snabbmenyn för ”Toolbox”
Alternativt, i menyn, välj Välj ”Tools” -> ”Choose Toolbox Items...”.
Den ”Choose Toolbox Items” dialogrutan skall infinna sig, vilket framgår av följande bild.

Den ”Choose Toolbox Items” dialogrutan
I ”Choose Toolbox Items” dialogrutan trycker ”Browse” knappen. I ”Open” dialogrutan som visas väljer du den DLL filen ”CSGL12Control.dll”, enligt nedanstående bild och tryck sedan på ”OK” knappen.

Den ”Open” dialogrutan med DLL fil ”CSGL12Control.dll” utvalda
Den ”CSGL12Control” posten ska nu visas i ”Choose Toolbox Items” dialogrutan som visas i följande bild. Tryck på ”OK” knappen.

Den ”CSGL12Control” punkt nu visas i ”Choose Toolbox Items” dialogrutan
Den ”CSGL12Control” posten ska nu visas i ”Toolbox”, enligt nedanstående bild.

Den ”CSGL12Control” punkt nu visas i ”Toolbox”
8.5 Lägga CSGL12Control till en ”Form” med ”Toolbox”
Detta avsnitt innehåller bilder för att använda Microsoft Visual C# 2008 Express Edition att lägga till en instans av CSGL12Control till en ”Form” med ”Toolbox”.
I menyn, välj ”View” -> ”Designer” (Shift+F7 som standard). Eller dubbelklicka på en ”Form*.cs” fil i ”Solution Explorer”. Eller högerklicka på en ”Form*.cs” fil i ”Solution Explorer” och välj ”View Designer”. Använda en av dessa tre metoder, ”Designer” fönster för en ”Form” ska visas.
I menyn, välj ”View” -> ”Toolbox”. I ”Toolbox”, gå direkt till det avsnitt som heter ”General”. En post som heter ”CSGL12Control” ska visas där, enligt nedanstående bild.

Den ”CSGL12Control” borde redan vara i ”Toolbox”
Använda markören klickar du på objektet som heter ”CSGL12Control” och dra den till ”Form” i ”Designer”. En instans av ”CSGL12Control” bör finnas på ”Form” enligt nedanstående bild.

En instans av ”CSGL12Control” på en ”Form” i ”Designer”
I ”Form” ”Designer” visa, flytta instans av ”CSGL12Control” på ”Form” och justera dess bredd och höjd.
Klicka på initiativ av ”CSGL12Control” på ”Form” att välja det. Då, i det ”Properties” panel in ”Anchor” värde att inkludera ”Top, Bottom, Left, Right” så att storleken på ”CSGL12Control” kommer att förändras till följd av ändringar i programmet fönsterstorleken. Du kan också ändra variabelnamn (dvs värdet för ”(Name)”) för fallet av ”CSGL12Control” från automatiskt standard (t.ex. ”csgL12Control”) till något lämpligt för din kod (t.ex. ”mCSGL12Control” eller ”mCSGL12Control1” etc).
Följande bild visar ”Form” ”Designer” visa och ”Properties” panelen.

En instans av CSGL12Control på en Form i Designer och ”Properties panel
9. Med hjälp av två fall av ”CSGL12Control” på en System.Windows.Forms.Form
Följande diagram visar ett exempel på hur två fall av ”CSGL12Control” kan läggas till en System.Windows.Forms.Form att göra ritning med OpenGL i ett program.

Ett program med hjälp av två fall av ”CSGL12Control” på en System.Windows.Forms.Form
Följ instruktionerna i föregående avsnitt för att lägga till en enda instans av ”CSGL12Control” till en ”Form”. Då, helt enkelt dra en andra instans av ”CSGL12Control” från ”Toolbox” till ”Form” att lägga till en andra ”CSGL12Control”.
Varje instans av ”CSGL12Control” att ha ett eget variabelnamn. Varje instans av ”CSGL12Control” kan ha sin egen tillhörande händelsehanterare klass, eller så kan använda separata instanser av en enda operatör klass typ.
Studera exempel projektet ”CSGL12Example2” att lära dig hur två fall ”CSGL12Control” kan ha sitt evenemang skickats till två olika instanser av anpassade händelsehanterare klasser med skilda OpenGL ritning funktioner.
Exemplet program ”CSGL12Example2” har varje instans av ”CSGL12Control” i en ”SplitContainer” ”Control” bara att visa ett sätt på vilket fall av ”CSGL12Control” kan användas. Men fall av ”CSGL12Control” kan istället gå direkt till ”Form”.
10. Exempel C# koden för en ”Form” med en instans av CSGL12Control
Nedan följer den fullständiga C# kod i filen ”CSGL12Example1Form.cs”, som är en del av t.ex. program ”CSGL12Example1”.
Denna kod som presenteras här som ett enkelt exempel på hur en instans av CSGL12Control kan skapas och används av en ”Form”.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CSGL12;
namespace CSGL12Example1
{
public partial class CSGL12Example1Form : Form
{
public CSGL12Example1Handler mCSGL12Example1Handler;
private System.Windows.Forms.Timer mTimer;
public CSGL12Example1Form()
{
InitializeComponent();
mCSGL12Example1Handler = new CSGL12Example1Handler();
mCSGL12Control1.OpenGLStarted += new CSGL12Control.DelegateOpenGLStarted( mCSGL12Example1Handler.OpenGLStarted );
mCSGL12Control1.KeyDown += new KeyEventHandler(mCSGL12Example1Handler.KeyDown);
mCSGL12Control1.KeyUp += new KeyEventHandler(mCSGL12Example1Handler.KeyUp);
mCSGL12Control1.MouseDown += new MouseEventHandler(mCSGL12Example1Handler.MouseDown);
mCSGL12Control1.MouseUp += new MouseEventHandler(mCSGL12Example1Handler.MouseUp);
mCSGL12Control1.MouseMove += new MouseEventHandler(mCSGL12Example1Handler.MouseMove);
mCSGL12Control1.MouseWheel += new MouseEventHandler(mCSGL12Example1Handler.MouseWheel);
mCSGL12Control1.Paint += new PaintEventHandler(mCSGL12Example1Handler.Paint);
// Use a timer to trigger drawing at the desired frame rate.
//
// Windows timers are not very precise. Also, if we call wglSwapIntervalEXT(1)
// and we specify in the global OpenGL control panel that OpenGL drawing
// should wait for vertical sync (vsync) of the display, then the frame
// rate would be limited to 60 frames/second or 75 frames/second, for example,
// and our program would have to draw each frame in less than 1/60 seconds
// (16.6 milliseconds) or less than 1/75 seconds (13.3 milliseconds),
// otherwise the drawn frame would be forced to wait one or more full
// frame durations before appearing on the screen. Therefore, it would
// be best to have the timer interval somewhat shorter than a full frame
// interval, to ensure that even if there is a slight delay in responding
// to the timer event we will have at least one timer event per display
// frame interval.
//
// Theoretically, a timer interval of 16 milliseconds would be short enough
// to sustain a frame rate of 62.5 frames/second, and would seemingly have
// a corresponding rate sufficient to sustain 60 frames/second in the case
// of a vertical-sync limited drawing rate for OpenGL. However, in simple
// experiments on a system with a 2.5 GHz Core 2 Duo CPU with an nVidia
// GeForce 8600M GS with 512 MB, I found that a 16-millisecond Windows
// timer interval results in a 33 frames/second OpenGL frame rate (where
// vertical-sync locking is enabled, and the display refresh rate is
// 60 frames/second). So, despite theoretically being slightly more rapid
// than necessary to maintain a 60 frames/second drawing rate, a Windows
// timer with an interval of 16-milliseconds isn't quite rapid enough to
// ensure drawing soon enough to be ready for each display refresh; hence
// the rather significantly lower than desired frame rate of 33 frames/second.
//
// Here are the OpenGL drawing frame rates (limited to 60 Hz vertical sync)
// I observed on a particular computer for particular Windows timer intervals:
//
// 18-millisecond timer interval --> 31 frames/second OpenGL drawing
// 17-millisecond timer interval --> 31 frames/second OpenGL drawing
// 16-millisecond timer interval --> 33 frames/second OpenGL drawing
// 15-millisecond timer interval --> 60 frames/second OpenGL drawing
// 14-millisecond timer interval --> 60 frames/second OpenGL drawing
//
// So, it seems like choosing a Windows timer interval only a couple of
// milliseconds shorter than the theoretical 16.6 millisecond interval
// corresponding to a 60 frames/second rate is enough for this program to
// submit each new frame in time for the next display refresh.
//
// However, computers with slower CPUs or slower GPUs might benefit from
// an even shorter Windows timer interval, to ensure that drawing will
// happen soon enough for the next display refresh.
//
// Some displays are set to refresh at 75 frames/second, which corresponds
// to a frame duration of 13.3 milliseconds. We will aim for this drawing
// rate, and we will subtract a few milliseconds from the Windows timer
// interval to ensure that we receive and process the timer event soon
// enough to submit the frame in time for the next display refresh.
// Meanwhile, we will choose the Windows timer interval such that it isn't
// absurdly short, lest future faster computers actually manage to draw
// at that wasteful rate.
//
// Choosing a Windows timer interval of 10 milliseconds seems like it will
// reliably be able to trigger OpenGL frame drawing in time to keep up with
// a 75 frames/second display (13.3 millisecond frame duration), while
// only causing the OpenGL drawing to happen at a maximum rate of
// 100 frames/second in the unlikely scenario of a very fast computer
// actually being able to draw frames at that rate (given the overhead of
// C#, etc).
mTimer = new System.Windows.Forms.Timer();
mTimer.Interval = 10; // 10-millisecond interval
mTimer.Tick += new EventHandler(PrivateTimerTickEventHandler);
mTimer.Start();
// Set focus to a control so that it can immediately accept input
mCSGL12Control1.Focus();
// Also, whenever the form becomes activated, set focus to the main
// control on the form. The following sets up an event handler for
// that purpose.
this.Activated += new EventHandler(PrivateActivatedEventHandler);
// We want to preview dialog keys (most importantly, the cursor
// keys: up, down, right, left) so we can forward such events to
// the appropriate child control.
this.KeyPreview = true;
}
void PrivateTimerTickEventHandler(object sender, EventArgs e)
{
if (false == DesignMode)
{
mCSGL12Control1.Invalidate();
}
}
private void PrivateActivatedEventHandler(object sender, EventArgs e)
{
// When this form becomes activated, after some time of not
// being active, set input focus to a GL control on the form.
if (false == mCSGL12Control1.Focused)
{
mCSGL12Control1.Focus();
}
}
// Cursor keys (up,down,left,right) need to be specially captured
// and forwarded to the control.
// CAUTION: The KeyPreview property of this Form must be set to 'true'
// for the following method to be called.
protected override bool ProcessDialogKey(Keys keyData)
{
if
(
(keyData == Keys.Up)
|| (keyData == Keys.Down)
|| (keyData == Keys.Left)
|| (keyData == Keys.Right)
)
{
KeyEventArgs e = new KeyEventArgs(keyData);
if (true == mCSGL12Control1.Focused)
{
mCSGL12Example1Handler.KeyDown(mCSGL12Control1, e);
}
else
{
// The CSGL12Control does not have focus.
// Let's simply drop the dialog key event. The user
// may have focus on a different control.
}
return (true);
}
return base.ProcessDialogKey(keyData);
}
}
}
Observera att medlem variabel ”mCSGL12Example1Handler” förklaras att hänvisa till en instans av en class namngivna ”CSGL12Example1Handler”. Denna klass kommer att beskrivas i ett senare avsnitt i detta dokument. Observera att konstruktören för ”CSGL12Example1Form” tillägger metoder för fallet av ”CSGL12Example1Handler” till ”multicast delegates” samband med olika händelser som genereras av en instans av ”CSGL12Control”. Detta innebär att när den instans av ”CSGL12Control” genererar olika händelser, dessa händelser kommer att leda till olika typer av initiativ av ”CSGL12Example1Handler” (dvs. ”mCSGL12Example1Handler”) för att kunna åberopas.
Observera att medlem variabel ”mTimer” förklaras att hänvisa till en instans av en class namngivna ”System.Windows.Forms.Timer”. Detta objekt används för att åberopa en funktion som heter ”PrivateTimerTickEventHandler” var 10 millisekunder. Funktionen heter ”PrivateTimerTickEventHandler” kräver en metod för att fallet av ”CSGL12Control” (dvs. ”mCSGL12Control1”) som orsakar att ”Control” att dra själv. Detta är hur en instans av ”CSGL12Control” kan animerade vid en ungefärlig hastighet.
Endast en del av definitionen av ”class CSGL12Example1Form” visas i C# fil med namnet ”CSGL12Example1Form.cs”. En annan del av definitionen av ”class CSGL12Example1Form” verkar i en C# fil med namnet ”CSGL12Example1Form.Designer.cs”. Även filer med namn som matchar mönstret ”*.Designer.cs” i allmänhet skapas och ändras endast av den grafiska ”Form Designer” fönster i en C# redaktör är det också möjligt att skapa och ändra C# filer med en textredigerare.
Nedan följer den fullständiga C# kod i filen ”CSGL12Example1Form.Designer.cs”, som är en del av t.ex. program ”CSGL12Example1”.
namespace CSGL12Example1
{
partial class CSGL12Example1Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mCSGL12Control1 = new CSGL12.CSGL12Control();
this.SuspendLayout();
//
// mCSGL12Control1
//
this.mCSGL12Control1.Anchor = ((System.Windows.Forms.AnchorStyles)
((((System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.mCSGL12Control1.BackColor = System.Drawing.SystemColors.Control;
this.mCSGL12Control1.Location = new System.Drawing.Point(12, 12);
this.mCSGL12Control1.Name = "mCSGL12Control1";
this.mCSGL12Control1.Size = new System.Drawing.Size(640, 480);
this.mCSGL12Control1.TabIndex = 0;
this.mCSGL12Control1.Text = "CSGL12Control1";
//
// CSGL12Example1Form
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(664, 504);
this.Controls.Add(this.mCSGL12Control1);
this.Name = "CSGL12Example1Form";
this.Text = "CSGL12Example1";
this.ResumeLayout(false);
}
#endregion
private CSGL12.CSGL12Control mCSGL12Control1;
}
}
Observera att detta C# koden innehåller deklarationen av variabeln ”mCSGL12Control1”, som hänvisar till ett fall av ”class CSGL12.CSGL12Control” (dvs. ”class CSGL12Control” i ”namespace CSGL12”). Detta exempel skapas och konfigureras i funktionen ”InitializeComponent”.
11. Hantering av händelser som åberopas av en instans av CSGL12Control
Föregående avsnitt visade C# koden för en ”Form” som innehöll en enda instans av ”CSGL12Control”. Den C# koden lägga metoder för en ”class” namngivna ”CSGL12Example1Handler” så fall hanterar olika händelser som genereras av fallet av ”CSGL12Control”.
Här är en lista på intressanta händelser ”CSGL12Control” och ”delegate” typer samband med dessa händelser:
OpenGLStarted CSGL12Control.DelegateOpenGLStarted
KeyDown System.Windows.Forms.KeyEventHandler
KeyUp System.Windows.Forms.KeyEventHandler
MouseDown System.Windows.Forms.MouseEventHandler
MouseUp System.Windows.Forms.MouseEventHandler
MouseMove System.Windows.Forms.MouseEventHandler
MouseWheel System.Windows.Forms.MouseEventHandler
Paint System.Windows.Forms.PaintEventHandler
Endast ”OpenGLStarted” händelse är en händelse typspecifika till ”CSGL12Control”.
Alla andra evenemang är standard System.Windows.Forms evenemang, vars händelsehanterare måste ha vissa parametrar (anges i varje Forms dokumentation).
Den ”OpenGLStarted” och ”Paint” händelser är de viktigaste faktorerna för OpenGL ritning.
Den ”OpenGLStarted” händelsen är åberopas vid den allra första ”Paint” omständigheter åberopas.
Därför är ”OpenGLStarted” händelsehanterare måste läggas till den kontroll innan kontrollen har en möjlighet att försöka måla själv, annars ett-tiden händelse inte kommer att mottas.
Den här händelsen är bara en bekvämlighet, och kan ignoreras.
Men att lägga till en handler för denna händelse gör det möjligt för hanterare kod att göra ett engångsbidrag initiering som beror på OpenGL är redo att använda.
(OpenGL inte kan användas fram till fönstret finns och fönstret är redo att utföra sitt första måla.
Så, det ”OpenGLStarted” händelse skonar programmerare från risken att försöka använda OpenGL för tidigt när programmet startar.
) Det är ganska lätt att lägga till logik i en ”Paint” hanterare att göra en en-Temne initieringsfil med hjälp av OpenGL samband med ”CSGL12Control”.
Den ”OpenGLStarted” fall erbjuds som en tjänst.
Nedan följer den fullständiga C# kod i filen ”CSGL12Example1Handler.cs”, som är en del av t.ex. program ”CSGL12Example1”.
Denna kod som presenteras här som ett enkelt exempel på hur de händelser som genereras av en instans av ”CSGL12Control” kan hanteras för att dra med hjälp OpenGL.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
// This program requires "references" to the following:
//
// CSGL12DLL.dll (defines CSGL12.GL)
// CSGL12Control.dll (defines CSGL12.CSGL12Control)
using CSGL12;
namespace CSGL12Example1
{
public class CSGL12Example1Handler
{
private Mesh mMesh;
private ShaderProgram mShaderProgram1;
private ShaderProgram mShaderProgram2;
private ShaderProgram mShaderProgram3;
private ShaderProgram mShaderProgram4;
private ShaderProgram mShaderProgramSelected;
private Bitmap mHUDBitmap;
private Texture mHUDTexture;
private Font mFont1;
private Font mFont2;
private Font mFont3;
private Font mFont4;
private Pen mPen1;
private Brush mBrush1;
private double mViewDistance = 800.0;
private double mViewAzimuthDegrees = 0.0;
private double mViewAltitudeDegrees = 0.0;
private double mViewAzimuthDegreesVelocity = 9.0;
private double mViewAltitudeDegreesVelocity = 5.0;
private Point mMouseClientPositionStart;
private double mViewAzimuthDegreesStart = 0.0;
private double mViewAltitudeDegreesStart = 0.0;
public CSGL12Example1Handler()
{
mMesh = new Mesh();
mShaderProgram1 = new ShaderProgramMandelbrotSet();
mShaderProgram2 = new ShaderProgramWood();
mShaderProgram3 = new ShaderProgramBrick();
mShaderProgram4 = new ShaderProgramCartoon();
mShaderProgramSelected = mShaderProgram1;
mHUDBitmap = new Bitmap(512, 512, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
mHUDTexture = new Texture();
mFont1 = new Font("Verdana", 36.0f);
mFont2 = new Font("Verdana", 24.0f);
mFont3 = new Font("Courier New", 16.0f);
mFont4 = new Font("Courier New", 10.0f);
mPen1 = new Pen(Color.Red, 3.0f);
mBrush1 = new SolidBrush(Color.FromArgb(64, 128, 128, 140));
}
public void OpenGLStarted( CSGL12Control csgl12Control )
{
GL gl = csgl12Control.GetGL();
if (null == gl) { return; }
// Load shaders and set variables
if (true == gl.bglCreateProgramObjectARB)
{
if (null != mShaderProgram1)
{
mShaderProgram1.ShaderProgramCreate(gl);
}
if (null != mShaderProgram2)
{
mShaderProgram2.ShaderProgramCreate(gl);
}
if (null != mShaderProgram3)
{
mShaderProgram3.ShaderProgramCreate(gl);
}
if (null != mShaderProgram4)
{
mShaderProgram4.ShaderProgramCreate(gl);
}
}
// Create cube mesh
mMesh = new Mesh();
mMesh.BuildCube(400.0f);
// Create a texture
mHUDTexture.CreateTextureFromBitmap(gl, mHUDBitmap, true);
// To prevent "tearing" (irregular streaks) due to swapping buffers at
// arbitrary times relative to the vsync times, we indicate that we wish
// to wait for vsync before swapping buffers.
// This request applies when the display driver control panel -- in the
// OpenGL settings area -- is set to let the application decide whether or
// not to wait for vsync. Otherwise, the driver control panel overrides
// any request made here.
if (true == gl.bwglSwapIntervalEXT)
{
gl.wglSwapIntervalEXT(1);
}
}
public void Paint(object sender, PaintEventArgs e)
{
if (null == sender) { return; }
if (false == (sender is CSGL12Control)) { return; }
CSGL12Control csgl12Control = (sender as CSGL12Control);
GL gl = csgl12Control.GetGL();
int clientWidth = csgl12Control.ClientRectangle.Width;
int clientHeight = csgl12Control.ClientRectangle.Height;
if (clientWidth <= 0)
{
clientWidth = 1;
}
if (clientHeight <= 0)
{
clientHeight = 1;
}
// Set the viewport
gl.glViewport(0, 0, clientWidth, clientHeight);
// Clear the viewport
gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// Basic drawing conditions
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glEnable(GL.GL_CULL_FACE);
gl.glCullFace(GL.GL_BACK);
gl.glFrontFace(GL.GL_CCW);
// PROJECTION matrix, typically for perspective correction or orthographic projection
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
double aspectRatio = 1.0;
if (0 != clientHeight)
{
aspectRatio = ((double)(clientWidth) / (double)(clientHeight));
}
double verticalFieldOfViewAngle = 60.0;
gl.gluPerspective
(
verticalFieldOfViewAngle, // Field of view angle (Y angle; degrees)
aspectRatio, // width/height
0.1, // distance to near clipping plane
64000.0 // distance to far clipping plane
);
// MODELVIEW matrix, typically used to transform individual models
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
// Preserve current matrix for the active matrix stack (in this case the MODELVIEW matrix)
gl.glPushMatrix();
if (mViewAltitudeDegreesVelocity != 0.0)
{
if (mViewAltitudeDegrees > 70.0)
{
mViewAltitudeDegrees = 70.0;
mViewAltitudeDegreesVelocity *= -1.0;
}
else if (mViewAltitudeDegrees < -70.0)
{
mViewAltitudeDegrees = -70.0;
mViewAltitudeDegreesVelocity *= -1.0;
}
mViewAzimuthDegrees += mViewAzimuthDegreesVelocity * csgl12Control.GetPreviousFrameDurationSeconds();
mViewAltitudeDegrees += mViewAltitudeDegreesVelocity * csgl12Control.GetPreviousFrameDurationSeconds();
}
Vector3f from =
new Vector3f
(
(float)(mViewDistance * Math.Cos(mViewAltitudeDegrees * (Math.PI / 180.0)) * Math.Sin(mViewAzimuthDegrees * (Math.PI / 180.0))),
(float)(mViewDistance * Math.Sin(mViewAltitudeDegrees * (Math.PI / 180.0))),
(float)(mViewDistance * Math.Cos(mViewAltitudeDegrees * (Math.PI / 180.0)) * Math.Cos(mViewAzimuthDegrees * (Math.PI / 180.0)))
);
Vector3f to = new Vector3f(0.0f, 0.0f, 0.0f);
Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
Matrix4x4f camera = Matrix4x4f.LookAt(from, to, up);
float[] matrix = new float[16];
matrix[0] = camera.m11;
matrix[1] = camera.m21;
matrix[2] = camera.m31;
matrix[3] = 0.0f;
matrix[4] = camera.m12;
matrix[5] = camera.m22;
matrix[6] = camera.m32;
matrix[7] = 0.0f;
matrix[8] = camera.m13;
matrix[9] = camera.m23;
matrix[10] = camera.m33;
matrix[11] = 0.0f;
matrix[12] = camera.m14;
matrix[13] = camera.m24;
matrix[14] = camera.m34;
matrix[15] = 1.0f;
gl.glMultMatrixf(matrix);
if (mShaderProgramSelected != null)
{
mShaderProgramSelected.DemonstrateModificationOfVariables(gl, csgl12Control.GetPreviousFrameStartTimeSeconds(), csgl12Control.GetPreviousFrameDurationSeconds());
mShaderProgramSelected.Select(gl);
}
// Draw model(s), using active texture or shader
mMesh.Draw(gl);
// If we used a shader, disable it now...
if (true == gl.bglUseProgramObjectARB)
{
ShaderProgram.ShaderProgram_Select(gl, 0);
}
// Restore the previously-preserved matrix for the active matrix stack (in this case the MODELVIEW matrix)
gl.glPopMatrix();
// Demonstrate drawing text to a GDI+ Bitmap and then copying to
// an OpenGL texture.
DemonstrateDrawingTextToAGDIBitmapAndCopyingToAnOpenGLTexture(csgl12Control, gl);
// Flush all the current rendering and flip the back buffer to the front.
gl.wglSwapBuffers(csgl12Control.GetHDC());
}
public void DemonstrateDrawingTextToAGDIBitmapAndCopyingToAnOpenGLTexture(CSGL12Control csgl12Control, GL gl)
{
bool updateOverlayImage = false;
// The following code only enables an update of the Bitmap
// and OpenGL texture every 64 frames, thus avoiding the
// slowdown of performing updates every single frame.
// HOWEVER, updating the Bitmap and OpenGL texture can be
// done EVERY frame with acceptable speed.
// Updates should be limited to once per frame, but the
// logic to trigger updates can be based on when the relevant
// text changes.
if ((csgl12Control.GetTotalFramesDrawn() % 64) == 0)
{
updateOverlayImage = true;
}
bool showOverlayImage = true;
if (true == updateOverlayImage)
{
using (Graphics g = Graphics.FromImage(mHUDBitmap))
{
g.Clear(Color.FromArgb(0, Color.White));
g.FillEllipse(mBrush1, new Rectangle(0, 0, 256, 256));
g.FillEllipse(mBrush1, new Rectangle(256, 256, 256, 256));
PointF center = new PointF(0.5f * (256.0f + 0.0f), 0.5f * (256.0f + 0.0f));
PointF displacement = new PointF();
double fraction = csgl12Control.GetTotalElapsedTimeSeconds() * 0.1;
displacement.X = 128.0f * (float)Math.Cos(2.0 * Math.PI * fraction);
displacement.Y = 128.0f * (float)Math.Sin(2.0 * Math.PI * fraction);
g.DrawLine(mPen1, center, new PointF(center.X + displacement.X, center.Y + displacement.Y));
PointF carat = new PointF(0.0f, 0.0f);
String text = "";
text = "C# OpenGL (CSGL)";
g.DrawString(text, mFont1, Brushes.Black, carat);
carat.Y += mFont1.GetHeight();
text = "Здравствуйте";
g.DrawString(text, mFont2, Brushes.Black, carat);
carat.Y += mFont2.GetHeight();
text = "γεια σου";
g.DrawString(text, mFont2, Brushes.Black, carat);
carat.Y += mFont2.GetHeight();
text = "مرحبا";
g.DrawString(text, mFont2, Brushes.Black, carat);
carat.Y += mFont2.GetHeight();
text = "שלום";
g.DrawString(text, mFont2, Brushes.Black, carat);
carat.Y += mFont2.GetHeight();
carat.Y += 64.0f;
text = "Shift + 0: Save BMP,PNG,JPG,GIF";
g.DrawString(text, mFont4, Brushes.Black, carat);
carat.Y += mFont4.GetHeight();
text = "1,2,3,4 : Switch shader program";
g.DrawString(text, mFont4, Brushes.Black, carat);
carat.Y += mFont4.GetHeight();
carat.Y += 12.0f;
text = "Text : GDI+ on 512*512 Bitmap.";
g.DrawString(text, mFont4, Brushes.Black, carat);
carat.Y += mFont4.GetHeight();
text = "Bitmap copied to OpenGL texture.";
g.DrawString(text, mFont4, Brushes.Black, carat);
carat.Y += mFont4.GetHeight();
text = "Texture update once per 64 frames,";
g.DrawString(text, mFont4, Brushes.Black, carat);
carat.Y += mFont4.GetHeight();
text = "but more often would be OK.";
g.DrawString(text, this.mFont4, Brushes.Black, carat);
carat.Y += this.mFont4.GetHeight();
carat.Y += 12.0f;
text = String.Format("Frame:{0}", csgl12Control.GetTotalFramesDrawn());
text += " ";
text += String.Format("Time:{0:f2}", csgl12Control.GetTotalElapsedTimeSeconds());
double previousFrameDurationSeconds =
csgl12Control.GetPreviousFrameDurationSeconds();
if (previousFrameDurationSeconds > 1.0e-10)
{
double framesPerSecondOverall =
1.0 / previousFrameDurationSeconds;
text += " ";
text += String.Format("FPS:{0:f2}", framesPerSecondOverall );
}
g.DrawString(text, mFont3, Brushes.Black, carat);
carat.Y += mFont3.GetHeight();
}
mHUDTexture.UpdateTextureWithBitmapData(gl, mHUDBitmap);
}
if (true == showOverlayImage)
{
CSGL12Support.SupportDrawTextureImageUnrotatedAndOrthographically
(
gl,
csgl12Control.ClientSize.Width,
csgl12Control.ClientSize.Height,
mHUDTexture,
0,
0, // i.e., 0 == draw TOP of image at TOP of viewport, Y-axis points DOWN
mHUDTexture.GetWidth(), // glControl.ClientSize.Width, // mHUDTexture.GetWidth(),
mHUDTexture.GetHeight() // glControl.ClientSize.Height // mHUDTexture.GetHeight()
);
}
}
public void KeyDown(object sender, KeyEventArgs e)
{
if (null == sender) { return; }
if (false == (sender is CSGL12Control)) { return; }
CSGL12Control csgl12Control = (sender as CSGL12Control);
GL gl = csgl12Control.GetGL();
if (e.KeyCode == Keys.A)
{
}
if (e.KeyCode == Keys.Z)
{
}
if (e.KeyCode == Keys.D1)
{
mShaderProgramSelected = mShaderProgram1;
}
if (e.KeyCode == Keys.D2)
{
mShaderProgramSelected = mShaderProgram2;
}
if (e.KeyCode == Keys.D3)
{
mShaderProgramSelected = mShaderProgram3;
}
if (e.KeyCode == Keys.D4)
{
mShaderProgramSelected = mShaderProgram4;
}
// NOTE: The only way for cursor key events (up,down,left,right)
// to make it to this function is for the main form to implement
// the following:
//
// protected override bool ProcessDialogKey ( Keys keyData )
//
// and explicitly invoke this KeyDown() method with the
// an appropriately formed KeyEventArgs instance.
if (e.KeyCode == Keys.Up)
{
mViewDistance -= 10.0;
}
if (e.KeyCode == Keys.Down)
{
mViewDistance += 10.0;
}
if (e.KeyCode == Keys.Left)
{
mViewAzimuthDegrees += 1.0;
}
if (e.KeyCode == Keys.Right)
{
mViewAzimuthDegrees -= 1.0;
}
// Save an image of the viewport (press Shift-0 (zero)). The following
// code writes out the viewport in the following image formats: BMP, PNG, GIF, JPG.
// If you only want a single format, comment out the other file write commands.
// BMP has no compression artifacts, but the file can be quite large.
// PNG looks good, and supports 8-bit transparancy (good for textures, etc).
// GIF looks bad unless you build the color table intelligently (there is a
// neural network color table builder for GIF, in C#/.NET, that you can
// find on the Internet; perhaps Paint.NET uses that code); but GIF files
// can be quite small, and supports animation.
// JPG looks good under most circumstances, and the file size can be quite small,
// but transparency is not supported.
// So, for pixel-perfect images, where file size is not important, BMP might be appropriate.
// For textures with transparency, PNG might be appropriate.
// For good-looking images, and small file size, and use in Web pages, JPG might be appropriate.
// For some purposes, with small file sizes, and use in Web pages, GIF might be appropriate.
if ((e.KeyCode == Keys.D0) && (e.Shift == true))
{
DateTime now = DateTime.Now;
String dateTimeString = String.Format("{0:d4}{1:d2}{2:d2}{3:d2}{4:d2}{5:d2}{6:d3}", now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond);
String frameIndexString = String.Format("{0:d6}", csgl12Control.GetTotalFramesDrawn());
String fileNameWithoutExtension = "screen" + "_" + dateTimeString + "_" + frameIndexString;
CSGL12Support.SupportWriteViewportToImageFile(gl, fileNameWithoutExtension + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
CSGL12Support.SupportWriteViewportToImageFile(gl, fileNameWithoutExtension + ".png", System.Drawing.Imaging.ImageFormat.Png);
CSGL12Support.SupportWriteViewportToImageFile(gl, fileNameWithoutExtension + ".gif", System.Drawing.Imaging.ImageFormat.Gif);
CSGL12Support.SupportWriteViewportToImageFile(gl, fileNameWithoutExtension + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
public void KeyUp(object sender, KeyEventArgs e)
{
}
public void MouseDown(object sender, MouseEventArgs e)
{
if (null == sender) { return; }
if (false == (sender is CSGL12Control)) { return; }
CSGL12Control csgl12Control = (sender as CSGL12Control);
mMouseClientPositionStart = csgl12Control.PointToClient(Cursor.Position);
mViewAzimuthDegreesStart = mViewAzimuthDegrees;
mViewAltitudeDegreesStart = mViewAltitudeDegrees;
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
mViewAzimuthDegreesVelocity = 0.0;
mViewAltitudeDegreesVelocity = 0.0;
}
if ((e.Button & MouseButtons.Right) == MouseButtons.Right)
{
mViewAzimuthDegreesVelocity = 9.0;
mViewAltitudeDegreesVelocity = 5.0;
}
}
public void MouseUp(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Right) == MouseButtons.Right)
{
}
}
public void MouseMove(object sender, MouseEventArgs e)
{
if (null == sender) { return; }
if (false == (sender is CSGL12Control)) { return; }
CSGL12Control csgl12Control = (sender as CSGL12Control);
Point mouseClientPositionCurrent = csgl12Control.PointToClient(Cursor.Position);
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
double azimuth =
mViewAzimuthDegreesStart
- (360.0 / (double)(csgl12Control.Width + 1))
* (double)(mouseClientPositionCurrent.X - mMouseClientPositionStart.X);
double altitude =
mViewAltitudeDegreesStart
+ (180.0 / (double)(csgl12Control.Height + 1))
* (double)(mouseClientPositionCurrent.Y - mMouseClientPositionStart.Y);
double epsilon = 0.05;
if (azimuth < (-180 + epsilon)) { azimuth = (-180 + epsilon); }
if (azimuth > (180 - epsilon)) { azimuth = (180 - epsilon); }
if (altitude < (-90 + epsilon)) { altitude = (-90 + epsilon); }
if (altitude > (90 - epsilon)) { altitude = (90 - epsilon); }
mViewAzimuthDegrees = azimuth;
mViewAltitudeDegrees = altitude;
}
}
public void MouseWheel(object sender, MouseEventArgs e)
{
mViewDistance -= 0.1 * (double)e.Delta;
}
}
}
Lägg märke till att den funktion som heter ”OpenGLStarted” används i detta exempel för att skapa ”pixel shader programs” och ett OpenGL textur. För det här programmet kan vi bara att skapa de resurser en gång, och det är mer effektivt att skapa dem endast en gång.
Observera att funktionen heter ”OpenGLStarted” koden kontrollerar om ett WGL ”extension” funktion som heter ”wglSwapIntervalEXT()” existerar, och om denna funktion finns, den kod som åberopar denna funktion. Den funktionen innehåller en stat som påverkar driften av programmet under hela sessionen, och så behöver vi bara ringa som fungerar en gång, varför vi försöker kalla det för funktion i ”OpenGLStarted” funktion (som i sig är bara åberopas en gång, när OpenGL startas ett särskilt ”CSGL12Control”, förutsatt att vi lagt till ”OpenGLStarted” metoden till händelsen delegera).
Funktionen heter ”Paint” innehåller all kod för att dra en enda ”bildruta” animering med hjälp OpenGL. Den ”Paint” funktionen kommer att kallas kanske 60 gånger per sekund, beror på att de associerade ”CSGL12Control” exempel är ”ogiltiga” (tvingas dra sig igen) på den nivån. (Titta på ”Form” kodexemplet i föregående avsnitt för att se timer som bestämmer graden av ”ogiltigförklaringen” och den faktiska funktionen samtal som orsakar fallet av ”CSGL12Control” att bli ”ogiltiga.)”
Alla OpenGL funktioner åberopas med hjälp av en instans av ”class GL” (exempel: gl.gl*()). Den instans av ”class GL” förvärvas från fallet av ”CSGL12Control”, som är implicit lagras i första parametern till ”Paint” funktion.
Alla OpenGL konstanter kan anges genom att ange ”class” namn ”GL” följt av en punkt och namnet på den konstant, dvs ”GL.GL_TRIANGLES”.
Den OpenGL kod i detta exempel är inte helt självklart och lätt att förstå, men förhoppningsvis kan du känna igen hur koden kan anpassas för dina egna syften.
12. Kontrollera om det finns en ”förlängning” funktion OpenGL
Att bara kontrollera om boolesk flagga samma namn som OpenGL funktion är ”sant” innan du försöker använda motsvarande funktion.
Den booleska variabeln har ett namn som börjar med ”b” följt av OpenGL funktion namn.
if (true == gl.bglCreateProgramObjectARB)
{
// glCreateProgramObjectARB() exists and can be invoked.
// Also, because that function is related to pixel shaders, it is very
// likely that other functions that are required for the use of pixel
// shaders also exist and can be invoked.
// . . .
}
Kontroll behövs endast för ”utvidgning” funktioner.
OpenGL 1.1 funktioner, och alla GLU funktioner och grundläggande WGL funktioner som inte kräver sådan kontroll. Men booleska flaggor finns och är inställda på lämpligt sätt, för alla sådana funktioner som ”class GL” inklusive kärnan OpenGL 1.1 funktioner. Det finns således ett konsekvent sätt för att kontrollera tillgängligheten för alla funktioner i den klassen.
Att veta om en funktion är en ”förlängning” åligga den programmerare.
Men funktionen namn suffix, t.ex. ”EXT”, ”ARB”, ”MESA”, ”NV” (NVidia), ”APPLE”, etc, hjälpa ange förlängning funktioner.
Om en funktion ”gl*()” har en grannstaten funktion ”gl*ARB()” eller ”gl*NV(),” då funktionen ”gl*()” är förmodligen en förlängning (vad Windows OPENGL32.DLL är berörda).
Den enda fördelen av att veta om en funktion är en ”förlängning” (med avseende på Windows OPENGL32.DLL) är att kunna undvika att kontrollera om uppgifter finns tillgängliga.
Du kan söka efter alla OpenGL funktioner som används i din kod och sedan bygga en alfabetisk förteckning över de olika funktioner som används.
Sedan i början av programmet, efter CSGL12Control kallar OpenGLStarted delegera bara kontrollera alla booleska flaggor för alla de funktioner du tänker använda.
Om du väljer att avsluta programmet om något ”krävs” funktioner saknas, sedan alla kontroller för sådana funktioner i koden kan undanröjas.
Du kan också bilda en grupp av icke väsentliga funktioner inom kontrollera och eventuellt informera användare om eventuella inslag förändringar, och eventuellt lämna kontroller spridda runt i koden.
Med mer OpenGL erfarenhet, kan du få en känsla för vad förlängningar är relaterade (exempel: imaging, shaders, buffertar, kompression, ...).
Därför kan du kontrollerar förekomsten av en enda kritisk funktion och använda informationen för att avgöra om hela delmängd som finns.
13. Speed
Av olika skäl, C# är långsammare än non-CLR C/C++.
C# så småningom sammanställas till infödda montering språk, precis som för C/C++, men på grund av de garantier som C# språk och .NET CLR den totala hastighet av programvara bygger på C# och .NET är något långsammare än mjukvara byggs med hjälp non-CLR C/C++.
Därför får den högsta hastigheten möjliga sätt använda non-CLR C/C++ stället för C#.
Dessutom skulle ringa någon native-bibliotek från C# innebär P/Invoke, åberopar funktioner såsom OpenGL funktioner kommer att kräva viss tid att utföra arbete inom P/Invoke skikt.
Trots ”CSGL12” verkar arbeta snabbt för att kunna användas för många i realtid grafiska ändamål, exempelvis för enkla spel, 3D-tittare, redaktörer, eller 3D-presentationer. Detta gäller särskilt om det mesta av arbetet görs av GPU i stället för CPU.
14. Jämförelse mellan ”CSGL12” och ”Tao Framework”
Den ”Tao Framework” är ett stort C# / .NET bibliotek som tillhandahåller ett gränssnitt för många open-source bibliotek, såsom OpenGL, OpenAL (ljud), SDL (ett spel / simulering plattform), Open Dynamics Engine (ODE) (fysik), etc.
Den Tao Framework är plattformsoberoende (Windows, Linux, Mac OS X).
”CSGL12” bara ger ett gränssnitt till OpenGL och är bara för Windows operativsystem.
Den Tao Framework har en gemenskap. En person kan dra nytta av att kommunicera med andra användare av Tao Framework.
Det kan dock finnas många ändamål för vilka ”CSGL12” kan vara lättare att använda för Windows program.