From b5c275a9d7a238e38bca422036baa15d073c9b39 Mon Sep 17 00:00:00 2001 From: Alexander Klingenbeck Date: Thu, 15 Jun 2023 18:32:08 +0200 Subject: [PATCH] still not working --- .gitignore | 1 + .vscode/settings.json | 3 +- src/lightmapper_example.c.bakk | 757 +++++++++++++++++++++++++++++++++ 3 files changed, 760 insertions(+), 1 deletion(-) create mode 100644 src/lightmapper_example.c.bakk diff --git a/.gitignore b/.gitignore index 2b0a607..712a374 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ controls_test.exe debug_interpolation.tga result.tga lightmapper_example +lightmapper_example.exe diff --git a/.vscode/settings.json b/.vscode/settings.json index 554c054..069e543 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,7 @@ "embedded_shader.h": "c", "common.h": "c", "raylib.h": "c", - "glad.h": "c" + "glad.h": "c", + "lightmapper.h": "c" } } \ No newline at end of file diff --git a/src/lightmapper_example.c.bakk b/src/lightmapper_example.c.bakk new file mode 100644 index 0000000..f1dfa53 --- /dev/null +++ b/src/lightmapper_example.c.bakk @@ -0,0 +1,757 @@ +#include +#include "raylib.h" +#include "rlgl.h" +#define GLAD_MALLOC(sz) malloc(sz) +#define GLAD_FREE(sz) free(sz) +//#define GLAD_GL_IMPLEMENTATION +#include "../thirdparty/raylib/src/external/glad.h" + +#define LIGHTMAPPER_IMPLEMENTATION +#define LM_DEBUG_INTERPOLATION +#include "lightmapper.h" + +// load shader +const char *vp = + "#version 150 core\n" + "in vec3 a_position;\n" + "in vec2 a_texcoord;\n" + "uniform mat4 u_view;\n" + "uniform mat4 u_projection;\n" + "out vec2 v_texcoord;\n" + + "void main()\n" + "{\n" + "gl_Position = u_projection * (u_view * vec4(a_position, 1.0));\n" + "v_texcoord = a_texcoord;\n" + "}\n"; + +const char *fp = + "#version 150 core\n" + "in vec2 v_texcoord;\n" + "uniform sampler2D u_lightmap;\n" + "out vec4 o_color;\n" + + "void main()\n" + "{\n" + "o_color = vec4(texture(u_lightmap, v_texcoord).rgb, gl_FrontFacing ? 1.0 : 0.0);\n" + "}\n"; + +const char *attribs[] = +{ + "a_position", + "a_texcoord" +}; + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] lightmapping"); + + + + Model model = LoadModel("thirdparty/lightmapper/example/gazebo.obj"); + Shader shader = LoadShaderFromMemory(vp, fp); + Texture texture = LoadTextureFromImage(GenImageColor(1,1,BLACK)); + int u_view = GetShaderLocation(shader, "u_view"); + int u_projection = GetShaderLocation(shader, "u_projection"); + int u_lightmap = GetShaderLocation(shader, "u_lightmap"); + + + Vector3 position = { 0.0f, 0.0f, 0.0f }; + + //-------------------------------------------------------------------------------------- + + lm_context *ctx = lmCreate( + 64, // hemisphere resolution (power of two, max=512) + 0.001f, 100.0f, // zNear, zFar of hemisphere cameras + 1.0f, 1.0f, 1.0f, // background color (white for ambient occlusion) + 2, 0.01f, // lightmap interpolation threshold (small differences are interpolated rather than sampled) + // check debug_interpolation.tga for an overview of sampled (red) vs interpolated (green) pixels. + 0.0f); // modifier for camera-to-surface distance for hemisphere rendering. + // tweak this to trade-off between interpolated normals quality and other artifacts (see declaration). + + if (!ctx) TraceLog(LOG_ERROR, "Lightmapper not initialized"); + + int w = 512; + int h = 512; + float *data = calloc(w*h*4,sizeof(float)); + + lmSetTargetLightmap(ctx, data, w, h, 4); + + Mesh m = model.meshes[0]; + + lmSetGeometry(ctx, NULL, // no transformation in this example + LM_FLOAT, m.vertices, 0, + LM_NONE , NULL, 0, + LM_FLOAT, m.texcoords, 0, + m.vertexCount, LM_NONE, 0); + + printf("%p\n", m.texcoords); + + int vp[4]; + Matrix view, projection; + double lastUpdateTime = 0.0; + + Mesh mesh = model.meshes[0]; + //SetTargetFPS(10000); + while (lmBegin(ctx, vp, (float*)&view, (float*)&projection)) + { + printf("%d, %d, %d, %d\n", vp[0], vp[1], vp[2], vp[3]); + glViewport(vp[0], vp[1], vp[2], vp[3]); + glEnable(GL_DEPTH_TEST); + + glUseProgram(shader.id); + glUniform1i(u_lightmap, 0); + glUniformMatrix4fv(u_projection, 1, GL_FALSE, (float *)&projection); + glUniformMatrix4fv(u_view, 1, GL_FALSE, (float *)&view); + + glBindTexture(GL_TEXTURE_2D, texture.id); + + glBindVertexArray(mesh.vaoId); + glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); + + double time = GetTime(); + if (time - lastUpdateTime > 1.0) + { + lastUpdateTime = time; + printf("\r%6.2f%%", lmProgress(ctx) * 100.0f); + fflush(stdout); + } + + lmEnd(ctx); + if(WindowShouldClose()) break; + + } + + // postprocess texture + float *temp = calloc(w * h * 4, sizeof(float)); + for (int i = 0; i < 16; i++) + { + lmImageDilate(data, temp, w, h, 4); + lmImageDilate(temp, data, w, h, 4); + } + lmImageSmooth(data, temp, w, h, 4); + lmImageDilate(temp, data, w, h, 4); + lmImagePower(data, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels + free(temp); + + // save result to a file + if (lmImageSaveTGAf("result.tga", data, w, h, 4, 1.0f)) + printf("Saved result.tga\n"); + + rlViewport(0,0, screenWidth, screenHeight); + + +// Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 1.0f, 0.5f, 1.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera mode type + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + //UpdateCamera(&camera, CAMERA_FIRST_PERSON); + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawModel(model, position, 1.0f, WHITE); + + EndMode3D(); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + //UnloadTexture(texture); // Unload texture + UnloadModel(model); // Unload model + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} +// #define _USE_MATH_DEFINES +// #include +// #include +// #include +// #include +// //#include "glad/glad.h" +// #define GLAD_MALLOC(sz) malloc(sz) +// #define GLAD_FREE(sz) free(sz) +// //#define GLAD_GL_IMPLEMENTATION +// #include "../thirdparty/raylib/src/external/glad.h" +// #include "GLFW/glfw3.h" +// #include "raylib.h" + +// #define LIGHTMAPPER_IMPLEMENTATION +// #define LM_DEBUG_INTERPOLATION +// #include "lightmapper.h" + +// #ifndef M_PI // even with _USE_MATH_DEFINES not always available +// #define M_PI 3.14159265358979323846 +// #endif + +// typedef struct { +// float p[3]; +// float t[2]; +// } vertex_t; + +// typedef struct +// { +// GLuint program; +// GLint u_lightmap; +// GLint u_projection; +// GLint u_view; + +// GLuint lightmap; +// int w, h; +// Model raylib_model; +// GLuint vao, vbo, ibo; +// vertex_t *vertices; +// unsigned short *indices; +// unsigned int vertexCount, indexCount; +// } scene_t; + +// static int initScene(scene_t *scene); +// static void drawScene(scene_t *scene, float *view, float *projection); +// static void destroyScene(scene_t *scene); + +// static int bake(scene_t *scene) +// { +// lm_context *ctx = lmCreate( +// 64, // hemisphere resolution (power of two, max=512) +// 0.001f, 100.0f, // zNear, zFar of hemisphere cameras +// 1.0f, 1.0f, 1.0f, // background color (white for ambient occlusion) +// 2, 0.01f, // lightmap interpolation threshold (small differences are interpolated rather than sampled) +// // check debug_interpolation.tga for an overview of sampled (red) vs interpolated (green) pixels. +// 0.0f); // modifier for camera-to-surface distance for hemisphere rendering. +// // tweak this to trade-off between interpolated normals quality and other artifacts (see declaration). + +// if (!ctx) +// { +// fprintf(stderr, "Error: Could not initialize lightmapper.\n"); +// return 0; +// } + +// int w = scene->w, h = scene->h; +// float *data = calloc(w * h * 4, sizeof(float)); +// lmSetTargetLightmap(ctx, data, w, h, 4); + +// lmSetGeometry(ctx, NULL, // no transformation in this example +// LM_FLOAT, (unsigned char*)scene->vertices + offsetof(vertex_t, p), sizeof(vertex_t), +// LM_NONE , NULL , 0 , // no interpolated normals in this example +// LM_FLOAT, (unsigned char*)scene->vertices + offsetof(vertex_t, t), sizeof(vertex_t), +// scene->indexCount, LM_UNSIGNED_SHORT, scene->indices); + +// int vp[4]; +// float view[16], projection[16]; +// double lastUpdateTime = 0.0; +// while (lmBegin(ctx, vp, view, projection)) +// { +// // render to lightmapper framebuffer +// glViewport(vp[0], vp[1], vp[2], vp[3]); +// drawScene(scene, view, projection); + +// // display progress every second (printf is expensive) +// double time = glfwGetTime(); +// if (time - lastUpdateTime > 1.0) +// { +// lastUpdateTime = time; +// printf("\r%6.2f%%", lmProgress(ctx) * 100.0f); +// fflush(stdout); +// } + +// lmEnd(ctx); +// } +// printf("\rFinished baking %d triangles.\n", scene->indexCount / 3); + +// lmDestroy(ctx); + +// // postprocess texture +// float *temp = calloc(w * h * 4, sizeof(float)); +// for (int i = 0; i < 16; i++) +// { +// lmImageDilate(data, temp, w, h, 4); +// lmImageDilate(temp, data, w, h, 4); +// } +// lmImageSmooth(data, temp, w, h, 4); +// lmImageDilate(temp, data, w, h, 4); +// lmImagePower(data, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels +// free(temp); + +// // save result to a file +// if (lmImageSaveTGAf("result.tga", data, w, h, 4, 1.0f)) +// printf("Saved result.tga\n"); + +// // upload result +// glBindTexture(GL_TEXTURE_2D, scene->lightmap); +// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, data); +// free(data); + +// return 1; +// } + +// static void error_callback(int error, const char *description) +// { +// fprintf(stderr, "Error: %s\n", description); +// } + +// static void fpsCameraViewMatrix(GLFWwindow *window, float *view); +// static void perspectiveMatrix(float *out, float fovy, float aspect, float zNear, float zFar); + +// static void mainLoop(GLFWwindow *window, scene_t *scene) +// { +// glfwPollEvents(); +// if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) +// bake(scene); + +// int w, h; +// glfwGetFramebufferSize(window, &w, &h); +// glViewport(0, 0, w, h); + +// // camera for glfw window +// float view[16], projection[16]; +// fpsCameraViewMatrix(window, view); +// perspectiveMatrix(projection, 45.0f, (float)w / (float)h, 0.01f, 100.0f); + +// // draw to screen with a blueish sky +// glClearColor(0.6f, 0.8f, 1.0f, 1.0f); +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// drawScene(scene, view, projection); + +// glfwSwapBuffers(window); +// } + +// int main(int argc, char* argv[]) +// { +// glfwSetErrorCallback(error_callback); + +// if (!glfwInit()) +// { +// fprintf(stderr, "Could not initialize GLFW.\n"); +// return EXIT_FAILURE; +// } + +// glfwWindowHint(GLFW_RED_BITS, 8); +// glfwWindowHint(GLFW_GREEN_BITS, 8); +// glfwWindowHint(GLFW_BLUE_BITS, 8); +// glfwWindowHint(GLFW_ALPHA_BITS, 8); +// glfwWindowHint(GLFW_DEPTH_BITS, 32); +// glfwWindowHint(GLFW_STENCIL_BITS, GLFW_DONT_CARE); +// glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); +// glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); +// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +// glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); +// glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); +// glfwWindowHint(GLFW_SAMPLES, 4); + +// GLFWwindow *window = glfwCreateWindow(1024, 768, "Lightmapping Example", NULL, NULL); +// if (!window) +// { +// fprintf(stderr, "Could not create window.\n"); +// glfwTerminate(); +// return EXIT_FAILURE; +// } + +// glfwMakeContextCurrent(window); +// gladLoadGL((GLADloadfunc)glfwGetProcAddress); +// glfwSwapInterval(1); + +// scene_t scene = {0}; +// if (!initScene(&scene)) +// { +// fprintf(stderr, "Could not initialize scene.\n"); +// glfwDestroyWindow(window); +// glfwTerminate(); +// return EXIT_FAILURE; +// } + +// printf("Ambient Occlusion Baking Example.\n"); +// printf("Use your mouse and the W, A, S, D, E, Q keys to navigate.\n"); +// printf("Press SPACE to start baking one light bounce!\n"); +// printf("This will take a few seconds and bake a lightmap illuminated by:\n"); +// printf("1. The mesh itself (initially black)\n"); +// printf("2. A white sky (1.0f, 1.0f, 1.0f)\n"); + +// while (!glfwWindowShouldClose(window)) +// { +// mainLoop(window, &scene); +// } + +// destroyScene(&scene); +// glfwDestroyWindow(window); +// glfwTerminate(); +// return EXIT_SUCCESS; +// } + +// // helpers //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// static int loadSimpleObjFile(const char *filename, vertex_t **vertices, unsigned int *vertexCount, unsigned short **indices, unsigned int *indexCount); +// static GLuint loadProgram(const char *vp, const char *fp, const char **attributes, int attributeCount); + +// static int initScene(scene_t *scene) +// { +// // load mesh +// scene->raylib_model = LoadModel("thirdparty/lightmapper/example/gazebo.obj"); +// //scene->vertices = myModel.meshes[0]. +// if (!loadSimpleObjFile("thirdparty/lightmapper/example/gazebo.obj", &scene->vertices, &scene->vertexCount, &scene->indices, &scene->indexCount)) +// { +// fprintf(stderr, "Error loading obj file\n"); +// return 0; +// } + +// glGenVertexArrays(1, &scene->vao); +// glBindVertexArray(scene->vao); + +// glGenBuffers(1, &scene->vbo); +// glBindBuffer(GL_ARRAY_BUFFER, scene->vbo); +// glBufferData(GL_ARRAY_BUFFER, scene->vertexCount * sizeof(vertex_t), scene->vertices, GL_STATIC_DRAW); + +// glGenBuffers(1, &scene->ibo); +// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, scene->ibo); +// glBufferData(GL_ELEMENT_ARRAY_BUFFER, scene->indexCount * sizeof(unsigned short), scene->indices, GL_STATIC_DRAW); + +// glEnableVertexAttribArray(0); +// glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void*)offsetof(vertex_t, p)); +// glEnableVertexAttribArray(1); +// glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void*)offsetof(vertex_t, t)); + +// // create lightmap texture +// scene->w = 654; +// scene->h = 654; +// glGenTextures(1, &scene->lightmap); +// glBindTexture(GL_TEXTURE_2D, scene->lightmap); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +// unsigned char emissive[] = { 0, 0, 0, 255 }; +// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, emissive); + +// // load shader +// const char *vp = +// "#version 150 core\n" +// "in vec3 a_position;\n" +// "in vec2 a_texcoord;\n" +// "uniform mat4 u_view;\n" +// "uniform mat4 u_projection;\n" +// "out vec2 v_texcoord;\n" + +// "void main()\n" +// "{\n" +// "gl_Position = u_projection * (u_view * vec4(a_position, 1.0));\n" +// "v_texcoord = a_texcoord;\n" +// "}\n"; + +// const char *fp = +// "#version 150 core\n" +// "in vec2 v_texcoord;\n" +// "uniform sampler2D u_lightmap;\n" +// "out vec4 o_color;\n" + +// "void main()\n" +// "{\n" +// "o_color = vec4(texture(u_lightmap, v_texcoord).rgb, gl_FrontFacing ? 1.0 : 0.0);\n" +// "}\n"; + +// const char *attribs[] = +// { +// "a_position", +// "a_texcoord" +// }; + +// scene->program = loadProgram(vp, fp, attribs, 2); +// if (!scene->program) +// { +// fprintf(stderr, "Error loading shader\n"); +// return 0; +// } +// scene->u_view = glGetUniformLocation(scene->program, "u_view"); +// scene->u_projection = glGetUniformLocation(scene->program, "u_projection"); +// scene->u_lightmap = glGetUniformLocation(scene->program, "u_lightmap"); + +// return 1; +// } + +// static void drawScene(scene_t *scene, float *view, float *projection) +// { +// glEnable(GL_DEPTH_TEST); + +// glUseProgram(scene->program); +// glUniform1i(scene->u_lightmap, 0); +// glUniformMatrix4fv(scene->u_projection, 1, GL_FALSE, projection); +// glUniformMatrix4fv(scene->u_view, 1, GL_FALSE, view); + +// glBindTexture(GL_TEXTURE_2D, scene->lightmap); + +// glBindVertexArray(scene->vao); +// glDrawElements(GL_TRIANGLES, scene->indexCount, GL_UNSIGNED_SHORT, 0); +// } + +// static void destroyScene(scene_t *scene) +// { +// free(scene->vertices); +// free(scene->indices); +// glDeleteVertexArrays(1, &scene->vao); +// glDeleteBuffers(1, &scene->vbo); +// glDeleteBuffers(1, &scene->ibo); +// glDeleteTextures(1, &scene->lightmap); +// glDeleteProgram(scene->program); +// } + +// static int loadSimpleObjFile(const char *filename, vertex_t **vertices, unsigned int *vertexCount, unsigned short **indices, unsigned int *indexCount) +// { +// FILE *file = fopen(filename, "rt"); +// if (!file) +// return 0; +// char line[1024]; + +// // first pass +// unsigned int np = 0, nn = 0, nt = 0, nf = 0; +// while (!feof(file)) +// { +// fgets(line, 1024, file); +// if (line[0] == '#') continue; +// if (line[0] == 'v') +// { +// if (line[1] == ' ') { np++; continue; } +// if (line[1] == 'n') { nn++; continue; } +// if (line[1] == 't') { nt++; continue; } +// assert(!"unknown vertex attribute"); +// } +// if (line[0] == 'f') { nf++; continue; } +// assert(!"unknown identifier"); +// } +// assert(np && np == nn && np == nt && nf); // only supports obj files without separately indexed vertex attributes + +// // allocate memory +// *vertexCount = np; +// *vertices = calloc(np, sizeof(vertex_t)); +// *indexCount = nf * 3; +// *indices = calloc(nf * 3, sizeof(unsigned short)); + +// // second pass +// fseek(file, 0, SEEK_SET); +// unsigned int cp = 0, cn = 0, ct = 0, cf = 0; +// while (!feof(file)) +// { +// fgets(line, 1024, file); +// if (line[0] == '#') continue; +// if (line[0] == 'v') +// { +// if (line[1] == ' ') { float *p = (*vertices)[cp++].p; char *e1, *e2; p[0] = (float)strtod(line + 2, &e1); p[1] = (float)strtod(e1, &e2); p[2] = (float)strtod(e2, 0); continue; } +// if (line[1] == 'n') { /*float *n = (*vertices)[cn++].n; char *e1, *e2; n[0] = (float)strtod(line + 3, &e1); n[1] = (float)strtod(e1, &e2); n[2] = (float)strtod(e2, 0);*/ continue; } // no normals needed +// if (line[1] == 't') { float *t = (*vertices)[ct++].t; char *e1; t[0] = (float)strtod(line + 3, &e1); t[1] = (float)strtod(e1, 0); continue; } +// assert(!"unknown vertex attribute"); +// } +// if (line[0] == 'f') +// { +// unsigned short *tri = (*indices) + cf; +// cf += 3; +// char *e1, *e2, *e3 = line + 1; +// for (int i = 0; i < 3; i++) +// { +// unsigned long pi = strtoul(e3 + 1, &e1, 10); +// assert(e1[0] == '/'); +// unsigned long ti = strtoul(e1 + 1, &e2, 10); +// assert(e2[0] == '/'); +// unsigned long ni = strtoul(e2 + 1, &e3, 10); +// assert(pi == ti && pi == ni); +// tri[i] = (unsigned short)(pi - 1); +// } +// continue; +// } +// assert(!"unknown identifier"); +// } + +// fclose(file); +// return 1; +// } + +// static GLuint loadShader(GLenum type, const char *source) +// { +// GLuint shader = glCreateShader(type); +// if (shader == 0) +// { +// fprintf(stderr, "Could not create shader!\n"); +// return 0; +// } +// glShaderSource(shader, 1, &source, NULL); +// glCompileShader(shader); +// GLint compiled; +// glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); +// if (!compiled) +// { +// fprintf(stderr, "Could not compile shader!\n"); +// GLint infoLen = 0; +// glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); +// if (infoLen) +// { +// char* infoLog = (char*)malloc(infoLen); +// glGetShaderInfoLog(shader, infoLen, NULL, infoLog); +// fprintf(stderr, "%s\n", infoLog); +// free(infoLog); +// } +// glDeleteShader(shader); +// return 0; +// } +// return shader; +// } +// static GLuint loadProgram(const char *vp, const char *fp, const char **attributes, int attributeCount) +// { +// GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vp); +// if (!vertexShader) +// return 0; +// GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fp); +// if (!fragmentShader) +// { +// glDeleteShader(vertexShader); +// return 0; +// } + +// GLuint program = glCreateProgram(); +// if (program == 0) +// { +// fprintf(stderr, "Could not create program!\n"); +// return 0; +// } +// glAttachShader(program, vertexShader); +// glAttachShader(program, fragmentShader); + +// for (int i = 0; i < attributeCount; i++) +// glBindAttribLocation(program, i, attributes[i]); + +// glLinkProgram(program); +// glDeleteShader(vertexShader); +// glDeleteShader(fragmentShader); +// GLint linked; +// glGetProgramiv(program, GL_LINK_STATUS, &linked); +// if (!linked) +// { +// fprintf(stderr, "Could not link program!\n"); +// GLint infoLen = 0; +// glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen); +// if (infoLen) +// { +// char* infoLog = (char*)malloc(sizeof(char) * infoLen); +// glGetProgramInfoLog(program, infoLen, NULL, infoLog); +// fprintf(stderr, "%s\n", infoLog); +// free(infoLog); +// } +// glDeleteProgram(program); +// return 0; +// } +// return program; +// } + +// static void multiplyMatrices(float *out, float *a, float *b) +// { +// for (int y = 0; y < 4; y++) +// for (int x = 0; x < 4; x++) +// out[y * 4 + x] = a[x] * b[y * 4] + a[4 + x] * b[y * 4 + 1] + a[8 + x] * b[y * 4 + 2] + a[12 + x] * b[y * 4 + 3]; +// } +// static void translationMatrix(float *out, float x, float y, float z) +// { +// out[ 0] = 1.0f; out[ 1] = 0.0f; out[ 2] = 0.0f; out[ 3] = 0.0f; +// out[ 4] = 0.0f; out[ 5] = 1.0f; out[ 6] = 0.0f; out[ 7] = 0.0f; +// out[ 8] = 0.0f; out[ 9] = 0.0f; out[10] = 1.0f; out[11] = 0.0f; +// out[12] = x; out[13] = y; out[14] = z; out[15] = 1.0f; +// } +// static void rotationMatrix(float *out, float angle, float x, float y, float z) +// { +// angle *= (float)M_PI / 180.0f; +// float c = cosf(angle), s = sinf(angle), c2 = 1.0f - c; +// out[ 0] = x*x*c2 + c; out[ 1] = y*x*c2 + z*s; out[ 2] = x*z*c2 - y*s; out[ 3] = 0.0f; +// out[ 4] = x*y*c2 - z*s; out[ 5] = y*y*c2 + c; out[ 6] = y*z*c2 + x*s; out[ 7] = 0.0f; +// out[ 8] = x*z*c2 + y*s; out[ 9] = y*z*c2 - x*s; out[10] = z*z*c2 + c; out[11] = 0.0f; +// out[12] = 0.0f; out[13] = 0.0f; out[14] = 0.0f; out[15] = 1.0f; +// } +// static void transformPosition(float *out, float *m, float *p) +// { +// float d = 1.0f / (m[3] * p[0] + m[7] * p[1] + m[11] * p[2] + m[15]); +// out[2] = d * (m[2] * p[0] + m[6] * p[1] + m[10] * p[2] + m[14]); +// out[1] = d * (m[1] * p[0] + m[5] * p[1] + m[ 9] * p[2] + m[13]); +// out[0] = d * (m[0] * p[0] + m[4] * p[1] + m[ 8] * p[2] + m[12]); +// } +// static void transposeMatrix(float *out, float *m) +// { +// out[ 0] = m[0]; out[ 1] = m[4]; out[ 2] = m[ 8]; out[ 3] = m[12]; +// out[ 4] = m[1]; out[ 5] = m[5]; out[ 6] = m[ 9]; out[ 7] = m[13]; +// out[ 8] = m[2]; out[ 9] = m[6]; out[10] = m[10]; out[11] = m[14]; +// out[12] = m[3]; out[13] = m[7]; out[14] = m[11]; out[15] = m[15]; +// } +// static void perspectiveMatrix(float *out, float fovy, float aspect, float zNear, float zFar) +// { +// float f = 1.0f / tanf(fovy * (float)M_PI / 360.0f); +// float izFN = 1.0f / (zNear - zFar); +// out[ 0] = f / aspect; out[ 1] = 0.0f; out[ 2] = 0.0f; out[ 3] = 0.0f; +// out[ 4] = 0.0f; out[ 5] = f; out[ 6] = 0.0f; out[ 7] = 0.0f; +// out[ 8] = 0.0f; out[ 9] = 0.0f; out[10] = (zFar + zNear) * izFN; out[11] = -1.0f; +// out[12] = 0.0f; out[13] = 0.0f; out[14] = 2.0f * zFar * zNear * izFN; out[15] = 0.0f; +// } + +// static void fpsCameraViewMatrix(GLFWwindow *window, float *view) +// { +// // initial camera config +// static float position[] = { 0.0f, 0.3f, 1.5f }; +// static float rotation[] = { 0.0f, 0.0f }; + +// // mouse look +// static double lastMouse[] = { 0.0, 0.0 }; +// double mouse[2]; +// glfwGetCursorPos(window, &mouse[0], &mouse[1]); +// if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) +// { +// rotation[0] += (float)(mouse[1] - lastMouse[1]) * -0.2f; +// rotation[1] += (float)(mouse[0] - lastMouse[0]) * -0.2f; +// } +// lastMouse[0] = mouse[0]; +// lastMouse[1] = mouse[1]; + +// float rotationY[16], rotationX[16], rotationYX[16]; +// rotationMatrix(rotationX, rotation[0], 1.0f, 0.0f, 0.0f); +// rotationMatrix(rotationY, rotation[1], 0.0f, 1.0f, 0.0f); +// multiplyMatrices(rotationYX, rotationY, rotationX); + +// // keyboard movement (WSADEQ) +// float speed = (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) ? 0.1f : 0.01f; +// float movement[3] = {0}; +// if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) movement[2] -= speed; +// if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) movement[2] += speed; +// if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) movement[0] -= speed; +// if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) movement[0] += speed; +// if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) movement[1] -= speed; +// if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) movement[1] += speed; + +// float worldMovement[3]; +// transformPosition(worldMovement, rotationYX, movement); +// position[0] += worldMovement[0]; +// position[1] += worldMovement[1]; +// position[2] += worldMovement[2]; + +// // construct view matrix +// float inverseRotation[16], inverseTranslation[16]; +// transposeMatrix(inverseRotation, rotationYX); +// translationMatrix(inverseTranslation, -position[0], -position[1], -position[2]); +// multiplyMatrices(view, inverseRotation, inverseTranslation); // = inverse(translation(position) * rotationYX); +// }