From 9577ddcf9baa71f0bed9f0c8484cea9b4a0c6d06 Mon Sep 17 00:00:00 2001
From: jp9000 <obs.jim@gmail.com>
Date: Sat, 12 Oct 2013 20:18:05 -0700
Subject: [PATCH] fill in the rest of the GL functions.  finally

---
 libobs-d3d11/d3d11-exports.h        |   5 +-
 libobs-d3d11/d3d11-subsystem.cpp    |   4 +-
 libobs-opengl/gl-exports.h          |   5 +-
 libobs-opengl/gl-helpers.h          |  16 ++-
 libobs-opengl/gl-indexbuffer.c      |   1 +
 libobs-opengl/gl-shader.c           |   9 ++
 libobs-opengl/gl-subsystem.c        | 195 ++++++++++++++++++++++++++--
 libobs-opengl/gl-subsystem.h        |  81 ++++++++++++
 libobs-opengl/gl-windows.c          |  31 +++++
 libobs/graphics/graphics-internal.h |   4 +-
 libobs/graphics/graphics.c          |   6 +-
 libobs/graphics/graphics.h          |   2 +-
 12 files changed, 329 insertions(+), 30 deletions(-)

diff --git a/libobs-d3d11/d3d11-exports.h b/libobs-d3d11/d3d11-exports.h
index 8993728a3..865be2646 100644
--- a/libobs-d3d11/d3d11-exports.h
+++ b/libobs-d3d11/d3d11-exports.h
@@ -97,8 +97,8 @@ EXPORT void device_enable_blending(device_t device, bool enable);
 EXPORT void device_enable_depthtest(device_t device, bool enable);
 EXPORT void device_enable_stenciltest(device_t device, bool enable);
 EXPORT void device_enable_stencilwrite(device_t device, bool enable);
-EXPORT void device_enable_color(device_t device, bool red, bool blue,
-		bool green, bool alpha);
+EXPORT void device_enable_color(device_t device, bool red, bool green,
+		bool blue, bool alpha);
 EXPORT void device_blendfunction(device_t device, enum gs_blend_type src,
 		enum gs_blend_type dest);
 EXPORT void device_depthfunction(device_t device, enum gs_depth_test test);
@@ -125,7 +125,6 @@ EXPORT void device_frustum(device_t device, float left, float right,
 		float top, float bottom, float znear, float zfar);
 EXPORT void device_perspective(device_t device, float fovy, float aspect,
 		float znear, float zfar);
-EXPORT void device_set_view_matrix(device_t device, struct matrix3 *mat);
 EXPORT void device_projection_push(device_t device);
 EXPORT void device_projection_pop(device_t device);
 
diff --git a/libobs-d3d11/d3d11-subsystem.cpp b/libobs-d3d11/d3d11-subsystem.cpp
index abe9ca6c6..bce6160b0 100644
--- a/libobs-d3d11/d3d11-subsystem.cpp
+++ b/libobs-d3d11/d3d11-subsystem.cpp
@@ -1130,8 +1130,8 @@ void device_enable_stencilwrite(device_t device, bool enable)
 	device->zstencilStateChanged = true;
 }
 
