commit 41be94b6da3ad67a73189d9e63b8766d3bd1516c
parent c666a97ee9a1201d40402c4f29e1fa8b8dc41e9e
Author: David DiPaola <DavidDiPaola@users.noreply.github.com>
Date: Sun, 3 Jun 2018 12:32:15 -0400
01-perspective: initial commit
ogl: update to latest version
Diffstat:
31 files changed, 1443 insertions(+), 18 deletions(-)
diff --git a/00-triangle.c b/00-triangle.c
@@ -10,7 +10,9 @@ licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/
#include <stdlib.h>
#include <GL/glew.h>
+
#include <GLFW/glfw3.h>
+
#include "ogl/ogl.h"
int
diff --git a/01-perspective-orig.c b/01-perspective-orig.c
@@ -0,0 +1,236 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+#include "ogl/ogl.h"
+
+int
+ogl_program_uniform_set_m4f(
+ GLint program_ID, const char * uniform_name, const float * matrix4by4
+) {
+ GLint uniform_ID = 0;
+ int status = ogl_program_uniform_get_ID(program_ID, uniform_name, &uniform_ID);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ glUniformMatrix4fv(uniform_ID, 1, GL_FALSE, matrix4by4);
+
+ return 0;
+}
+
+struct ogl_vec3f {
+ GLfloat x;
+ GLfloat y;
+ GLfloat z;
+};
+
+int
+ogl_model_set(
+ GLint program_ID, const char * uniform_name
+) {
+ GLfloat model[4*4] = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ };
+ int status = ogl_program_uniform_set_m4f(program_ID, uniform_name, model);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ return 0;
+}
+
+int
+ogl_view_set(
+ GLint program_ID, const char * uniform_name, struct ogl_vec3f location, struct ogl_vec3f direction
+) {
+ GLfloat view[4*4] = /*{
+ location.x, location.y, location.z, 0.0f,
+ direction.x, direction.y, direction.z, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ */
+ {
+ 0.600000, 0.000000, -0.800000, -0.000000,
+ -0.411597, 0.857493, -0.308697, -0.000000,
+ 0.685994, 0.514496, 0.514496, -5.830953,
+ 0.000000, 0.000000, 0.000000, 1.000000,
+ };
+ int status = ogl_program_uniform_set_m4f(program_ID, uniform_name, view);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ return 0;
+}
+
+int
+ogl_projection_set(
+ GLint program_ID, const char * uniform_name, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearVal, GLfloat farVal
+) {
+ GLfloat projection[4*4] = /*{
+ (2*nearVal)/(right-left), 0.0f, (right+left)/(right-left), 0.0f,
+ 0.0f, (2*nearVal)/(top-bottom), (top+bottom)/(top-bottom), 0.0f,
+ 0.0f, 0.0f, (farVal+nearVal)/(farVal-nearVal), (2*farVal*nearVal)/(farVal-nearVal),
+ 0.0f, 0.0f, -1.0f, 0.0f,
+ */
+ {
+ 1.344443, 0.000000, 0.000000, 0.000000,
+ 0.000000, 1.792591, 0.000000, 0.000000,
+ 0.000000, 0.000000, -1.002002, -0.200200,
+ 0.000000, 0.000000, -1.000000, 0.000000,
+ };
+ int status = ogl_program_uniform_set_m4f(program_ID, uniform_name, projection);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ return 0;
+}
+
+
+int
+main() {
+ int status;
+
+ GLFWwindow * window = NULL;
+ status = ogl_init(400, 240, "01 - triangle with perspective", &window);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ const char * vertexshader =
+ "#version 100" "\n"
+#if 0
+ "uniform mat4 model;" "\n"
+ "uniform mat4 view;" "\n"
+ "uniform mat4 projection;" "\n"
+#endif
+ "uniform mat4 MVP;" "\n"
+ "attribute vec4 position;" "\n"
+ "void main(){" "\n"
+ //" gl_Position = projection * view * model * position;" "\n"
+ " gl_Position = MVP * position;" "\n"
+ //" gl_Position = position;" "\n"
+ "}" "\n"
+ ;
+ const char * fragmentshader =
+ "#version 100" "\n"
+ "void main() {" "\n"
+ " gl_FragColor = vec4(1,0,0,1);" "\n"
+ "}" "\n"
+ ;
+ GLuint program_ID = 0;
+ status = ogl_program_build(
+ vertexshader, fragmentshader,
+ &program_ID
+ );
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ GLint program_attribute_position_ID = 0;
+ status = ogl_program_attribute_get_ID(program_ID, "position", &program_attribute_position_ID);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+#if 0
+ status = ogl_model_set(program_ID, "model");
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ struct ogl_vec3f view_location = { .x=4.0f, .y=3.0f, .z=3.0f };
+ struct ogl_vec3f view_direction = { .x=0.0f, .y=0.0f, .z=0.0f };
+ status = ogl_view_set(program_ID, "view", view_location, view_direction);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ status = ogl_projection_set(program_ID, "projection",
+ -100.0f, 100.0f, /* left, right */
+ -100.0f, 100.0f, /* bottom, top */
+ 0.5f, 5.0f /* nearVal, farVal */
+ );
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+#endif
+#if 1
+ GLfloat MVP[4*4] = {
+ 0.806666, 0.000000, -1.075554, 0.000000,
+ -0.737824, 1.537134, -0.553368, 0.000000,
+ -0.687368, -0.515526, -0.515526, 5.642426,
+ -0.685994, -0.514496, -0.514496, 5.830953,
+ };
+ ogl_program_uniform_set_m4f(program_ID, "MVP", MVP);
+#endif
+
+ static const GLfloat triangle_vertex_data[] = {
+ -1.0f, -1.0f, 0.0f,
+ 1.0f, -1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ };
+ GLuint triangle_vertex_buffer_ID = 0;
+ status = ogl_vertex_buffer_load(triangle_vertex_data, sizeof(triangle_vertex_data), &triangle_vertex_buffer_ID);
+ if (status < 0) {
+ return status;
+ }
+
+ do {
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glUseProgram(program_ID);
+
+ glEnableVertexAttribArray(program_attribute_position_ID);
+ glBindBuffer(GL_ARRAY_BUFFER, triangle_vertex_buffer_ID);
+ glVertexAttribPointer(
+ program_attribute_position_ID, // The attribute we want to configure
+ 3, // size
+ GL_FLOAT, // type
+ GL_FALSE, // is normalized?
+ 0, // stride
+ (GLvoid *)0 // array buffer offset
+ );
+ glDrawArrays(GL_TRIANGLES, 0, 3); // 3 indices starting at 0 -> 1 triangle
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glDisableVertexAttribArray(triangle_vertex_buffer_ID);
+
+ glfwSwapBuffers(window);
+ glfwPollEvents();
+ }
+ while (
+ (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS)
+ &&
+ (glfwWindowShouldClose(window) == 0)
+ );
+
+ glDeleteBuffers(1, &triangle_vertex_buffer_ID);
+ glDeleteProgram(program_ID);
+
+ glfwTerminate();
+
+ return 0;
+}
+
diff --git a/01-perspective.c b/01-perspective.c
@@ -0,0 +1,130 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+#include <GL/glew.h>
+
+#include <GLFW/glfw3.h>
+
+#include "ogl/ogl.h"
+
+int
+main() {
+ int status;
+
+ GLFWwindow * window = NULL;
+ status = ogl_init(400, 240, "01 - triangle with perspective", &window);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ const char * vertexshader =
+ "#version 100" "\n"
+ "uniform mat4 MVP;" "\n"
+ "attribute vec4 position;" "\n"
+ "void main(){" "\n"
+ " gl_Position = MVP * position;" "\n"
+ "}" "\n"
+ ;
+ const char * fragmentshader =
+ "#version 100" "\n"
+ "void main() {" "\n"
+ " gl_FragColor = vec4(1,0,0,1);" "\n"
+ "}" "\n"
+ ;
+ GLuint program_ID = 0;
+ status = ogl_program_build(
+ vertexshader, fragmentshader,
+ &program_ID
+ );
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ GLint program_attribute_position_ID = 0;
+ status = ogl_program_attribute_get_ID(program_ID, "position", &program_attribute_position_ID);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ struct ogl_mat4f MVP_projection;
+ status = ogl_perspective(45.0f, 0.1f, 100.0f, &MVP_projection);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ struct ogl_mat4f MVP_view;
+ struct ogl_vec3f MVP_view_eye = { .x=4.0f, .y=3.0f, .z=3.0f };
+ struct ogl_vec3f MVP_view_center = { .x=0.0f, .y=0.0f, .z=0.0f };
+ struct ogl_vec3f MVP_view_up = { .x=0.0f, .y=1.0f, .z=0.0f };
+ ogl_lookat(
+ MVP_view_eye, MVP_view_center, MVP_view_up,
+ &MVP_view
+ );
+
+ struct ogl_mat4f MVP_model;
+ ogl_mat4f_identity(&MVP_model);
+
+ struct ogl_mat4f MVP;
+ ogl_mat4f_identity(&MVP);
+ ogl_mat4f_multiply(MVP, MVP_projection, &MVP);
+ ogl_mat4f_multiply(MVP, MVP_view, &MVP);
+ ogl_mat4f_multiply(MVP, MVP_model, &MVP);
+
+ static const GLfloat triangle_vertex_data[] = {
+ -1.0f, -1.0f, 0.0f,
+ 1.0f, -1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ };
+ GLuint triangle_vertex_buffer_ID = 0;
+ status = ogl_vertex_buffer_load(triangle_vertex_data, sizeof(triangle_vertex_data), &triangle_vertex_buffer_ID);
+ if (status < 0) {
+ return status;
+ }
+
+ do {
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glUseProgram(program_ID);
+ ogl_program_uniform_set_mat4f(program_ID, "MVP", MVP);
+
+ glEnableVertexAttribArray(program_attribute_position_ID);
+ glBindBuffer(GL_ARRAY_BUFFER, triangle_vertex_buffer_ID);
+ glVertexAttribPointer(
+ program_attribute_position_ID, // The attribute we want to configure
+ 3, // size
+ GL_FLOAT, // type
+ GL_FALSE, // is normalized?
+ 0, // stride
+ (GLvoid *)0 // array buffer offset
+ );
+ glDrawArrays(GL_TRIANGLES, 0, 3); // 3 indices starting at 0 -> 1 triangle
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glDisableVertexAttribArray(triangle_vertex_buffer_ID);
+
+ glfwSwapBuffers(window);
+ glfwPollEvents();
+ }
+ while (
+ (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS)
+ &&
+ (glfwWindowShouldClose(window) == 0)
+ );
+
+ glDeleteBuffers(1, &triangle_vertex_buffer_ID);
+ glDeleteProgram(program_ID);
+
+ glfwTerminate();
+
+ return 0;
+}
+
diff --git a/Makefile b/Makefile
@@ -1,22 +1,34 @@
-00_SRC = \
- 00-triangle.c \
- ogl/_ogl.c ogl/ogl_init.c ogl/ogl_program_build.c ogl/ogl_program_attribute_get_ID.c ogl/ogl_vertex_buffer_load.c
-00_OBJ = $(00_SRC:.c=.o)
+OGL_BIN = ogl/ogl.a
+
+00_SRC = 00-triangle.c
+00_OBJ = $(00_SRC:.c=.o) $(OGL_BIN)
00_BIN = 00-triangle
+01_SRC = 01-perspective.c
+01_OBJ = $(01_SRC:.c=.o) $(OGL_BIN)
+01_BIN = 01-perspective
+
+
CFLAGS ?= -std=c99 -Wall -fwrapv -g
LIB_CFLAGS += $(shell pkg-config --cflags glew gl glfw3)
-LIB_LDFLAGS += $(shell pkg-config --libs glew gl glfw3)
-
-$(00_BIN): $(00_OBJ)
+LIB_LDFLAGS += $(shell pkg-config --libs glew gl glfw3) -lm
.PHONY: all
-all: $(00_BIN)
+all: $(00_BIN) $(01_BIN)
.PHONY: clean
clean:
- @rm -rf \
- $(00_OBJ) $(00_BIN)
+ rm -rf \
+ $(00_OBJ) $(00_BIN) \
+ $(01_OBJ) $(01_BIN)
+ $(MAKE) --directory=./ogl/ clean
+
+$(00_BIN): $(00_OBJ)
+
+$(01_BIN): $(01_OBJ)
+
+$(OGL_BIN):
+ $(MAKE) --directory=./ogl/ all
%.o: %.c
@echo [CC] $<
@@ -24,5 +36,5 @@ clean:
%: %.o
@echo [LD] $^ -o $@
- @$(CC) $(LDFLAGS) $^ -o $@ $(LIB_LDFLAGS)
+ @$(CC) $(LDFLAGS) $^ $(OGL_BIN) -o $@ $(LIB_LDFLAGS)
diff --git a/ogl/LICENSE b/ogl/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+<http://creativecommons.org/publicdomain/zero/1.0/>
diff --git a/ogl/Makefile b/ogl/Makefile
@@ -0,0 +1,44 @@
+SRC = \
+ _ogl.c ogl_init.c \
+ ogl_GLfloat_isapproxequal.c ogl_GLfloat_print.c \
+ ogl_mat4f_identity.c ogl_mat4f_isapproxequal.c ogl_mat4f_multiply.c ogl_mat4f_print.c \
+ ogl_lookat.c \
+ ogl_perspective.c \
+ ogl_program_build.c ogl_program_attribute_get_ID.c ogl_program_uniform_get_ID.c ogl_program_uniform_set_mat4f.c \
+ ogl_vec3f_cross.c ogl_vec3f_dot.c ogl_vec3f_isapproxequal.c ogl_vec3f_magnitude.c ogl_vec3f_normal.c ogl_vec3f_print.c \
+ ogl_vertex_buffer_load.c
+OBJ = $(SRC:.c=.o)
+BIN = ogl.a
+TEST = \
+ mat4f_multiply.test \
+ vec3f_cross.test vec3f_magnitude.test vec3f_normal.test
+
+CFLAGS ?= -std=c99 -Wall -fwrapv -g
+LIB_CFLAGS += $(shell pkg-config --cflags glew gl glfw3)
+LIB_LDFLAGS += $(shell pkg-config --libs glew gl glfw3) -lm
+
+.PHONY: all
+all: $(BIN)
+
+.PHONY: test
+test: $(TEST)
+ @for t in $^ ; do \
+ ./$$t ; \
+ done
+
+.PHONY: clean
+clean:
+ @rm -rf $(OBJ) $(TEST) $(BIN)
+
+%.o: %.c
+ @echo [CC] $<
+ @$(CC) $(CFLAGS) $(LIB_CFLAGS) -c $< -o $@
+
+$(BIN): $(OBJ)
+ @echo [AR] cvq $@ $^
+ @ar cvq $@ $^ > /dev/null
+
+%.test: %.test.o $(BIN)
+ @echo [CC] $^ -o $@
+ @$(CC) $(LDFLAGS) $^ -o $@ $(LIB_LDFLAGS)
+
diff --git a/ogl/README.md b/ogl/README.md
@@ -0,0 +1,5 @@
+# ogl
+OpenGL (ES 2.0) helper library
+
+TODO: everything. it's all busted right now
+
diff --git a/ogl/_ogl.c b/ogl/_ogl.c
@@ -5,8 +5,13 @@ licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/
#include <stdio.h>
-int _ogl_window_width = 0;
-int _ogl_window_height = 0;
+#include <GLFW/glfw3.h>
+
+#include "_ogl.h"
+
+GLFWwindow * _ogl_window = NULL;
+int _ogl_window_width = 0;
+int _ogl_window_height = 0;
void
_ogl_glfw_error(int error, const char * description) {
diff --git a/ogl/_ogl.h b/ogl/_ogl.h
@@ -3,9 +3,16 @@
licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
*/
-extern int _ogl_window_width;
-extern int _ogl_window_height;
+#ifndef __OGL_H
+#define __OGL_H
+
+#include <GLFW/glfw3.h>
+
+extern int _ogl_window_width;
+extern int _ogl_window_height;
void
_ogl_glfw_error(int error, const char * description);
+#endif
+
diff --git a/ogl/mat4f_multiply.test.c b/ogl/mat4f_multiply.test.c
@@ -0,0 +1,87 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include "ogl.h"
+
+struct _test_values {
+ const char * desc;
+ struct ogl_mat4f a;
+ struct ogl_mat4f b;
+ struct ogl_mat4f correct;
+};
+
+static int fail = 0;
+
+static void
+_test(struct _test_values values) {
+ printf("[TEST]");
+
+ struct ogl_mat4f result;
+ ogl_mat4f_multiply(values.a, values.b, &result);
+
+ int pass = ogl_mat4f_isapproxequal(values.correct, result);
+ if (pass) {
+ printf("[ OK ] (%s)" "\n", values.desc);
+ }
+ else {
+ fail = 1;
+
+ printf("[FAIL] (%s)" "\n", values.desc);
+
+ ogl_mat4f_print(values.a, "\t", NULL);
+
+ printf("\t" "*" "\n");
+
+ ogl_mat4f_print(values.b, "\t", NULL);
+
+ printf("\t" "was" "\n");
+
+ ogl_mat4f_print(result, "\t", NULL);
+
+ printf("\t" "should be" "\n");
+
+ ogl_mat4f_print(values.correct, "\t", NULL);
+ }
+}
+
+int
+main() {
+ struct _test_values testvalues[] = {
+ {
+ .desc="mat4f multiply() test 1",
+ .a={.values={
+ 0.0f, 1.0f, 2.0f, 3.0f,
+ 4.0f, 5.0f, 6.0f, 7.0f,
+ 8.0f, 9.0f, 10.0f, 11.0f,
+ 12.0f, 13.0f, 14.0f, 15.0f,
+ }},
+ .b={.values={
+ 0.0f, 1.0f, 2.0f, 3.0f,
+ 4.0f, 5.0f, 6.0f, 7.0f,
+ 8.0f, 9.0f, 10.0f, 11.0f,
+ 12.0f, 13.0f, 14.0f, 15.0f,
+ }},
+ .correct={.values={
+ 56.0f, 62.0f, 68.0f, 74.0f,
+ 152.0f, 174.0f, 196.0f, 218.0f,
+ 248.0f, 286.0f, 324.0f, 362.0f,
+ 344.0f, 398.0f, 452.0f, 506.0f,
+ }},
+ },
+ };
+ size_t testvalues_length = sizeof(testvalues) / sizeof(*testvalues);
+ for (size_t i=0; i<testvalues_length; i++) {
+ _test(testvalues[i]);
+ }
+
+ if (fail) {
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/ogl/ogl.h b/ogl/ogl.h
@@ -3,12 +3,45 @@
licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
*/
+#ifndef _OGL_H
+#define _OGL_H
+
+#include <GL/glew.h>
+
+#include <GLFW/glfw3.h>
+
+
+
+struct ogl_mat4f {
+ GLfloat values[4*4];
+};
+
+struct ogl_vec3f {
+ GLfloat x;
+ GLfloat y;
+ GLfloat z;
+};
+
+
+
int
ogl_init(
int window_width, int window_height, const char * window_title,
GLFWwindow ** out_window
);
+void
+ogl_lookat(
+ struct ogl_vec3f eye, struct ogl_vec3f center, struct ogl_vec3f up,
+ struct ogl_mat4f * out_matrix
+);
+
+int
+ogl_perspective(
+ GLfloat fovy, GLfloat zNear, GLfloat zFar,
+ struct ogl_mat4f * out_matrix
+);
+
int
ogl_program_build(
const char * vertexshader, const char * fragmentshader,
@@ -22,8 +55,88 @@ ogl_program_attribute_get_ID(
);
int
+ogl_program_uniform_get_ID(
+ GLuint programID, const char * uniform_name,
+ GLint * out_uniform_ID
+);
+
+int
+ogl_program_uniform_set_mat4f(
+ GLint program_ID, const char * uniform_name, const struct ogl_mat4f matrix
+);
+
+int
ogl_vertex_buffer_load(
const GLvoid * data, GLsizeiptr data_size,
GLuint * out_bufferID
);
+
+
+
+int
+ogl_GLfloat_isapproxequal(
+ GLfloat a, GLfloat b
+);
+
+void
+ogl_GLfloat_print(
+ GLfloat f
+);
+
+void
+ogl_mat4f_identity(
+ struct ogl_mat4f * out_matrix
+);
+
+int
+ogl_mat4f_isapproxequal(
+ struct ogl_mat4f a, struct ogl_mat4f b
+);
+
+void
+ogl_mat4f_multiply(
+ struct ogl_mat4f a, struct ogl_mat4f b,
+ struct ogl_mat4f * out_c
+);
+
+void
+ogl_mat4f_print(
+ struct ogl_mat4f matrix, const char * line_prefix, const char * line_suffix
+);
+
+void
+ogl_vec3f_cross(
+ struct ogl_vec3f a, struct ogl_vec3f b,
+ struct ogl_vec3f * out_result
+);
+
+void
+ogl_vec3f_dot(
+ struct ogl_vec3f a, struct ogl_vec3f b,
+ GLfloat * out_result
+);
+
+int
+ogl_vec3f_isapproxequal(
+ struct ogl_vec3f a, struct ogl_vec3f b
+);
+
+GLfloat
+ogl_vec3f_magnitude(
+ struct ogl_vec3f vector
+);
+
+int
+ogl_vec3f_normal(
+ struct ogl_vec3f vector,
+ struct ogl_vec3f * out_result
+);
+
+void
+ogl_vec3f_print(
+ struct ogl_vec3f vector
+);
+
+#endif
+
diff --git a/ogl/ogl_GLfloat_isapproxequal.c b/ogl/ogl_GLfloat_isapproxequal.c
@@ -0,0 +1,18 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include <math.h>
+
+#include <float.h>
+
+int
+ogl_GLfloat_isapproxequal(
+ GLfloat a, GLfloat b
+) {
+ return (fabsf(a - b) < 0.000001f);
+}
+
diff --git a/ogl/ogl_GLfloat_print.c b/ogl/ogl_GLfloat_print.c
@@ -0,0 +1,27 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include <stdio.h>
+
+#include <math.h>
+
+#include "ogl.h"
+
+void
+ogl_GLfloat_print(
+ GLfloat f
+) {
+ printf("%g", f);
+
+ long int rounded = lroundf(f);
+ if (ogl_GLfloat_isapproxequal((float)rounded, f)) {
+ printf(".0");
+ }
+
+ printf("f");
+}
+
diff --git a/ogl/ogl_init.c b/ogl/ogl_init.c
@@ -40,8 +40,6 @@ ogl_init(
glfwTerminate();
return -1;
}
- _ogl_window_width = window_width;
- _ogl_window_height = window_height;
glfwMakeContextCurrent(window);
@@ -58,7 +56,9 @@ ogl_init(
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
- (*out_window) = window;
+ (*out_window) = window;
+ _ogl_window_width = window_width;
+ _ogl_window_height = window_height;
return 0;
}
diff --git a/ogl/ogl_lookat.c b/ogl/ogl_lookat.c
@@ -0,0 +1,56 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+void
+ogl_lookat(
+ struct ogl_vec3f eye, struct ogl_vec3f center, struct ogl_vec3f up,
+ struct ogl_mat4f * out_matrix
+) {
+ /* equivelant to gluLookAt() followed by glTranslatef(). see: https://www.opengl.org/discussion_boards/showthread.php/130409-using-gluLookAt-properly */
+ /* see OpenGL 2.1 gluLookAt(): https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml */
+ /* see OpenGL 2.1 glTranslatef(): https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml */
+
+ struct ogl_vec3f f = {
+ .x = center.x - eye.x,
+ .y = center.y - eye.y,
+ .z = center.z - eye.z,
+ };
+ struct ogl_vec3f f_norm;
+ ogl_vec3f_normal(f, &f_norm);
+
+ struct ogl_vec3f up_norm;
+ ogl_vec3f_normal(up, &up_norm);
+
+ struct ogl_vec3f s;
+ ogl_vec3f_cross(f_norm, up_norm, &s);
+
+ struct ogl_vec3f s_norm;
+ ogl_vec3f_normal(s, &s_norm);
+
+ struct ogl_vec3f u;
+ ogl_vec3f_cross(s_norm, f_norm, &u);
+
+ GLfloat eye_translate_x;
+ ogl_vec3f_dot(s_norm, eye, &eye_translate_x);
+ eye_translate_x *= -1.0f;
+
+ GLfloat eye_translate_y;
+ ogl_vec3f_dot(u, eye, &eye_translate_y);
+ eye_translate_y *= -1.0f;
+
+ GLfloat eye_translate_z;
+ ogl_vec3f_dot(f_norm, eye, &eye_translate_z);
+
+ GLfloat * values = (*out_matrix).values;
+ values[ 0] = s.x; values[ 1] = s.y; values[ 2] = s.z; values[ 3] = eye_translate_x;
+ values[ 4] = u.x; values[ 5] = u.y; values[ 6] = u.z; values[ 7] = eye_translate_y;
+ values[ 8] = -f_norm.x; values[ 9] = -f_norm.y; values[10] = -f_norm.z; values[11] = eye_translate_z;
+ values[12] = 0.0f; values[13] = 0.0f; values[14] = 0.0f; values[15] = 1.0f;
+}
+
diff --git a/ogl/ogl_mat4f_identity.c b/ogl/ogl_mat4f_identity.c
@@ -0,0 +1,20 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+void
+ogl_mat4f_identity(
+ struct ogl_mat4f * out_matrix
+) {
+ GLfloat * values = (*out_matrix).values;
+ values[ 0] = 1.0f; values[ 1] = 0.0f; values[ 2] = 0.0f; values[ 3] = 0.0f;
+ values[ 4] = 0.0f; values[ 5] = 1.0f; values[ 6] = 0.0f; values[ 7] = 0.0f;
+ values[ 8] = 0.0f; values[ 9] = 0.0f; values[10] = 1.0f; values[11] = 0.0f;
+ values[12] = 0.0f; values[13] = 0.0f; values[14] = 0.0f; values[15] = 1.0f;
+}
+
diff --git a/ogl/ogl_mat4f_isapproxequal.c b/ogl/ogl_mat4f_isapproxequal.c
@@ -0,0 +1,22 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+int
+ogl_mat4f_isapproxequal(
+ struct ogl_mat4f a, struct ogl_mat4f b
+) {
+ int result = 1;
+
+ for (size_t i=0; i<16; i++) {
+ result &= (ogl_GLfloat_isapproxequal(a.values[i], b.values[i]));
+ }
+
+ return result;
+}
+
diff --git a/ogl/ogl_mat4f_multiply.c b/ogl/ogl_mat4f_multiply.c
@@ -0,0 +1,48 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+void
+ogl_mat4f_multiply(
+ struct ogl_mat4f a, struct ogl_mat4f b,
+ struct ogl_mat4f * out_c
+) {
+ GLfloat
+ a_1_1 = a.values[ 0], a_1_2 = a.values[ 1], a_1_3 = a.values[ 2], a_1_4 = a.values[ 3],
+ a_2_1 = a.values[ 4], a_2_2 = a.values[ 5], a_2_3 = a.values[ 6], a_2_4 = a.values[ 7],
+ a_3_1 = a.values[ 8], a_3_2 = a.values[ 9], a_3_3 = a.values[10], a_3_4 = a.values[11],
+ a_4_1 = a.values[12], a_4_2 = a.values[13], a_4_3 = a.values[14], a_4_4 = a.values[15]
+ ;
+
+ GLfloat
+ b_1_1 = b.values[ 0], b_1_2 = b.values[ 1], b_1_3 = b.values[ 2], b_1_4 = b.values[ 3],
+ b_2_1 = b.values[ 4], b_2_2 = b.values[ 5], b_2_3 = b.values[ 6], b_2_4 = b.values[ 7],
+ b_3_1 = b.values[ 8], b_3_2 = b.values[ 9], b_3_3 = b.values[10], b_3_4 = b.values[11],
+ b_4_1 = b.values[12], b_4_2 = b.values[13], b_4_3 = b.values[14], b_4_4 = b.values[15]
+ ;
+
+ /* from https://en.wikipedia.org/wiki/Matrix_multiplication#Definition */
+ GLfloat * values = (*out_c).values;
+ values[ 0] = (a_1_1*b_1_1) + (a_1_2*b_2_1) + (a_1_3*b_3_1) + (a_1_4*b_4_1);
+ values[ 1] = (a_1_1*b_1_2) + (a_1_2*b_2_2) + (a_1_3*b_3_2) + (a_1_4*b_4_2);
+ values[ 2] = (a_1_1*b_1_3) + (a_1_2*b_2_3) + (a_1_3*b_3_3) + (a_1_4*b_4_3);
+ values[ 3] = (a_1_1*b_1_4) + (a_1_2*b_2_4) + (a_1_3*b_3_4) + (a_1_4*b_4_4);
+ values[ 4] = (a_2_1*b_1_1) + (a_2_2*b_2_1) + (a_2_3*b_3_1) + (a_2_4*b_4_1);
+ values[ 5] = (a_2_1*b_1_2) + (a_2_2*b_2_2) + (a_2_3*b_3_2) + (a_2_4*b_4_2);
+ values[ 6] = (a_2_1*b_1_3) + (a_2_2*b_2_3) + (a_2_3*b_3_3) + (a_2_4*b_4_3);
+ values[ 7] = (a_2_1*b_1_4) + (a_2_2*b_2_4) + (a_2_3*b_3_4) + (a_2_4*b_4_4);
+ values[ 8] = (a_3_1*b_1_1) + (a_3_2*b_2_1) + (a_3_3*b_3_1) + (a_3_4*b_4_1);
+ values[ 9] = (a_3_1*b_1_2) + (a_3_2*b_2_2) + (a_3_3*b_3_2) + (a_3_4*b_4_2);
+ values[10] = (a_3_1*b_1_3) + (a_3_2*b_2_3) + (a_3_3*b_3_3) + (a_3_4*b_4_3);
+ values[11] = (a_3_1*b_1_4) + (a_3_2*b_2_4) + (a_3_3*b_3_4) + (a_3_4*b_4_4);
+ values[12] = (a_4_1*b_1_1) + (a_4_2*b_2_1) + (a_4_3*b_3_1) + (a_4_4*b_4_1);
+ values[13] = (a_4_1*b_1_2) + (a_4_2*b_2_2) + (a_4_3*b_3_2) + (a_4_4*b_4_2);
+ values[14] = (a_4_1*b_1_3) + (a_4_2*b_2_3) + (a_4_3*b_3_3) + (a_4_4*b_4_3);
+ values[15] = (a_4_1*b_1_4) + (a_4_2*b_2_4) + (a_4_3*b_3_4) + (a_4_4*b_4_4);
+}
+
diff --git a/ogl/ogl_mat4f_print.c b/ogl/ogl_mat4f_print.c
@@ -0,0 +1,33 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include "ogl.h"
+
+void
+ogl_mat4f_print(
+ struct ogl_mat4f matrix, const char * line_prefix, const char * line_suffix
+) {
+ line_prefix = (line_prefix == NULL) ? "" : line_prefix;
+ line_suffix = (line_suffix == NULL) ? "" : line_suffix;
+
+ printf("%s" "{" "%s" "\n", line_prefix, line_suffix);
+ for (int i=0; i<16; i++) {
+ if ((i%4) == 0) {
+ printf("%s" "\t", line_prefix);
+ }
+ //printf("%8g" "f, ", matrix.values[i]);
+ ogl_GLfloat_print(matrix.values[i]);
+ printf(", ");
+ if ((i%4) == 3) {
+ printf("%s" "\n", line_suffix);
+ }
+ }
+ printf("%s" "}" "%s" "\n", line_prefix, line_suffix);
+
+}
+
+
diff --git a/ogl/ogl_perspective.c b/ogl/ogl_perspective.c
@@ -0,0 +1,34 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include <math.h>
+
+#include "ogl.h"
+#include "_ogl.h"
+
+int
+ogl_perspective(
+ GLfloat fovy, GLfloat zNear, GLfloat zFar,
+ struct ogl_mat4f * out_matrix
+) {
+ /* from https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml */
+ GLfloat aspect = (GLfloat)_ogl_window_width / (GLfloat)_ogl_window_height;
+
+ if ((fovy < 0.0f) || (aspect < 0.0f) || (zNear < 0.0f) || (zFar < 0.0f) || (zNear > zFar)) {
+ return -1;
+ }
+
+ GLfloat f = 1.0f / tanf(fovy / 2.0f);
+
+ GLfloat * values = (*out_matrix).values;
+ values[ 0] = f / aspect; values[ 1] = 0.0f; values[ 2] = 0.0f; values[ 3] = 0.0f;
+ values[ 4] = 0.0f; values[ 5] = f; values[ 6] = 0.0f; values[ 7] = 0.0f;
+ values[ 8] = 0.0f; values[ 9] = 0.0f; values[10] = (zFar+zNear) / (zNear-zFar); values[11] = (2*zFar*zNear) / (zNear-zFar);
+ values[12] = 0.0f; values[13] = 0.0f; values[14] = -1.0f; values[15] = 0.0f;
+ return 0;
+}
+
diff --git a/ogl/ogl_program_uniform_get_ID.c b/ogl/ogl_program_uniform_get_ID.c
@@ -0,0 +1,27 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include <GL/glew.h>
+
+int
+ogl_program_uniform_get_ID(
+ GLuint program_ID, const char * uniform_name,
+ GLint * out_uniform_ID
+) {
+ GLint uniform_ID;
+
+ uniform_ID = glGetUniformLocation(program_ID, uniform_name);
+ if (uniform_ID < 0) {
+ fprintf(stderr, "GL glGetUniformLocation(%i, \"%s\"): ERROR" "\n", program_ID, uniform_name);
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return -1;
+ }
+
+ (*out_uniform_ID) = uniform_ID;
+ return 0;
+}
+
diff --git a/ogl/ogl_program_uniform_set_mat4f.c b/ogl/ogl_program_uniform_set_mat4f.c
@@ -0,0 +1,27 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+int
+ogl_program_uniform_set_mat4f(
+ GLint program_ID, const char * uniform_name, const struct ogl_mat4f matrix
+) {
+ GLint uniform_ID = 0;
+ int status = ogl_program_uniform_get_ID(program_ID, uniform_name, &uniform_ID);
+ if (status < 0) {
+ fprintf(stderr, "\t" "at %s : %d" "\n", __FILE__, __LINE__);
+ return status;
+ }
+
+ glUniformMatrix4fv(uniform_ID, 1, GL_FALSE, matrix.values);
+
+ return 0;
+}
+
diff --git a/ogl/ogl_vec3f_cross.c b/ogl/ogl_vec3f_cross.c
@@ -0,0 +1,23 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+void
+ogl_vec3f_cross(
+ struct ogl_vec3f a, struct ogl_vec3f b,
+ struct ogl_vec3f * out_result
+) {
+ GLfloat a_x = a.x, a_y = a.y, a_z = a.z;
+ GLfloat b_x = b.x, b_y = b.y, b_z = b.z;
+
+ /* from Wikipedia (https://en.wikipedia.org/wiki/Cross_product#Coordinate_notation) */
+ (*out_result).x = (a_y*b_z) - (a_z*b_y);
+ (*out_result).y = (a_z*b_x) - (a_x*b_z);
+ (*out_result).z = (a_x*b_y) - (a_y*b_x);
+}
+
diff --git a/ogl/ogl_vec3f_dot.c b/ogl/ogl_vec3f_dot.c
@@ -0,0 +1,18 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+void
+ogl_vec3f_dot(
+ struct ogl_vec3f a, struct ogl_vec3f b,
+ GLfloat * out_result
+) {
+ /* from Wikipedia (https://en.wikipedia.org/wiki/Dot_product#Algebraic_definition) */
+ (*out_result) = (a.x*b.x) + (a.y*b.y) + (a.z*b.z);
+}
+
diff --git a/ogl/ogl_vec3f_isapproxequal.c b/ogl/ogl_vec3f_isapproxequal.c
@@ -0,0 +1,20 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include "ogl.h"
+
+int
+ogl_vec3f_isapproxequal(
+ struct ogl_vec3f a, struct ogl_vec3f b
+) {
+ return (
+ ogl_GLfloat_isapproxequal(a.x, b.x)
+ &&
+ ogl_GLfloat_isapproxequal(a.y, b.y)
+ &&
+ ogl_GLfloat_isapproxequal(a.z, b.z)
+ );
+}
+
diff --git a/ogl/ogl_vec3f_magnitude.c b/ogl/ogl_vec3f_magnitude.c
@@ -0,0 +1,18 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include <math.h>
+
+#include "ogl.h"
+
+GLfloat
+ogl_vec3f_magnitude(
+ struct ogl_vec3f vector
+) {
+ return sqrtf((vector.x*vector.x) + (vector.y*vector.y) + (vector.z*vector.z));
+}
+
diff --git a/ogl/ogl_vec3f_normal.c b/ogl/ogl_vec3f_normal.c
@@ -0,0 +1,25 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+int
+ogl_vec3f_normal(
+ struct ogl_vec3f vector,
+ struct ogl_vec3f * out_result
+) {
+ GLfloat vector_magnitude = ogl_vec3f_magnitude(vector);
+ if (ogl_GLfloat_isapproxequal(vector_magnitude, 0.0f)) {
+ return -1;
+ }
+
+ (*out_result).x = vector.x / vector_magnitude;
+ (*out_result).y = vector.y / vector_magnitude;
+ (*out_result).z = vector.z / vector_magnitude;
+ return 0;
+}
+
diff --git a/ogl/ogl_vec3f_print.c b/ogl/ogl_vec3f_print.c
@@ -0,0 +1,30 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include "ogl.h"
+
+void
+ogl_vec3f_print(
+ struct ogl_vec3f vector
+) {
+ printf("{ ");
+
+ printf(".x=");
+ ogl_GLfloat_print(vector.x);
+ printf(", ");
+
+ printf(".y=");
+ ogl_GLfloat_print(vector.y);
+ printf(", ");
+
+ printf(".z=");
+ ogl_GLfloat_print(vector.z);
+
+ printf(" }");
+}
+
+
diff --git a/ogl/vec3f_cross.test.c b/ogl/vec3f_cross.test.c
@@ -0,0 +1,71 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include "ogl.h"
+
+struct _test_values {
+ const char * desc;
+ struct ogl_vec3f a;
+ struct ogl_vec3f b;
+ struct ogl_vec3f correct;
+};
+
+static int fail = 0;
+
+static void
+_test(struct _test_values values) {
+ printf("[TEST]");
+
+ struct ogl_vec3f result;
+ ogl_vec3f_cross(values.a, values.b, &result);
+
+ int pass = ogl_vec3f_isapproxequal(values.correct, result);
+ if (pass) {
+ printf("[ OK ] (%s)" "\n", values.desc);
+ }
+ else {
+ fail = 1;
+
+ printf("[FAIL] (%s)" "\n", values.desc);
+
+ printf("\t");
+ ogl_vec3f_print(values.a);
+ printf(" x ");
+ ogl_vec3f_print(values.b);
+ printf("\n");
+
+ printf("\t" "was" "\n");
+
+ printf("\t");
+ ogl_vec3f_print(result);
+ printf("\n");
+
+ printf("\t" "should be" "\n");
+
+ printf("\t");
+ ogl_vec3f_print(values.correct);
+ printf("\n");
+ }
+}
+
+int
+main() {
+ struct _test_values testvalues[] = {
+ { .desc="vec3f cross() test 1", .a={.x=1.0f, .y=2.0f, .z=3.0f}, .b={.x=4.0f, .y=5.0f, .z=6.0f}, .correct={.x=-3.0f, .y=6.0f, .z=-3.0f} },
+ };
+ size_t testvalues_length = sizeof(testvalues) / sizeof(*testvalues);
+ for (size_t i=0; i<testvalues_length; i++) {
+ _test(testvalues[i]);
+ }
+
+ if (fail) {
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/ogl/vec3f_magnitude.test.c b/ogl/vec3f_magnitude.test.c
@@ -0,0 +1,67 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+struct _test_values {
+ const char * desc;
+ struct ogl_vec3f a;
+ GLfloat correct;
+};
+
+static int fail = 0;
+
+static void
+_test(struct _test_values values) {
+ printf("[TEST]");
+
+ GLfloat result = ogl_vec3f_magnitude(values.a);
+ if (ogl_GLfloat_isapproxequal(result, values.correct)) {
+ printf("[ OK ] (%s)" "\n", values.desc);
+ }
+ else {
+ fail = 1;
+
+ printf("[FAIL] (%s)" "\n", values.desc);
+
+ printf("\t" "| ");
+ ogl_vec3f_print(values.a);
+ printf(" |" "\n");
+
+ printf("\t" "was" "\n");
+
+ printf("\t");
+ ogl_GLfloat_print(result);
+ printf("\n");
+
+ printf("\t" "should be" "\n");
+
+ printf("\t");
+ ogl_GLfloat_print(values.correct);
+ printf("\n");
+ }
+}
+
+int
+main() {
+ struct _test_values testvalues[] = {
+ { .desc="vec3f magnitude() test 1", .a={.x=2.0f, .y=4.0f, .z=-2.0f}, .correct=4.89898f },
+ };
+ size_t testvalues_length = sizeof(testvalues) / sizeof(*testvalues);
+ for (size_t i=0; i<testvalues_length; i++) {
+ _test(testvalues[i]);
+ }
+
+ if (fail) {
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/ogl/vec3f_normal.test.c b/ogl/vec3f_normal.test.c
@@ -0,0 +1,84 @@
+/*
+2018 David DiPaola
+licensed under CC0 (public domain, see https://creativecommons.org/publicdomain/zero/1.0/)
+*/
+
+#include <stdio.h>
+
+#include <GL/glew.h>
+
+#include "ogl.h"
+
+struct _test_values {
+ const char * desc;
+ struct ogl_vec3f a;
+ struct ogl_vec3f correct;
+};
+
+static int fail = 0;
+
+static void
+_test(struct _test_values values) {
+ printf("[TEST]");
+
+ struct ogl_vec3f output;
+ int status = ogl_vec3f_normal(values.a, &output);
+ int pass_status = (status >= 0);
+ int pass_output = ogl_vec3f_isapproxequal(output, values.correct);
+ if (pass_status && pass_output) {
+ printf("[ OK ] (%s)" "\n", values.desc);
+ }
+ else {
+ fail = 1;
+
+ printf("[FAIL] (%s)" "\n", values.desc);
+
+ if (!pass_status) {
+ printf("\t" "status FAIL: %i" "\n", status);
+ }
+ else {
+ printf("\t" "status OK: %i" "\n", status);
+ }
+
+ if (!pass_output) {
+ printf("\t" "output FAIL:" "\n");
+
+ printf("\t\t" "|| ");
+ ogl_vec3f_print(values.a);
+ printf(" ||" "\n");
+
+ printf("\t\t" "was" "\n");
+
+ printf("\t\t");
+ ogl_vec3f_print(output);
+ printf("\n");
+
+ printf("\t\t" "should be" "\n");
+
+ printf("\t\t");
+ ogl_vec3f_print(values.correct);
+ printf("\n");
+ }
+ else {
+ printf("\t" "output OK" "\n");
+ }
+ }
+}
+
+int
+main() {
+ struct _test_values testvalues[] = {
+ { .desc="vec3f normal() test 1", .a={.x=1.0f, .y=2.0f, .z=3.0f}, .correct={.x=0.267261f, .y=0.534522f, .z=0.801784f}},
+ };
+ size_t testvalues_length = sizeof(testvalues) / sizeof(*testvalues);
+ for (size_t i=0; i<testvalues_length; i++) {
+ _test(testvalues[i]);
+ }
+
+ if (fail) {
+ return -1;
+ }
+
+ return 0;
+}
+