Vinicius Teshima hai 1 ano
pai
achega
ca608b2051
Modificáronse 8 ficheiros con 680 adicións e 49 borrados
  1. 36 2
      shaders/font.frag
  2. 40 4
      shaders/font.vert
  3. 48 12
      src/app.h
  4. 4 2
      src/font.h
  5. 230 26
      src/main.c
  6. 24 0
      src/texture.h
  7. 155 3
      src/vec2.h
  8. 143 0
      src/vec4.h

+ 36 - 2
shaders/font.frag

@@ -1,6 +1,40 @@
 #version 330 core
 
+#define FONT_WIDTH 128
+#define FONT_HEIGHT 64
+#define FONT_COLS 18
+#define FONT_ROWS 7
+#define FONT_CH_W (FONT_WIDTH  / FONT_COLS)
+#define FONT_CH_H (FONT_HEIGHT / FONT_ROWS)
+#define FONT_CH_W_UV (float(FONT_CH_W) / float(FONT_WIDTH))
+#define FONT_CH_H_UV (float(FONT_CH_H) / float(FONT_HEIGHT))
+
+uniform sampler2D font;
+uniform float time;
+
+flat in int glyph_c;
+in vec4 glyph_fg_color;
+in vec4 glyph_bg_color;
+in vec2 uv;
+
 void main() {
-  vec2 uv = gl_FragCoord.xy / (vec2(800.0, 600.0) * 2);
-  gl_FragColor = vec4(uv.x, uv.y, 0.0, 1.0);
+  int c = glyph_c;
+  if ( ! (c >= 32 && c <= 126) ) {
+    c = 63;
+  }
+
+  int index = c - 32;
+  float x = float(index % FONT_COLS) * FONT_CH_W_UV;
+  float y = float(index / FONT_COLS) * FONT_CH_H_UV;
+
+  vec2 ch_size = vec2(FONT_CH_W_UV, -FONT_CH_H_UV);
+  vec2 pos = vec2(x, y + FONT_CH_H_UV);
+  vec2 uv_ = vec2(uv.x, uv.y);
+
+  vec4 t = texture(font, pos + ch_size * uv_);
+  gl_FragColor = glyph_bg_color * (1.0 - t.x) + t.x * glyph_fg_color;
+    // * vec4((sin(uv.x + time) + 1.0) / 2.0,
+    // 	   (cos(uv.y + time) + 1.0) / 2.0,
+    // 	   (sin(uv.x + uv.y + time) + 1.0) / 2.0,
+    // 	   1);
 }

+ 40 - 4
shaders/font.vert

@@ -1,9 +1,45 @@
 #version 330 core
 
+#define FONT_WIDTH 128
+#define FONT_HEIGHT 64
+#define FONT_COLS 18
+#define FONT_ROWS 7
+#define FONT_CH_W (FONT_WIDTH / FONT_COLS)
+#define FONT_CH_H (FONT_HEIGHT / FONT_ROWS)
 
-void main() {
-  float x = float(gl_VertexID & 1);
-  float y = float((gl_VertexID >> 1) & 1);
+uniform float scale;
+uniform vec2 resolution;
+uniform ivec2 cursor;
 
-  gl_Position = vec4(x - 0.5, y - 0.5, 0.0, 1.0);
+layout(location = 0) in ivec2 tile;
+layout(location = 1) in int c;
+layout(location = 2) in vec4 color;
+
+out vec2 uv;
+flat out int glyph_c;
+out vec4 glyph_fg_color;
+out vec4 glyph_bg_color;
+
+vec2 project_point(vec2 point)
+{
+  return (2.0 * point) / resolution;
+}
+
+void main()
+{
+  uv = vec2(float(gl_VertexID & 1),
+	    float((gl_VertexID >> 1) & 1));
+
+  vec2 char_size = vec2(float(FONT_CH_W), float(FONT_CH_H));
+  vec2 pos = tile * char_size * scale;
+  gl_Position = vec4(project_point(uv * char_size * scale + pos), 0.0, 1.0);
+
+  glyph_c = c;
+  glyph_fg_color = color;
+  glyph_bg_color = vec4(0);
+
+  if ( tile == cursor ) {
+    glyph_fg_color = vec4(0);
+    glyph_bg_color = vec4(1);
+  }
 }

+ 48 - 12
src/app.h

@@ -24,6 +24,12 @@ struct app {
 		uint8_t tab_size;
 	} cfg;
 	bool show_fps;
+	struct {
+		int32_t time;
+		int32_t resolution;
+		int32_t scale;
+		int32_t cursor;
+	} uniforms;
 };
 
 struct app app_create(const char *win_title);