-void device_enable_color(device_t device, bool red, bool blue,
-		bool green, bool alpha)
+void device_enable_color(device_t device, bool red, bool green,
+		bool blue, bool alpha)
 {
 	if (device->blendState.redEnabled   == red   &&
 	    device->blendState.greenEnabled == green &&
diff --git a/libobs-opengl/gl-exports.h b/libobs-opengl/gl-exports.h
index f27608f73..27242217c 100644
--- a/libobs-opengl/gl-exports.h
+++ b/libobs-opengl/gl-exports.h
@@ -91,8 +91,8 @@ EXPORT void device_enable_blending(device_t device, bool enable);
 EXPORT void device_enable_depthtest(device_t device, bool enable);
 EXPORT void device_enable_stenciltest(device_t device, bool enable);
 EXPORT void device_enable_stencilwrite(device_t device, bool enable);
-EXPORT void device_enable_color(device_t device, bool red, bool blue,
-		bool green, bool alpha);
+EXPORT void device_enable_color(device_t device, bool red, bool green,
+		bool blue, bool alpha);
 EXPORT void device_blendfunction(device_t device, enum gs_blend_type src,
 		enum gs_blend_type dest);
 EXPORT void device_depthfunction(device_t device, enum gs_depth_test test);
@@ -119,7 +119,6 @@ EXPORT void device_frustum(device_t device, float left, float right,
 		float top, float bottom, float znear, float zfar);
 EXPORT void device_perspective(device_t device, float fovy, float aspect,
 		float znear, float zfar);
-EXPORT void device_set_view_matrix(device_t device, struct matrix3 *mat);
 EXPORT void device_projection_push(device_t device);
 EXPORT void device_projection_pop(device_t device);
 
diff --git a/libobs-opengl/gl-helpers.h b/libobs-opengl/gl-helpers.h
index 7517e968e..1d7f84860 100644
--- a/libobs-opengl/gl-helpers.h
+++ b/libobs-opengl/gl-helpers.h
@@ -96,12 +96,24 @@ static inline bool gl_tex_param_i(GLenum target, GLenum param, GLint val)
 	return gl_success("glTexParameteri");
 }
 
-static inline bool gl_active_texture(GLenum texture)
+static inline bool gl_active_texture(GLenum texture_id)
 {
-	glActiveTexture(texture);
+	glActiveTexture(texture_id);
 	return gl_success("glActiveTexture");
 }
 
+static inline bool gl_enable(GLenum capability)
+{
+	glEnable(capability);
+	return gl_success("glEnable");
+}
+
+static inline bool gl_disable(GLenum capability)
+{
+	glDisable(capability);
+	return gl_success("glDisable");
+}
+
 extern bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
 		GLenum format, GLint internal_format, bool compressed,
 		uint32_t width, uint32_t height, uint32_t size, void ***p_data);
