feat: swap canvas for opengl context

This commit is contained in:
2026-03-05 18:39:38 +05:30
parent f001b90745
commit 8e09748d3e
7 changed files with 155 additions and 31 deletions

View File

@@ -3,29 +3,33 @@
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { outputs =
self, {
nixpkgs, self,
}: let nixpkgs,
system = "x86_64-linux"; }:
pkgs = import nixpkgs {inherit system;}; let
in { system = "x86_64-linux";
devShells.${system}.default = pkgs.mkShell { pkgs = import nixpkgs { inherit system; };
nativeBuildInputs = with pkgs; [ in
gcc {
clang-tools devShells.${system}.default = pkgs.mkShell {
lldb nativeBuildInputs = with pkgs; [
gcc
clang-tools
lldb
meson meson
ninja ninja
pkg-config pkg-config
gtk4 gtk4
libepoxy
gdb gdb
]; ];
shellHook = ""; shellHook = "";
};
}; };
};
} }

View File

@@ -11,6 +11,7 @@ project(
) )
gtk = dependency('gtk4', required: true) gtk = dependency('gtk4', required: true)
epoxy = dependency('epoxy')
src = files( src = files(
'src/main.c', 'src/main.c',
@@ -25,7 +26,7 @@ src = files(
executable( executable(
'vektor', 'vektor',
src, src,
dependencies: [gtk], dependencies: [gtk,epoxy],
link_args: ['-lm'], link_args: ['-lm'],
install: true, install: true,
) )

View File

@@ -26,7 +26,7 @@ void vektor_uictrl_init(GtkApplication* app, VektorWidgetState* stateOut) {
stateOut->workspacePaned = stateOut->workspacePaned =
GTK_PANED(gtk_builder_get_object(builder, "workspace_paned")); GTK_PANED(gtk_builder_get_object(builder, "workspace_paned"));
stateOut->workspaceCanvas = stateOut->workspaceCanvas =
GTK_PICTURE(gtk_builder_get_object(builder, "workspace")); GTK_GL_AREA(gtk_builder_get_object(builder, "workspace"));
stateOut->workspaceButtonLinetool = stateOut->workspaceButtonLinetool =
GTK_BUTTON(gtk_builder_get_object(builder, "button_linetool")); GTK_BUTTON(gtk_builder_get_object(builder, "button_linetool"));

View File

@@ -10,7 +10,7 @@ all the widgets used in internal logic of the program
typedef struct VektorWidgetState { typedef struct VektorWidgetState {
GtkWindow* window; GtkWindow* window;
GtkPaned* workspacePaned; GtkPaned* workspacePaned;
GtkPicture* workspaceCanvas; GtkGLArea* workspaceCanvas;
GtkButton* workspaceButtonLinetool; GtkButton* workspaceButtonLinetool;

View File

@@ -1,3 +1,4 @@
#include "epoxy/gl.h"
#include "gtk/gtk.h" #include "gtk/gtk.h"
#include "../core/raster.h" #include "../core/raster.h"
@@ -8,6 +9,114 @@
#define VKTR_CANVAS_HEIGHT 400 #define VKTR_CANVAS_HEIGHT 400
#define VKTR_CANVAS_SIZE (VKTR_CANVAS_WIDTH * VKTR_CANVAS_HEIGHT * 4) #define VKTR_CANVAS_SIZE (VKTR_CANVAS_WIDTH * VKTR_CANVAS_HEIGHT * 4)
static GLuint shader_program;
static GLuint vao;
static const char* vertex_shader_src =
"#version 300 es\n" // <- ES version
"layout(location = 0) in vec2 aPos;\n"
"void main() {\n"
" gl_Position = vec4(aPos, 0.0, 1.0);\n"
"}\n";
static const char* fragment_shader_src =
"#version 300 es\n" // <- ES version
"precision mediump float;\n" // required in ES for fragment color
"out vec4 FragColor;\n"
"void main() {\n"
" FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
static GLuint compile_shader(GLenum type, const char* src) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char info[512];
glGetShaderInfoLog(shader, 512, NULL, info);
g_error("Shader compile failed: %s", info);
}
return shader;
}
static void init_shader(void) {
GLuint vertex = compile_shader(GL_VERTEX_SHADER, vertex_shader_src);
GLuint fragment = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_src);
shader_program = glCreateProgram();
glAttachShader(shader_program, vertex);
glAttachShader(shader_program, fragment);
glLinkProgram(shader_program);
GLint success;
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
if (!success) {
char info[512];
glGetProgramInfoLog(shader_program, 512, NULL, info);
g_error("Shader link failed: %s", info);
}
glDeleteShader(vertex);
glDeleteShader(fragment);
}
static void init_geometry(void) {
// Vertices for a rectangle in NDC coordinates
float vertices[] = {
-0.5f, -0.5f, // bottom-left
0.5f, -0.5f, // bottom-right
0.5f, 0.5f, // top-right
-0.5f, 0.5f // top-left
};
unsigned int indices[] = {0, 1, 2, 2, 3, 0};
GLuint vbo, ebo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float),
(void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
}
static gboolean render(GtkGLArea* area, GdkGLContext* context) {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader_program);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glUseProgram(0);
return TRUE;
}
static void realize(GtkGLArea* area, gpointer user_data) {
gtk_gl_area_make_current(area);
if (gtk_gl_area_get_error(area) != NULL)
return; // context creation failed
init_shader();
init_geometry();
}
void vektor_canvas_init(VektorWidgetState* state, VektorCanvas* canvasOut) { void vektor_canvas_init(VektorWidgetState* state, VektorCanvas* canvasOut) {
canvasOut->canvasWidget = state->workspaceCanvas; canvasOut->canvasWidget = state->workspaceCanvas;
canvasOut->width = VKTR_CANVAS_WIDTH; canvasOut->width = VKTR_CANVAS_WIDTH;
@@ -20,10 +129,14 @@ void vektor_canvas_init(VektorWidgetState* state, VektorCanvas* canvasOut) {
VKTR_CANVAS_WIDTH, VKTR_CANVAS_HEIGHT, GDK_MEMORY_R8G8B8A8, VKTR_CANVAS_WIDTH, VKTR_CANVAS_HEIGHT, GDK_MEMORY_R8G8B8A8,
canvasOut->canvasPixelBytes, VKTR_CANVAS_WIDTH * 4); canvasOut->canvasPixelBytes, VKTR_CANVAS_WIDTH * 4);
gtk_picture_set_paintable(canvasOut->canvasWidget, g_signal_connect(canvasOut->canvasWidget, "realize", G_CALLBACK(realize),
GDK_PAINTABLE(canvasOut->canvasTexture)); NULL);
gtk_picture_set_content_fit(GTK_PICTURE(canvasOut->canvasWidget), g_signal_connect(canvasOut->canvasWidget, "render", G_CALLBACK(render),
GTK_CONTENT_FIT_CONTAIN); NULL);
// gtk_picture_set_paintable(canvasOut->canvasWidget,
// GDK_PAINTABLE(canvasOut->canvasTexture));
// gtk_picture_set_content_fit(GTK_PICTURE(canvasOut->canvasWidget),
// GTK_CONTENT_FIT_CONTAIN);
// g_object_unref(bytes); // g_object_unref(bytes);
} }
@@ -38,8 +151,8 @@ void vektor_canvas_update(VektorCanvas* canvas) {
canvas->width, canvas->height, GDK_MEMORY_R8G8B8A8, canvas->width, canvas->height, GDK_MEMORY_R8G8B8A8,
canvas->canvasPixelBytes, canvas->width * 4); canvas->canvasPixelBytes, canvas->width * 4);
gtk_picture_set_paintable(canvas->canvasWidget, // gtk_picture_set_paintable(canvas->canvasWidget,
GDK_PAINTABLE(canvas->canvasTexture)); // GDK_PAINTABLE(canvas->canvasTexture));
} }
void vektor_canvas_fill(VektorCanvas* canvas, VektorColor color) { void vektor_canvas_fill(VektorCanvas* canvas, VektorColor color) {

View File

@@ -3,10 +3,11 @@
#include "../core/raster.h" #include "../core/raster.h"
#include "../util/color.h" #include "../util/color.h"
#include "gtk/gtk.h"
#include "uicontroller.h" #include "uicontroller.h"
typedef struct VektorCanvas { typedef struct VektorCanvas {
GtkPicture* canvasWidget; GtkGLArea* canvasWidget;
// texture related stuff // texture related stuff
guchar* canvasPixels; guchar* canvasPixels;

View File

@@ -45,11 +45,16 @@
<!--Main canvas--> <!--Main canvas-->
<child> <child>
<object class="GtkPicture" id="workspace"> <!-- <object class="GtkPicture" id="workspace">
<property name="content-fit">contain</property> <property name="content-fit">contain</property>
<property name="hexpand">true</property> <property name="hexpand">true</property>
<property name="vexpand">true</property> <property name="vexpand">true</property>
</object> -->
<object class="GtkGLArea" id="workspace">
<property name="hexpand">true</property>
<property name="vexpand">true</property>
</object> </object>
</child> </child>