Compare commits

...

No commits in common. "main" and "master" have entirely different histories.
main ... master

33 changed files with 162 additions and 3512 deletions

11
.gitignore vendored
View File

@ -1,11 +0,0 @@
evwm
.vscode/*
bin/
obj/
debug/
*.pdf
!.vscode/launch.json
!.vscode/tasks.json
research/render_triangle

27
.vscode/launch.json vendored
View File

@ -1,27 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/debug/evwm",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"preLaunchTask":"(Debug) Build",
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

13
.vscode/tasks.json vendored
View File

@ -1,13 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks":
[
{
"label": "(Debug) Build",
"type": "shell",
"command": "make clean && make debug"
},
]
}

View File

@ -1,71 +0,0 @@
# Template taken from https://github.com/TheNetAdmin/Makefile-Templates/blob/master/SmallProject/Template/Makefile
TARGET_NAME := evwm
# tool macros
CC ?= gcc
CCFLAGS := -Wall -Wpedantic
LDFLAGS := $(shell pkg-config --cflags --libs x11 glew gl xcomposite xfixes) -lm
DBGFLAGS := -g -ggdb
CCOBJFLAGS := $(CCFLAGS) -c
# path macros
BIN_PATH := bin
OBJ_PATH := obj
SRC_PATH := src
DBG_PATH := debug
# compile macros
ifeq ($(OS),Windows_NT)
TARGET_NAME := $(addsuffix .exe,$(TARGET_NAME))
endif
TARGET := $(BIN_PATH)/$(TARGET_NAME)
TARGET_DEBUG := $(DBG_PATH)/$(TARGET_NAME)
# src files & obj files
SRC := $(foreach x, $(SRC_PATH), $(wildcard $(addprefix $(x)/*,.c*)))
OBJ := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
OBJ_DEBUG := $(addprefix $(DBG_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
# clean files list
DISTCLEAN_LIST := $(OBJ) \
$(OBJ_DEBUG)
CLEAN_LIST := $(TARGET) \
$(TARGET_DEBUG) \
$(DISTCLEAN_LIST)
# default rule
default: makedir all
# non-phony targets
$(TARGET): $(OBJ)
$(CC) $(CCFLAGS) -o $@ $(OBJ) $(LDFLAGS)
$(OBJ_PATH)/%.o: $(SRC_PATH)/%.c*
$(CC) $(CCOBJFLAGS) -o $@ $<
$(DBG_PATH)/%.o: $(SRC_PATH)/%.c*
$(CC) $(CCOBJFLAGS) $(DBGFLAGS) -o $@ $<
$(TARGET_DEBUG): $(OBJ_DEBUG)
$(CC) $(CCFLAGS) $(DBGFLAGS) $(OBJ_DEBUG) $(LDFLAGS) -o $@
# phony rules
.PHONY: makedir
makedir:
@mkdir -p $(BIN_PATH) $(OBJ_PATH) $(DBG_PATH)
.PHONY: all
all: $(TARGET)
.PHONY: debug
debug: $(TARGET_DEBUG)
.PHONY: clean
clean:
@echo CLEAN $(CLEAN_LIST)
@rm -f $(CLEAN_LIST)
.PHONY: distclean
distclean:
@echo CLEAN $(DISTCLEAN_LIST)
@rm -f $(DISTCLEAN_LIST)

View File

@ -1,3 +0,0 @@
# evwm
A minimalist window manager for the lazy

View File

@ -1,10 +0,0 @@
#version 330
out vec4 fragment_colour;
in vec2 local_position;
uniform sampler2D texture_sampler;
void main(void) {
fragment_colour = vec4(texture(texture_sampler, local_position * vec2(0.5,0.5) + vec2(0.5)).rgb, 1.0);
}

View File

@ -1,13 +0,0 @@
#version 330
layout(location = 0) in vec3 vertex_position;
out vec2 local_position;
uniform mat4 global_transform = mat4(1.0);
void main(void) {
// The texture position is the same as the vertices as they go from -1.0 to 1.0
// in both dimensions
local_position = vec2(vertex_position.x, -vertex_position.y);
gl_Position = vec4(vertex_position.x, vertex_position.y, vertex_position.z, 1.0)* global_transform;
}

18
log.c Normal file
View File

@ -0,0 +1,18 @@
#include "log.h"
#include <stdio.h>
#include <time.h>
const char *
_current_time()
{
time_t tt;
struct tm * ti;
static char ts[21] = {0};
time(&tt);
ti = localtime(&tt);
snprintf(ts, 21, "%02d:%02d:%02d", ti->tm_hour, ti->tm_min, ti->tm_sec);
return ts;
}

54
log.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef __LOG_H__
#define __LOG_H__
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define TERM_BLUE "\033[1;94m"
#define TERM_GREEN "\033[1;92m"
#define TERM_YELLOW "\033[1;93m"
#define TERM_RED "\033[1;91m"
#define TERM_CYAN "\033[1;96m"
#define TERM_WHITE "\033[1;97m"
#define TERM_PURPLE "\033[1;95m"
#define TERM_RESET "\033[0m"
#define TERM_TME TERM_WHITE
#define TERM_INF TERM_WHITE
#define TERM_WRN TERM_YELLOW
#define TERM_ERR TERM_RED
#define TERM_ABT TERM_RED
#define TERM_DBG TERM_CYAN
#define TERM_FUN TERM_PURPLE
#define TERM_FLE TERM_BLUE
#define TERM_NRM TERM_RESET
// Not very C99 ish, but hey, nobody is perfect
#define __STD_LOG(_file, _fmt, ...) fprintf(\
_file, TERM_NRM TERM_TME "[%s] " TERM_FLE "[%s:%d] " TERM_NRM \
TERM_FUN "[%s] " TERM_NRM \
_fmt "%s\n", \
_current_time(), __FILENAME__, __LINE__, __func__, __VA_ARGS__ \
)
#define __FORM_LOG(_color, _name, ...) __STD_LOG(stdout, _color "[" _name "]" TERM_NRM " " __VA_ARGS__, "")
#define inf(...) __FORM_LOG(TERM_INF , "INFO", __VA_ARGS__)
#define dbg(...) __FORM_LOG(TERM_DBG, "DEBUG", __VA_ARGS__)
#define wrn(...) __FORM_LOG(TERM_WRN, "WARNING", __VA_ARGS__)
#define err(...) __FORM_LOG(TERM_ERR, "ERROR", __VA_ARGS__)
#define __ftl(...) __FORM_LOG(TERM_ERR, "FATAL", __VA_ARGS__)
#define ABS(X) ((X) < 0 ? (-X) : (X))
#define SWAP(X, Y, T) do { T s = X; X = Y; Y = s; } while(0)
#define UNUSED(x) ((void)(x))
const char *
_current_time();
#endif

7
mema.c Normal file
View File

@ -0,0 +1,7 @@
#include "mema.h"
// Global context for memory allocations
static struct
_mema_context _gbl_context;

35
mema.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef __MEMA_H__
#define __MEMA_H__
#include <stdlib.h>
struct _mema_block
{
void * data;
size_t size;
struct _mema_block * prev, * next;
};
struct _mema_context
{
struct _mema_block *blocks;
size_t size;
};
struct _mema_context
_mema_global_context;
#define lmema_init() struct _mema_context _mema_local
#define lalloc(size) _mema_alloc(&_mema_local, size)
#define lcalloc(nmemb, size) _mema_calloc(&_mema_local, nmemb, size)
#define lfree(ptr) _mema_free(&_mema_local, ptr)
void * _mema_free_all(struct _mema_context * context);
void * _mema_alloc(struct _mema_context * context, size_t size);
void * _mema_calloc(struct _mema_context * context, size_t nmemb, size_t size);
void * _mema_free(struct _mema_context * context, void *ptr);
#endif

View File

@ -1,3 +0,0 @@
# ROCK64
- https://www.olimex.com/Products/SOM/RK3328/RK3328-SOM-1G/
- https://wiki.pine64.org/wiki/ROCK64

View File

@ -1,198 +0,0 @@
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// build and compile our shader program
// ------------------------------------
// vertex shader
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// fragment shader
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// link shaders
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first Triangle
1, 2, 3 // second Triangle
};
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
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, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound.
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0);
// uncomment this call to draw in wireframe polygons.
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// draw our first triangle
glUseProgram(shaderProgram);
glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
//glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// glBindVertexArray(0); // no need to unbind it every time
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}

View File

@ -1,20 +0,0 @@
#include "atoms.h"
const char
*atom_str_identifiers[atom_no_id] =
{
[utf8_string] = (char *)"UTF8_STRING",
[wm_protocols] = (char *)"WM_PROTOCOLS",
[wm_delete_window] = (char *)"WM_DELETE_WINDOW",
[wm_state] = (char *)"WM_STATE",
[wm_take_focus] = (char *)"WM_TAKE_FOCUS",
[net_active_window] = (char *)"_NET_ACTIVE_WINDOW",
[net_wm_supported] = (char *)"_NET_SUPPORTED",
[net_wm_name] = (char *)"_NET_WM_NAME",
[net_wm_state] = (char *)"_NET_WM_STATE",
[net_supporting_wm_check] = (char *)"_NET_SUPPORTING_WM_CHECK",
[net_wm_state_fullscreen] = (char *)"_NET_WM_STATE_FULLSCREEN",
[net_wm_window_type] = (char *)"_NET_WM_WINDOW_TYPE",
[net_wm_window_type_dialog] = (char *)"_NET_WM_WINDOW_TYPE_DIALOG",
[net_client_list] = (char *)"_NET_CLIENT_LIST"
};

View File

@ -1,41 +0,0 @@
#ifndef __ATOMS_H__
#define __ATOMS_H__
// These are the same atoms used by dwm as of the
// initial writing of this code
typedef enum
{
utf8_string,
wm_protocols,
wm_delete_window,
wm_state,
wm_take_focus,
// Used to specify the start of net_wm
// atoms, do not move it
net_start,
net_active_window,
net_wm_supported,
net_wm_name,
net_wm_state,
net_supporting_wm_check,
net_wm_state_fullscreen,
net_wm_window_type,
net_wm_window_type_dialog,
net_client_list,
atom_no_id
} atom_id_t;
extern const char *atom_str_identifiers[atom_no_id];
static inline const char*
atom_to_str(atom_id_t id)
{
return id < atom_no_id && id > 0 ?
atom_str_identifiers[id] : "UNKNOWN_ATOM";
}
#endif

621
src/cm.c
View File

@ -1,621 +0,0 @@
#include "cm.h"
#include "geometry.h"
#include "shader.h"
#include "wm.h"
#include "util.h"
#ifndef SHADERS_PATH
#define SHADERS_PATH "assets/shaders"
#endif
#define MAIN_SHADER_NAME "main"
#define XCOMPMGR_PROPERTY "xcompmgr"
// Taken from https://github.com/obiwac/x-compositing-wm/blob/main/src/cwm.h
typedef GLXContext (*glXCreateContextAttribsARB_t) (Display*, GLXFBConfig, GLXContext, Bool, const int*);
typedef void (*glXBindTexImageEXT_t) (Display*, GLXDrawable, int, const int*);
typedef void (*glXReleaseTexImageEXT_t) (Display*, GLXDrawable, int);
typedef void (*glXSwapIntervalEXT_t) (Display*, GLXDrawable, int);
typedef struct window_vertices_t
{
float vertices[4 * 2];
} window_vertices_t;
static const char * MAIN_SHADER_UNIFORM_NAMES[] = {
// "screen_width",
// "screen_height",
// "window_x",
// "window_y",
// "window_width",
// "window_height",
"texture_sampler",
"global_transform"
};
typedef struct main_shader_t
{
GLuint program;
struct
{
// int screen_width;
// int screen_height;
// int window_x;
// int window_y;
// int window_width;
// int window_height;
int texture_sampler;
int global_transform;
} uniforms;
} main_shader_t;
typedef struct window_extra_t
{
bool drawable;
Pixmap xpixmap;
GLXPixmap pixmap;
} window_extra_t;
typedef struct cm_t
{
int screen;
Display* display;
Window root_window;
XWindowAttributes root_window_attributes,
output_window_attributes;
Window check_window, overlay_window,
output_window;
Atom net_wm_cm_atom;
XVisualInfo * default_visual;
GLXFBConfig * fb_config;
int fb_config_count;
GLXContext glx_context;
glXCreateContextAttribsARB_t glXCreateContextAttribsARB;
glXBindTexImageEXT_t glXBindTexImageEXT;
glXReleaseTexImageEXT_t glXReleaseTexImageEXT;
glXSwapIntervalEXT_t glXSwapIntervalEXT;
main_shader_t main_shader;
bool allocated_buffer;
unsigned int vbo, vao, ebo;
} cm_t;
static cm_t cm = {0};
static const int
DEFAULT_GLX_VISUAL_ATTRIBUTES[] = {
GLX_RGBA, GLX_DOUBLEBUFFER,
GLX_SAMPLE_BUFFERS, 1,
GLX_SAMPLES, 4,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 16,
0
};
static const int
DEFAULT_GLX_FB_ATTRIBUTES[] = {
GLX_BIND_TO_TEXTURE_RGBA_EXT, 1,
GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_X_RENDERABLE, 1,
GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, (GLint) GLX_DONT_CARE,
GLX_BUFFER_SIZE, 32,
GLX_SAMPLE_BUFFERS, 1,
GLX_SAMPLES, 4,
GLX_DOUBLEBUFFER, 1,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_STENCIL_SIZE, 0,
GLX_DEPTH_SIZE, 16,
0
};
static const int
DEFAULT_GLX_VERSION_ATTRIBUTES[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
0
};
static const unsigned int
WINDOW_INDICES[] = {
0, 1, 3,
1, 2, 3,
};
static const float
WINDOW_VERTICES[] = {
// Top right
1.0, -1.0, 0.0f,
// Botom right
1.0, 1.0, 0.0f,
// Bottom left
-1.0, 1.0, 0.0f,
// Top left
-1.0, -1.0, 0.0f
};
static inline bool
should_render_window( window_node_t * node )
{
return (
node->window != cm.check_window &&
node->window != cm.overlay_window &&
node->window != cm.output_window &&
node->window != cm.root_window &&
node->attributes.width > 1 &&
node->attributes.height > 1
);
}
static void
free_window_pixmap(window_extra_t *extra)
{
if (extra->xpixmap)
XFreePixmap(cm.display, extra->xpixmap);
if (extra->pixmap)
glXDestroyPixmap(cm.display, extra->pixmap);
extra->xpixmap = extra->pixmap = 0;
}
static void
create_window_pixmap( window_node_t * window_node )
{
XVisualInfo* visual = NULL;
int format = 0, has_alpha = 0, visual_depth = 0;
window_extra_t * extra = NULL;
GLXFBConfig config = {0};
extra = (window_extra_t *)window_node->extra;
XGetWindowAttributes(cm.display, window_node->window, &window_node->attributes);
for (int i = 0; i < cm.fb_config_count; i++) {
config = cm.fb_config[i];
glXGetFBConfigAttrib(cm.display, config, GLX_BIND_TO_TEXTURE_RGBA_EXT, &has_alpha);
visual = glXGetVisualFromFBConfig(cm.display, config);
visual_depth = visual->depth;
free(visual);
if (window_node->attributes.depth != visual_depth)
continue;
format = has_alpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT;
break;
}
int pixmap_attributes[] = {
GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
GLX_TEXTURE_FORMAT_EXT, format,
0
};
extra->xpixmap = XCompositeNameWindowPixmap(cm.display, window_node->window);
extra->pixmap = glXCreatePixmap(cm.display, config, extra->xpixmap, (const int *)pixmap_attributes);
}
static inline window_extra_t *
create_window_extra( window_node_t * node )
{
window_extra_t * extra = NULL;
extra = gcalloc(1, sizeof(window_extra_t));
node->extra = extra;
return extra;
}
static window_extra_t *
create_window_extra_if_none( window_node_t * node )
{
if(!node->extra)
node->extra = create_window_extra(node);
return (window_extra_t *)node->extra;
}
static char *
get_shader_path(const char * filename)
{
size_t size = 0;
char * path = NULL;
size = arrlen(SHADERS_PATH) + strlen(filename) + 2;
path = gcalloc(size, sizeof(char));
snprintf(path, size, "%s/%s", SHADERS_PATH, filename);
return path;
}
static int
compile_shader(const char * name, const char *vertex_shader_filename,
const char *fragment_shader_filename, const char *uniform_names[],
int *uniforms, size_t uniform_len)
{
int ret = 0;
char * path = NULL;
char *vertex_source = NULL, *fragment_source = NULL;
dbg("compiling \"%s\" shader...", name);
path = get_shader_path(vertex_shader_filename);
if((ret = read_file(path, &vertex_source, NULL)))
{
err("cannot open %s: %s", path, strerror(ret));
return ret;
}
gfree(path);
path = get_shader_path(fragment_shader_filename);
if((ret = read_file(path, &fragment_source, NULL)))
{
err("cannot open %s: %s", path, strerror(ret));
return ret;
}
gfree(path);
ret = shader_create(&cm.main_shader.program, vertex_source, fragment_source,
uniform_names, uniforms, uniform_len);
if(ret)
return ret;
dbg("done compiling \"%s\" shader", name);
return 0;
}
static int
compile_shaders( void )
{
int ret = 0;
ret = compile_shader(MAIN_SHADER_NAME, MAIN_SHADER_NAME ".vs", MAIN_SHADER_NAME ".fs",
MAIN_SHADER_UNIFORM_NAMES, (int *)&cm.main_shader.uniforms,
arrlen(MAIN_SHADER_UNIFORM_NAMES));
if(ret)
return ret;
return 0;
}
static int
bind_window_texture( window_node_t * window_node )
{
window_extra_t * extra = NULL;
extra = window_node->extra;
if(!extra || !extra->drawable)
return 0;
if(!extra->pixmap)
create_window_pixmap(window_node);
cm.glXBindTexImageEXT(cm.display, extra->pixmap, GLX_FRONT_LEFT_EXT, NULL);
return 0;
}
static int
unbind_window_texture( window_node_t * window_node )
{
window_extra_t * extra = NULL;
extra = window_node->extra;
if(extra->pixmap)
cm.glXReleaseTexImageEXT(cm.display, extra->pixmap, GLX_FRONT_LEFT_EXT);
return 0;
}
int
cm_swap_buffers( void )
{
glXSwapBuffers(cm.display, cm.output_window);
return 0;
}
static int
render_window( window_node_t * window_node )
{
int ret = 0;
matrix_t ma, mb, transform;
float height = 0.0f, width = 0.0f, x = 0.0f, y = 0.0f,
output_width = 0.0f, output_height = 0.0f;
window_extra_t * extra = NULL;
extra = create_window_extra_if_none(window_node);
XGetWindowAttributes(cm.display, cm.output_window, &cm.output_window_attributes);
XGetWindowAttributes(cm.display, window_node->window, &window_node->attributes);
x = (float)window_node->attributes.x;
y = (float)window_node->attributes.y;
width = (float)window_node->attributes.width;
height = (float)window_node->attributes.height;
output_width = (float)cm.output_window_attributes.width;
output_height = (float)cm.output_window_attributes.height;
if(window_node->attributes.width % 2) x += .5f;
if(window_node->attributes.height % 2) y += .5f;
y = -y;
// Setup unifroms for main shader
glUseProgram(cm.main_shader.program);
glUniform1i(cm.main_shader.uniforms.texture_sampler, 0);
make_scaling_matrix(width/output_width, height/output_height, 0.0f, ma);
make_translation_matrix((x - width/2.0f)/output_width, (y + height/2.0f)/output_height, 0.0f, mb);
mxm(mb, ma, transform);
glUniformMatrix4fv(cm.main_shader.uniforms.global_transform, 1, GL_FALSE, &transform[0][0]);
// Bind texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glActiveTexture(GL_TEXTURE0);
bind_window_texture(window_node);
glBindVertexArray(cm.vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
unbind_window_texture(window_node);
return ret;
}
int
cm_render_windows(void)
{
window_node_t * node = NULL;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(cm.vao);
glBindBuffer(GL_ARRAY_BUFFER, cm.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(WINDOW_VERTICES), WINDOW_VERTICES, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cm.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(WINDOW_INDICES), WINDOW_INDICES, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// XGrabServer(cm.display);
node = wm_get_first_window_node();
while(node)
{
if(should_render_window(node))
render_window(node);
node = node->next;
}
uint64_t delta = time_ms();
cm_swap_buffers();
delta = time_ms() - delta;
// XUngrabServer(cm.display);
return 0;
}
static inline void
free_window_extra(window_node_t * node)
{
window_extra_t * extra = NULL;
if(extra)
{
extra = (window_extra_t *)node->extra;
free_window_pixmap(extra);
gfree(extra);
extra = NULL;
}
}
static void
on_create_window(window_node_t * node)
{
if(node->extra)
free_window_extra(node->extra);
create_window_extra(node);
((window_extra_t *)node->extra)->drawable = true;
}
static void
on_destroy_window(window_node_t * node)
{
free_window_extra(node);
}
int
cm_init( unsigned int modkey )
{
int err = 0;
XserverRegion region = {0};
wm_callbacks_t callbacks = {0};
XWindowAttributes window_attrbiutes = {0};
XSetWindowAttributes default_visual_attributes = {0};
char net_wm_cm[15] = "_NET_WM_CM_S##";
clear(&cm);
err = wm_init(modkey);
if(err)
ftl("cannot initialize window manager");
cm.screen = wm_get_screen();
cm.display = wm_get_display();
cm.root_window = wm_get_root_window();
XGetWindowAttributes(cm.display, cm.root_window, &cm.root_window_attributes);
// Make it known to other apps that you are a compositing window
// manager
cm.check_window = XCreateSimpleWindow(cm.display, cm.root_window, 0, 0, 1, 1, 0, 0, 0);
Xutf8SetWMProperties(cm.display, cm.check_window, XCOMPMGR_PROPERTY, XCOMPMGR_PROPERTY,
NULL, 0, NULL, NULL, NULL);
snprintf(net_wm_cm, sizeof(net_wm_cm), "_NET_WM_CM_S%d", cm.screen);
cm.net_wm_cm_atom = XInternAtom(cm.display, net_wm_cm, 0);
XSetSelectionOwner(cm.display, cm.net_wm_cm_atom, cm.check_window, 0);
XCompositeRedirectSubwindows(cm.display, cm.root_window, CompositeRedirectManual);
// We use this so we can make windows transparents to events
cm.overlay_window = XCompositeGetOverlayWindow(cm.display, cm.root_window);
region = XFixesCreateRegion(cm.display, NULL, 0);
XFixesSetWindowShapeRegion(cm.display, cm.overlay_window, ShapeInput, 0, 0, region);
XFixesDestroyRegion(cm.display, region);
// Create the window where we will be drawing on
cm.default_visual = glXChooseVisual(cm.display, cm.screen, (int *)DEFAULT_GLX_VISUAL_ATTRIBUTES);
if(!cm.default_visual)
ftl("cannot get default glx visual");
default_visual_attributes = (XSetWindowAttributes){
.colormap = XCreateColormap(cm.display, cm.root_window, cm.default_visual->visual, AllocNone),
.border_pixel = 0};
// Get root window attributes for the output window
wm_get_window_attributes(cm.root_window, &window_attrbiutes);
cm.output_window = XCreateWindow(cm.display, cm.root_window, 0, 0, window_attrbiutes.width,
window_attrbiutes.height, 0, cm.default_visual->depth, InputOutput, cm.default_visual->visual,
CWBorderPixel | CWColormap, &default_visual_attributes);
XReparentWindow(cm.display, cm.output_window, cm.overlay_window, 0, 0);
XMapRaised(cm.display, cm.output_window);
// Get the glx frame buffer configurations that match DEFAULT_GLX_FB_ATTRIBUTES
cm.fb_config = glXChooseFBConfig(cm.display, cm.screen, DEFAULT_GLX_FB_ATTRIBUTES,
&cm.fb_config_count);
if(!cm.fb_config)
ftl("cannot get glx framebuffer configs");
// Get OpenGL function callbacks
cm.glXCreateContextAttribsARB = (glXCreateContextAttribsARB_t) glXGetProcAddressARB( (const GLubyte*) "glXCreateContextAttribsARB");
cm.glXBindTexImageEXT = (glXBindTexImageEXT_t) glXGetProcAddress((const GLubyte*) "glXBindTexImageEXT");
cm.glXReleaseTexImageEXT = (glXReleaseTexImageEXT_t) glXGetProcAddress((const GLubyte*) "glXReleaseTexImageEXT");
cm.glXSwapIntervalEXT = (glXSwapIntervalEXT_t) glXGetProcAddress((const GLubyte*) "glXSwapIntervalEXT");
// Create OpenGL context
cm.glx_context = cm.glXCreateContextAttribsARB(cm.display, cm.fb_config[0], NULL, 1, DEFAULT_GLX_VERSION_ATTRIBUTES);
if(!cm.glx_context)
ftl("cannot create OpenGL context");
// Make that OpenGL context our current context
glXMakeCurrent(cm.display, cm.output_window, cm.glx_context);
// Initialize GLEW
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK)
ftl("cannot initialize GLEW");
inf("compiling shaders..");
err = compile_shaders();
if(err)
ftl("cannot compile shaders")
inf("done compiling shaders");
callbacks.on_create_window = on_create_window;
callbacks.on_destroy_window = on_destroy_window;
wm_set_callbacks(callbacks);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGenVertexArrays(1, &cm.vao);
glGenBuffers(1, &cm.vbo);
glGenBuffers(1, &cm.ebo);
cm.allocated_buffer = true;
glClearColor(0.16015625, 0.15625, 0.15625, 1.);
return 0;
}
int
cm_destroy( void )
{
window_node_t *node = NULL, *next_node = NULL;
node = wm_get_first_window_node();
while(node)
{
next_node = node->next;
free_window_extra(node);
node = next_node;
}
if(cm.main_shader.program)
glDeleteProgram(cm.main_shader.program);
if(cm.allocated_buffer)
{
glDeleteVertexArrays(1, &cm.vao);
glDeleteBuffers(1, &cm.vbo);
glDeleteBuffers(1, &cm.ebo);
}
wm_destroy();
clear(&cm);
return 0;
}

View File

@ -1,20 +0,0 @@
#ifndef __CM_H__
#define __CM_H__
#include "wm.h"
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
#include <GL/glew.h>
#include <GL/glx.h>
int cm_init( unsigned int modkey );
int cm_destroy( void );
int cm_swap_buffers( void );
int cm_render_windows( void );
#endif

View File

@ -1,38 +0,0 @@
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include "util.h"
#define pow2(x) (x*x)
#define randf() ((float)rand()/(float)(RAND_MAX + 1.0))
#define rrandf(min, max) (min + (max - min)*randf())
static inline bool
solve_quadratic(float a, float b, float c, float *x1, float *x2)
{
float d = 0.0, q = 0.0;
d = pow2(b) - 4.0 * a * c;
// No imaginary numbers pls
if(d < 0)
return false;
// Easy
else if(d == 0.0)
*x1 = *x2 = (-0.5 * b/a);
// Frick
else
{
q = b> 0.0 ? -0.5 * (b + sqrt(d)) : -0.5 * (b - sqrt(d));
*x1 = q/a;
*x2 = c/q;
}
if(*x1 > *x2)
swap(*x1, *x2, float);
return true;
}

View File

@ -1,689 +0,0 @@
#include <stdio.h>
#include "geometry.h"
#include "fmath.h"
// Debug functions I use to display the contents of
// some structures. No need to pay much attention to
// these tho
const char*
matrix_to_str(matrix_t m)
{
static char buff[1024] = {0};
snprintf(buff, 1024,
"[%f]\t[%f]\t[%f]\t[%f]\n"
"[%f]\t[%f]\t[%f]\t[%f]\n"
"[%f]\t[%f]\t[%f]\t[%f]\n"
"[%f]\t[%f]\t[%f]\t[%f]",
m[0][0], m[0][1], m[0][2], m[0][3],
m[1][0], m[1][1], m[1][2], m[1][3],
m[2][0], m[2][1], m[2][2], m[2][3],
m[3][0], m[3][1], m[3][2], m[3][3]
);
return buff;
}
const char*
column_to_str(column_t c)
{
static char buff[1024] = {0};
snprintf(buff, 1024,
"c[0][0] = %f, c[1][0] = %f, c[2][0] = %f, c[3][0] = %f",
c[0][0],c[1][0],c[2][0],c[3][0]
);
return buff;
}
const char*
pv_to_str(struct pv_t *p)
{
static char buff[1024] = {0};
snprintf(buff, 1024,
"p->x = %f, p->y = %f, p->z = %f, p->w = %f",
p->x, p->y, p->z, p->w
);
return buff;
}
// Copy the contents of matrix d to s
void
copy_matrix(matrix_t s, matrix_t d)
{
int r = 0;
for(r = 0; r < 4; r++)
{
d[r][0] = s[r][0];
d[r][1] = s[r][1];
d[r][2] = s[r][2];
d[r][3] = s[r][3];
}
}
// Sets all the contents of a matrix to 0.0
void
clear_matrix(matrix_t m)
{
matrix_t b = {{0.0}};
copy_matrix(b, m);
}
// r = a - b
void
substract_pv(struct pv_t *a, struct pv_t *b, struct pv_t *r)
{
r->x = a->x - b->x;
r->y = a->y - b->y;
r->z = a->z - b->z;
r->w = 0.0;
}
// Returns a + b
void
add_pv(struct pv_t *a, struct pv_t *b, struct pv_t *r)
{
r->x = a->x + b->x;
r->y = a->y + b->y;
r->z = a->z + b->z;
r->w = 0.0;
}
// r = p * s
void
scale_pv(struct pv_t * p, float s, struct pv_t *r)
{
r->x = p->x * s;
r->y = p->y * s;
r->z = p->z * s;
}
// r = p / s
void
divide_pv(struct pv_t *p, float s, struct pv_t *r)
{
scale_pv(p, 1.0/s, r);
}
// r = a * b
void
multiply_pv(struct pv_t *a, struct pv_t *b, struct pv_t *r)
{
r->x = a->x * b->x;
r->y = a->y * b->y;
r->z = a->z * b->z;
}
// Returns ||v||
float
magnitude_pv(struct pv_t *v)
{
return sqrtf(pow2((v)->x) + pow2((v)->y) + pow2((v)->z));
}
// r = v/(||v||)
void
normalize_pv(struct pv_t *v, struct pv_t *r)
{
float m = 0.0;
m = magnitude_pv(v);
r->x = v->x/m;
r->y = v->y/m;
r->z = v->z/m;
}
// r = 1/p
// Returns the inverse of p.
// I had to get a little experimental with this, so I hope
// it works. Essentially this will check if any of the
// components on the vector is equal to 0, and if they are,
// the resulting value on r will be equal to INFINITY
void inverse_pv(struct pv_t* p, struct pv_t *r)
{
#define csign(x) (((x) >= 0) - ((x) < 0))
r->x = (p->x == 0 ? csign(p->x) * INFINITY : 1.0/p->x);
r->y = (p->y == 0 ? csign(p->y) * INFINITY : 1.0/p->y);
r->z = (p->z == 0 ? csign(p->z) * INFINITY : 1.0/p->z);
#undef csgin
}
float
dot_product(struct pv_t *a, struct pv_t *b)
{
return a->x * b->x + a->y * b->y + a->z * b->z;
}
void
cross_pv(struct pv_t *a, struct pv_t *b, struct pv_t *r)
{
r->x = a->y * b->z - a->z * b->y;
r->y = a->z * b->x - a->x * b->z;
r->z = a->x * b->y - a->y * b->x;
}
// Okay, so everyone seems to
// Checks if pointvector is a point
// Just in case I need to add other criteria to this
// later
static inline bool
is_point(struct pv_t *p)
{
return p->w > 0;
}
// Converts a pv_t to a column_t
static inline void
pv_to_column(struct pv_t *p, column_t c)
{
c[0][0] = p->x;
c[1][0] = p->y;
c[2][0] = p->z;
c[3][0] = p->w;
}
// Converts a column_t to a pv_t
static inline void
column_to_pv(column_t c, struct pv_t *p)
{
p->x = c[0][0];
p->y = c[1][0];
p->z = c[2][0];
p->w = c[3][0];
}
// Yeah... I don't have time to worry about
// how to calculate the inverse of a matrix.
// Like, I know how to do this, but I was spending
// too much time writing my own method so f*ck it,
// I asked San Google for some help with this one.
//
// Taken from
// https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix
// (I would have referenced the original source for the function
// but I couldn't find it)
//
// Also, I made this inlined since it's only going to be used
// in one place. So essentially, this would be the same as
// wiriting this function on inv_matrix, but I wanted to separate
// this from inv_matrix since I didn't write this myself.
inline static bool
_inv_matrix(const float m[16], float r[16])
{
float inv[16], det;
int i;
inv[0] =
m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
inv[4] =
-m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
inv[8] =
m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
inv[12] =
-m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
inv[1] =
-m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
inv[5] =
m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
inv[9] =
-m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
inv[13] =
m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
inv[2] =
m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
inv[6] =
-m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
inv[10] =
m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
inv[14] =
-m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
inv[3] =
-m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
inv[7] =
m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
inv[11] =
-m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
inv[15] =
m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0)
return false;
det = 1.0 / det;
for (i = 0; i < 16; i++)
r[i] = inv[i] * det;
return true;
}
// r = inv(m)
// If m doesn't have an inverse, then inv_matrix
// will act just like copy_matrix
void
inv_matrix(matrix_t m, matrix_t r)
{
bool s;
s = _inv_matrix((const float *)m, (float *)r);
if(s)
return;
else
copy_matrix(m, r);
}
// r = m * x
// Matrix times column operation. Do not use
// c as r as well. This will cause problems
void
mxc(matrix_t m, column_t c, column_t r)
{
r[0][0] = m[0][0] * c[0][0] + m[0][1] * c[1][0] + m[0][2] * c[2][0] + m[0][3] * c[3][0];
r[1][0] = m[1][0] * c[0][0] + m[1][1] * c[1][0] + m[1][2] * c[2][0] + m[1][3] * c[3][0];
r[2][0] = m[2][0] * c[0][0] + m[2][1] * c[1][0] + m[2][2] * c[2][0] + m[2][3] * c[3][0];
r[3][0] = m[3][0] * c[0][0] + m[3][1] * c[1][0] + m[3][2] * c[2][0] + m[3][3] * c[3][0];
}
// r = m * c
// Matrix times column operation. Do not use
// c as r as well. This will cause problems
void
mxm(matrix_t m, matrix_t c, matrix_t r)
{
unsigned char i = 0;
// I know I didn't NEED to use a loop here, but this is due in
// a week
for(i = 0; i < 4; i++)
{
r[0][i] = m[0][0] * c[0][i] + m[0][1] * c[1][i] + m[0][2] * c[2][i] + m[0][3] * c[3][i];
r[1][i] = m[1][0] * c[0][i] + m[1][1] * c[1][i] + m[1][2] * c[2][i] + m[1][3] * c[3][i];
r[2][i] = m[2][0] * c[0][i] + m[2][1] * c[1][i] + m[2][2] * c[2][i] + m[2][3] * c[3][i];
r[3][i] = m[3][0] * c[0][i] + m[3][1] * c[1][i] + m[3][2] * c[2][i] + m[3][3] * c[3][i];
}
}
// m = Im
void
make_identity_matrix(matrix_t m)
{
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0;
m[0][1] = m[0][2] = m[0][3] =
m[1][0] = m[1][2] = m[1][3] =
m[2][0] = m[2][1] = m[2][3] =
m[3][0] = m[3][1] = m[3][2] = 0.0;
}
// m = T(x, y, z)
void
make_translation_matrix(float x, float y, float z, matrix_t m)
{
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0;
m[0][3] = x;
m[1][3] = y;
m[2][3] = z;
m[0][1] = 0.0;
m[0][2] = 0.0;
m[1][0] = 0.0;
m[1][2] = 0.0;
m[2][0] = 0.0;
m[2][1] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
}
// m = S(x, y, z)
void
make_scaling_matrix(float x, float y, float z, matrix_t m)
{
m[0][0] = x;
m[1][1] = y;
m[2][2] = z;
m[3][3] = 1.0;
m[0][1] = 0.0;
m[0][2] = 0.0;
m[0][3] = 0.0;
m[1][0] = 0.0;
m[1][2] = 0.0;
m[1][3] = 0.0;
m[2][0] = 0.0;
m[2][1] = 0.0;
m[2][3] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
}
// m = R(t, u)
// t => Thetha: Angle for the rotation
// u => Unit Vector: Normal vector indicating the rotation axis(es)
void
make_rotation_matrix(float t, struct pv_t *u, matrix_t m)
{
float x2 = .0, y2 = .0, z2 = .0, sint = .0, cost = .0, d = .0;
x2 = pow2(u->x);
y2 = pow2(u->y);
z2 = pow2(u->z);
d = deg2rad(t);
cost = cos(d);
sint = sin(d);
m[0][0] = x2 + cost*(1-x2);
m[0][1] = u->x * u->y * (1-cost) - u->z*sint;
m[0][2] = u->x * u->z * (1-cost) + u->y*sint;
m[0][3] = 0.0;
m[1][0] = u->x * u->y * (1-cost) + u->z*sint;
m[1][1] = y2 + cost*(1-y2);
m[1][2] = u->y * u->z * (1-cost) - u->x*sint;
m[1][3] = 0.0;
m[2][0] = u->x * u->z * (1-cost) - u->y*sint;
m[2][1] = u->y * u->z * (1-cost) + u->x*sint;
m[2][2] = z2 + cost*(1-z2);
m[2][3] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
m[3][3] = 1.0;
}
// Apply transform matrix m to pv
void
transform_pv(matrix_t m, struct pv_t *p, struct pv_t *r)
{
column_t a, c;
pv_to_column(p, c);
mxc(m, c, a);
column_to_pv(a, r);
}
// Multiply m by all the pv_t on src and save
// the results on dst
void
transform_pv_arr(matrix_t m, struct pv_t *src, struct pv_t *dst, size_t s)
{
column_t a, c;
while(s > 0)
{
s--;
pv_to_column(&src[s], c);
mxc(m, c, a);
column_to_pv(a, &dst[s]);
}
}
// Reflects i around normal n
void
reflect_pv(struct pv_t *i, struct pv_t *n, struct pv_t *r)
{
struct pv_t p = {0.0};
scale_pv(n, dot_product(i, n) * 2.0, &p);
substract_pv(i, &p, r);
}
void
make_sphere(struct pv_t *center, float radius, struct sphere_t *s)
{
s->radius = radius;
s->radius2 = pow2(radius);
s->center = *center;
s->type = GEOMETRY_SPHERE;
s->param = NULL;
}
void
make_plane(struct pv_t *center, struct pv_t *normal, struct plane_t * plane)
{
plane->center = *center;
plane->normal = *normal;
plane->type = GEOMETRY_PLANE;
}
void
make_triangle(struct pv_t *a, struct pv_t *b, struct pv_t *c, struct triangle_t *t)
{
// I know I could have used ac instead... but
// I also want to be able to understand this in
// the future
struct pv_t ca, cp;
t->edges[0] = *a;
t->edges[1] = *b;
t->edges[2] = *c;
// Use for intersection check
substract_pv(b, a, &t->ba);
substract_pv(c,b, &t->cb);
substract_pv(a,c, &t->ac);
substract_pv(c, a, &ca);
cross_pv(&t->ba, &ca, &cp);
normalize_pv(&cp, &t->normal);
t->area = dot_product(&cp, &t->normal);
t->type = GEOMETRY_TRIANGLE;
}
void
transform_triangle(struct triangle_t *t, matrix_t m, struct triangle_t *r)
{
transform_pv(m, &t->edges[0], &t->edges[0]);
transform_pv(m, &t->edges[1], &t->edges[1]);
transform_pv(m, &t->edges[2], &t->edges[2]);
make_triangle(&t->edges[0], &t->edges[1], &t->edges[2], r);
}
void
new_mesh(struct mesh_t *m, size_t c)
{
matrix_t i;
m->triangles = (struct triangle_t *)calloc(c, sizeof(struct triangle_t));
m->triangle_count = c;
make_identity_matrix(i);
copy_matrix(i, m->transform);
copy_matrix(i, m->inv_transform);
}
void
free_mesh(struct mesh_t *m)
{
if(m->triangles != NULL)
free(m->triangles);
m->triangles = NULL;
m->triangle_count = 0;
}
void
transform_mesh(struct mesh_t *m, matrix_t t, struct mesh_t *r)
{
size_t i = 0;
matrix_t b;
for(; i < m->triangle_count; i++)
transform_triangle(&m->triangles[i], t, &r->triangles[i]);
mxm(t, m->transform, b);
inv_matrix(b, r->inv_transform);
copy_matrix(b, r->transform);
}
void transform_object(struct gobject_t *g, matrix_t t, struct gobject_t *r)
{
switch (g->type)
{
case GEOMETRY_SPHERE:
transform_pv(t, &g->center, &r->center);
break;
case GEOMETRY_TRIANGLE:
transform_triangle(g, t, r);
default:
break;
}
}
void
new_rectangle_mesh(struct pv_t *a, struct pv_t *b, struct pv_t *c, struct pv_t *d, struct mesh_t *m)
{
new_mesh(m, 2);
make_triangle(a, b, c, &m->triangles[0]);
make_triangle(c, d, a, &m->triangles[1]);
m->triangles[0].single_sided = m->triangles[1].single_sided = false;
m->has_bounding_sphere = true;
// substract_pv(b, a, &p);
// radius = magnitude_pv(&p)/2;
// normalize_pv(&p, &p);
// scale_pv(&p, radius, &p);
// add_pv(a, &p, &p);
// make_sphere(&p, radius, &m->bounding_sphere);
}
void
new_rectangle_mesh_wh(float width, float height, struct mesh_t *m)
{
struct pv_t a, b, c;
a = b = c = PV(0.0, 0.0, 0.0);
new_mesh(m, 2);
a.x = width;
c.z = -height;
make_triangle(&b, &a, &c, &m->triangles[0]);
b.z = c.z;
b.x = a.x;
make_triangle(&a, &b, &c, &m->triangles[1]);
m->triangles[0].single_sided = m->triangles[1].single_sided = false;
}

View File

@ -1,135 +0,0 @@
#ifndef GEOMETRY_H__
#define GEOMETRY_H__
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#ifndef M_PI
#define M_PI ((double)3.14159265358979323846)
#endif
// // Returns p^2
// // Because p*p takes too long to write
// #define pow2(p) (p)*(p)
// Converts angle from degrees to radiants
#define deg2rad(t) ((t * M_PI)/180.0)
#define PV(a, b, c) (struct pv_t){.x = a, .y = b, .z = c, .w = 1.0}
#define SPHERE(v, r) (struct gobject_t){.type = GEOMETRY_SPHERE, .center = v, .radius = r, .radius2 = pow2(r)}
#define DISK(c, n, r) (struct gobject_t){.type = GEOMETRY_DISK, .center = c, .normal = n, .radius = r, .radius2 = pow2(r)}
#define PLANE(c, n) (struct gobject_t){.type = GEOMETRY_PLANE, .center = c, .normal = n}
#define TRIANGLE(a, b, c, n) (struct gobject_t){.type = GEOMETRY_TRIANGLE, .edges[0] = a, .edges[1] = b, .edges[2] = c, .normal = n}
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
typedef uint32_t pixel_t;
typedef float matrix_t[4][4];
typedef float column_t[4][1];
struct pv_t
{ float x,y,z,w; };
enum gobject_type_t
{
GEOMETRY_TRIANGLE,
GEOMETRY_SPHERE,
GEOMETRY_PLANE,
GEOMETRY_DISK,
};
struct gobject_t
{
enum gobject_type_t type;
struct pv_t center;
bool emitter;
struct pv_t normal;
union
{
struct
{
float radius;
float radius2;
};
struct
{
struct pv_t edges[3], ba, cb, ac;
bool single_sided;
float area;
};
};
void *param;
};
#define triangle_t gobject_t
#define sphere_t gobject_t
#define plane_t gobject_t
struct mesh_t
{
struct triangle_t *triangles;
size_t triangle_count;
matrix_t transform, inv_transform;
struct gobject_t bounding_sphere;
bool has_bounding_sphere;
};
const char* matrix_to_str(matrix_t m);
const char* column_to_str(column_t c);
const char* pv_to_str(struct pv_t *p);
void copy_matrix(matrix_t s, matrix_t d);
void clear_matrix(matrix_t m);
float magnitude_pv(struct pv_t *v);
void reflect_pv(struct pv_t *i, struct pv_t *n, struct pv_t *r);
void substract_pv(struct pv_t *a, struct pv_t *b, struct pv_t *r);
void add_pv(struct pv_t *a, struct pv_t *b, struct pv_t *r);
void scale_pv(struct pv_t * p, float s, struct pv_t *r);
void divide_pv(struct pv_t *p, float s, struct pv_t *r);
void multiply_pv(struct pv_t *a, struct pv_t *b, struct pv_t *r);
void normalize_pv(struct pv_t *v, struct pv_t *r);
void inverse_pv(struct pv_t* p, struct pv_t *r);
void cross_pv(struct pv_t *a, struct pv_t *b, struct pv_t *r);
float dot_product(struct pv_t *a, struct pv_t *b);
void inv_matrix(matrix_t m, matrix_t r);
void mxc(matrix_t m, column_t c, column_t r);
void mxm(matrix_t m, matrix_t c, matrix_t r);
void make_identity_matrix(matrix_t m);
void make_translation_matrix(float x, float y, float z, matrix_t m);
void make_scaling_matrix(float x, float y, float z, matrix_t m);
void make_rotation_matrix(float t, struct pv_t *u, matrix_t m);
void transform_pv(matrix_t m, struct pv_t *p, struct pv_t *r);
void transform_pv_arr(matrix_t m, struct pv_t *src, struct pv_t *dst, size_t s);
void make_triangle(struct pv_t *a, struct pv_t *b, struct pv_t *c, struct triangle_t *t);
void transform_triangle(struct triangle_t *t, matrix_t m, struct triangle_t *r);
void make_sphere(struct pv_t *center, float radius, struct sphere_t *s);
void make_plane(struct pv_t *center, struct pv_t *normal, struct plane_t * plane);
void new_mesh(struct mesh_t *m, size_t c);
void free_mesh(struct mesh_t *m);
void transform_object(struct gobject_t *g, matrix_t t, struct gobject_t *r);
void transform_mesh(struct mesh_t *m, matrix_t t, struct mesh_t *r);
void new_rectangle_mesh(struct pv_t *a, struct pv_t *b, struct pv_t *c, struct pv_t *d, struct mesh_t *m);
void new_rectangle_mesh_wh(float width, float height, struct mesh_t *m);
#endif

View File

@ -1,21 +0,0 @@
#include "log.h"
// Writes current time on HH:MM:SS format
// on buf with a max size of len
void
get_time_str(char *buf, size_t len)
{
time_t tt;
struct tm * ti;
time(&tt);
ti = localtime(&tt);
snprintf(buf, len,
"%02d:%02d:%02d",
ti->tm_hour,
ti->tm_min,
ti->tm_sec
);
}

View File

@ -1,72 +0,0 @@
#ifndef __LOGGER_H__
#define __LOGGER_h__
#include <stdio.h>
#include <time.h>
// Logger
// It's just used to log events and get the function
// and line number where they were called from
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
// Color definitions for the logger
#define TERM_BLUE "\033[1;94m"
#define TERM_GREEN "\033[1;92m"
#define TERM_YELLOW "\033[1;93m"
#define TERM_RED "\033[1;91m"
#define TERM_CYAN "\033[1;96m"
#define TERM_WHITE "\033[1;97m"
#define TERM_PURPLE "\033[1;95m"
#define TERM_RESET "\033[0m"
#define TERM_TME TERM_WHITE
#define TERM_INF TERM_WHITE
#define TERM_WRN TERM_YELLOW
#define TERM_ERR TERM_RED
#define TERM_ABT TERM_RED
#define TERM_DBG TERM_CYAN
#define TERM_FUN TERM_PURPLE
#define TERM_FLE TERM_BLUE
#define TERM_NRM TERM_RESET
#define STRTIME_BUFFER_LEN 20
// Not very C99 ish, but hey, nobody is perfect
#define _STD_LOG(_file, _fmt, ...) \
{ \
char _tstr[STRTIME_BUFFER_LEN] = {0}; \
get_time_str(_tstr, sizeof(_tstr)/sizeof(*_tstr)); \
fprintf( \
_file, \
TERM_TME "[%s] " \
TERM_FLE "[%s:%d] " \
TERM_FUN "[%s] " \
TERM_NRM _fmt "%s\n", \
\
_tstr, \
__FILENAME__, __LINE__, \
__func__, \
__VA_ARGS__ \
); \
}
// Used for logger internals
#define _FORM_LOG(_color, _name, ...) _STD_LOG(stdout, _color "[" _name "]" TERM_NRM " " __VA_ARGS__, "")
// info - logs regular information, use it as regular printf
#define inf(...) _FORM_LOG(TERM_INF, "info", __VA_ARGS__)
// debug - logs debug information
#define dbg(...) _FORM_LOG(TERM_DBG, "debug", __VA_ARGS__)
// warning - logs warnings
#define wrn(...) _FORM_LOG(TERM_WRN, "warning", __VA_ARGS__)
// error - logs errors
#define err(...) _FORM_LOG(TERM_ERR, "error", __VA_ARGS__)
// Gets current time string on "%02d:%02d:%02d" format
void get_time_str(char *buf, size_t len);
#endif

View File

@ -1,51 +0,0 @@
#include <signal.h>
#include "util.h"
#include "wm.h"
#include "cm.h"
#include "mema.h"
static volatile bool stop_loop = false;
static void
signal_handler()
{
stop_loop = true;
}
int
main(int argc, char const *argv[])
{
uint64_t current_update = 0, last_update = 0, accum = 0;
gmema_init();
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
cm_init(Mod1Mask);
while(!wm_process_events() && !stop_loop)
{
current_update = time_ms();
accum += current_update - last_update;
last_update = current_update;
if(accum >= 16)
{
accum = 0;
cm_render_windows();
}
usleep(100);
}
cm_destroy();
// wm_init(Mod1Mask);
// while(!wm_process_events())
// {
// usleep(100);
// }
// wm_destroy();
return 0;
}

View File

@ -1,193 +0,0 @@
#include "mema.h"
#include <errno.h>
#include "util.h"
extern int errno;
static bool initialized = false;
struct mema_context _mema_global = {0};
// Frees all the elements allocated on mema context
void
_mema_free_all(struct mema_context * ctx)
{
abort_if_null(ctx);
struct _mema_block *b = NULL, *ob = NULL;
// Go through all the blocks on the context
// and free them and their data
b = ctx->blocks;
while(b)
{
if(b->data)
free(b->data);
ob = b;
b = ob->next;
free(ob);
}
}
// Meant for internal use.
// Gets the last element on the context's block
// list, that is, the first element with no data
void *
_mema_last_block(struct mema_context * ctx)
{
struct _mema_block *b = NULL;
abort_if_null(ctx);
b = ctx->blocks;
while(b)
{
if(!b->next)
break;
b = b->next;
}
if(!b)
ctx->blocks = b = calloc(1, sizeof(*b));
return b;
}
// Meant for internal use.
// Finds the block containing ptr. Returns NULL
// if none was found.
void *
_mema_find_block(struct mema_context * ctx, void * ptr)
{
struct _mema_block *b = NULL, *m = NULL;
abort_if_null(ctx);
b = ctx->blocks;
while(b)
{
if(b->data == ptr)
m = b;
b = b->next;
}
return m;
}
// Meant for internal use.
// Allocates a block next to another
struct _mema_block *
_allocate_next_block(struct _mema_block *r)
{
struct _mema_block *b = NULL;
b = (struct _mema_block *)calloc(1, sizeof(*b->next));
if(!b)
ftl("%s", strerror(errno));
b->prev = r;
return b;
}
// Allocates memory and adds allocation to mema context
void *
_mema_malloc(struct mema_context * ctx, size_t size)
{
struct _mema_block *b = NULL;
abort_if_null(ctx);
b = _mema_last_block(ctx);
b->data = malloc(size);
if(!b->data)
ftl("%s", strerror(errno));
b->size = size;
b->nmemb = 1;
b->next = _allocate_next_block(b);
return b->data;
}
// Allocates and initializes memory and adds allocation
// to mema context
void *
_mema_calloc(struct mema_context * ctx, size_t nmemb, size_t size)
{
struct _mema_block *b = NULL;
abort_if_null(ctx);
b = _mema_last_block(ctx);
b->data = calloc(nmemb, size);
if(!b->data)
ftl("%s", strerror(errno));
b->size = size;
b->nmemb = nmemb;
b->next = _allocate_next_block(b);
return b->data;
}
// Frees memory allocated on mema context and deletes
// allocation from context. If no such ptr was found
// on ctx, it does nothing
void
_mema_free(struct mema_context * ctx, void *ptr)
{
struct _mema_block *b = NULL;
abort_if_null(ctx);
b = _mema_find_block(ctx, ptr);
if(!b)
return;
if(b->prev)
b->prev->next = b->next;
if(b->next)
b->next->prev = b->prev;
// In case we are freeing the first block
// on the context, set its next block as
// the new first
if(b == ctx->blocks)
ctx->blocks = b->next;
if(b->data)
free(b->data);
free(b);
}
// Meant from internal use.
// Sets up atexit callback for mema global context
void
_mema_free_on_exit()
{
_mema_free_all(&_mema_global);
initialized = false;
}
// Meant from internal use.
// Initializes global context
void
_mema_global_init()
{
if(initialized)
return;
atexit(_mema_free_on_exit);
clear(&_mema_global);
initialized = true;
}

View File

@ -1,91 +0,0 @@
#ifndef __MEMA_H__
#define __MEMA_H__
#include <stdlib.h>
#include <string.h>
// Garbage collerctor
// Used to allocate memory without having to worry about
// freeing it later
// Local memory allocators, lmema_init needs to be called
// before any of the other functions are called. Before
// returning.
// Initializes local mema context
#define lmema_init() struct mema_context _mema_local = {0}
// malloc using local mema context
#define lmalloc(size) _mema_malloc(&_mema_local, size)
// calloc using local mema context
#define lcalloc(nmemb, size) _mema_calloc(&_mema_local, nmemb, size)
// free using local mema context
#define lfree(ptr) _mema_free(&_mema_local, ptr)
// Frees local mema context
#define lmema_deinit() _mema_free_all(&_mema_local)
// lreturn and lnreturn can be used to instead of return
// to exit a function by first freeing any locally
// allocated memory
// Frees local mema context and returns x
#define lreturn lmema_deinit(); return
// Frees local mema context and returns
#define lnreturn lmema_deinit(); return
// Global memory allocators
// Used to allocate memory on a global context. The data
// will be freed when the program exits (destructor called
// via atexit)
// Initializes global mema context if it wasn't already initialized
#define gmema_init() _mema_global_init()
// malloc call using global mema context
#define gmalloc(size) _mema_malloc(&_mema_global, size)
// calloc call using global mema context
#define gcalloc(nmemb, size) _mema_calloc(&_mema_global, nmemb, size)
// free call using global mema context
#define gfree(ptr) _mema_free(&_mema_global, ptr)
// Meant for internal use.
// All the data allocated on the garbage collector is
// stored as a linked list, which makes freeing kind of
// a pain in the ass, such is life
struct _mema_block
{
void * data;
size_t size;
size_t nmemb;
struct _mema_block * prev, * next;
};
// Garbage collector context
struct mema_context
{
struct _mema_block *blocks;
};
// Meant for internal use.
// Context for the garbage collector global allocations
struct mema_context _mema_global;
void _mema_free_all(struct mema_context * ctx);
void * _mema_last_block(struct mema_context * ctx);
void * _mema_find_block(struct mema_context * ctx, void * ptr);
struct _mema_block * _allocate_next_block(struct _mema_block *r);
void * _mema_malloc(struct mema_context * ctx, size_t size);
void * _mema_calloc(struct mema_context * ctx, size_t nmemb, size_t size);
void _mema_free(struct mema_context * ctx, void *ptr);
void _mema_free_on_exit();
void _mema_global_init();
#endif

View File

@ -1,93 +0,0 @@
#include "shader.h"
#include "log.h"
#include "util.h"
#include "mema.h"
static char* error_log_buffer = NULL;
GLint error_log_lenght = 0;
int
shader_compile(GLuint shader, const char * source, const char * err[])
{
int ret = 0;
gmema_init();
glShaderSource(shader, 1, &source, 0);
glCompileShader(shader);
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &error_log_lenght);
glGetShaderiv(shader, GL_COMPILE_STATUS, &ret);
if(error_log_buffer)
gfree(error_log_buffer);
error_log_buffer = gmalloc(sizeof(*error_log_buffer) * error_log_lenght);
if(error_log_lenght || ret == GL_FALSE)
{
glGetShaderInfoLog(shader, error_log_lenght, NULL, error_log_buffer);
if(err)
*err = error_log_buffer;
return 1;
}
if(err)
*err = NULL;
return 0;
}
GLuint
shader_create_program(GLuint vertext_shader, GLuint fragment_shader)
{
GLuint program = 0;
program = glCreateProgram();
glAttachShader(program, vertext_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
return program;
}
int
shader_create(GLuint * program, const char * vertex_shader_source, const char * fragment_shader_source,
const char * uniforms_name[], int *uniforms_locations, size_t uniform_len)
{
size_t i = 0;
const char *err = NULL;
GLuint vertex_shader = 0, fragment_shader = 0;
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
if(shader_compile(vertex_shader, vertex_shader_source, &err))
{
err("cannot compile vertex shader: %s", err);
return 1;
}
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
if(shader_compile(fragment_shader, fragment_shader_source, &err))
{
glDeleteShader(vertex_shader);
err("cannot compile fragment shader: %s", err);
return 1;
}
*program = shader_create_program(vertex_shader, fragment_shader);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
for(i = 0; i < uniform_len; i++)
{
uniforms_locations[i] = glGetUniformLocation(*program, uniforms_name[i]);
if(uniforms_locations[i] == -1)
{
err("cannot find \"%s\" uniform", uniforms_name[i]);
return 1;
}
}
return 0;
}

View File

@ -1,13 +0,0 @@
#ifndef __SHADER_H__
#define __SHADER_H__
#include <GL/glew.h>
#include <GL/glx.h>
int shader_compile(GLuint shader, const char * source, const char * err[]);
GLuint shader_create_program(GLuint vertext_shader, GLuint fragment_shader);
int shader_create(GLuint * program, const char * vertex_shader_source, const char * fragment_shader_source,
const char * uniforms_name[], int * uniforms_locations, size_t uniform_len);
#endif

View File

@ -1,103 +0,0 @@
#ifndef __UTIL_H__
#define __UTIL_H__
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "mema.h"
#include "log.h"
// General porpuse utilities
// Used all across the code, not really related to any
// particular module
// fatal - ogs out a fatal message and aborts the program
#define ftl(...) {_FORM_LOG(TERM_ERR, "fatal", __VA_ARGS__); abort();}
// Aborts the program if x == NULL while logging
// "[name of the variable holding x] cannot be null"
#define abort_if_null(x) if(x == NULL) {ftl(#x " cannot be null");}
#define swap(X, Y, T) do { T s = X; X = Y; Y = s; } while(0)
#define unused(x) ((void)(x))
#define clear(x) memset((void *)(x), 0, sizeof(*(x)))
#define arrlen(s) (sizeof(s)/sizeof(*s))
#define min(x, y) ((x) <= (y) ? (x) : (y))
#define max(x, y) ((x) >= (y) ? (x) : (y))
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
typedef unsigned int uint;
#endif
static inline uint64_t
time_ms(void)
{
struct timeval current_time = {0};
gettimeofday(&current_time, 0);
return current_time.tv_sec*1000 + current_time.tv_usec/1000;
}
static inline int
msleep(long msec)
{
struct timespec ts;
int res;
if (msec < 0)
{
errno = EINVAL;
return -1;
}
ts.tv_sec = msec / 1000;
ts.tv_nsec = (msec % 1000) * 1000000;
do {
res = nanosleep(&ts, &ts);
} while (res && errno == EINTR);
return res;
}
static inline int
read_file(const char * file_path, char ** data, size_t *size)
{
ssize_t read_size = 0;
FILE * fp = NULL;
extern int errno;
gmema_init();
fp = fopen(file_path, "r");
if(fp == NULL)
return errno;
fseek(fp, 0, SEEK_END);
read_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
*data = gcalloc(read_size + 1, 1);
if(size)
*size = read_size;
while(read_size > 0)
read_size -= fread(*data, sizeof(**data), read_size, fp);
fclose(fp);
return 0;
}
#endif

582
src/wm.c
View File

@ -1,582 +0,0 @@
#include "wm.h"
#include "xerror.h"
#include "mema.h"
#include "util.h"
#ifndef WM_NAME
#define WM_NAME "evwm"
#endif
#define XERROR_MSG_LEN 255
#ifndef XDISPLAY_NAME
#define XDISPLAY_NAME ":4.0"
#endif
typedef struct active_window_t
{
bool defined;
XEvent event;
Window window;
XWindowAttributes attributes;
} active_window_t;
typedef struct wm_t
{
int screen;
Display* display;
Window root_window, check_window;
XWindowAttributes root_window_attributes;
uint modkey;
Atom atoms[atom_no_id];
window_node_t * window_root_node;
active_window_t active_window;
wm_callbacks_t callbacks;
} wm_t;
static wm_t wm;
static int
wm_display_error( void )
{
return x_get_error_code(wm.display);
}
static const char*
wm_display_error_str( void )
{
static char m[XERROR_MSG_LEN] = {0};
x_get_error_str(wm.display, m, arrlen(m));
return m;
}
static inline bool
has_active_window( void )
{
return wm.active_window.defined;
}
static int
set_active_window( Window window, XEvent event )
{
active_window_t active = {0};
if(window == wm.root_window)
return 1;
active.defined = true;
active.window = window;
active.event = event;
wm_get_window_attributes(window, &active.attributes);
wm.active_window = active;
return 0;
}
static inline void
clear_active_window( void )
{
clear(&wm.active_window);
}
static void
window_grab_buttons(Window window)
{
int err = 0;
err = XGrabButton(
wm.display,
AnyButton,
AnyModifier,
window,
True,
ButtonPressMask|ButtonReleaseMask|ButtonMotionMask,
GrabModeAsync,
GrabModeAsync,
None,
None
);
if(err == BadCursor || err == BadValue || err == BadWindow)
ftl("cannot grab buttons for window %lu: %s", window, x_get_error_name(err));
}
static int
count_windows( void )
{
int count = 0;
window_node_t * wn = NULL;
wn = wm.window_root_node;
for(; wn && wn->next != NULL; wn = wn->next)
count++;
return count;
}
static void
update_client_list( void )
{
lmema_init();
int i = 0, client_count = 0;
Window *client_list = NULL;
window_node_t * wn = NULL;
client_count = count_windows();
client_list = lcalloc(client_count, sizeof(Window));
wn = wm.window_root_node;
for(; wn && wn->next != NULL; wn = wn->next)
client_list[i++] = wn->window;
XChangeProperty(wm.display, wm.root_window,
wm.atoms[net_client_list], XA_WINDOW, 32, PropModeReplace,
(unsigned char*) client_list, client_count);
lnreturn;
}
static window_node_t *
find_window(Window window)
{
window_node_t * wn = NULL;
wn = wm.window_root_node;
for(; wn != NULL; wn = wn->next)
if(wn->window == window) break;
return wn;
}
static struct window_node_t *
add_window(Window window)
{
window_node_t * wn = NULL, * nw = NULL;
wn = find_window(window);
if(wn)
{
dbg("window (id: %lu) already on list", window);
return wn;
}
wn = wm.window_root_node;
for(; wn && wn->next != NULL; wn = wn->next);
nw = gcalloc(1, sizeof(window_node_t));
// If you are adding the root window
if(wm.window_root_node == NULL)
{
wm.window_root_node = nw;
XSelectInput(wm.display, window, SubstructureNotifyMask |
PointerMotionMask | ButtonMotionMask | ButtonPressMask |
ButtonReleaseMask);
}
// If you are not
else
{
wn->next = nw;
XSelectInput(wm.display, window, FocusChangeMask);
window_grab_buttons(window);
}
nw->prev = wn;
nw->window = window;
update_client_list();
dbg("window (id: %lu) added to list", window);
if(wm.callbacks.on_create_window)
wm.callbacks.on_create_window(nw);
return nw;
}
static void
remove_window(Window window)
{
window_node_t * wn = NULL;
wn = find_window(window);
if(wn == NULL)
{
dbg("window (id: %lu) is not on list", window);
return;
}
if(wn->prev)
wn->prev->next = wn->next;
if(wn->next)
wn->next->prev = wn->prev;
if(wm.window_root_node == wn)
wm.window_root_node = wn->next;
update_client_list();
dbg("window (id: %lu) removed from list", window);
if(wm.callbacks.on_destroy_window)
wm.callbacks.on_destroy_window(wn);
gfree(wn);
}
int
wm_add_window( Window window )
{
return add_window(window) != NULL;
}
int
wm_close_window( Window window )
{
XEvent event = {0};
if(find_window(window) == NULL)
return 1;
event.xclient.type = ClientMessage;
event.xclient.window = window;
event.xclient.message_type = wm.atoms[wm_protocols];
event.xclient.format = 32;
event.xclient.data.l[0] = wm.atoms[wm_delete_window];
event.xclient.data.l[1] = CurrentTime;
XSendEvent(wm.display, window, 0, NoEventMask, &event);
return 0;
}
unsigned int
wm_get_window_count( void )
{
return count_windows();
}
window_node_t *
wm_get_first_window_node( void )
{
if(wm.window_root_node)
return wm.window_root_node->next;
return NULL;
}
int
wm_get_screen( void )
{
return wm.screen;
}
Display *
wm_get_display( void )
{
return wm.display;
}
Window
wm_get_root_window( void )
{
return wm.root_window;
}
Atom
wm_get_atom( atom_id_t id )
{
return id < atom_no_id ? wm.atoms[id] :
wm.atoms[arrlen(wm.atoms)-1];
}
int
wm_kill_window( Window window )
{
return XDestroyWindow(wm.display, window);
}
int
wm_set_callbacks( wm_callbacks_t callbacks )
{
wm.callbacks = callbacks;
return 0;
}
int
wm_init(unsigned int modkey)
{
unused(wm_display_error);
int i = 0;
clear(&wm);
if((wm.display = XOpenDisplay(XDISPLAY_NAME)) == NULL)
ftl("cannot open X11 display");
// Setup X11 error handler
x_register_xerror_handler();
x_attach_display_error(wm.display);
// Get default screen and window
wm.screen = DefaultScreen(wm.display);
wm.root_window = DefaultRootWindow(wm.display);
XGetWindowAttributes(wm.display, wm.root_window,
&wm.root_window_attributes);
// Add root window to the window list
add_window(wm.root_window);
wm.modkey = modkey;
// Setup Atoms
for(i = 0; i < atom_no_id; i++)
{
if(i == net_start)
continue;
wm.atoms[i] = XInternAtom( wm.display, atom_to_str(i), false);
}
// Be nice with EWMH:
// https://specifications.freedesktop.org/wm-spec/1.3/ar01s03.html
// Taken from dwm.c
// Create empty, tiny window to apply the wm atoms spec into
wm.check_window = XCreateSimpleWindow(
wm.display,
wm.root_window,
0, 0, 1, 1, 0, 0, 0
);
// Do the _NET_SUPPORTING_WM_CHECK thing. I'm not gonna lie, I haven't done
// much research on this, so I should get back to this later
XChangeProperty(wm.display, wm.check_window,
wm.atoms[net_supporting_wm_check], XA_WINDOW, 32,
PropModeReplace, (unsigned char *) &wm.check_window, 1);
XChangeProperty(wm.display, wm.root_window,
wm.atoms[net_supporting_wm_check], XA_WINDOW, 32,
PropModeReplace, (unsigned char *) &wm.check_window, 1);
XChangeProperty(wm.display, wm.check_window,
wm.atoms[net_wm_name], wm.atoms[utf8_string], 8,
PropModeReplace, (unsigned char *) WM_NAME, arrlen(WM_NAME));
// Specify _NET_SUPPORTED
XChangeProperty(wm.display, wm.root_window,
wm.atoms[net_wm_supported], XA_ATOM, 32, PropModeReplace,
(unsigned char *)&wm.atoms[net_start + 1], atom_no_id - net_start -1);
return 0;
}
int
wm_destroy( void )
{
window_node_t *node = NULL, *next_node = NULL;
node = wm.window_root_node;
while(node)
{
next_node = node->next;
gfree(node);
node = next_node;
}
if(wm.display)
return XCloseDisplay(wm.display);
clear(&wm);
return 0;
}
int
wm_focus_window( Window window )
{
if(!find_window(window))
{
add_window(window);
}
XSetInputFocus(wm.display, window, RevertToParent, CurrentTime);
XMapRaised(wm.display, window);
dbg("focusing on window %ld", window);
return 0;
}
int
wm_move_window( Window window, int x, int y )
{
int err = 0;
if(window == wm.root_window)
return 0;
if(!find_window(window))
add_window(window);
err = XMoveWindow(wm.display, window, x, y);
return err;
}
static int
button_press_handler(Window window, XEvent xevent)
{
XButtonEvent *event = NULL;
event = &xevent.xbutton;
if(xevent.type == ButtonPress)
{
if(event->state & wm.modkey)
{
set_active_window(window, xevent);
if(window != wm.root_window)
wm_focus_window(window);
switch (event->button)
{
case Button1:
dbg("moving window (id: %lu)", event->window);
break;
case Button3:
dbg("mesizing window (id: %lu)", event->window);
break;
default:
break;
}
}
}
else
clear_active_window();
return 1;
}
int
wm_get_window_attributes( Window window, XWindowAttributes* attributes )
{
return XGetWindowAttributes(wm.display, window, attributes);
}
int
wm_process_events()
{
int ret = 0;
window_node_t * node = NULL;
XEvent event = {0};
Window window = 0;
static XEvent previous_event = {0};
if(XPending(wm.display) < 1)
return 0;
ret = XNextEvent(wm.display, &event);
if(ret != Success)
{
err("cannot process event: %s", wm_display_error_str());
return 1;
}
if(previous_event.type != event.type &&
previous_event.xany.window == event.xany.window)
{
dbg("received \"%s\" on window (id: %ld)", x_get_event_name(event.type), event.xany.window);
previous_event = event;
}
window = x_get_event_window(event);
if(window == wm.root_window)
return 0;
if(window)
node = find_window(window);
switch(event.type)
{
case CreateNotify:
{
if(!window)
break;
add_window(window);
wm_focus_window(window);
dbg("received create event for window (id: %lu)", window);
break;
}
case DestroyNotify:
{
if(!window)
break;
remove_window(window);
dbg("received destroy event for window (id: %lu)", window);
break;
}
case ButtonPress:
case ButtonRelease:
{
window_node_t * node = NULL;
if(!(node = find_window(event.xbutton.window)))
{
dbg("adding unregistered window (id: %lu) to list",
event.xbutton.window);
add_window(event.xbutton.window);
}
if(button_press_handler(node->window, event))
XAllowEvents(wm.display, ReplayPointer, CurrentTime);
else
XAllowEvents(wm.display, SyncPointer, CurrentTime);
}
case MotionNotify:
{
if(wm.active_window.window != window)
break;
wm_move_window(window,
event.xmotion.x_root - wm.active_window.event.xbutton.x,
event.xmotion.y_root- wm.active_window.event.xbutton.y);
XGetWindowAttributes(wm.display, window, &node->attributes);
}
case ConfigureNotify:
case MapNotify:
case UnmapNotify:
{
node = find_window(window);
XGetWindowAttributes(wm.display, window, &node->attributes);
}
default:
break;
}
return 0;
}

View File

@ -1,57 +0,0 @@
#ifndef __WM_H__
#define __WM_H__
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include "atoms.h"
typedef struct window_node_t
{
void *extra;
Window window;
XWindowAttributes attributes;
struct window_node_t * prev, * next;
} window_node_t;
typedef struct wm_callbacks_t
{
void (*on_destroy_window)(window_node_t * node);
void (*on_create_window)(window_node_t * node);
} wm_callbacks_t;
int wm_init( unsigned int modkey );
int wm_destroy( void );
int wm_set_callbacks( wm_callbacks_t callbacks );
int wm_get_screen( void );
Display * wm_get_display( void );
Window wm_get_root_window( void );
int wm_get_display_error( void );
const char wm_get_display_error_str( void );
Atom wm_get_atom( atom_id_t id );
unsigned int wm_get_window_count( void );
window_node_t * wm_get_first_window_node( void );
int wm_add_window( Window window );
int wm_close_window( Window window );
int wm_kill_window( Window window );
int wm_process_events( void );
int wm_get_window_attributes( Window window, XWindowAttributes* attributes );
int wm_focus_window( Window window );
int wm_move_window( Window window, int x, int y );
#endif

View File

@ -1,307 +0,0 @@
#include "xerror.h"
#include <string.h>
#include "util.h"
#include "mema.h"
struct display_error_ev_t
{
Display *display;
XErrorEvent event;
struct display_error_ev_t *next;
};
static struct display_error_ev_t *display_errors = NULL;
const static char *
XEVENT_NAMES[LASTEvent] =
{
[KeyPress] = "KeyPress",
[KeyRelease] = "KeyRelease",
[ButtonPress] = "ButtonPress",
[ButtonRelease] = "ButtonRelease",
[MotionNotify] = "MotionNotify",
[EnterNotify] = "EnterNotify",
[LeaveNotify] = "LeaveNotify",
[FocusIn] = "FocusIn",
[FocusOut] = "FocusOut",
[KeymapNotify] = "KeymapNotify",
[Expose] = "Expose",
[GraphicsExpose] = "GraphicsExpose",
[NoExpose] = "NoExpose",
[VisibilityNotify] = "VisibilityNotify",
[CreateNotify] = "CreateNotify",
[DestroyNotify] = "DestroyNotify",
[UnmapNotify] = "UnmapNotify",
[MapNotify] = "MapNotify",
[MapRequest] = "MapRequest",
[ReparentNotify] = "ReparentNotify",
[ConfigureNotify] = "ConfigureNotify",
[ConfigureRequest] = "ConfigureRequest",
[GravityNotify] = "GravityNotify",
[ResizeRequest] = "ResizeRequest",
[CirculateNotify] = "CirculateNotify",
[CirculateRequest] = "CirculateRequest",
[PropertyNotify] = "PropertyNotify",
[SelectionClear] = "SelectionClear",
[SelectionRequest] = "SelectionRequest",
[SelectionNotify] = "SelectionNotify",
[ColormapNotify] = "ColormapNotify",
[ClientMessage] = "ClientMessage",
[MappingNotify] = "MappingNotify",
[GenericEvent] = "GenericEvent"
};
const static char *
XERROR_NAME[LastExtensionError] =
{
[Success] = "Success",
[BadRequest] = "BadRequest",
[BadValue] = "BadValue",
[BadWindow] = "BadWindow",
[BadPixmap] = "BadPixmap",
[BadAtom] = "BadAtom",
[BadCursor] = "BadCursor",
[BadFont] = "BadFont",
[BadMatch] = "BadMatch",
[BadDrawable] = "BadDrawable",
[BadAccess] = "BadAccess",
[BadAlloc] = "BadAlloc",
[BadColor] = "BadColor",
[BadGC] = "BadGC",
[BadIDChoice] = "BadIDChoice",
[BadName] = "BadName",
[BadLength] = "BadLength",
[BadImplementation] = "BadImplementation"
};
// Find the display error given display d. If error was not
// found, return NULL
static inline struct display_error_ev_t*
find_display_error(Display *d)
{
struct display_error_ev_t *de = display_errors;
while(de)
if((void*)de->display == (void*)d)
break;
return de;
}
// X11 error handler. For now we just want it
// to set error_event and to attach a display to the chain if
// it's not already there
static int
x_error_handler(Display *d, XErrorEvent *e)
{
struct display_error_ev_t *de = NULL;
de = find_display_error(d);
if(!de)
{
x_attach_display_error(d);
// I know this is not efficient, but it's nice to double check
de = find_display_error(d);
}
de->event = *e;
return 0;
}
// Returns the last error code emitted for display
int
x_get_error_code(Display * display)
{
struct display_error_ev_t *de = NULL;
de = find_display_error(display);
if(!de)
return -1;
return de->event.error_code;
}
const char *
x_get_event_name(int event_type)
{
if(event_type >= arrlen(XEVENT_NAMES))
return "UNKNOWN";
return XEVENT_NAMES[event_type];
}
Window
x_get_event_window( XEvent event )
{
switch (event.type)
{
case KeyPress:
case KeyRelease:
return event.xkey.window;
case ButtonRelease:
case ButtonPress:
return event.xbutton.window;
case MotionNotify:
return event.xmotion.window;
case EnterNotify:
case LeaveNotify:
return event.xcrossing.window;
return event.xcrossing.window;
case FocusIn:
case FocusOut:
return event.xfocus.window;
case KeymapNotify:
return event.xkeymap.window;
case Expose:
return event.xexpose.window;
case VisibilityNotify:
return event.xvisibility.window;
case CreateNotify:
return event.xcreatewindow.window;
case DestroyNotify:
return event.xdestroywindow.window;
case UnmapNotify:
return event.xunmap.window;
case MapNotify:
return event.xmap.window;
case MapRequest:
return event.xmaprequest.window;
case ReparentNotify:
return event.xreparent.window;
case ConfigureNotify:
return event.xconfigure.window;
case ConfigureRequest:
return event.xconfigurerequest.window;
case GravityNotify:
return event.xgravity.window;
case ResizeRequest:
return event.xresizerequest.window;
case CirculateNotify:
return event.xcirculate.window;
case CirculateRequest:
return event.xcirculaterequest.window;
case PropertyNotify:
return event.xproperty.window;
case SelectionClear:
return event.xselectionclear.window;
case ColormapNotify:
return event.xcolormap.window;
case ClientMessage:
return event.xclient.window;
case MappingNotify:
return event.xmapping.window;
default:
return 0;
}
}
const char *
x_get_error_name(int error_name)
{
if(error_name >= arrlen(XERROR_NAME))
return "UNKNOWN";
return XERROR_NAME[error_name];
}
// Writes into buffer the last error received from display.
// Can only work if x_attach_display_error was called on display beforehand
int
x_get_error_str(Display *display, char * buffer, size_t lenght)
{
const char *default_msg = "None";
struct display_error_ev_t *de = NULL;
if(!display)
return -1;
// Copy the default message into buffer
memcpy(buffer, (void *)default_msg, min(lenght*sizeof(*buffer),
sizeof(default_msg)));
de = find_display_error(display);
// If the display was registered, copy the error string into
// buffer
if(de)
{
XGetErrorText(
display,
de->event.error_code,
buffer,
lenght*sizeof(*buffer)
);
return 0;
}
return -1;
}
// Attaches display to error event chain. You should call this on
// display before calling x_get_error_str
void
x_attach_display_error(Display *display)
{
struct display_error_ev_t *de = display_errors, *ne = NULL;
gmema_init();
abort_if_null(display);
if(find_display_error(display))
return;
ne = gcalloc(1, sizeof(*display_errors));
ne->display = display;
if(!de)
{
display_errors = ne;
return;
}
else
{
while(de->next)
de = de->next;
de->next = ne;
}
XSynchronize(display, 0);
}
// Attaches the interal error handler to X11
// Needs to be called in order to receive any errors from X11
void
x_register_xerror_handler()
{
XSetErrorHandler(x_error_handler);
}

View File

@ -1,16 +0,0 @@
#ifndef __XERROR_H__
#define __XERROR_H__
#include <X11/Xlib.h>
void x_register_xerror_handler();
void x_attach_display_error(Display *Display);
Window x_get_event_window(XEvent event);
const char * x_get_event_name(int event_type);
const char * x_get_error_name(int error_type);
int x_get_error_code(Display * display);
int x_get_error_str(Display *display, char * buffer, size_t lenght);
#endif

48
utils.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#include <stdlib.h>
#include "log.h"
#ifndef uint
#define uint unsigned int
#endif
#define ftl(...) {__ftl(__VA_ARGS__); abort();}
#define abort_if_null(x) if(x == NULL) {ftl(#x " cannot be null");}
#define ABS(X) ((X) < 0 ? (-X) : (X))
#define SWAP(X, Y, T) do { T s = X; X = Y; Y = s; } while(0)
#define UNUSED(x) ((void)(x))
#define CLEAR(x) memset((void *)(x), 0, sizeof(*(x)))
#define DYNAMIC_ARRAY(NAME, T) \
typedef struct NAME { \
T *data; \
size_t used; \
size_t reserved; \
} NAME; \
static inline void init_##NAME(NAME *v) { \
v->data = NULL; v->used = v->reserved = 0; \
} \
static inline void reserve_##NAME(NAME *v, size_t n) { \
v->reserved += n; \
v->data = (T *)realloc(v->data, v->reserved*sizeof(T)); \
} \
static inline void shrink_##NAME(NAME *v) { \
v->reserved = v->used; \
v->data = (T *)realloc(v->data, v->reserved*sizeof(T)); \
} \
static inline void append_##NAME(NAME *v, T *t) { \
if(v->reserved <= v->used) \
reserve_##NAME(v, 1); \
v->data[v->used++] = *t; \
} \
static inline void free_##NAME(NAME *v) { \
free(v->data); \
memset(v, 0, sizeof(T)); \
}
#endif