diff --git a/libobs-opengl/gl-indexbuffer.c b/libobs-opengl/gl-indexbuffer.c
index 6e2fa1e01..6a3d8cc55 100644
--- a/libobs-opengl/gl-indexbuffer.c
+++ b/libobs-opengl/gl-indexbuffer.c
@@ -45,6 +45,7 @@ indexbuffer_t device_create_indexbuffer(device_t device,
 	ib->data    = indices;
 	ib->dynamic = flags & GS_DYNAMIC;
 	ib->num     = num;
+	ib->width   = width;
 	ib->size    = width * num;
 	ib->type    = type;
 	ib->gl_type = type == GS_UNSIGNED_LONG ? GL_UNSIGNED_INT :
diff --git a/libobs-opengl/gl-shader.c b/libobs-opengl/gl-shader.c
index 199a18c6f..bc098d419 100644
--- a/libobs-opengl/gl-shader.c
+++ b/libobs-opengl/gl-shader.c
@@ -77,6 +77,9 @@ static bool gl_add_param(struct gs_shader *shader, struct shader_var *var,
 	if (!gl_success("glGetUniformLocation"))
 		return false;
 
+	if (param.type == SHADER_PARAM_TEXTURE)
+		glUniform1i(param.param, param.texture_id);
+
 	return true;
 }
 
@@ -155,6 +158,12 @@ static inline bool gl_add_attrib(struct gs_shader *shader,
 	if (attrib.attrib == -1)
 		return false;
 
+	if (attrib.type == ATTRIB_TARGET) {
+		glBindFragDataLocation(shader->program, 0, pa->name.array);
+		if (!gl_success("glBindFragDataLocation"))
+			return false;
+	}
+
 	da_push_back(shader->attribs, &attrib);
 	return true;
 }
diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c
index 5d434ee27..13af947e7 100644
--- a/libobs-opengl/gl-subsystem.c
+++ b/libobs-opengl/gl-subsystem.c
@@ -17,6 +17,18 @@
 
 #include "gl-subsystem.h"
 
+static void clear_textures(struct gs_device *device)
+{
+	GLenum i;
+	for (i = 0; i < GS_MAX_TEXTURES; i++) {
+		if (device->cur_textures[i]) {
+			gl_active_texture(GL_TEXTURE0 + i);
+			gl_bind_texture(device->cur_textures[i]->gl_target, 0);
+			device->cur_textures[i] = NULL;
+		}
+	}
+}
+
 void convert_sampler_info(struct gs_sampler_state *sampler,
 		struct gs_sampler_info *info)
 {
@@ -45,6 +57,10 @@ device_t device_create(struct gs_init_data *info)
 	if (!gl_success("glBindProgramPipeline"))
 		goto fail;
 
+#ifdef _DEBUG
+	gl_enable(GL_DEBUG_OUTPUT);
+#endif
+
 	return device;
 
 fail:
@@ -63,6 +79,7 @@ void device_destroy(device_t device)
 		if (device->pipeline)
 			glDeleteProgramPipelines(1, &device->pipeline);
 
+		da_free(device->proj_stack);
 		da_free(device->fbos);
 		gl_platform_destroy(device->plat);
 		bfree(device);
@@ -191,13 +208,16 @@ void device_load_texture(device_t device, texture_t tex, int unit)
 {
 	struct shader_param *param;
 	struct gs_sampler_state *sampler;
+	struct gs_texture *cur_tex = device->cur_textures[unit];
 
 	/* need a pixel shader to properly bind textures */
 	if (!device->cur_pixel_shader)
 		tex = NULL;
 
-	if (device->cur_textures[unit] == tex)
+	if (cur_tex == tex)
 		return;
+	if (cur_tex && cur_tex->gl_target != tex->gl_target)
+		gl_bind_texture(cur_tex->gl_target, 0);
 
 	device->cur_textures[unit] = tex;
 	param = get_texture_param(device, unit);
@@ -323,6 +343,7 @@ void device_load_pixelshader(device_t device, shader_t pixelshader)
 	if (!gl_success("glUseProgramStages"))
 		goto fail;
 
+	clear_textures(device);
 	return;
 
 fail:
@@ -581,144 +602,290 @@ fail:
 
 void device_beginscene(device_t device)
 {
+	clear_textures(device);
 }
 
-void device_draw(device_t device, enum gs_draw_mode draw_mode,
-		uint32_t start_vert, uint32_t num_verts)
+static inline bool can_render(device_t device)
 {
+	if (!device->cur_vertex_buffer) {
+		blog(LOG_ERROR, "No vertex buffer specified");
+		return false;
+	}
+
+	if (!device->cur_vertex_buffer) {
+		blog(LOG_ERROR, "No vertex buffer specified");
+		return false;
+	}
+
+	if (!device->cur_vertex_buffer) {
+		blog(LOG_ERROR, "No vertex buffer specified");
+		return false;
+	}
+
+	return true;
 }
 
-void device_endscene(device_t device)
+void device_draw(device_t device, enum gs_draw_mode draw_mode,
+		uint32_t start_vert, uint32_t num_verts)
 {
+	struct gs_index_buffer *ib = device->cur_index_buffer;
+	GLenum  topology = convert_gs_topology(draw_mode);
+
+	if (!can_render(device))
+		goto fail;
+
+	if (ib) {
+		glDrawElements(topology, num_verts, ib->gl_type,
+				(const GLvoid*)(start_vert * ib->width));
+		if (!gl_success("glDrawElements"))
+			goto fail;
+
+	} else {
+		glDrawArrays(topology, start_vert, num_verts);
+		if (!gl_success("glDrawArrays"))
+			goto fail;
+	}
+
+	return;
+
+fail:
+	blog(LOG_ERROR, "device_draw (GL) failed");
 }
 
-void device_load_swapchain(device_t device, swapchain_t swapchain)
+void device_endscene(device_t device)
 {
+	/* does nothing */
 }
 
 void device_clear(device_t device, uint32_t clear_flags,
 		struct vec4 *color, float depth, uint8_t stencil)
 {
-}
+	GLbitfield gl_flags = 0;
 
-void device_present(device_t device)
-{
+	if (clear_flags & GS_CLEAR_COLOR) {
+		glClearColor(color->x, color->y, color->x, color->w);
+		gl_flags |= GL_COLOR_BUFFER_BIT;
+	}
+
+	if (clear_flags & GS_CLEAR_DEPTH) {
+		glClearDepth(depth);
+		gl_flags |= GL_DEPTH_BUFFER_BIT;
+	}
+
+	if (clear_flags & GS_CLEAR_STENCIL) {
+		glClearStencil(stencil);
+		gl_flags |= GL_STENCIL_BUFFER_BIT;
+	}
+
+	glClear(clear_flags);
+	if (!gl_success("glClear"))
+		blog(LOG_ERROR, "device_clear (GL) failed");
 }
 
 void device_setcullmode(device_t device, enum gs_cull_mode mode)
 {
+	if (device->cur_cull_mode == mode)
+		return;
+
+	if (device->cur_cull_mode == GS_NEITHER)
+		gl_enable(GL_CULL_FACE);
+
+	device->cur_cull_mode = mode;
+	if (mode == GS_BACK)
+		glCullFace(GL_BACK);
+	else if (mode == GS_FRONT)
+		glCullFace(GL_FRONT);
+	else
+		gl_disable(GL_CULL_FACE);
 }
 
 enum gs_cull_mode device_getcullmode(device_t device)
 {
+	return device->cur_cull_mode;
 }
 
 void device_enable_blending(device_t device, bool enable)
 {
+	if (enable)
+		gl_enable(GL_BLEND);
+	else
+		gl_disable(GL_BLEND);
 }
 
 void device_enable_depthtest(device_t device, bool enable)
 {
+	if (enable)
+		gl_enable(GL_DEPTH_TEST);
+	else
+		gl_disable(GL_DEPTH_TEST);
 }
 
 void device_enable_stenciltest(device_t device, bool enable)
 {
+	if (enable)
+		gl_enable(GL_STENCIL_TEST);
+	else
+		gl_disable(GL_STENCIL_TEST);
 }
 
 void device_enable_stencilwrite(device_t device, bool enable)
 {
+	if (enable)
+		glStencilMask(0xFFFFFFFF);
+	else
+		glStencilMask(0);
 }
 
-void device_enable_color(device_t device, bool red, bool blue,
-		bool green, bool alpha)
+void device_enable_color(device_t device, bool red, bool green,
+		bool blue, bool alpha)
 {
+	glColorMask(red, green, blue, alpha);
 }
 
 void device_blendfunction(device_t device, enum gs_blend_type src,
 		enum gs_blend_type dest)
 {
+	GLenum gl_src = convert_gs_blend_type(src);
+	GLenum gl_dst = convert_gs_blend_type(dest);
+
+	glBlendFunc(gl_src, gl_dst);
+	if (!gl_success("glBlendFunc"))
+		blog(LOG_ERROR, "device_blendfunction (GL) failed");
 }
 
 void device_depthfunction(device_t device, enum gs_depth_test test)
 {
+	GLenum gl_test = convert_gs_depth_test(test);
+
+	glDepthFunc(gl_test);
+	if (!gl_success("glDepthFunc"))
+		blog(LOG_ERROR, "device_depthfunction (GL) failed");
 }
 
 void device_stencilfunction(device_t device, enum gs_stencil_side side,
 		enum gs_depth_test test)
 {
+	GLenum gl_side = convert_gs_stencil_side(side);
+	GLenum gl_test = convert_gs_depth_test(test);
+
+	glStencilFuncSeparate(gl_side, gl_test, 0, 0xFFFFFFFF);
+	if (!gl_success("glStencilFuncSeparate"))
+		blog(LOG_ERROR, "device_stencilfunction (GL) failed");
 }
 
 void device_stencilop(device_t device, enum gs_stencil_side side,
 		enum gs_stencil_op fail, enum gs_stencil_op zfail,
 		enum gs_stencil_op zpass)
 {
+	GLenum gl_side  = convert_gs_stencil_side(side);
+	GLenum gl_fail  = convert_gs_stencil_op(fail);
+	GLenum gl_zfail = convert_gs_stencil_op(zfail);
+	GLenum gl_zpass = convert_gs_stencil_op(zpass);
+
+	glStencilOpSeparate(gl_side, gl_fail, gl_zfail, gl_zpass);
+	if (!gl_success("glStencilOpSeparate"))
+		blog(LOG_ERROR, "device_stencilop (GL) failed");
 }
 
 void device_enable_fullscreen(device_t device, bool enable)
 {
+	/* TODO */
 }
 
 int device_fullscreen_enabled(device_t device)
 {
+	/* TODO */
+	return false;
 }
 
 void device_setdisplaymode(device_t device,
 		const struct gs_display_mode *mode)
 {
+	/* TODO */
 }
 
 void device_getdisplaymode(device_t device,
 		struct gs_display_mode *mode)
 {
+	/* TODO */
 }
 
 void device_setcolorramp(device_t device, float gamma, float brightness,
 		float contrast)
 {
+	/* TODO */
 }
 
 void device_setviewport(device_t device, int x, int y, int width,
 		int height)
 {
+	glViewport(x, y, width, height);
+	if (!gl_success("glViewport"))
+		blog(LOG_ERROR, "device_setviewport (GL) failed");
+
+	device->cur_viewport.x  = x;
+	device->cur_viewport.y  = y;
+	device->cur_viewport.cx = width;
+	device->cur_viewport.cy = height;
 }
 
 void device_getviewport(device_t device, struct gs_rect *rect)
 {
+	*rect = device->cur_viewport;
 }
 
 void device_setscissorrect(device_t device, struct gs_rect *rect)
 {
+	glScissor(rect->x, rect->y, rect->cx, rect->cy);
+	if (!gl_success("glScissor"))
+		blog(LOG_ERROR, "device_setscissorrect (GL) failed");
 }
 
 void device_ortho(device_t device, float left, float right,
 		float top, float bottom, float znear, float zfar)
 {
+	matrix4_ortho(&device->cur_proj, left, right, top, bottom, znear, zfar);
 }
 
 void device_frustum(device_t device, float left, float right,
 		float top, float bottom, float znear, float zfar)
 {
+	matrix4_frustum(&device->cur_proj, left, right, top, bottom,
+			znear, zfar);
 }
 
 void device_perspective(device_t device, float fovy, float aspect,
 		float znear, float zfar)
 {
-}
-
-void device_set_view_matrix(device_t device, struct matrix3 *mat)
-{
+	matrix4_perspective(&device->cur_proj, fovy, aspect, znear, zfar);
 }
 
 void device_projection_push(device_t device)
 {
+	da_push_back(device->proj_stack, &device->cur_proj);
 }
 
 void device_projection_pop(device_t device)
 {
+	struct matrix4 *end;
+	if (!device->proj_stack.num)
+		return;
+
+	end = da_end(device->proj_stack);
+	device->cur_proj = *end;
+	da_pop_back(device->proj_stack);
 }
 
 void swapchain_destroy(swapchain_t swapchain)
 {
+	if (!swapchain)
+		return;
+
+	if (swapchain->device->cur_swap == swapchain)
+		device_load_swapchain(swapchain->device, NULL);
+
+	gl_windowinfo_destroy(swapchain->wi);
+	bfree(swapchain);
 }
 
 void volumetexture_destroy(texture_t voltex)
diff --git a/libobs-opengl/gl-subsystem.h b/libobs-opengl/gl-subsystem.h
index 5c53db296..50c3ae583 100644
--- a/libobs-opengl/gl-subsystem.h
+++ b/libobs-opengl/gl-subsystem.h
@@ -20,6 +20,7 @@
 
 #include "util/darray.h"
 #include "graphics/graphics.h"
+#include "graphics/matrix4.h"
 #include "glew/include/GL/glew.h"
 #include "gl-helpers.h"
 #include "gl-exports.h"
@@ -116,6 +117,62 @@ static inline GLenum convert_zstencil_format(enum gs_zstencil_format format)
 	}
 }
 
+static inline GLenum convert_gs_depth_test(enum gs_depth_test test)
+{
+	switch (test) {
+	default:
+	case GS_NEVER:    return GL_NEVER;
+	case GS_LESS:     return GL_LESS;
+	case GS_LEQUAL:   return GL_LEQUAL;
+	case GS_EQUAL:    return GL_EQUAL;
+	case GS_GEQUAL:   return GL_GEQUAL;
+	case GS_GREATER:  return GL_GREATER;
+	case GS_NOTEQUAL: return GL_NOTEQUAL;
+	case GS_ALWAYS:   return GL_ALWAYS;
+	}
+}
+
+static inline GLenum convert_gs_stencil_op(enum gs_stencil_op op)
+{
+	switch (op) {
+	default:
+	case GS_KEEP:    return GL_KEEP;
+	case GS_ZERO:    return GL_ZERO;
+	case GS_REPLACE: return GL_REPLACE;
+	case GS_INCR:    return GL_INCR;
+	case GS_DECR:    return GL_DECR;
+	case GS_INVERT:  return GL_INVERT;
+	}
+}
+
+static inline GLenum convert_gs_stencil_side(enum gs_stencil_side side)
+{
+	switch (side) {
+	default:
+	case GS_STENCIL_FRONT: return GL_FRONT;
+	case GS_STENCIL_BACK:  return GL_BACK;
+	case GS_STENCIL_BOTH:  return GL_FRONT_AND_BACK;
+	}
+}
+
+static inline GLenum convert_gs_blend_type(enum gs_blend_type type)
+{
+	switch (type) {
+	default:
+	case GS_BLEND_ZERO:        return GL_ZERO;
+	case GS_BLEND_ONE:         return GL_ONE;
+	case GS_BLEND_SRCCOLOR:    return GL_SRC_COLOR;
+	case GS_BLEND_INVSRCCOLOR: return GL_ONE_MINUS_SRC_COLOR;
+	case GS_BLEND_SRCALPHA:    return GL_SRC_ALPHA;
+	case GS_BLEND_INVSRCALPHA: return GL_ONE_MINUS_SRC_ALPHA;
+	case GS_BLEND_DSTCOLOR:    return GL_DST_COLOR;
+	case GS_BLEND_INVDSTCOLOR: return GL_ONE_MINUS_DST_COLOR;
+	case GS_BLEND_DSTALPHA:    return GL_DST_ALPHA;
+	case GS_BLEND_INVDSTALPHA: return GL_ONE_MINUS_DST_ALPHA;
+	case GS_BLEND_SRCALPHASAT: return GL_SRC_ALPHA_SATURATE;
+	}
+}
+
 static inline GLenum convert_shader_type(enum shader_type type)
 {
 	switch (type) {
@@ -181,6 +238,18 @@ static inline GLint convert_address_mode(enum gs_address_mode mode)
 	}
 }
 
+static inline GLenum convert_gs_topology(enum gs_draw_mode mode)
+{
+	switch (mode) {
+	default:
+	case GS_POINTS:    return GL_POINTS;
+	case GS_LINES:     return GL_LINES;
+	case GS_LINESTRIP: return GL_LINE_STRIP;
+	case GS_TRIS:      return GL_TRIANGLES;
+	case GS_TRISTRIP:  return GL_TRIANGLE_STRIP;
+	}
+}
+
 extern void convert_sampler_info(struct gs_sampler_state *sampler,
 		struct gs_sampler_info *info);
 
@@ -274,6 +343,7 @@ struct gs_index_buffer {
 	device_t             device;
 	void                 *data;
 	size_t               num;
+	size_t               width;
 	size_t               size;
 	bool                 dynamic;
 };
@@ -369,6 +439,15 @@ struct gs_device {
 	shader_t             cur_pixel_shader;
 	swapchain_t          cur_swap;
 
+	enum gs_cull_mode    cur_cull_mode;
+	struct gs_rect       cur_viewport;
+
+	struct matrix4       cur_proj;
+	struct matrix4       cur_view;
+	struct matrix4       cur_viewproj;
+
+	DARRAY(struct matrix4)   proj_stack;
+
 	DARRAY(struct fbo_info*) fbos;
 	struct fbo_info          *cur_fbo;
 };
@@ -381,4 +460,6 @@ extern void                  gl_platform_destroy(struct gl_platform *platform);
 extern struct gl_windowinfo *gl_windowinfo_create(struct gs_init_data *info);
 extern void                  gl_windowinfo_destroy(struct gl_windowinfo *wi);
 
+
+
 #endif
diff --git a/libobs-opengl/gl-windows.c b/libobs-opengl/gl-windows.c
index 508fcaeb2..990523c3d 100644
--- a/libobs-opengl/gl-windows.c
+++ b/libobs-opengl/gl-windows.c
@@ -427,3 +427,34 @@ void gl_windowinfo_destroy(struct gl_windowinfo *wi)
 		bfree(wi);
 	}
 }
