protected uint CompileShaderObject(int type, string name) { var ext = type == OpenGL.GL_VERTEX_SHADER ? "vert" : "frag"; var filename = Path.Combine(Platform.EngineDir, "glsl", name + "." + ext); var code = File.ReadAllText(filename); var version = OpenGL.Profile == GLProfile.Embedded ? "300 es" : OpenGL.Profile == GLProfile.Legacy ? "120" : "140"; code = code.Replace("{VERSION}", version); var shader = OpenGL.glCreateShader(type); OpenGL.CheckGLError(); unsafe { var length = code.Length; OpenGL.glShaderSource(shader, 1, new string[] { code }, new IntPtr(&length)); } OpenGL.CheckGLError(); OpenGL.glCompileShader(shader); OpenGL.CheckGLError(); OpenGL.glGetShaderiv(shader, OpenGL.GL_COMPILE_STATUS, out var success); OpenGL.CheckGLError(); if (success == OpenGL.GL_FALSE) { OpenGL.glGetShaderiv(shader, OpenGL.GL_INFO_LOG_LENGTH, out var len); var log = new StringBuilder(len); OpenGL.glGetShaderInfoLog(shader, len, out _, log); Log.Write("graphics", "GL Info Log:\n{0}", log.ToString()); throw new InvalidProgramException("Compile error in shader object '{0}'".F(filename)); } return(shader); }
public void PrepareRender() { VerifyThreadAffinity(); OpenGL.glUseProgram(program); OpenGL.CheckGLError(); // bind the textures foreach (var kv in textures) { var texture = (ITextureInternal)kv.Value; // Evict disposed textures from the cache if (OpenGL.glIsTexture(texture.ID)) { OpenGL.glActiveTexture(OpenGL.GL_TEXTURE0 + kv.Key); OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, texture.ID); // Work around missing textureSize GLSL function by explicitly tracking sizes in a uniform if (OpenGL.Profile == GLProfile.Legacy && legacySizeUniforms.TryGetValue(kv.Key, out var param)) { OpenGL.glUniform2f(param, texture.Size.Width, texture.Size.Height); OpenGL.CheckGLError(); } } else { unbindTextures.Enqueue(kv.Key); } } while (unbindTextures.Count > 0) { textures.Remove(unbindTextures.Dequeue()); } OpenGL.CheckGLError(); }
public void DisableDepthBuffer() { VerifyThreadAffinity(); OpenGL.glDisable(OpenGL.GL_DEPTH_TEST); OpenGL.CheckGLError(); }
public void DrawPrimitives(PrimitiveType pt, int firstVertex, int numVertices) { VerifyThreadAffinity(); OpenGL.glDrawArrays(ModeFromPrimitiveType(pt), firstVertex, numVertices); OpenGL.CheckGLError(); }
public void DisableScissor() { VerifyThreadAffinity(); OpenGL.glDisable(OpenGL.GL_SCISSOR_TEST); OpenGL.CheckGLError(); }
public Texture() { OpenGL.glGenTextures(1, out texture); OpenGL.CheckGLError(); }
public void ActivateVertextBuffer() { OpenGL.glBindBuffer(OpenGL.GL_ARRAY_BUFFER, buffer); OpenGL.CheckGLError(); }
public Shader(string name) { var vertexShader = CompileShaderObject(OpenGL.GL_VERTEX_SHADER, name); var fragmentShader = CompileShaderObject(OpenGL.GL_FRAGMENT_SHADER, name); // Assemble program program = OpenGL.glCreateProgram(); OpenGL.CheckGLError(); OpenGL.glBindAttribLocation(program, VertexPosAttributeIndex, "aVertexPosition"); OpenGL.CheckGLError(); OpenGL.glBindAttribLocation(program, TexCoordAttributeIndex, "aVertexTexCoord"); OpenGL.CheckGLError(); OpenGL.glBindAttribLocation(program, TexMetadataAttributeIndex, "aVertexTexMetadata"); OpenGL.CheckGLError(); if (OpenGL.Profile != GLProfile.Legacy) { OpenGL.glBindFragDataLocation(program, 0, "fragColor"); OpenGL.CheckGLError(); } OpenGL.glAttachShader(program, vertexShader); OpenGL.CheckGLError(); OpenGL.glAttachShader(program, fragmentShader); OpenGL.CheckGLError(); OpenGL.glLinkProgram(program); OpenGL.CheckGLError(); int success; OpenGL.glGetProgramiv(program, OpenGL.GL_LINK_STATUS, out success); OpenGL.CheckGLError(); if (success == OpenGL.GL_FALSE) { int len; OpenGL.glGetProgramiv(program, OpenGL.GL_INFO_LOG_LENGTH, out len); var log = new StringBuilder(len); int length; OpenGL.glGetProgramInfoLog(program, len, out length, log); Log.Write("graphics", "GL Info Log:\n{0}", log.ToString()); throw new InvalidProgramException("Link error in shader program '{0}'".F(name)); } OpenGL.glUseProgram(program); OpenGL.CheckGLError(); int numUniforms; OpenGL.glGetProgramiv(program, OpenGL.GL_ACTIVE_UNIFORMS, out numUniforms); OpenGL.CheckGLError(); var nextTexUnit = 0; for (var i = 0; i < numUniforms; i++) { int length, size; int type; var sb = new StringBuilder(128); OpenGL.glGetActiveUniform(program, i, 128, out length, out size, out type, sb); var sampler = sb.ToString(); OpenGL.CheckGLError(); if (type == OpenGL.GL_SAMPLER_2D) { samplers.Add(sampler, nextTexUnit); var loc = OpenGL.glGetUniformLocation(program, sampler); OpenGL.CheckGLError(); OpenGL.glUniform1i(loc, nextTexUnit); OpenGL.CheckGLError(); if (OpenGL.Profile == GLProfile.Legacy) { var sizeLoc = OpenGL.glGetUniformLocation(program, sampler + "Size"); if (sizeLoc >= 0) { legacySizeUniforms.Add(nextTexUnit, sizeLoc); } } nextTexUnit++; } } }
public Texture(Bitmap bitmap) { OpenGL.glGenTextures(1, out texture); OpenGL.CheckGLError(); SetData(bitmap); }
public Sdl2GraphicsDevice(Size windowSize, WindowMode windowMode) { Console.WriteLine("Using SDL 2 with OpenGL renderer"); WindowSize = windowSize; // Disable legacy scaling on Windows if (Platform.CurrentPlatform == PlatformType.Windows && !Game.Settings.Graphics.DisableWindowsDPIScaling) { SetProcessDPIAware(); } SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0); SDL.SDL_DisplayMode display; SDL.SDL_GetCurrentDisplayMode(0, out display); Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h); if (WindowSize.Width == 0 && WindowSize.Height == 0) { Console.WriteLine("No custom resolution provided, using desktop resolution"); WindowSize = new Size(display.w, display.h); } Console.WriteLine("Using resolution: {0}x{1}", WindowSize.Width, WindowSize.Height); var windowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI; window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED, WindowSize.Width, WindowSize.Height, windowFlags); SurfaceSize = WindowSize; WindowScale = 1; // Enable high resolution rendering for Retina displays if (Platform.CurrentPlatform == PlatformType.OSX) { // OSX defines the window size in "points", with a device-dependent number of pixels per point. // The window scale is simply the ratio of GL pixels / window points. int width, height; SDL.SDL_GL_GetDrawableSize(window, out width, out height); SurfaceSize = new Size(width, height); WindowScale = width * 1f / WindowSize.Width; } else if (Platform.CurrentPlatform == PlatformType.Windows) { float ddpi, hdpi, vdpi; if (!Game.Settings.Graphics.DisableWindowsDPIScaling && SDL.SDL_GetDisplayDPI(0, out ddpi, out hdpi, out vdpi) == 0) { WindowScale = ddpi / 96; WindowSize = new Size((int)(SurfaceSize.Width / WindowScale), (int)(SurfaceSize.Height / WindowScale)); } } else { float scale = 1; var scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE"); if (scaleVariable != null && float.TryParse(scaleVariable, out scale)) { WindowScale = scale; WindowSize = new Size((int)(SurfaceSize.Width / WindowScale), (int)(SurfaceSize.Height / WindowScale)); } } Console.WriteLine("Using window scale {0:F2}", WindowScale); if (Game.Settings.Game.LockMouseWindow) { GrabWindowMouseFocus(); } else { ReleaseWindowMouseFocus(); } if (windowMode == WindowMode.Fullscreen) { SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN); } else if (windowMode == WindowMode.PseudoFullscreen) { // Work around a visual glitch in OSX: the window is offset // partially offscreen if the dock is at the left of the screen if (Platform.CurrentPlatform == PlatformType.OSX) { SDL.SDL_SetWindowPosition(window, 0, 0); } SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP); SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); } context = SDL.SDL_GL_CreateContext(window); if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window, context) < 0) { throw new InvalidOperationException("Can not create OpenGL context. (Error: {0})".F(SDL.SDL_GetError())); } OpenGL.Initialize(); OpenGL.glEnableVertexAttribArray(Shader.VertexPosAttributeIndex); OpenGL.CheckGLError(); OpenGL.glEnableVertexAttribArray(Shader.TexCoordAttributeIndex); OpenGL.CheckGLError(); OpenGL.glEnableVertexAttribArray(Shader.TexMetadataAttributeIndex); OpenGL.CheckGLError(); SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE); input = new Sdl2Input(); }
public void PumpInput(IInputHandler inputHandler) { var mods = MakeModifiers((int)SDL.SDL_GetModState()); var scrollDelta = 0; inputHandler.ModifierKeys(mods); MouseInput?pendingMotion = null; SDL.SDL_Event e; while (SDL.SDL_PollEvent(out e) != 0) { switch (e.type) { case SDL.SDL_EventType.SDL_QUIT: Game.Exit(); break; case SDL.SDL_EventType.SDL_WINDOWEVENT: { switch (e.window.windowEvent) { case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST: Game.HasInputFocus = false; break; case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED: Game.HasInputFocus = true; break; } break; } case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN: { if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } var button = MakeButton(e.button.button); lastButtonBits |= button; var pos = new int2(e.button.x, e.button.y); inputHandler.OnMouseInput(new MouseInput( MouseInputEvent.Down, button, scrollDelta, pos, mods, MultiTapDetection.DetectFromMouse(e.button.button, pos))); break; } case SDL.SDL_EventType.SDL_MOUSEBUTTONUP: { if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } var button = MakeButton(e.button.button); lastButtonBits &= ~button; var pos = new int2(e.button.x, e.button.y); inputHandler.OnMouseInput(new MouseInput( MouseInputEvent.Up, button, scrollDelta, pos, mods, MultiTapDetection.InfoFromMouse(e.button.button))); break; } case SDL.SDL_EventType.SDL_MOUSEMOTION: { pendingMotion = new MouseInput( MouseInputEvent.Move, lastButtonBits, scrollDelta, new int2(e.motion.x, e.motion.y), mods, 0); break; } case SDL.SDL_EventType.SDL_MOUSEWHEEL: { int x, y; SDL.SDL_GetMouseState(out x, out y); scrollDelta = e.wheel.y; inputHandler.OnMouseInput(new MouseInput(MouseInputEvent.Scroll, MouseButton.None, scrollDelta, new int2(x, y), mods, 0)); break; } case SDL.SDL_EventType.SDL_TEXTINPUT: { var rawBytes = new byte[SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE]; unsafe { Marshal.Copy((IntPtr)e.text.text, rawBytes, 0, SDL.SDL_TEXTINPUTEVENT_TEXT_SIZE); } inputHandler.OnTextInput(Encoding.UTF8.GetString(rawBytes, 0, Array.IndexOf(rawBytes, (byte)0))); break; } case SDL.SDL_EventType.SDL_KEYDOWN: case SDL.SDL_EventType.SDL_KEYUP: { var keyCode = (Keycode)e.key.keysym.sym; var type = e.type == SDL.SDL_EventType.SDL_KEYDOWN ? KeyInputEvent.Down : KeyInputEvent.Up; var tapCount = e.type == SDL.SDL_EventType.SDL_KEYDOWN ? MultiTapDetection.DetectFromKeyboard(keyCode) : MultiTapDetection.InfoFromKeyboard(keyCode); var keyEvent = new KeyInput { Event = type, Key = keyCode, Modifiers = mods, UnicodeChar = (char)e.key.keysym.sym, MultiTapCount = tapCount }; // Special case workaround for windows users if (e.key.keysym.sym == SDL.SDL_Keycode.SDLK_F4 && mods.HasModifier(Modifiers.Alt) && Platform.CurrentPlatform == PlatformType.Windows) { Game.Exit(); } else { inputHandler.OnKeyInput(keyEvent); } break; } } } if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } OpenGL.CheckGLError(); }
public Texture() { OpenGL.glGenTextures(1, out texture); OpenGL.CheckGLError(); SetThreadAffinity(); }
public static void ReserveVAOList() { VAOList = new int[30]; OpenGL.glGenVertexArrays(30, VAOList); OpenGL.CheckGLError(); }
public void ClearDepthBuffer() { VerifyThreadAffinity(); OpenGL.glClear(OpenGL.GL_DEPTH_BUFFER_BIT); OpenGL.CheckGLError(); }
public Sdl2GraphicsDevice(Size windowSize, WindowMode windowMode) { Console.WriteLine("Using SDL 2 with OpenGL renderer"); WindowSize = windowSize; SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0); SDL.SDL_DisplayMode display; SDL.SDL_GetCurrentDisplayMode(0, out display); Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h); if (WindowSize.Width == 0 && WindowSize.Height == 0) { Console.WriteLine("No custom resolution provided, using desktop resolution"); WindowSize = new Size(display.w, display.h); } Console.WriteLine("Using resolution: {0}x{1}", WindowSize.Width, WindowSize.Height); window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED, WindowSize.Width, WindowSize.Height, SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL); if (Game.Settings.Game.LockMouseWindow) { GrabWindowMouseFocus(); } else { ReleaseWindowMouseFocus(); } if (windowMode == WindowMode.Fullscreen) { SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN); } else if (windowMode == WindowMode.PseudoFullscreen) { // Work around a visual glitch in OSX: the window is offset // partially offscreen if the dock is at the left of the screen if (Platform.CurrentPlatform == PlatformType.OSX) { SDL.SDL_SetWindowPosition(window, 0, 0); } SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP); SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); } context = SDL.SDL_GL_CreateContext(window); if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window, context) < 0) { throw new InvalidOperationException("Can not create OpenGL context. (Error: {0})".F(SDL.SDL_GetError())); } OpenGL.Initialize(); OpenGL.glEnableVertexAttribArray(Shader.VertexPosAttributeIndex); OpenGL.CheckGLError(); OpenGL.glEnableVertexAttribArray(Shader.TexCoordAttributeIndex); OpenGL.CheckGLError(); OpenGL.glEnableVertexAttribArray(Shader.TexMetadataAttributeIndex); OpenGL.CheckGLError(); SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE); input = new Sdl2Input(); }
public void SetBlendMode(BlendMode mode) { VerifyThreadAffinity(); OpenGL.glBlendEquation(OpenGL.GL_FUNC_ADD); OpenGL.CheckGLError(); switch (mode) { case BlendMode.None: OpenGL.glDisable(OpenGL.GL_BLEND); break; case BlendMode.Alpha: OpenGL.glEnable(OpenGL.GL_BLEND); OpenGL.CheckGLError(); OpenGL.glBlendFunc(OpenGL.GL_ONE, OpenGL.GL_ONE_MINUS_SRC_ALPHA); break; case BlendMode.Additive: case BlendMode.Subtractive: OpenGL.glEnable(OpenGL.GL_BLEND); OpenGL.CheckGLError(); OpenGL.glBlendFunc(OpenGL.GL_ONE, OpenGL.GL_ONE); if (mode == BlendMode.Subtractive) { OpenGL.CheckGLError(); OpenGL.glBlendEquationSeparate(OpenGL.GL_FUNC_REVERSE_SUBTRACT, OpenGL.GL_FUNC_ADD); } break; case BlendMode.Multiply: OpenGL.glEnable(OpenGL.GL_BLEND); OpenGL.CheckGLError(); OpenGL.glBlendFunc(OpenGL.GL_DST_COLOR, OpenGL.GL_ONE_MINUS_SRC_ALPHA); OpenGL.CheckGLError(); break; case BlendMode.Multiplicative: OpenGL.glEnable(OpenGL.GL_BLEND); OpenGL.CheckGLError(); OpenGL.glBlendFunc(OpenGL.GL_ZERO, OpenGL.GL_SRC_COLOR); break; case BlendMode.DoubleMultiplicative: OpenGL.glEnable(OpenGL.GL_BLEND); OpenGL.CheckGLError(); OpenGL.glBlendFunc(OpenGL.GL_DST_COLOR, OpenGL.GL_SRC_COLOR); break; case BlendMode.LowAdditive: OpenGL.glEnable(OpenGL.GL_BLEND); OpenGL.CheckGLError(); OpenGL.glBlendFunc(OpenGL.GL_DST_COLOR, OpenGL.GL_ONE); break; case BlendMode.Screen: OpenGL.glEnable(OpenGL.GL_BLEND); OpenGL.CheckGLError(); OpenGL.glBlendFunc(OpenGL.GL_SRC_COLOR, OpenGL.GL_ONE_MINUS_SRC_COLOR); break; case BlendMode.Translucent: OpenGL.glEnable(OpenGL.GL_BLEND); OpenGL.CheckGLError(); OpenGL.glBlendFunc(OpenGL.GL_DST_COLOR, OpenGL.GL_ONE_MINUS_DST_COLOR); break; } OpenGL.CheckGLError(); }
public byte[] GetData() { VerifyThreadAffinity(); var data = new byte[4 * Size.Width * Size.Height]; // GLES doesn't support glGetTexImage so data must be read back via a frame buffer if (OpenGL.Profile == GLProfile.Embedded) { // Query the active framebuffer so we can restore it afterwards int lastFramebuffer; OpenGL.glGetIntegerv(OpenGL.GL_FRAMEBUFFER_BINDING, out lastFramebuffer); uint framebuffer; OpenGL.glGenFramebuffers(1, out framebuffer); OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, framebuffer); OpenGL.CheckGLError(); OpenGL.glFramebufferTexture2D(OpenGL.GL_FRAMEBUFFER, OpenGL.GL_COLOR_ATTACHMENT0, OpenGL.GL_TEXTURE_2D, texture, 0); OpenGL.CheckGLError(); var canReadBGRA = OpenGL.Features.HasFlag(OpenGL.GLFeatures.ESReadFormatBGRA); unsafe { fixed(byte *ptr = &data[0]) { var intPtr = new IntPtr(ptr); var format = canReadBGRA ? OpenGL.GL_BGRA : OpenGL.GL_RGBA; OpenGL.glReadPixels(0, 0, Size.Width, Size.Height, format, OpenGL.GL_UNSIGNED_BYTE, intPtr); OpenGL.CheckGLError(); } } // Convert RGBA to BGRA if (!canReadBGRA) { for (var i = 0; i < 4 * Size.Width * Size.Height; i += 4) { var temp = data[i]; data[i] = data[i + 2]; data[i + 2] = temp; } } OpenGL.glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, (uint)lastFramebuffer); OpenGL.glDeleteFramebuffers(1, ref framebuffer); OpenGL.CheckGLError(); } else { OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, texture); unsafe { fixed(byte *ptr = &data[0]) { var intPtr = new IntPtr((void *)ptr); OpenGL.glGetTexImage(OpenGL.GL_TEXTURE_2D, 0, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE, intPtr); } } OpenGL.CheckGLError(); } return(data); }