diff --git a/assets/VolumeControl.h b/assets/VolumeControl.h new file mode 100755 index 0000000..257e024 --- /dev/null +++ b/assets/VolumeControl.h @@ -0,0 +1,124 @@ +/******************************************************************************************* +* +* VolumeControl v1.0.0 - Tool Description +* +* MODULE USAGE: +* #define GUI_VOLUMECONTROL_IMPLEMENTATION +* #include "gui_VolumeControl.h" +* +* INIT: GuiVolumeControlState state = InitGuiVolumeControl(); +* DRAW: GuiVolumeControl(&state); +* +* LICENSE: Propietary License +* +* Copyright (c) 2022 Joshua Dahl. All Rights Reserved. +* +* Unauthorized copying of this file, via any medium is strictly prohibited +* This project is proprietary and confidential unless the owner allows +* usage in any other form by expresely written permission. +* +**********************************************************************************************/ + +#include "raylib.h" + +// WARNING: raygui implementation is expected to be defined before including this header +// #undef RAYGUI_IMPLEMENTATION +#include "raygui.h" + +#include // Required for: strcpy() + +#ifndef GUI_VOLUMECONTROL_H +#define GUI_VOLUMECONTROL_H + +typedef struct { + // Define anchors + Vector2 anchor01; // ANCHOR ID:1 + + // Define controls variables + float SFXSliderValue; // Slider: SFXSlider + float MusicSliderValue; // Slider: MusicSlider + float DialogueSliderValue; // Slider: DialogueSlider + + // Custom state variables (depend on development software) + // NOTE: This variables should be added manually if required + +} GuiVolumeControlState; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +GuiVolumeControlState InitGuiVolumeControl(void); +void GuiVolumeControl(GuiVolumeControlState *state); +// static void PingButton(); // Button: PingButton logic + +#ifdef __cplusplus +} +#endif + +#endif // GUI_VOLUMECONTROL_H + +/*********************************************************************************** +* +* GUI_VOLUMECONTROL IMPLEMENTATION +* +************************************************************************************/ +#if defined(GUI_VOLUMECONTROL_IMPLEMENTATION) + +#include "raygui.h" + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +GuiVolumeControlState InitGuiVolumeControl(void) { + GuiVolumeControlState state = { 0 }; + + // Init anchors + state.anchor01 = (Vector2){ 24, 24 }; // ANCHOR ID:1 + + // Initilize controls variables + state.SFXSliderValue = 0.0f; // Slider: SFXSlider + state.MusicSliderValue = 0.0f; // Slider: MusicSlider + state.DialogueSliderValue = 0.0f; // Slider: DialogueSlider + + // Custom variables initialization + + return state; +} + +// Button: PingButton logic +// static void PingButton() +// { +// // TODO: Implement in outer file! +// } + + +void GuiVolumeControl(GuiVolumeControlState *state) { + // Const text + const char *VolumeGroupText = "Volume Controls"; // GROUPBOX: VolumeGroup + const char *SFXGroupText = "SFXVolume"; // GROUPBOX: SFXGroup + const char *SFXSliderText = ""; // SLIDER: SFXSlider + const char *MusicGroupText = "MusicVolume"; // GROUPBOX: MusicGroup + const char *MusicSliderText = ""; // SLIDER: MusicSlider + const char *DialogueGroupText = "DialogueVolume"; // GROUPBOX: DialogueGroup + const char *DialogueSliderText = ""; // SLIDER: DialogueSlider + const char *PingButtonText = "Ping"; // BUTTON: PingButton + + // Draw controls + GuiGroupBox((Rectangle){ state->anchor01.x + 0, state->anchor01.y + 0, 256, 264 }, VolumeGroupText); + GuiGroupBox((Rectangle){ state->anchor01.x + 24, state->anchor01.y + 24, 208, 56 }, SFXGroupText); + GuiLabel((Rectangle){ 64, 64, 120, 24 }, TextFormat("%.0f%%", state->SFXSliderValue)); + state->SFXSliderValue = GuiSlider((Rectangle){ state->anchor01.x + 72, state->anchor01.y + 40, 144, 24 }, SFXSliderText, NULL, state->SFXSliderValue, 0, 100); + GuiGroupBox((Rectangle){ state->anchor01.x + 24, state->anchor01.y + 104, 208, 56 }, MusicGroupText); + GuiLabel((Rectangle){ 64, 144, 120, 24 }, TextFormat("%.0f%%", state->MusicSliderValue)); + state->MusicSliderValue = GuiSlider((Rectangle){ state->anchor01.x + 72, state->anchor01.y + 120, 144, 24 }, MusicSliderText, NULL, state->MusicSliderValue, 0, 100); + GuiGroupBox((Rectangle){ state->anchor01.x + 24, state->anchor01.y + 184, 208, 56 }, DialogueGroupText); + GuiLabel((Rectangle){ 64, 224, 120, 24 }, TextFormat("%.0f%%", state->DialogueSliderValue)); + state->DialogueSliderValue = GuiSlider((Rectangle){ state->anchor01.x + 72, state->anchor01.y + 200, 144, 24 }, DialogueSliderText, NULL, state->DialogueSliderValue, 0, 100); + if (GuiButton((Rectangle){ 24, 304, 256, 24 }, PingButtonText)) PingButton(); +} + +#endif // GUI_VOLUMECONTROL_IMPLEMENTATION diff --git a/assets/audio/crowd.wav b/assets/audio/crowd.wav new file mode 100755 index 0000000..86ef156 Binary files /dev/null and b/assets/audio/crowd.wav differ diff --git a/assets/audio/ping.wav b/assets/audio/ping.wav new file mode 100755 index 0000000..0993443 Binary files /dev/null and b/assets/audio/ping.wav differ diff --git a/assets/audio/price-of-freedom.mp3 b/assets/audio/price-of-freedom.mp3 new file mode 100755 index 0000000..cbe4b35 Binary files /dev/null and b/assets/audio/price-of-freedom.mp3 differ diff --git a/assets/includeable.cmake b/assets/includeable.cmake new file mode 100755 index 0000000..4d64a9a --- /dev/null +++ b/assets/includeable.cmake @@ -0,0 +1,7 @@ +#from: https://stackoverflow.com/questions/410980/include-a-text-file-in-a-c-program-as-a-char +function(make_includeable input_file output_file) + file(READ ${input_file} content) + set(delim "for_C++_include") + set(content "R\"${delim}(${content})${delim}\"") + file(WRITE ${output_file} "${content}") +endfunction(make_includeable) \ No newline at end of file diff --git a/assets/models/eagle.glb b/assets/models/eagle.glb new file mode 100644 index 0000000..a9f0062 Binary files /dev/null and b/assets/models/eagle.glb differ diff --git a/assets/models/penguin.glb b/assets/models/penguin.glb new file mode 100644 index 0000000..5763932 Binary files /dev/null and b/assets/models/penguin.glb differ diff --git a/assets/shaders/cubemap.fs b/assets/shaders/cubemap.fs new file mode 100755 index 0000000..69d1a97 --- /dev/null +++ b/assets/shaders/cubemap.fs @@ -0,0 +1,30 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; + +// Input uniform values +uniform sampler2D equirectangularMap; + +// Output fragment color +out vec4 finalColor; + +vec2 SampleSphericalMap(vec3 v) +{ + vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); + uv *= vec2(0.1591, 0.3183); + uv += 0.5; + return uv; +} + +void main() +{ + // Normalize local position + vec2 uv = SampleSphericalMap(normalize(fragPosition)); + + // Fetch color from texture map + vec3 color = texture(equirectangularMap, uv).rgb; + + // Calculate final fragment color + finalColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/assets/shaders/cubemap.vs b/assets/shaders/cubemap.vs new file mode 100755 index 0000000..5c791cc --- /dev/null +++ b/assets/shaders/cubemap.vs @@ -0,0 +1,20 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; + +// Input uniform values +uniform mat4 matProjection; +uniform mat4 matView; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; + +void main() +{ + // Calculate fragment position based on model transformations + fragPosition = vertexPosition; + + // Calculate final vertex position + gl_Position = matProjection*matView*vec4(vertexPosition, 1.0); +} \ No newline at end of file diff --git a/assets/shaders/skybox.fs b/assets/shaders/skybox.fs new file mode 100755 index 0000000..4a52428 --- /dev/null +++ b/assets/shaders/skybox.fs @@ -0,0 +1,30 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; + +// Input uniform values +uniform samplerCube environmentMap; +uniform bool vflipped; +uniform bool doGamma; + +// Output fragment color +out vec4 finalColor; + +void main() +{ + // Fetch color from texture map + vec3 color = vec3(0.0); + + if (vflipped) color = texture(environmentMap, vec3(fragPosition.x, -fragPosition.y, fragPosition.z)).rgb; + else color = texture(environmentMap, fragPosition).rgb; + + if (doGamma)// Apply gamma correction + { + color = color/(color + vec3(1.0)); + color = pow(color, vec3(1.0/2.2)); + } + + // Calculate final fragment color + finalColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/assets/shaders/skybox.vs b/assets/shaders/skybox.vs new file mode 100755 index 0000000..07ee8e8 --- /dev/null +++ b/assets/shaders/skybox.vs @@ -0,0 +1,24 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; + +// Input uniform values +uniform mat4 matProjection; +uniform mat4 matView; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; + +void main() +{ + // Calculate fragment position based on model transformations + fragPosition = vertexPosition; + + // Remove translation from the view matrix + mat4 rotView = mat4(mat3(matView)); + vec4 clipPos = matProjection*rotView*vec4(vertexPosition, 1.0); + + // Calculate final vertex position + gl_Position = clipPos; +} \ No newline at end of file diff --git a/assets/skybox.cpp b/assets/skybox.cpp new file mode 100644 index 0000000..0cd145c --- /dev/null +++ b/assets/skybox.cpp @@ -0,0 +1,168 @@ +/******************************************************************************************* +* +* raylib [models] example - Skybox loading and drawing +* +* Example originally created with raylib 1.8, last time updated with raylib 4.0 +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "skybox.hpp" +#include + +#include "rlgl.h" + +namespace cs381 { + + SkyBox& SkyBox::Init() { + // Load skybox model + cube = raylib::Mesh::Cube(1.0f, 1.0f, 1.0f).LoadModelFrom(); + + // Load skybox shader and set required locations + // NOTE: Some locations are automatically set at shader loading + shader = raylib::Shader::LoadFromMemory(vertexShader, fragmentShader); + cube.materials[0].shader = shader; + shader.SetValue("environmentMap", (int)MATERIAL_MAP_CUBEMAP, SHADER_UNIFORM_INT); + + return *this; + } + + SkyBox& SkyBox::Load(const std::string_view filename, bool isEnviornment/* = false*/) { + if(shader.id == 0) Init(); + + shader.SetValue("doGamma", int(isEnviornment ? 1 : 0), SHADER_UNIFORM_INT); + shader.SetValue("vflipped", int(isEnviornment ? 1 : 0), SHADER_UNIFORM_INT); + + if(isEnviornment) { + if(cubemapShader.id == 0){ + cubemapShader = raylib::Shader::LoadFromMemory(cubemapVertexShader, cubemapFragmentShader); + cubemapShader.SetValue("equirectangularMap", int(0), SHADER_UNIFORM_INT); + } + + // Load HDR panorama (sphere) texture + texture.Load(filename); + // Make sure that things aren't sampled in a pixelated manor! + texture.SetFilter(TEXTURE_FILTER_BILINEAR); + + // Generate cubemap (texture with 6 quads-cube-mapping) from panorama HDR texture + // NOTE 1: New texture is generated rendering to texture, shader calculates the sphere->cube coordinates mapping + // NOTE 2: It seems on some Android devices WebGL, fbo does not properly support a FLOAT-based attachment, + // despite texture can be successfully created.. so using PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 instead of PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 + cube.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = GenTextureCubemap(cubemapShader, texture, 1024, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); + } else { + raylib::Image img(filename); + texture.Load(img, CUBEMAP_LAYOUT_AUTO_DETECT); + // Make sure that things aren't sampled in a pixelated manor! + texture.SetFilter(TEXTURE_FILTER_BILINEAR); + cube.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = texture; // CUBEMAP_LAYOUT_PANORAMA + } + + return *this; + } + + SkyBox& SkyBox::Draw() { + // We are inside the cube, we need to disable backface culling! + rlDisableBackfaceCulling(); + rlDisableDepthMask(); + cube.Draw({}); + rlEnableBackfaceCulling(); + rlEnableDepthMask(); + + return *this; + } + + // Generate cubemap texture from HDR texture + TextureCubemap SkyBox::GenTextureCubemap(Shader shader, Texture2D panorama, int size, int format) { + TextureCubemap cubemap = { 0 }; + + rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube + + // STEP 1: Setup framebuffer + //------------------------------------------------------------------------------------------ + unsigned int rbo = rlLoadTextureDepth(size, size, true); + cubemap.id = rlLoadTextureCubemap(0, size, format); + + // unsigned int fbo = rlLoadFramebuffer(size, size); + unsigned int fbo = rlLoadFramebuffer(); + rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0); + rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X, 0); + + // Check if framebuffer is complete with attachments (valid) + if (rlFramebufferComplete(fbo)) TraceLog(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", fbo); + //------------------------------------------------------------------------------------------ + + // STEP 2: Draw to framebuffer + //------------------------------------------------------------------------------------------ + // NOTE: Shader is used to convert HDR equirectangular environment map to cubemap equivalent (6 faces) + rlEnableShader(shader.id); + + // Define projection matrix and send it to shader + Matrix matFboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); + rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_PROJECTION], matFboProjection); + + // Define view matrix for every side of the cubemap + Matrix fboViews[6] = { + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }) + }; + + rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions + + // Activate and enable texture for drawing to cubemap faces + rlActiveTextureSlot(0); + rlEnableTexture(panorama.id); + + for (int i = 0; i < 6; i++) { + // Set the view matrix for the current cube face + rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]); + + // Select the current cubemap face attachment for the fbo + // WARNING: This function by default enables->attach->disables fbo!!! + rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i, 0); + rlEnableFramebuffer(fbo); + + // Load and draw a cube, it uses the current enabled texture + rlClearScreenBuffers(); + rlLoadDrawCube(); + + // ALTERNATIVE: Try to use internal batch system to draw the cube instead of rlLoadDrawCube + // for some reason this method does not work, maybe due to cube triangles definition? normals pointing out? + // TODO: Investigate this issue... + //rlSetTexture(panorama.id); // WARNING: It must be called after enabling current framebuffer if using internal batch system! + //rlClearScreenBuffers(); + //DrawCubeV(Vector3Zero(), Vector3One(), WHITE); + //rlDrawRenderBatchActive(); + } + //------------------------------------------------------------------------------------------ + + // STEP 3: Unload framebuffer and reset state + //------------------------------------------------------------------------------------------ + rlDisableShader(); // Unbind shader + rlDisableTexture(); // Unbind texture + rlDisableFramebuffer(); // Unbind framebuffer + rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer) + + // Reset viewport dimensions to default + rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight()); + rlEnableBackfaceCulling(); + //------------------------------------------------------------------------------------------ + + cubemap.width = size; + cubemap.height = size; + cubemap.mipmaps = 1; + cubemap.format = format; + + return cubemap; + } + + raylib::Shader SkyBox::cubemapShader(0); + +} \ No newline at end of file diff --git a/assets/skybox.hpp b/assets/skybox.hpp new file mode 100644 index 0000000..fb481a4 --- /dev/null +++ b/assets/skybox.hpp @@ -0,0 +1,58 @@ +/******************************************************************************************* +* +* raylib [models] example - Skybox loading and drawing +* +* Example originally created with raylib 1.8, last time updated with raylib 4.0 +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2017-2023 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib-cpp.hpp" + +namespace cs381 { + struct SkyBox { + constexpr static std::string_view vertexShader = + #include "../generated/skybox.vs" + ; + constexpr static std::string_view fragmentShader = + #include "../generated/skybox.fs" + ; + constexpr static std::string_view cubemapVertexShader = + #include "../generated/cubemap.vs" + ; + constexpr static std::string_view cubemapFragmentShader = + #include "../generated/cubemap.fs" + ; + + static raylib::Shader cubemapShader; + + raylib::Texture texture; + raylib::Shader shader; + raylib::Model cube; + + SkyBox() : shader(0) {}; + SkyBox(SkyBox&) = delete; + SkyBox(SkyBox&&) = default; + SkyBox(const std::string_view filename, bool isEnviornment = false) : SkyBox() { + Load(filename, isEnviornment); + } + + ~SkyBox() { + if(cube.IsReady()) + UnloadTexture(cube.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture); + } + + SkyBox& Init(); + SkyBox& Load(const std::string_view filename, bool isEnviornment = false); + SkyBox& Draw(); + + + private: + // Generate cubemap texture from HDR texture + static TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, int format); + }; +} \ No newline at end of file diff --git a/assets/textures/grass.jpg b/assets/textures/grass.jpg new file mode 100755 index 0000000..736ab24 Binary files /dev/null and b/assets/textures/grass.jpg differ diff --git a/assets/textures/kloppenheim_05_puresky_1k.hdr b/assets/textures/kloppenheim_05_puresky_1k.hdr new file mode 100755 index 0000000..fbefa95 Binary files /dev/null and b/assets/textures/kloppenheim_05_puresky_1k.hdr differ diff --git a/assets/textures/runway.jpg b/assets/textures/runway.jpg new file mode 100755 index 0000000..af754c3 Binary files /dev/null and b/assets/textures/runway.jpg differ diff --git a/assets/textures/skybox.png b/assets/textures/skybox.png new file mode 100755 index 0000000..36a79b2 Binary files /dev/null and b/assets/textures/skybox.png differ