+
+void device_load_swapchain(device_t device, swapchain_t swap)
+{
+	HDC hdc = device->plat->swap.wi->hdc;
+	if (device->cur_swap == swap)
+		return;
+
+	device->cur_swap = swap;
+
+	if (swap)
+		hdc = swap->wi->hdc;
+
+	if (!wglMakeCurrent(hdc, device->plat->hrc)) {
+		blog(LOG_ERROR, "wglMakeCurrent failed, GetLastError "
+				"returned %u", GetLastError());
+		blog(LOG_ERROR, "device_load_swapchain (GL) failed");
+	}
+}
+
+void device_present(device_t device)
+{
+	HDC hdc = device->plat->swap.wi->hdc;
+	if (device->cur_swap)
+		hdc = device->cur_swap->wi->hdc;
+
+	if (!SwapBuffers(hdc)) {
+		blog(LOG_ERROR, "SwapBuffers failed, GetLastError "
+				"returned %u", GetLastError());
+		blog(LOG_ERROR, "device_present (GL) failed");
+	}
+}
diff --git a/libobs/graphics/graphics-internal.h b/libobs/graphics/graphics-internal.h
index 9a0fa7949..d3b1dccf1 100644
--- a/libobs/graphics/graphics-internal.h
+++ b/libobs/graphics/graphics-internal.h
@@ -100,8 +100,8 @@ struct gs_exports {
 	void (*device_enable_depthtest)(device_t device, bool enable);
 	void (*device_enable_stenciltest)(device_t device, bool enable);
 	void (*device_enable_stencilwrite)(device_t device, bool enable);
-	void (*device_enable_color)(device_t device, bool red, bool blue,
-			bool green, bool alpha);
+	void (*device_enable_color)(device_t device, bool red, bool green,
+			bool blue, bool alpha);
 	void (*device_blendfunction)(device_t device, enum gs_blend_type src,
 			enum gs_blend_type dest);
 	void (*device_depthfunction)(device_t device, enum gs_depth_test test);
diff --git a/libobs/graphics/graphics.c b/libobs/graphics/graphics.c
index f32eb50d3..f14853ad0 100644
--- a/libobs/graphics/graphics.c
+++ b/libobs/graphics/graphics.c
@@ -1035,11 +1035,11 @@ void gs_enable_stencilwrite(bool enable)
 	graphics->exports.device_enable_stencilwrite(graphics->device, enable);
 }
 