@@ -48,6 +54,8 @@ void MessageCallback(GLenum source, GLenum type, GLuint id,
 		     GLenum severity, GLsizei length,
 		     const GLchar *msg, const void *up);
 
+struct vec2i app_calc_cursor(struct app app);
+
 #if defined(APP_IMP) || defined(IMP)
 
 #define UNHEX_COLOR(hex)			\
@@ -65,17 +73,6 @@ app_create(const char *win_title)
 {
 	SCE(SDL_Init(SDL_INIT_VIDEO));
 
-	struct app app = {
-		.win = window_create(win_title),
-		.rdr = NULL,
-		.running = true,
-		.buf = buffer_create(),
-		.cfg = {
-			.tab_size = 8
-		},
-		.target_fps = 120,
-	};
-
 	{
 		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
 		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
@@ -90,6 +87,22 @@ app_create(const char *win_title)
 		printf("GL Version: %d.%d\n", major, minor);
 	}
 
+	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, GL_DOUBLEBUFFER);
+	SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
+	SDL_GL_SetSwapInterval(0);
+
+	struct app app = {
+		.win = window_create(win_title),
+		.rdr = NULL,
+		.running = true,
+		.buf = buffer_create(),
+		.cfg = {
+			.tab_size = 8
+		},
+		.target_fps = 120,
+	};
+
+
 	app.glctx = SDL_GL_CreateContext(app.win.ptr);
 	SCP(app.glctx);
 
@@ -101,12 +114,24 @@ app_create(const char *win_title)
 	glEnable(GL_BLEND);
 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
+	if ( ! GLEW_ARB_draw_instanced ) {
+		fprintf(stderr,
+			"WARNING! GLEW_ARB_draw_instanced is not availible\n");
+		exit(EXIT_FAILURE);
+	}
+	if ( ! GLEW_ARB_instanced_arrays ) {
+		fprintf(stderr,
+			"WARNING! GLEW_ARB_instanced_arrays"
+			" is not availible\n");
+		exit(EXIT_FAILURE);
+	}
+
 	if ( GLEW_ARB_debug_output ) {
 		glEnable(GL_DEBUG_OUTPUT);
 		glDebugMessageCallback(MessageCallback, 0);
 	} else {
 		fprintf(stderr,
-			"WARNING! GLEW_ARB_debug_output is not availible");
+			"WARNING! GLEW_ARB_debug_output is not availible\n");
 	}
 
 	/* app.rdr = SDL_CreateRenderer(app.win.ptr, -1, SDL_RENDERER_ACCELERATED); */
@@ -331,6 +356,17 @@ MessageCallback(GLenum source, GLenum type, GLuint id,
 		type, severity, msg);
 }
 
+struct vec2i
+app_calc_cursor(struct app app)
+{
+	size_t row, col;
+	RET_UNWRAP2(col, row,
+		    struct ret_size_t_size_t, buffer_calc_cur_pos(app.buf));
+
+	return vec2i((int32_t)col, (int32_t)row);
+}
+
+
 #endif /* defined(APP_IMP) || defined(IMP) */
 
 #endif

+ 4 - 2
src/font.h

