public Texture() { OpenGL.glGenTextures(1, out texture); OpenGL.CheckGLError(); }
public Texture(Bitmap bitmap) { OpenGL.glGenTextures(1, out texture); OpenGL.CheckGLError(); SetData(bitmap); }
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(); 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(); nextTexUnit++; } } }
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 OpenGL.glGetIntegerv(OpenGL.GL_FRAMEBUFFER_BINDING, out var lastFramebuffer); OpenGL.glGenFramebuffers(1, out var 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); }
public void ClearDepthBuffer() { VerifyThreadAffinity(); OpenGL.glClear(OpenGL.GL_DEPTH_BUFFER_BIT); OpenGL.CheckGLError(); }
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 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 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), Modifiers.None, 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 { // Only register initial key press if (e.key.repeat == 0) { inputHandler.OnKeyInput(keyEvent); } } break; } } } if (pendingMotion != null) { inputHandler.OnMouseInput(pendingMotion.Value); pendingMotion = null; } OpenGL.CheckGLError(); }
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; // HiDPI doesn't work properly on OSX with (legacy) fullscreen mode if (Platform.CurrentPlatform == PlatformType.OSX && windowMode == WindowMode.Fullscreen) { SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1"); } 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); // Fullscreen mode on OSX will ignore the configured display resolution // and instead always picks an arbitrary scaled resolution choice that may // not match the window size, leading to graphical and input issues. // We work around this by force disabling HiDPI and resetting the window and // surface sizes to match the size that is forced by SDL. // This is usually not what the player wants, but is the best we can consistently do. if (Platform.CurrentPlatform == PlatformType.OSX) { int width, height; SDL.SDL_GetWindowSize(window, out width, out height); WindowSize = SurfaceSize = new Size(width, height); WindowScale = 1; } } 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(); }