public static CVar Register(string Name, object DefaultVal = null, CVarType Type = CVarType.Default, CVarSetFunc OnSet = null, CVarGetFunc OnGet = null) { if (Find(Name) != null) { throw new Exception("CVar " + Name + " already registered"); } CVar Var = new CVar(Name, DefaultVal, Type, OnSet, OnGet); CVars.Add(Var); return(Var); }
public static string GetString(string Name, string Default = "") { CVar CVar = Find(Name); if (CVar != null) { object Val = CVar.Value; if (Val != null) { return(Val.ToString()); } } return(Default); }
static void LoadContent() { string GameDllPath = Path.Combine(CVar.GetString("game"), "Game.dll"); if (!File.Exists(GameDllPath)) { FatalError("File not found: {0}", GameDllPath); } Assembly GameAssembly = Reflect.LoadAssembly(GameDllPath); Importers.RegisterAll(GameAssembly); Type[] GameImplementations = Reflect.GetAllImplementationsOf(GameAssembly, typeof(LibTechGame)).ToArray(); if (GameImplementations.Length == 0) { FatalError("Could not find game implementation in {0}", GameDllPath); } if (GameImplementations.Length > 1) { FatalError("Found too many game implementations in {0}", GameDllPath); } Game = (LibTechGame)Activator.CreateInstance(GameImplementations[0]); Game.Load(); RenderDevice = new RenderDevice(ShaderProgram.GUI, Width, Height); NuklearAPI.Init(RenderDevice); NuklearAPI.SetClipboardCallback((Txt) => { if (string.IsNullOrEmpty(Txt)) { return; } Glfw.SetClipboardString(Window, Txt); }, () => { string Str = Glfw.GetClipboardString(Window); if (Str == null) { Str = ""; } return(Str); }); Glfw.SetCursorPosCallback(Window, (Wnd, X, Y) => { RenderDevice.OnMouseMove((int)X, (int)Y); }); Glfw.SetMouseButtonCallback(Window, (Wnd, Button, State, Mods) => { NuklearEvent.MouseButton NkButton; bool IsDown = State == Glfw.InputState.Press ? true : false; if (!(State == Glfw.InputState.Press || State == Glfw.InputState.Release)) { return; } if (Button == Glfw.MouseButton.ButtonLeft) { NkButton = NuklearEvent.MouseButton.Left; } else if (Button == Glfw.MouseButton.ButtonMiddle) { NkButton = NuklearEvent.MouseButton.Middle; } else if (Button == Glfw.MouseButton.ButtonRight) { NkButton = NuklearEvent.MouseButton.Right; } else { return; } RenderDevice.OnMouseButton(NkButton, (int)MousePos.X, (int)MousePos.Y, IsDown); }); Glfw.SetScrollCallback(Window, (Wnd, X, Y) => { RenderDevice.OnScroll((float)X, (float)Y); }); Glfw.SetCharCallback(Window, (Wnd, Chr) => { RenderDevice.OnText(((char)Chr).ToString()); }); Glfw.SetKeyCallback(Window, (Wnd, KCode, SCode, State, Mods) => { if (KCode == Glfw.KeyCode.F1 && State == Glfw.InputState.Press) { GConsole.Open = true; } NkKeys K = ConvertToNkKey(KCode, Mods); if (K != NkKeys.None) { RenderDevice.OnKey(K, State == Glfw.InputState.Press); if (State == Glfw.InputState.Repeat) { RenderDevice.OnKey(K, true); } } }); Glfw.SetDropCallback(Window, (Wnd, Cnt, Paths) => { DragDropPaths = Paths; }); }
static void CreateContext(/*params string[] RequiredExtensions*/) { GConsole.WriteLine("Initializing OpenGL"); #if DEBUG Khronos.KhronosApi.Log += (S, E) => { if (E.Name == "glGetError") { return; } Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("OpenGL> {0}", string.Format("{0}({1}) = {2}", E.Name, string.Join(", ", E.Args), E.ReturnValue ?? "null")); Console.ResetColor(); }; Khronos.KhronosApi.LogEnabled = false; //*/ #endif GConsole.WriteLine("Initializing GLFW"); Glfw.ConfigureNativesDirectory("native/glfw3_64"); if (!Glfw.Init()) { FatalError("Could not initialize GLFW"); } Glfw.SetErrorCallback((Err, Msg) => { FatalError("GLFW({0}) {1}", Err, Msg); }); Width = CVar.GetInt("width", 800); Height = CVar.GetInt("height", 600); Glfw.WindowHint(Glfw.Hint.Resizable, CVar.GetBool("resizable")); //Glfw.WindowHint(Glfw.Hint.ClientApi, Glfw.ClientApi.None); Glfw.WindowHint(Glfw.Hint.ClientApi, Glfw.ClientApi.OpenGL); Glfw.WindowHint(Glfw.Hint.ContextCreationApi, Glfw.ContextApi.Native); Glfw.WindowHint(Glfw.Hint.Doublebuffer, CVar.GetBool("gl_doublebuffer")); Glfw.WindowHint(Glfw.Hint.ContextVersionMajor, CVar.GetInt("gl_major")); Glfw.WindowHint(Glfw.Hint.ContextVersionMinor, CVar.GetInt("gl_minor")); Glfw.WindowHint(Glfw.Hint.Samples, CVar.GetInt("gl_samples")); Glfw.WindowHint(Glfw.Hint.OpenglForwardCompat, CVar.GetBool("gl_forwardcompat")); Glfw.WindowHint(Glfw.Hint.OpenglProfile, Glfw.OpenGLProfile.Core); #if DEBUG Glfw.WindowHint(Glfw.Hint.OpenglDebugContext, true); #endif GConsole.WriteLine("Creating window"); Window = Glfw.CreateWindow(Width, Height, "libTech"); if (!Window) { FatalError("Could not create window({0}x{1})", Width, Height); } Gl.Initialize(); Glfw.MakeContextCurrent(Window); /*bool AllSupported = true; * * for (int i = 0; i < RequiredExtensions.Length; i++) { * if (!Glfw.ExtensionSupported(RequiredExtensions[i])) { * GConsole.WriteLine("{0} not supported", RequiredExtensions[i]); * AllSupported = false; * } * } * * if (!AllSupported) * while (true) * Thread.Sleep(10);*/ #if DEBUG Gl.DebugMessageCallback((Src, DbgType, ID, Severity, Len, Buffer, UserPtr) => { if (Severity == Gl.DebugSeverity.Notification) { return; } GConsole.WriteLine("OpenGL {0} {1} {2}, {3}", Src, DbgType, ID, Severity); GConsole.WriteLine(Encoding.ASCII.GetString((byte *)Buffer, Len)); if ((/*Severity == Gl.DebugSeverity.Medium ||*/ Severity == Gl.DebugSeverity.High) && Debugger.IsAttached) { Debugger.Break(); } }, IntPtr.Zero); Gl.Enable((EnableCap)Gl.DEBUG_OUTPUT); Gl.Enable((EnableCap)Gl.DEBUG_OUTPUT_SYNCHRONOUS); #endif GConsole.WriteLine("{0}, {1}", Gl.GetString(StringName.Vendor), Gl.GetString(StringName.Renderer)); GConsole.WriteLine("OpenGL {0}", Gl.GetString(StringName.Version)); GConsole.WriteLine("GLSL {0}", Gl.GetString(StringName.ShadingLanguageVersion)); Gl.ClearColor(69 / 255.0f, 112 / 255.0f, 56 / 255.0f, 1.0f); // F**k the police Gl.Enable((EnableCap)Gl.DEPTH_CLAMP); Gl.Enable(EnableCap.Blend); //Gl.VERTEX_PROGRAM_POINT_SIZE; Gl.Enable((EnableCap)Gl.VERTEX_PROGRAM_POINT_SIZE); //Gl.Enable((EnableCap)Gl.SAMPLE_SHADING); //Gl.Enable(EnableCap.FramebufferSrgb); Gl.BlendEquationSeparate(BlendEquationMode.FuncAdd, BlendEquationMode.FuncAdd); Gl.BlendFuncSeparate(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha, BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); //Gl.BlendEquation(BlendEquationMode.FuncAdd); //Gl.BlendFunc(BlendingFactor.One, BlendingFactor.One); ShaderProgram.LoadDefaultShaders(); }
static void Main(string[] args) { CVar.InitMode = true; CVar.Register("game", "basegame", CVarType.Replicated | CVarType.Init, (This, Old, New) => This.Value = Path.GetFullPath((string)New)); CVar.Register("width", 1366, CVarType.Archive); CVar.Register("height", 768, CVarType.Archive); CVar.Register("borderless", false, CVarType.Archive); CVar.Register("resizable", false, CVarType.Archive); CVar.Register("gl_doublebuffer", true, CVarType.Archive); CVar.Register("gl_samples", 8, CVarType.Archive); CVar.Register("gl_forwardcompat", true, CVarType.Archive | CVarType.Init | CVarType.Unsafe); CVar.Register("gl_major", 4, CVarType.Archive | CVarType.Init | CVarType.Unsafe); CVar.Register("gl_minor", 5, CVarType.Archive | CVarType.Init | CVarType.Unsafe); // Parse all arguments and set CVars foreach (var Arg in ArgumentParser.All) { switch (Arg.Key) { case "console": GConsole.Open = true; break; default: { CVar CVar = CVar.Find(Arg.Key); if (CVar != null) { CVar.Value = Arg.Value.LastOrDefault(); } else { CVar.Register(Arg.Key, Arg.Value.LastOrDefault()); } break; } } } CVar.InitMode = false; foreach (var CVar in CVar.GetAll()) { GConsole.WriteLine(CVar); } FileWatcher.Init("content"); Importers.RegisterAll(Reflect.GetExeAssembly()); CreateContext(); InitPhysics(); LoadContent(); Stopwatch SWatch = Stopwatch.StartNew(); float Target = 1.0f / 120; float Dt = Target; TextureTarget Tgt = TextureTarget.Texture2dMultisample; if (CVar.GetInt("gl_samples") == 0) { Tgt = TextureTarget.Texture2d; } Texture ColorTex = new Texture(Width, Height, Tgt, 1, InternalFormat.Rgb16f); Texture DepthTex = new Texture(Width, Height, Tgt, 1, InternalFormat.Depth24Stencil8); Framebuffer FB = new Framebuffer(); FB.AttachColorTexture(ColorTex); FB.AttachDepthTexture(DepthTex); Texture SkyboxCubeMap = new Texture(1024, 1024, TextureTarget.TextureCubeMap, 1, InternalFormat.Srgb8Alpha8); SkyboxCubeMap.SetFilter(Gl.LINEAR, Gl.LINEAR); SkyboxCubeMap.SubImage3D(Image.FromFile("content/textures/skybox/interstellar/front.png"), Z: Texture.FRONT); SkyboxCubeMap.SubImage3D(Image.FromFile("content/textures/skybox/interstellar/back.png"), Z: Texture.BACK); SkyboxCubeMap.SubImage3D(Image.FromFile("content/textures/skybox/interstellar/left.png"), Z: Texture.LEFT); SkyboxCubeMap.SubImage3D(Image.FromFile("content/textures/skybox/interstellar/right.png"), Z: Texture.RIGHT); SkyboxCubeMap.SubImage3D(Image.FromFile("content/textures/skybox/interstellar/top.png"), Z: Texture.TOP); SkyboxCubeMap.SubImage3D(Image.FromFile("content/textures/skybox/interstellar/bottom.png"), Z: Texture.BOTTOM); //FB.Clear(new Vector4(1, 0, 0, 1)); Model SkyboxCube = Importers.Load <Model>("content/models/cube.obj"); SkyboxCube.Scale = new Vector3(2); SkyboxCube.Meshes[0].Material.Shader = ShaderProgram.Skybox; SkyboxCube.Meshes[0].Material.Diffuse = SkyboxCubeMap; //bool DoDebug = true; while (!Glfw.WindowShouldClose(Window)) { /*if (Khronos.KhronosApi.LogEnabled) { * Khronos.KhronosApi.LogCommand("END FRAME", null, null); * Khronos.KhronosApi.LogEnabled = false; * } * * if (DoDebug) { * DoDebug = false; * Khronos.KhronosApi.LogEnabled = true; * Khronos.KhronosApi.LogCommand("BEGIN FRAME", null, null); * }*/ Update(Dt); Gl.Clear(ClearBufferMask.DepthBufferBit | ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit); FB.Bind(); { Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit); SetupState(); Gl.Disable(EnableCap.CullFace); Gl.DepthMask(false); SkyboxCube.Position = Camera.ActiveCamera?.Position ?? Vector3.Zero; SkyboxCube.Draw(); Gl.DepthMask(true); DrawScene(Dt); } FB.Unbind(); // Swap to GUI camera Gl.Disable(EnableCap.DepthTest); Gl.Disable(EnableCap.CullFace); Camera.ActiveCamera = Camera.GUICamera; Immediate.UseShaders(() => { if (ColorTex.Multisampled) { Immediate.TriangleShader = ShaderProgram.PostMultisample; Immediate.TriangleShader.Uniform2f("TexSize", new Vector2(ColorTex.Width, ColorTex.Height)); } else { Immediate.TriangleShader = ShaderProgram.Post; } Immediate.TriangleShader.Uniform1f("Exposure", 1.0f); Gl.Enable(EnableCap.FramebufferSrgb); Immediate.Texture2D(Vector2.Zero, ColorTex, UVInvertY: true); Gl.Disable(EnableCap.FramebufferSrgb); }); DrawGUI(Dt); Glfw.SwapBuffers(Window); // Cap at Target framerate while ((float)SWatch.ElapsedMilliseconds / 1000 < Target) { ; } Dt = (float)SWatch.ElapsedMilliseconds / 1000; FPS = (int)(1.0f / Dt); SWatch.Restart(); } Environment.Exit(0); }