@@ -39,8 +39,10 @@ font_create(SDL_Renderer *rdr, const char *filepath,
 
 	SDL_SetColorKey(f.sur, SDL_TRUE, 0x00000000);
 
-	f.tex = SDL_CreateTextureFromSurface(rdr, f.sur);
-	SCP(f.tex);
+	if ( rdr != NULL ) {
+		f.tex = SDL_CreateTextureFromSurface(rdr, f.sur);
+		SCP(f.tex);
+	}
 
 	f.w = (uint32_t) f.sur->w;
 	f.h = (uint32_t) f.sur->h;

+ 230 - 26
src/main.c

@@ -24,6 +24,7 @@
 #define IMP
 #include "app.h"
 #include "vec2.h"
+#include "vec4.h"
 #include "da.h"
 #include "unwrap.h"
 #include "file.h"
@@ -33,64 +34,263 @@
 
 struct app handle_events(struct app app);
 
+struct glyph {
+	struct vec2i tile;
+	int32_t c;
+	struct vec4f color;
+};
+
+DA_DEF_STRUCT(struct glyph, glyphs);
+
+struct glyph_attr {
+	GLint size;
+	GLenum type;
+	GLboolean norm;
+	GLsizei stride;
+	size_t offset;
+};
+
+enum glyph_attr_enum {
+	GLYPH_ATTR_TILE = 0,
+	GLYPH_ATTR_C,
+	GLYPH_ATTR_COLOR,
+	GLYPH_ATTR_TOTAL
+};
+
+static const struct glyph_attr glyph_attr[GLYPH_ATTR_TOTAL] = {
+	[GLYPH_ATTR_TILE] = {
+		.size = 2,
+		.type = GL_INT,
+		.norm = GL_FALSE,
+		.stride = sizeof(struct glyph),
+		.offset = offsetof(struct glyph, tile)
+	},
+	[GLYPH_ATTR_C] = {
+		.size = 1,
+		.type = GL_INT,
+		.norm = GL_FALSE,
+		.stride = sizeof(struct glyph),
+		.offset = offsetof(struct glyph, c)
+	},
+	[GLYPH_ATTR_COLOR] = {
+		.size = 4,
+		.type = GL_FLOAT,
+		.norm = GL_FALSE,
+		.stride = sizeof(struct glyph),
+		.offset = offsetof(struct glyph, color)
+	},
+};
+
+struct glyphs gl_render_text(struct app app, struct glyphs glys,
+			     struct vec2i tile);
+void glyphs_sync(struct app app, struct glyphs glys);
+
+int32_t get_uniform(uint32_t prog, const char *name);
+
 int32_t
 main(int32_t argc, char **argv)
 {
 	(void) argc; (void) argv;
 
 	struct app app = app_create("ged");
-	/* const char *font_path = "./charmap-oldschool_white.png"; */
-	/* app.font = font_create(app.rdr, font_path, 7, 18); */
-	/* app.font.scale = 2.0; */
+	const char *font_path = "./charmap-oldschool_white.png";
+	app.font = font_create(app.rdr, font_path, 7, 18);
+	app.font.scale = 2.0;
+
+	struct glyphs glys;
+	glys.cap = 1024;
+	glys.size = 0;
+	glys.items = calloc(glys.cap, sizeof(struct glyph));
 
 	enum shader_err err;
 
+	uint32_t prog;
 	uint32_t vert_shader;
 	uint32_t frag_shader;
 
-	RET_UNWRAP2(vert_shader, err, struct ret_uint32_t_err,
-		    shader_compile_file("./shaders/font.vert",
-					GL_VERTEX_SHADER));
-	if ( err != SHADER_ERR_OK ) {
-		fprintf(stderr, "Failed to compile shader font.vert\n");
-		exit(EXIT_FAILURE);
+	/* Loading shaders and linking prog */
+	{
+		RET_UNWRAP2(vert_shader, err, struct ret_uint32_t_err,
+			    shader_compile_file("./shaders/font.vert",
+						GL_VERTEX_SHADER));
+		if ( err != SHADER_ERR_OK ) {
+			fprintf(stderr, "Failed to compile shader font.vert\n");
+			exit(EXIT_FAILURE);
+		}
+
+		RET_UNWRAP2(frag_shader, err, struct ret_uint32_t_err,
+			    shader_compile_file("./shaders/font.frag",
+						GL_FRAGMENT_SHADER));
+		if ( err != SHADER_ERR_OK ) {
+			fprintf(stderr, "Failed to compile shader font.frag\n");
+			exit(EXIT_FAILURE);
+		}
+
+		RET_UNWRAP2(prog, err, struct ret_uint32_t_err,
+			    program_link(vert_shader, frag_shader));
+		if ( err != SHADER_ERR_OK ) {
+			fprintf(stderr, "Failed to link program\n");
+			exit(EXIT_FAILURE);
+		}
 	}
 
-	RET_UNWRAP2(frag_shader, err, struct ret_uint32_t_err,
-		    shader_compile_file("./shaders/font.frag",
-					GL_FRAGMENT_SHADER));
-	if ( err != SHADER_ERR_OK ) {
-		fprintf(stderr, "Failed to compile shader font.frag\n");
-		exit(EXIT_FAILURE);
+	glUseProgram(prog);
+
+	uint32_t font_tex = 0;
+	/* Init Font Texture */
+	{
+		int32_t w, h, n;
+		uint8_t *data = stbi_load(font_path,
+					  &w, &h, &n,
+					  STBI_rgb_alpha);
+
+		if ( data == NULL ) {
+			fprintf(stderr, "ERROR loading file %s: %s",
+				font_path, stbi_failure_reason());
+			exit(EXIT_FAILURE);
+		}
+
+		glActiveTexture(GL_TEXTURE0);
+		glGenTextures(1, &font_tex);
+		glBindTexture(GL_TEXTURE_2D, font_tex);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+				GL_NEAREST);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+				GL_NEAREST);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+				GL_CLAMP_TO_EDGE);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+				GL_CLAMP_TO_EDGE);
+
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h,
+			     0, GL_RGBA, GL_UNSIGNED_BYTE,
+			     data);
 	}
 
