diff --git a/.gitmodules b/.gitmodules index 14c1e6d..5228b17 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "libs/imgui"] path = libs/imgui url = git@github.com:ocornut/imgui.git +[submodule "libs/stb"] + path = libs/stb + url = https://github.com/nothings/stb diff --git a/build.sh b/build.sh index d466b68..c424f2a 100755 --- a/build.sh +++ b/build.sh @@ -6,20 +6,21 @@ mkdir -p build SOURCE="src/main.cpp" NAME="boids.html" VERSION="00" -CONFIG="-DSHOW_UI=0" +CONFIG="-DNO_CONTROL_PANEL" # files SET_FRONTEND_TEMPLATE="--shell-file site/index.html" FILES="${FILES} --preload-file src/view/shaders/boids.vertex.glsl" FILES="${FILES} --preload-file src/view/shaders/boids.fragment.glsl" +FILES="${FILES} --preload-file res/texture.jpeg" # includes and libs -INCS="${INCS} -I libs/base -I libs/glad -I libs/imgui" -LIBS="-lm -lGL -lpthread -lglfw -L libs/imgui/ -limgui" +INCS="-I libs/glad -I libs/imgui -I libs/base -I libs/stb" +LIBS="-L ./libs/archives -lm -lGL -lpthread -lglfw -limgui -lstb" # flags -EMFLAGS="-s USE_GLFW=3 -s FULL_ES3=1 -s USE_WEBGL2=1 -DPLATFORM_WEB" +EMFLAGS="-s USE_GLFW=3 -s FULL_ES3=1 -s USE_WEBGL2=1 -DPLATFORM_WEB -s MAXIMUM_MEMORY=1GB -s ALLOW_MEMORY_GROWTH" CPPFLAGS="${CPPFLAGS} -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\"" CFLAGS="${CFLAGS} -g -Wall -Wno-deprecated-declarations -Wno-write-strings -Wno-writable-strings -Wno-unused-function -O3 ${INCS} ${CPPFLAGS}" @@ -28,7 +29,7 @@ CC="em++" # building echo "[build.sh]# building $NAME" -echo ${CC} $CFLAGS ${EMFLAGS} ${FILES} -o "build/$NAME" $SOURCE $LIBS $SET_FRONTEND_TEMPLATE -${CC} $CFLAGS ${EMFLAGS} ${FILES} -o "build/$NAME" $SOURCE $LIBS $SET_FRONTEND_TEMPLATE +echo ${CC} $CFLAGS ${EMFLAGS} ${FILES} ${CONFIG} -o "build/$NAME" $SOURCE $LIBS $SET_FRONTEND_TEMPLATE +${CC} $CFLAGS ${EMFLAGS} ${FILES} ${CONFIG} -o "build/$NAME" $SOURCE $LIBS $SET_FRONTEND_TEMPLATE echo "[build.sh]# finished building" diff --git a/libs/.gitignore b/libs/.gitignore new file mode 100644 index 0000000..a565f01 --- /dev/null +++ b/libs/.gitignore @@ -0,0 +1 @@ +archives/ diff --git a/libs/build.sh b/libs/build.sh new file mode 100755 index 0000000..f9c2492 --- /dev/null +++ b/libs/build.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +ARCHIVE_DIR="archives" +mkdir -p $ARCHIVE_DIR + +IMGUI_DIR="imgui" +IMGUI_CXX=emcc +IMGUI_CXXFLAGS="-Wall -I. -Ibackends" +IMGUI_SOURCES=("imgui.cpp" "imgui_draw.cpp" "imgui_widgets.cpp" "imgui_tables.cpp" "backends/imgui_impl_glfw.cpp" "backends/imgui_impl_opengl3.cpp") + +STB_DIR="stb" +STB_CXX=emcc +STB_CXXFLAGS="-Wall -I." +STB_SOURCES=("stb_image.cpp") + + +build() { + local DIR=$1 + local CXX=$2 + local CXXFLAGS=$3 + shift 3 + local SOURCES=("$@") + + cd $DIR || exit 1 + + OBJECTS=() + LIBRARY="lib${DIR}.a" + + echo "building $LIBRARY... " + + for src in "${SOURCES[@]}"; do + OBJECTS+=("${src%.cpp}.o") + done + + for src in "${SOURCES[@]}"; do + $CXX $CXXFLAGS -c $src -o "${src%.cpp}.o" + done + + + ar rcs "../$ARCHIVE_DIR/$LIBRARY" "${OBJECTS[@]}" + + rm -f "${OBJECTS[@]}" + + cd .. || exit 1 +} + +case "$1" in + all) + build $IMGUI_DIR $IMGUI_CXX "$IMGUI_CXXFLAGS" "${IMGUI_SOURCES[@]}" + + echo '#define STB_IMAGE_IMPLEMENTATION' > "$STB_DIR/stb_image.cpp" + echo '#include "stb_image.h"' >> "$STB_DIR/stb_image.cpp" + build $STB_DIR $STB_CXX "$STB_CXXFLAGS" "${STB_SOURCES[@]}" + rm -f "$STB_DIR/stb_image.cpp" + ;; + clean) + echo "cleaning..." + rm -rf $ARCHIVE_DIR + ;; + *) + echo "Usage: $0 {all|clean}" + exit 1 + ;; +esac + diff --git a/libs/buildlibs.sh b/libs/buildlibs.sh deleted file mode 100755 index c24cb20..0000000 --- a/libs/buildlibs.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - - -cd imgui/ - -CXX=g++ -EMCXX=emcc -CXXFLAGS="-Wall" -EMCXXFLAGS="-Wall -I. -Ibackends" - -SOURCES=("imgui.cpp" "imgui_draw.cpp" "imgui_widgets.cpp" "imgui_tables.cpp" "backends/imgui_impl_glfw.cpp" "backends/imgui_impl_opengl3.cpp") -OBJECTS=() -EM_OBJECTS=() -EM_LIBRARY="libimgui.a" - -for src in "${SOURCES[@]}"; do - OBJECTS+=("${src%.cpp}.o") - EM_OBJECTS+=("${src%.cpp}.em.o") -done - -build_all() { - build_em_library -} - -build_em_library() { - for src in "${SOURCES[@]}"; do - emcc $EMCXXFLAGS -c $src -o "${src%.cpp}.em.o" - done - emcc -r "${EM_OBJECTS[@]}" -o $EM_LIBRARY -} - -clean() { - rm -f "${OBJECTS[@]}" "${EM_OBJECTS[@]}" $EM_LIBRARY -} - -case "$1" in - all) - build_all - ;; - clean) - clean - ;; - *) - echo "Usage: $0 {all|clean}" - exit 1 - ;; -esac - diff --git a/libs/imgui b/libs/imgui index 7237d3e..a18f020 160000 --- a/libs/imgui +++ b/libs/imgui @@ -1 +1 @@ -Subproject commit 7237d3e5c3a6b837b7b457460877cf5eea8c3745 +Subproject commit a18f02007234edbcf1082abf679f5db6623a38a9 diff --git a/libs/stb b/libs/stb new file mode 160000 index 0000000..f75e8d1 --- /dev/null +++ b/libs/stb @@ -0,0 +1 @@ +Subproject commit f75e8d1cad7d90d72ef7a4661f1b994ef78b4e31 diff --git a/res/texture.jpeg b/res/texture.jpeg new file mode 100644 index 0000000..c76b468 Binary files /dev/null and b/res/texture.jpeg differ diff --git a/src/boids.cpp b/src/boids.cpp index 03d34e6..25be5af 100644 --- a/src/boids.cpp +++ b/src/boids.cpp @@ -130,9 +130,6 @@ update_boid(BoidsApplication *app, Boid *b) { internal void update_boids(BoidsApplication *app) { - // TODO(Elias): use a swap buffer - // TODO(Elias): make this parallel -#pragma omp for parallel for (int32 i = 0; i < app->n; ++i) { update_boid(app, &(app->bs[i])); } @@ -144,21 +141,20 @@ init_boid(Boid *b, Param *p) { b->pos.y = rand() % window_height; b->vel.x = (rand() % 100 - 50) / 50.0f; b->vel.y = (rand() % 100 - 50) / 50.0f; - printf("b->vel.x: %f, b->vel.y: %f\n", b->vel.x, b->vel.y); } internal void init_boids_app(BoidsApplication *app) { Param *p = &app->p; - app->n = 800; + app->n = 2000; p->r = 50; - p->theta_max = 3.14 / 4; + p->theta_max = 3.14 / 5; p->c = 0.01; p->s_r = 10; p->s = 0.1; p->a = 0.1; p->max_vel = 10.0; - p->size = 1.0f; + p->size = 2.0f; app->bs = (Boid *)calloc(MAX_BOIDS, sizeof(Boid)); for (int32 i = 0; i < MAX_BOIDS; ++i) { diff --git a/src/main.cpp b/src/main.cpp index edcd809..fc2bf7a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #define ENABLE_ASSERT 1 #define ENABLE_DEBUGLOG 1 @@ -26,6 +27,7 @@ #include "boids.cpp" #include "view/shaders.cpp" +#include "view/textures.cpp" #include "view/rendering.cpp" // TODO(Elias): !!!! Let boids be influenced by music !!!! @@ -62,7 +64,7 @@ frame() { Process *p = &PROCESS; float64 start_time = glfwGetTime(); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glfwPollEvents(); @@ -71,9 +73,7 @@ frame() { update_boids(&p->boids_app); render(&p->gpu, &p->boids_app); -#if SHOW_UI imgui_frame(p); -#endif glfwSwapBuffers(p->ctx.window); diff --git a/src/view/imgui.cpp b/src/view/imgui.cpp index 82933d2..54fd5d6 100644 --- a/src/view/imgui.cpp +++ b/src/view/imgui.cpp @@ -20,13 +20,16 @@ imgui_frame(Process *p) { ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); - ImGui::SetNextWindowSize(ImVec2(500, 300)); - ImGui::Begin("Controls", NULL, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - ImGui::Text("Process Information"); + uint32 margin = 10; + ImGui::SetNextWindowSize(ImVec2(300, 50)); + ImGui::SetNextWindowPos(ImVec2(window_width - 300 - margin, + window_height - 50 - margin)); + ImGui::Begin("Process Information", NULL, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); ImGui::Text("Frame Time: %.3f ms | FPS: %.1f", p->ctx.frame_time * 1000.0f, p->ctx.fps); - ImGui::Separator(); - ImGui::Text("Boids controls"); + ImGui::End(); +#ifndef NO_CONTROL_PANEL + ImGui::Begin("Controls", NULL, ImGuiWindowFlags_NoCollapse); ImGui::SliderInt("Number of Boids", &p->boids_app.n, 0, MAX_BOIDS); ImGui::SliderFloat("Cohesion", &p->boids_app.p.c, 0.0f, 1.0f); ImGui::SliderFloat("Separation", &p->boids_app.p.s, 0.0f, 1.0f); @@ -37,6 +40,7 @@ imgui_frame(Process *p) { ImGui::SliderFloat("Max Velocity", &p->boids_app.p.max_vel, 1.0f, 20.0f); ImGui::SliderFloat("Point Size", &p->boids_app.p.size, 1.0f, 10.0f); ImGui::End(); +#endif ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); diff --git a/src/view/rendering.cpp b/src/view/rendering.cpp index d66631d..9ce61e0 100644 --- a/src/view/rendering.cpp +++ b/src/view/rendering.cpp @@ -4,6 +4,7 @@ struct gpu_context_t { uint32 boids_program; uint32 boids_vao_id; uint32 boids_vbo_id; + Texture tex; }; internal bool @@ -16,28 +17,34 @@ gpu_init(GpuContext *gpu) { print_error("Failed to load boids shader program"); return false; } + + if (!load_texture("res/texture.jpeg", &gpu->tex)) { + print_error("failed to load texture"); + return false; + } + + glUseProgram(gpu->boids_program); + glUniform1i(glGetUniformLocation(gpu->boids_program, "tex"), 0); + glGenVertexArrays(1, &gpu->boids_vao_id); glGenBuffers(1, &gpu->boids_vbo_id); + return is_success; } internal void gpu_die(GpuContext *gpu) { + texture_die(&gpu->tex); + glDeleteBuffers(1, &gpu->boids_vbo_id); + glDeleteVertexArrays(1, &gpu->boids_vao_id); glprogram_die(gpu->boids_program); } -internal void -push_data_to_gpu() { -} - internal void render(GpuContext *gpu, BoidsApplication *app) { - GLint u_window_width = glGetUniformLocation(gpu->boids_program, - "u_window_width"); - GLint u_window_height = glGetUniformLocation(gpu->boids_program, - "u_window_height"); - GLint u_point_size = glGetUniformLocation(gpu->boids_program, - "u_point_size"); + GLint u_window_width = glGetUniformLocation(gpu->boids_program, "u_window_width" ); + GLint u_window_height = glGetUniformLocation(gpu->boids_program, "u_window_height"); + GLint u_point_size = glGetUniformLocation(gpu->boids_program, "u_point_size" ); glBindVertexArray(gpu->boids_vao_id); glBindBuffer(GL_ARRAY_BUFFER, gpu->boids_vbo_id); @@ -50,6 +57,7 @@ render(GpuContext *gpu, BoidsApplication *app) { glEnableVertexAttribArray(1); glUseProgram(gpu->boids_program); + use_texture(&gpu->tex, 0); glUniform1f(u_window_width, window_width); glUniform1f(u_window_height, window_height); glUniform1f(u_point_size, app->p.size); diff --git a/src/view/shaders/boids.fragment.glsl b/src/view/shaders/boids.fragment.glsl index 6b1a8a4..3b7961d 100644 --- a/src/view/shaders/boids.fragment.glsl +++ b/src/view/shaders/boids.fragment.glsl @@ -2,13 +2,17 @@ precision mediump float; in vec2 v_vel; +in vec2 v_uv; + out vec4 out_color; +uniform sampler2D tex; + void main() { float hue = (atan(v_vel.y, v_vel.x) + 3.14159265359) / (2.0 * 3.14159265359); float r = abs(hue * 6.0 - 3.0) - 1.0; float g = 2.0 - abs(hue * 6.0 - 2.0); float b = 2.0 - abs(hue * 6.0 - 4.0); - out_color = vec4(r, g, b, 1.0); + out_color = mix(texture(tex, v_uv), vec4(r, g, b, 1.0), 0.0); } diff --git a/src/view/shaders/boids.vertex.glsl b/src/view/shaders/boids.vertex.glsl index 3b1d467..1fe0749 100644 --- a/src/view/shaders/boids.vertex.glsl +++ b/src/view/shaders/boids.vertex.glsl @@ -9,11 +9,13 @@ uniform float u_window_height; uniform float u_point_size; out vec2 v_vel; +out vec2 v_uv; void main() { gl_PointSize = u_point_size; - float x = (a_position.x / u_window_width) * 2.0 - 1.0; - float y = (a_position.y / u_window_height) * 2.0 - 1.0; - gl_Position = vec4(x, -y, 0.0, 1.0); + float x = (a_position.x / u_window_width) * 2.0 - 1.0; + float y = (a_position.y / u_window_height) * 2.0 - 1.0; + gl_Position = vec4(x, -y, 0.0, 1.0); + v_uv = a_position / vec2(u_window_width, u_window_height); v_vel = a_vel; } diff --git a/src/view/textures.cpp b/src/view/textures.cpp new file mode 100644 index 0000000..1fade83 --- /dev/null +++ b/src/view/textures.cpp @@ -0,0 +1,81 @@ + +struct Texture { + uint32 id; + uint32 w, h, c; +}; + +internal bool32 +load_texture_param(char *path, Texture *texture, int32 wrap_s, int32 wrap_t, + int32 min_filter, int32 mag_filter) { + uint32 t; + glGenTextures(1, &t); + glBindTexture(GL_TEXTURE_2D, t); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); + + int32 w, h, c; + uint8 *data = stbi_load(path, &w, &h, &c, 0); + if (!data) { + print_error("failed to load texture"); + return false; + } + + switch (c) { + case 3: { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + } break; + case 4: { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + } break; + case 1: { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data); + } break; + default: { + print_error("unsupported number of channels"); + return false; + } break; + } + + glGenerateMipmap(GL_TEXTURE_2D); + + stbi_image_free(data); + + texture->id = t; + texture->w = w; + texture->h = h; + texture->c = c; + return true; +} + +#define TEXTURE_DEFAULT_WRAP_S GL_REPEAT +#define TEXTURE_DEFAULT_WRAP_T GL_REPEAT +#define TEXTURE_DEFAULT_MIN_FILTER GL_LINEAR +#define TEXTURE_DEFAULT_MAG_FILTER GL_LINEAR + +internal bool32 +load_texture(char *path, Texture *texture) +{ + return load_texture_param(path, texture, + TEXTURE_DEFAULT_WRAP_S, + TEXTURE_DEFAULT_WRAP_T, + TEXTURE_DEFAULT_MIN_FILTER, + TEXTURE_DEFAULT_MAG_FILTER); +} + + +internal void +use_texture(Texture *texture, uint32 slot) +{ + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(GL_TEXTURE_2D, texture->id); +} + +internal void +texture_die(Texture *texture) +{ + glDeleteTextures(1, &texture->id); +} +