-void gs_enable_color(bool red, bool blue, bool green, bool alpha)
+void gs_enable_color(bool red, bool green, bool blue, bool alpha)
 {
 	graphics_t graphics = thread_graphics;
-	graphics->exports.device_enable_color(graphics->device, red, blue,
-			green, alpha);
+	graphics->exports.device_enable_color(graphics->device, red, green,
+			blue, alpha);
 }
 
 void gs_blendfunction(enum gs_blend_type src, enum gs_blend_type dest)
diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h
index a1e004149..2b6690f28 100644
--- a/libobs/graphics/graphics.h
+++ b/libobs/graphics/graphics.h
@@ -586,7 +586,7 @@ EXPORT void gs_enable_blending(bool enable);
 EXPORT void gs_enable_depthtest(bool enable);
 EXPORT void gs_enable_stenciltest(bool enable);
 EXPORT void gs_enable_stencilwrite(bool enable);
-EXPORT void gs_enable_color(bool red, bool blue, bool green, bool alpha);
+EXPORT void gs_enable_color(bool red, bool green, bool blue, bool alpha);
 
 EXPORT void gs_blendfunction(enum gs_blend_type src, enum gs_blend_type dest);
 EXPORT void gs_depthfunction(enum gs_depth_test test);
-- 
GitLab