-	uint32_t prog;
-	RET_UNWRAP2(prog, err, struct ret_uint32_t_err,
-		    program_link(vert_shader, frag_shader));
-	if ( err != SHADER_ERR_OK ) {
-		fprintf(stderr, "Failed to link program\n");
+	/* Getting the uniforms */
+	/* app.uniforms.time = get_uniform(prog, "time"); */
+	app.uniforms.resolution = get_uniform(prog, "resolution");
+	app.uniforms.scale = get_uniform(prog, "scale");
+	app.uniforms.cursor = get_uniform(prog, "cursor");
+
+	uint32_t vao = 0;
+	uint32_t vbo = 0;
+
+	/* Initialized array */
+	{
+		glGenVertexArrays(1, &vao);
+		glBindVertexArray(vao);
+
+		glGenBuffers(1, &vbo);
+		glBindBuffer(GL_ARRAY_BUFFER, vbo);
+		glBufferData(GL_ARRAY_BUFFER,
+			     (ssize_t)(glys.cap * sizeof(struct glyph)),
+			     glys.items,
+			     GL_DYNAMIC_DRAW);
+
+		for ( size_t i = 0; i < GLYPH_ATTR_TOTAL; ++i ) {
+			struct glyph_attr ga = glyph_attr[i];
+			glEnableVertexAttribArray((uint32_t) i);
+			switch ( ga.type ) {
+			case GL_FLOAT: {
+				glVertexAttribPointer((uint32_t) i,
+						      ga.size, ga.type,
+						      ga.norm, ga.stride,
+						      (void*)ga.offset);
+			} break;
+			case GL_INT: {
+				glVertexAttribIPointer((uint32_t) i,
+						       ga.size, ga.type,
+						       ga.stride,
+						       (void*)ga.offset);
+			} break;
+			}
+			glVertexAttribDivisor((uint32_t) i, 1);
+		}
+
+	}
+
+	enum buffer_err err_;
+	RET_UNWRAP2(app.buf, err_,
+		    struct ret_buffer_err,
+		    buffer_load_from_file(app.buf, "./m.c"));
+	if ( err_ != BUFFER_ERR_OK ) {
+		fprintf(stderr, "Failed to read load buffer: %d\n", err_);
 		exit(EXIT_FAILURE);
 	}
 
-	glUseProgram(prog);
-	uint32_t vao = 0;
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
+	glys = gl_render_text(app, glys, vec2is(0));
+	glyphs_sync(app, glys);
 
+	struct vec2i cur = app_calc_cursor(app);
+	glUniform1f(app.uniforms.scale, 5.0);
 	while ( app.running ) {
 		app = handle_events(app);
 
-		glClearColor(0.0, 0.0, 0.0, 1.0);
+		glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
 		glClear(GL_COLOR_BUFFER_BIT);
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+		glDrawArraysInstanced(GL_TRIANGLE_STRIP,
+				      0, 4,
+				      (int32_t) glys.size);
+
+		/* glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); */
 
 		SDL_GL_SwapWindow(app.win.ptr);
+		/* glUniform1f(app.uniforms.time, */
+		/* 	    (float) (SDL_GetTicks() / 1000)); */
+		cur = app_calc_cursor(app);
+		glUniform2i(app.uniforms.cursor, cur.x, cur.y);
 	}
 
 	app_destroy(app);
 	exit(EXIT_SUCCESS);
 }
 
