Compare commits
No commits in common. "main" and "master" have entirely different histories.
|
@ -1,11 +0,0 @@
|
|||
evwm
|
||||
.vscode/*
|
||||
bin/
|
||||
obj/
|
||||
debug/
|
||||
*.pdf
|
||||
|
||||
!.vscode/launch.json
|
||||
!.vscode/tasks.json
|
||||
|
||||
research/render_triangle
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
},
|
||||
]
|
||||
}
|
71
Makefile
71
Makefile
|
@ -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)
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
#include "mema.h"
|
||||
|
||||
// Global context for memory allocations
|
||||
static struct
|
||||
_mema_context _gbl_context;
|
||||
|
||||
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
# ROCK64
|
||||
- https://www.olimex.com/Products/SOM/RK3328/RK3328-SOM-1G/
|
||||
- https://wiki.pine64.org/wiki/ROCK64
|
|
@ -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);
|
||||
}
|
||||
|
20
src/atoms.c
20
src/atoms.c
|
@ -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"
|
||||
};
|
41
src/atoms.h
41
src/atoms.h
|
@ -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
621
src/cm.c
|
@ -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;
|
||||
}
|
20
src/cm.h
20
src/cm.h
|
@ -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
|
38
src/fmath.h
38
src/fmath.h
|
@ -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;
|
||||
}
|
689
src/geometry.c
689
src/geometry.c
|
@ -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;
|
||||
}
|
135
src/geometry.h
135
src/geometry.h
|
@ -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
|
21
src/log.c
21
src/log.c
|
@ -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
|
||||
);
|
||||
}
|
72
src/log.h
72
src/log.h
|
@ -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
|
51
src/main.c
51
src/main.c
|
@ -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;
|
||||
}
|
193
src/mema.c
193
src/mema.c
|
@ -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;
|
||||
}
|
91
src/mema.h
91
src/mema.h
|
@ -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
|
93
src/shader.c
93
src/shader.c
|
@ -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;
|
||||
}
|
13
src/shader.h
13
src/shader.h
|
@ -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
|
103
src/util.h
103
src/util.h
|
@ -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(¤t_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
582
src/wm.c
|
@ -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;
|
||||
}
|
57
src/wm.h
57
src/wm.h
|
@ -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
|
307
src/xerror.c
307
src/xerror.c
|
@ -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);
|
||||
}
|
16
src/xerror.h
16
src/xerror.h
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue