mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 00:22:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			271 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			271 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #define GL_GLEXT_PROTOTYPES
 | |
| 
 | |
| #include <LibAccelGfx/GL.h>
 | |
| #include <LibGfx/Bitmap.h>
 | |
| #include <LibGfx/Rect.h>
 | |
| 
 | |
| namespace AccelGfx::GL {
 | |
| 
 | |
| static void verify_no_error()
 | |
| {
 | |
|     VERIFY(glGetError() == GL_NO_ERROR);
 | |
| }
 | |
| 
 | |
| void set_viewport(Gfx::IntRect rect)
 | |
| {
 | |
|     glViewport(rect.left(), rect.top(), rect.width(), rect.height());
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void enable_blending()
 | |
| {
 | |
|     glEnable(GL_BLEND);
 | |
|     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void read_pixels(Gfx::IntRect rect, Gfx::Bitmap& bitmap)
 | |
| {
 | |
|     VERIFY(bitmap.format() == Gfx::BitmapFormat::BGRA8888);
 | |
|     glPixelStorei(GL_PACK_ALIGNMENT, 1);
 | |
|     glReadPixels(rect.left(), rect.top(), rect.width(), rect.height(), GL_BGRA, GL_UNSIGNED_BYTE, bitmap.scanline(0));
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| Shader create_shader(ShaderType type, char const* source)
 | |
| {
 | |
|     GLuint shader = glCreateShader(type == ShaderType::Vertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
 | |
|     glShaderSource(shader, 1, &source, nullptr);
 | |
|     glCompileShader(shader);
 | |
| 
 | |
|     int success;
 | |
|     glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
 | |
|     if (!success) {
 | |
|         char buffer[512];
 | |
|         glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
 | |
|         dbgln("GLSL shader compilation failed: {}", buffer);
 | |
|         VERIFY_NOT_REACHED();
 | |
|     }
 | |
| 
 | |
|     verify_no_error();
 | |
| 
 | |
|     return { shader };
 | |
| }
 | |
| 
 | |
| Program create_program(Shader const& vertex_shader, Shader const& fragment_shader)
 | |
| {
 | |
|     GLuint program = glCreateProgram();
 | |
| 
 | |
|     glAttachShader(program, vertex_shader.id);
 | |
|     glAttachShader(program, fragment_shader.id);
 | |
|     glLinkProgram(program);
 | |
| 
 | |
|     int linked;
 | |
|     glGetProgramiv(program, GL_LINK_STATUS, &linked);
 | |
|     if (!linked) {
 | |
|         char buffer[512];
 | |
|         glGetProgramInfoLog(program, sizeof(buffer), nullptr, buffer);
 | |
|         dbgln("GLSL program linking failed: {}", buffer);
 | |
|         VERIFY_NOT_REACHED();
 | |
|     }
 | |
| 
 | |
|     glDeleteShader(vertex_shader.id);
 | |
|     glDeleteShader(fragment_shader.id);
 | |
| 
 | |
|     verify_no_error();
 | |
| 
 | |
|     return { program };
 | |
| }
 | |
| 
 | |
| void use_program(Program const& program)
 | |
| {
 | |
|     glUseProgram(program.id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| VertexAttribute get_attribute_location(Program const& program, char const* name)
 | |
| {
 | |
|     auto id = glGetAttribLocation(program.id, name);
 | |
|     verify_no_error();
 | |
|     return { id };
 | |
| }
 | |
| 
 | |
| Uniform get_uniform_location(Program const& program, char const* name)
 | |
| {
 | |
|     auto id = glGetUniformLocation(program.id, name);
 | |
|     verify_no_error();
 | |
|     return { id };
 | |
| }
 | |
| 
 | |
| void delete_program(Program const& program)
 | |
| {
 | |
|     glDeleteProgram(program.id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| Texture create_texture()
 | |
| {
 | |
|     GLuint texture;
 | |
|     glGenTextures(1, &texture);
 | |
|     verify_no_error();
 | |
|     return { texture };
 | |
| }
 | |
| 
 | |
| void bind_texture(Texture const& texture)
 | |
| {
 | |
|     glBindTexture(GL_TEXTURE_2D, texture.id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void upload_texture_data(Texture const& texture, Gfx::Bitmap const& bitmap)
 | |
| {
 | |
|     VERIFY(bitmap.format() == Gfx::BitmapFormat::BGRx8888 || bitmap.format() == Gfx::BitmapFormat::BGRA8888);
 | |
|     bind_texture(texture);
 | |
|     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap.width(), bitmap.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, bitmap.scanline(0));
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void delete_texture(Texture const& texture)
 | |
| {
 | |
|     glDeleteTextures(1, &texture.id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void set_uniform(Uniform const& uniform, float value1, float value2, float value3, float value4)
 | |
| {
 | |
|     glUniform4f(uniform.id, value1, value2, value3, value4);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void set_vertex_attribute(VertexAttribute const& attribute, u32 offset, int number_of_components)
 | |
| {
 | |
|     glVertexAttribPointer(attribute.id, number_of_components, GL_FLOAT, GL_FALSE, number_of_components * sizeof(float), reinterpret_cast<void*>(offset));
 | |
|     glEnableVertexAttribArray(attribute.id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void set_texture_scale_mode(ScalingMode scaling_mode)
 | |
| {
 | |
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, scaling_mode == ScalingMode::Nearest ? GL_NEAREST : GL_LINEAR);
 | |
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, scaling_mode == ScalingMode::Nearest ? GL_NEAREST : GL_LINEAR);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void clear_color(Gfx::Color const& color)
 | |
| {
 | |
|     glClearColor(color.red() / 255.0f, color.green() / 255.0f, color.blue() / 255.0f, color.alpha() / 255.0f);
 | |
|     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void draw_arrays(DrawPrimitive draw_primitive, size_t count)
 | |
| {
 | |
|     GLenum mode = GL_TRIANGLES;
 | |
|     if (draw_primitive == DrawPrimitive::TriangleFan)
 | |
|         mode = GL_TRIANGLE_FAN;
 | |
|     glDrawArrays(mode, 0, count);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| Buffer create_buffer()
 | |
| {
 | |
|     GLuint buffer;
 | |
|     glGenBuffers(1, &buffer);
 | |
|     verify_no_error();
 | |
|     return { buffer };
 | |
| }
 | |
| 
 | |
| void bind_buffer(Buffer const& buffer)
 | |
| {
 | |
|     glBindBuffer(GL_ARRAY_BUFFER, buffer.id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void upload_to_buffer(Buffer const& buffer, Span<float> values)
 | |
| {
 | |
|     glBindBuffer(GL_ARRAY_BUFFER, buffer.id);
 | |
|     glBufferData(GL_ARRAY_BUFFER, values.size() * sizeof(float), values.data(), GL_STATIC_DRAW);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void delete_buffer(Buffer const& buffer)
 | |
| {
 | |
|     glDeleteBuffers(1, &buffer.id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| VertexArray create_vertex_array()
 | |
| {
 | |
|     GLuint vertex_array;
 | |
|     glGenVertexArrays(1, &vertex_array);
 | |
|     verify_no_error();
 | |
|     return { vertex_array };
 | |
| }
 | |
| 
 | |
| void bind_vertex_array(VertexArray const& vertex_array)
 | |
| {
 | |
|     glBindVertexArray(vertex_array.id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void delete_vertex_array(VertexArray const& vertex_array)
 | |
| {
 | |
|     glDeleteVertexArrays(1, &vertex_array.id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| Framebuffer create_framebuffer(Gfx::IntSize size)
 | |
| {
 | |
|     GLuint texture;
 | |
|     glGenTextures(1, &texture);
 | |
|     glBindTexture(GL_TEXTURE_2D, texture);
 | |
|     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
 | |
| 
 | |
|     GLuint fbo;
 | |
|     glGenFramebuffers(1, &fbo);
 | |
| 
 | |
|     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
 | |
|     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
 | |
|     if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
 | |
|         VERIFY_NOT_REACHED();
 | |
|     }
 | |
| 
 | |
|     verify_no_error();
 | |
| 
 | |
|     return { fbo, texture };
 | |
| }
 | |
| 
 | |
| void bind_framebuffer(Framebuffer const& framebuffer)
 | |
| {
 | |
|     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.fbo_id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void delete_framebuffer(Framebuffer const& framebuffer)
 | |
| {
 | |
|     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.fbo_id);
 | |
|     glDeleteFramebuffers(1, &framebuffer.fbo_id);
 | |
|     glDeleteTextures(1, &framebuffer.texture_id);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void enable_scissor_test(Gfx::IntRect rect)
 | |
| {
 | |
|     glEnable(GL_SCISSOR_TEST);
 | |
|     glScissor(rect.left(), rect.top(), rect.width(), rect.height());
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| void disable_scissor_test()
 | |
| {
 | |
|     glDisable(GL_SCISSOR_TEST);
 | |
|     verify_no_error();
 | |
| }
 | |
| 
 | |
| }
 | 