+struct glyphs
+gl_render_text(struct app app, struct glyphs glys, struct vec2i tile)
+{
+	struct vec2i pen = tile;
+	int32_t row = 0;
+	for ( size_t i = 0; i < app.buf.data.size; ++i ) {
+		char c = app.buf.data.items[i];
+		if ( c == '\n' ) {
+			pen.y -= 1;
+			row = 0;
+			continue;
+		}
+		struct glyph gly = {
+			.tile = vec2i_add(pen, vec2i(row, 0)),
+			.c = c,
+			.color = vec4fs(1)
+		};
+		DA_APPEND(glys, gly);
+		++row;
+	}
+	return glys;
+}
+
+void
+glyphs_sync(struct app app, struct glyphs glys)
+{
+	(void) app;
+	glBufferSubData(GL_ARRAY_BUFFER,
+			0,
+			(ssize_t) (glys.size * sizeof(struct glyph)),
+			glys.items);
+}
+
+int32_t
+get_uniform(uint32_t prog, const char *name)
+{
+	int32_t uni = glGetUniformLocation(prog, name);
+	if ( uni == -1 ) {
+		fprintf(stderr, "Failed getting %s uniform location\n", name);
+		exit(EXIT_FAILURE);
+	}
+	return uni;
+}
+
 int32_t main2(int32_t argc, char **argv);
 int32_t
 main2(int32_t argc, char **argv)
@@ -224,6 +424,10 @@ handle_events(struct app app)
 		} break;
 		case SDL_WINDOWEVENT: {
 			WINDOW_UP_SIZE(app.win);
+			glUniform2f(app.uniforms.resolution,
+				    (float) app.win.w,
+				    (float) app.win.h);
+			glViewport(0, 0 ,app.win.w, app.win.h);
 		} break;
 		}
 	}

+ 24 - 0
src/texture.h

@@ -0,0 +1,24 @@
+#ifndef TEXTURE_H
+#define TEXTURE_H
+
+GL_Texture create_texture(GLenum unit, bool nearest);
+
+#if defined(TEXTURE_IMP) || defined(IMP)
+
+#include <GL/glew.h>
+
+GL_Texture
+create_texture(GLenum unit, bool nearest)
+{
+	GL_Texture result = {0};
+
+	glActiveTexture(unit);
+
+	glGenTexture(1, &result.id)
+}
+
+
+
+#endif	/* defined(TEXTURE_IMP) || defined(IMP) */
+
+#endif

+ 155 - 3
src/vec2.h

@@ -5,17 +5,50 @@ struct vec2 {
 	double x, y;
 };
 
-
 struct vec2 vec2(double x, double y);
 struct vec2 vec2s(double x);
 
 struct vec2 vec2_add(struct vec2 a, struct vec2 b);
 struct vec2 vec2_sub(struct vec2 a, struct vec2 b);
 struct vec2 vec2_mul(struct vec2 a, struct vec2 b);
+struct vec2 vec2_mul3(struct vec2 a, struct vec2 b, struct vec2 c);
+struct vec2 vec2_mul4(struct vec2 a, struct vec2 b,
+			struct vec2 c, struct vec2 d);
 struct vec2 vec2_div(struct vec2 a, struct vec2 b);
 
+struct vec2f {
+	float x, y;
+};
+
+struct vec2f vec2f(float x, float y);
+struct vec2f vec2fs(float x);
+struct vec2f vec2_to_f(struct vec2 a);
 
-#if defined(BMP_IMP) || defined(IMP)
+struct vec2f vec2f_add(struct vec2f a, struct vec2f b);
+struct vec2f vec2f_sub(struct vec2f a, struct vec2f b);
+struct vec2f vec2f_mul(struct vec2f a, struct vec2f b);
+struct vec2f vec2f_mul3(struct vec2f a, struct vec2f b, struct vec2f c);
+struct vec2f vec2f_mul4(struct vec2f a, struct vec2f b,
+			struct vec2f c, struct vec2f d);
+struct vec2f vec2f_div(struct vec2f a, struct vec2f b);
+
+struct vec2i {
+	int32_t x, y;
+};
+
+struct vec2i vec2i(int32_t x, int32_t y);
+struct vec2i vec2is(int32_t x);
+struct vec2i vec2_to_i(struct vec2 a);
+
+struct vec2i vec2i_add(struct vec2i a, struct vec2i b);
+struct vec2i vec2i_sub(struct vec2i a, struct vec2i b);
+struct vec2i vec2i_mul(struct vec2i a, struct vec2i b);
+struct vec2i vec2i_mul3(struct vec2i a, struct vec2i b, struct vec2i c);
+struct vec2i vec2i_mul4(struct vec2i a, struct vec2i b,
+			struct vec2i c, struct vec2i d);
+struct vec2i vec2i_div(struct vec2i a, struct vec2i b);
+
+#if defined(VEC2_IMP) || defined(IMP)
 
 struct vec2
 vec2(double x, double y) {
@@ -45,12 +78,131 @@ vec2_mul(struct vec2 a, struct vec2 b)
 	return (struct vec2){.x = a.x * b.x, .y = a.y * b.y};
 }
 
