opengl_learn

Step-by-step introduction to OpenGL
git clone https://0xdd.org/code/opengl_learn.git
Log | Files | Refs | README | LICENSE

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:
M00-triangle.c | 2++
A01-perspective-orig.c | 236+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A01-perspective.c | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MMakefile | 34+++++++++++++++++++++++-----------
Aogl/LICENSE | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aogl/Makefile | 44++++++++++++++++++++++++++++++++++++++++++++
Aogl/README.md | 5+++++
Mogl/_ogl.c | 9+++++++--
Mogl/_ogl.h | 11+++++++++--
Aogl/mat4f_multiply.test.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mogl/ogl.h | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aogl/ogl_GLfloat_isapproxequal.c | 18++++++++++++++++++
Aogl/ogl_GLfloat_print.c | 27+++++++++++++++++++++++++++
Mogl/ogl_init.c | 6+++---
Aogl/ogl_lookat.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aogl/ogl_mat4f_identity.c | 20++++++++++++++++++++
Aogl/ogl_mat4f_isapproxequal.c | 22++++++++++++++++++++++
Aogl/ogl_mat4f_multiply.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Aogl/ogl_mat4f_print.c | 33+++++++++++++++++++++++++++++++++
Aogl/ogl_perspective.c | 34++++++++++++++++++++++++++++++++++
Aogl/ogl_program_uniform_get_ID.c | 27+++++++++++++++++++++++++++
Aogl/ogl_program_uniform_set_mat4f.c | 27+++++++++++++++++++++++++++
Aogl/ogl_vec3f_cross.c | 23+++++++++++++++++++++++
Aogl/ogl_vec3f_dot.c | 18++++++++++++++++++
Aogl/ogl_vec3f_isapproxequal.c | 20++++++++++++++++++++
Aogl/ogl_vec3f_magnitude.c | 18++++++++++++++++++
Aogl/ogl_vec3f_normal.c | 25+++++++++++++++++++++++++
Aogl/ogl_vec3f_print.c | 30++++++++++++++++++++++++++++++
Aogl/vec3f_cross.test.c | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aogl/vec3f_magnitude.test.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aogl/vec3f_normal.test.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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; +} +