+struct vec2
+vec2_mul3(struct vec2 a, struct vec2 b, struct vec2 c)
+{
+	return vec2_mul(vec2_mul(a, b), c);
+}
+
+struct vec2
+vec2_mul4(struct vec2 a, struct vec2 b, struct vec2 c, struct vec2 d)
+{
+	return vec2_mul(vec2_mul3(a, b, c), d);
+}
+
 struct vec2
 vec2_div(struct vec2 a, struct vec2 b)
 {
 	return (struct vec2){.x = a.x / b.x, .y = a.y / b.y};
 }
 
-#endif /* defined(BMP_IMP) || defined(IMP) */
+struct vec2f
+vec2f(float x, float y) {
+	return (struct vec2f) {.x = x, .y = y};
+}
+
+struct vec2f
+vec2fs(float x) {
+	return (struct vec2f) {.x = x, .y = x};
+}
+
+struct vec2f
+vec2_to_f(struct vec2 a)
+{
+	return (struct vec2f) { .x = (float) a.x, .y = (float) a.y };
+}
+
+
+struct vec2f
+vec2f_add(struct vec2f a, struct vec2f b)
+{
+	return (struct vec2f){.x = a.x + b.x, .y = a.y + b.y};
+}
+
+struct vec2f
+vec2f_sub(struct vec2f a, struct vec2f b)
+{
+	return (struct vec2f){.x = a.x - b.x, .y = a.y - b.y};
+}
+
+struct vec2f
+vec2f_mul(struct vec2f a, struct vec2f b)
+{
+	return (struct vec2f){.x = a.x * b.x, .y = a.y * b.y};
+}
+
+struct vec2f
+vec2f_mul3(struct vec2f a, struct vec2f b, struct vec2f c)
+{
+	return vec2f_mul(vec2f_mul(a, b), c);
+}
+
+struct vec2f
+vec2f_mul4(struct vec2f a, struct vec2f b, struct vec2f c, struct vec2f d)
+{
+	return vec2f_mul(vec2f_mul3(a, b, c), d);
+}
+
+struct vec2f
+vec2f_div(struct vec2f a, struct vec2f b)
+{
+	return (struct vec2f){.x = a.x / b.x, .y = a.y / b.y};
+}
+
+
+struct vec2i
+vec2i(int32_t x, int32_t y) {
+	return (struct vec2i) {.x = x, .y = y};
+}
+
+struct vec2i
+vec2is(int32_t x) {
+	return (struct vec2i) {.x = x, .y = x};
+}
+
+struct vec2i
+vec2_to_i(struct vec2 a)
+{
+	return (struct vec2i) { .x = (int32_t) a.x, .y = (int32_t) a.y };
+}
+
+struct vec2i
+vec2i_add(struct vec2i a, struct vec2i b)
+{
+	return (struct vec2i){.x = a.x + b.x, .y = a.y + b.y};
+}
+
+struct vec2i
+vec2i_sub(struct vec2i a, struct vec2i b)
+{
+	return (struct vec2i){.x = a.x - b.x, .y = a.y - b.y};
+}
+
+struct vec2i
+vec2i_mul(struct vec2i a, struct vec2i b)
+{
+	return (struct vec2i){.x = a.x * b.x, .y = a.y * b.y};
+}
+
+struct vec2i
+vec2i_mul3(struct vec2i a, struct vec2i b, struct vec2i c)
+{
+	return vec2i_mul(vec2i_mul(a, b), c);
+}
+
+struct vec2i
+vec2i_mul4(struct vec2i a, struct vec2i b, struct vec2i c, struct vec2i d)
+{
+	return vec2i_mul(vec2i_mul3(a, b, c), d);
+}
+
+struct vec2i
+vec2i_div(struct vec2i a, struct vec2i b)
+{
+	return (struct vec2i){.x = a.x / b.x, .y = a.y / b.y};
+}
+
+
+#endif /* defined(VEC2_IMP) || defined(IMP) */
 
 #endif	/* VEC2_H */

+ 143 - 0
src/vec4.h

@@ -0,0 +1,143 @@
+#ifndef VEC4_H
+#define VEC4_H
+
+struct vec4 {
+	double x, y, z, w;
+};
+
+
+struct vec4 vec4(double x, double y, double z, double w);
+struct vec4 vec4s(double x);
+
+struct vec4 vec4_add(struct vec4 a, struct vec4 b);
+struct vec4 vec4_sub(struct vec4 a, struct vec4 b);
+struct vec4 vec4_mul(struct vec4 a, struct vec4 b);
+struct vec4 vec4_div(struct vec4 a, struct vec4 b);
+
+struct vec4f {
+	float x, y, z, w;
+};
+
+
+struct vec4f vec4f(float x, float y, float z, float w);
+struct vec4f vec4fs(float x);
+
+struct vec4f vec4f_add(struct vec4f a, struct vec4f b);
+struct vec4f vec4f_sub(struct vec4f a, struct vec4f b);
+struct vec4f vec4f_mul(struct vec4f a, struct vec4f b);
+struct vec4f vec4f_div(struct vec4f a, struct vec4f b);
+
+#if defined(VEC4_IMP) || defined(IMP)
+
+struct vec4
+vec4(double x, double y, double z, double w) {
+	return (struct vec4) {.x = x, .y = y, .z = z, .w = w};
+}
+
+struct vec4
+vec4s(double x) {
+	return (struct vec4) {.x = x, .y = x, .z = x, .w = x};
+}
+
+struct vec4
+vec4_add(struct vec4 a, struct vec4 b)
+{
+	return (struct vec4){
+		.x = a.x + b.x,
+		.y = a.y + b.y,
+		.z = a.z + b.z,
+		.w = a.w + b.w
+	};
+}
+
+struct vec4
+vec4_sub(struct vec4 a, struct vec4 b)
+{
+	return (struct vec4){
+		.x = a.x - b.x,
+		.y = a.y - b.y,
+		.z = a.z - b.z,
+		.w = a.w - b.w
+	};
+}
+
+struct vec4
+vec4_mul(struct vec4 a, struct vec4 b)
+{
+	return (struct vec4){
+		.x = a.x * b.x,
+		.y = a.y * b.y,
+		.z = a.z * b.z,
+		.w = a.w * b.w
+	};
+}
+
+struct vec4
+vec4_div(struct vec4 a, struct vec4 b)
+{
+	return (struct vec4){
+		.x = a.x / b.x,
+		.y = a.y / b.y,
+		.z = a.z / b.z,
+		.w = a.w / b.w
+	};
+}
+
+
+struct vec4f
+vec4f(float x, float y, float z, float w) {
+	return (struct vec4f) {.x = x, .y = y, .z = z, .w = w};
+}
+
+struct vec4f
+vec4fs(float x) {
+	return (struct vec4f) {.x = x, .y = x, .z = x, .w = x};
+}
+
+struct vec4f
+vec4f_add(struct vec4f a, struct vec4f b)
+{
+	return (struct vec4f){
+		.x = a.x + b.x,
+		.y = a.y + b.y,
+		.z = a.z + b.z,
+		.w = a.w + b.w
+	};
+}
+
+struct vec4f
+vec4f_sub(struct vec4f a, struct vec4f b)
+{
+	return (struct vec4f){
+		.x = a.x - b.x,
+		.y = a.y - b.y,
+		.z = a.z - b.z,
+		.w = a.w - b.w
+	};
+}
+
+struct vec4f
+vec4f_mul(struct vec4f a, struct vec4f b)
+{
+	return (struct vec4f){
+		.x = a.x * b.x,
+		.y = a.y * b.y,
+		.z = a.z * b.z,
+		.w = a.w * b.w
+	};
+}
+
+struct vec4f
+vec4f_div(struct vec4f a, struct vec4f b)
+{
+	return (struct vec4f){
+		.x = a.x / b.x,
+		.y = a.y / b.y,
+		.z = a.z / b.z,
+		.w = a.w / b.w
+	};
+}
+
+#endif /* defined(VEC4_IMP) || defined(IMP) */
+
+#endif	/* VEC4_H */