Now all configurable with json.

This commit is contained in:
Zed A. Shaw 2026-08-26 19:56:01 -04:00
parent 3041ae0172
commit d3169d3eca
25 changed files with 720 additions and 244 deletions

View file

@ -0,0 +1,96 @@
{
"scene": {
"shader": {
"vertex_path": "shaders/16-vert.glsl",
"frag_path": "shaders/16-frag.glsl"
},
"light_shader": {
"vertex_path": "shaders/16-vert.glsl",
"frag_path": "shaders/16-lightsource.frag.glsl"
},
"materials": {
"crate": {
"ambient": [0.5, 0.5, 0.5],
"shininess": 32.0,
"diffuseMap": 0,
"specularMap": 0
},
"popcorn": {
"ambient": [0.5, 0.25, 0.31],
"shininess": 10000.0,
"diffuseMap": 0,
"specularMap": 0
}
},
"models": {
"crate": {
"directory": "assets",
"model_path": "crate.obj"
}
},
"things": [
{"model": "crate", "position": [0.0, 0.0, 0.0], "material": "crate"},
{"model": "crate", "position": [2.0, 5.0, -15.0], "material": "crate"},
{"model": "crate", "position": [-1.5, -2.2, -2.5], "material": "crate"},
{"model": "crate", "position": [-3.8, -2.0, -12.3], "material": "crate"},
{"model": "crate", "position": [ 2.4, -0.4, -3.5], "material": "crate"},
{"model": "crate", "position": [-1.7, 3.0, -7.5], "material": "crate"},
{"model": "crate", "position": [ 1.3, -2.0, -2.5], "material": "crate"},
{"model": "crate", "position": [ 1.5, 2.0, -2.5], "material": "crate"},
{"model": "crate", "position": [ 1.5, 0.2, -1.5], "material": "crate"},
{"model": "crate", "position": [-1.3, 1.0, -1.5], "material": "crate"}
],
"camera": {
"position": [0.0, 0.0, 3.0],
"front": [0.0, 0.0, -1.0],
"up": [0.0, 1.0, 0.0],
"direction": [0.0, 0.0, 0.0],
"movement_speed": 10.0
},
"light": {
"directional": [
{
"position": [0, 0, 0.0],
"direction":[-0.2, -1.0, -0.3],
"ambient":[0.2, 0.2, 0.2],
"diffuse":[0.8, 0.8, 0.8],
"specular":[1.0, 1.0, 1.0],
"constant": 0.0,
"linear": 0.0,
"quadratic": 0.0,
"cut_off": 0.0,
"outer_cut_off": 0.0
}
],
"positioned": [
{
"position": [1.2, 1.0, 2.0],
"direction":[-0.2, -1.0, -0.3],
"ambient":[0.2, 0.2, 0.2],
"diffuse":[0.8, 0.8, 0.8],
"specular":[1.0, 1.0, 1.0],
"constant": 1.0,
"linear": 0.09,
"quadratic": 0.032,
"cut_off": 12.5,
"outer_cut_off": 17.5
}
],
"spot": [
],
"camera": {
"position":[2.2, 1.0, 2.0],
"direction":[0.0, 0.0, -1.0],
"ambient":[0.2, 0.2, 0.2],
"diffuse":[0.8, 0.8, 0.8],
"specular":[1.0, 1.0, 1.0],
"constant": 1.0,
"linear": 0.09,
"quadratic": 0.032,
"cut_off": 12.5,
"outer_cut_off": 17.5
}
}
}
}

View file

@ -61,12 +61,12 @@ glfw3 = subproject('glfw').get_variable('glfw_dep')
fuc2 = subproject('fuc2').get_variable('fuc2_dep')
fmt = subproject('fmt').get_variable('fmt_dep')
glm = subproject('glm').get_variable('glm_dep')
box2d = subproject('box2d').get_variable('box2d_dep')
json = subproject('nlohmann_json').get_variable('nlohmann_json_dep')
assimp = subproject('assimp').get_variable('assimp_dep')
dependencies += [
glfw3, fuc2, fmt, glm, box2d, assimp
glfw3, fuc2, fmt, glm, assimp, json
]
inc_dirs = ['src']
@ -76,8 +76,8 @@ sources = [
'src/dbc.cpp',
'src/stb_image.cpp',
'src/shader.cpp',
'src/physics.cpp',
'src/mesh.cpp',
'src/utils.cpp',
'src/model.cpp',
'src/scene.cpp',
'src/camera.cpp',

View file

@ -0,0 +1,162 @@
#version 330 core
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;
struct DirLight {
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
struct PointLight {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
struct SpotLight {
vec3 direction;
vec3 position;
vec3 diffuse;
vec3 specular;
vec3 ambient;
float constant;
float linear;
float quadratic;
float cut_off;
float outer_cut_off;
};
#define MAX_LIGHTS 4
uniform int pointLightCount = 0;
uniform PointLight pointLights[MAX_LIGHTS];
uniform int dirLightCount = 0;
uniform DirLight dirLights[MAX_LIGHTS];
uniform int spotLightCount = 0;
uniform SpotLight spotLights[MAX_LIGHTS];
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{
vec3 mat_tex = vec3(texture(material.diffuse, TexCoords));
vec3 spec_tex = vec3(texture(material.specular, TexCoords));
vec3 lightDir = normalize(-light.direction);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 ambient = light.ambient * mat_tex;
vec3 diffuse = light.diffuse * diff * mat_tex;
vec3 specular = light.specular * spec * spec_tex;
return ambient + diffuse + specular;
}
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 mat_tex = vec3(texture(material.diffuse, TexCoords));
vec3 spec_tex = vec3(texture(material.specular, TexCoords));
vec3 lightDir = normalize(light.position - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
vec3 ambient = light.ambient * mat_tex;
vec3 diffuse = light.diffuse * diff * mat_tex;
vec3 specular = light.specular * spec * spec_tex;
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return ambient + diffuse + specular;
}
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 mat_tex = vec3(texture(material.diffuse, TexCoords));
vec3 spec_tex = vec3(texture(material.specular, TexCoords));
vec3 lightDir = normalize(light.position - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
vec3 ambient = light.ambient * mat_tex;
vec3 diffuse = light.diffuse * diff * mat_tex;
vec3 specular = light.specular * spec * spec_tex;
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cut_off - light.outer_cut_off;
float intensity = clamp((theta - light.outer_cut_off) / epsilon, 0.0, 1.0);
diffuse *= intensity;
specular *= intensity;
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return ambient + diffuse + specular;
}
void main()
{
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
// kick it off with the first dirlight
vec3 result = CalcDirLight(dirLights[0], norm, viewDir);
// then augment with more (off by one)
for(int i = 1; i < dirLightCount; i++) {
result += CalcDirLight(dirLights[i], norm, viewDir);
}
for(int i = 0; i < pointLightCount; i++) {
result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);
}
for(int i = 0; i < spotLightCount; i++) {
result += CalcSpotLight(spotLights[i], norm, FragPos, viewDir);
}
FragColor = vec4(result, 1.0);
}

View file

@ -0,0 +1,9 @@
#version 330 core
out vec4 FragColor;
uniform vec3 diffuse;
void main()
{
FragColor = vec4(diffuse, 1.0); // set all 4 vector values to 1.0
}

View file

@ -0,0 +1,20 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0f);
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = mat3(transpose(inverse(model))) * aNormal;
TexCoords = aTexCoords;
}

View file

@ -3,27 +3,27 @@
#include <glm/gtc/type_ptr.hpp>
glm::mat4 Camera::look_at() {
return glm::lookAt(pos, pos + front, up);
return glm::lookAt(position, position + front, up);
}
void Camera::forward() {
pos += speed * front;
position += speed * front;
}
void Camera::back() {
pos -= speed * front;
position -= speed * front;
}
void Camera::left() {
pos -= glm::normalize(glm::cross(front, up)) * speed;
position -= glm::normalize(glm::cross(front, up)) * speed;
}
void Camera::right() {
pos += glm::normalize(glm::cross(front, up)) * speed;
position += glm::normalize(glm::cross(front, up)) * speed;
}
void Camera::update(float deltaTime) {
speed = movementSpeed * deltaTime;
speed = movement_speed * deltaTime;
}
void Camera::mouse_move(double xpos, double ypos) {

View file

@ -2,11 +2,11 @@
#include <glm/glm.hpp>
struct Camera {
glm::vec3 pos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 front = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 direction = glm::vec3(0.0f, 0.0f, 0.0f);
float movementSpeed = 20.0f;
glm::vec3 position{0.0f, 0.0f, 3.0f};
glm::vec3 front{0.0f, 0.0f, -1.0f};
glm::vec3 up{0.0f, 1.0f, 0.0f};
glm::vec3 direction{0.0f, 0.0f, 0.0f};
float movement_speed = 20.0f;
float pitch = 0.0f;
float yaw = -90.0f;

View file

@ -0,0 +1,105 @@
#pragma once
#include <glm/glm.hpp>
#include <vector>
#include <map>
#include "json.hpp"
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
#define MAX_LIGHTS 4
namespace components {
template <typename T> struct NameOf;
struct Material {
glm::vec3 ambient{0.1f,0.1f,0.1f};
float shininess{32.0f};
unsigned int diffuseMap = 0;
unsigned int specularMap = 0;
};
ENROLL_COMPONENT(Material, ambient, shininess, diffuseMap, specularMap);
struct Light {
glm::vec3 position{0.0f, 0.0f, 0.0f};
glm::vec3 direction{0.0f, 0.0f, 0.0f};
glm::vec3 ambient{0.0f, 0.0f, 0.0f};
glm::vec3 diffuse{0.0f, 0.0f, 0.0f};
glm::vec3 specular{0.0f, 0.0f, 0.0f};
float constant=0.0f;
float linear=0.0f;
float quadratic=0.0f;
float cut_off=0.0f;
float outer_cut_off=0.0f;
void adjust(float amount) {
ambient += amount;
diffuse += amount;
specular += amount;
}
};
ENROLL_COMPONENT(Light,
position, direction,
ambient, diffuse, specular,
constant, linear, quadratic,
cut_off, outer_cut_off);
struct Lighting {
std::vector<Light> directional;
std::vector<Light> positioned;
std::vector<Light> spot;
Light camera;
};
ENROLL_COMPONENT(Lighting, directional, positioned, spot, camera);
struct Camera {
glm::vec3 position{0.0f, 0.0f, 3.0f};
glm::vec3 front{0.0f, 0.0f, -1.0f};
glm::vec3 up{0.0f, 1.0f, 0.0f};
glm::vec3 direction{0.0f, 0.0f, 0.0f};
float movement_speed = 20.0f;
};
ENROLL_COMPONENT(Camera, position, front, up, direction, movement_speed);
struct Model {
std::string directory;
std::string model_path;
};
ENROLL_COMPONENT(Model, directory, model_path);
using Position = glm::vec3;
struct Thing {
std::string model;
Position position;
std::string material;
};
ENROLL_COMPONENT(Thing, model, position, material);
struct Shader {
std::string vertex_path;
std::string frag_path;
};
ENROLL_COMPONENT(Shader, vertex_path, frag_path);
struct Scene {
components::Shader shader;
components::Shader light_shader;
std::map<std::string, Material> materials;
std::map<std::string, Model> models;
std::vector<Thing> things;
Camera camera;
Lighting light;
};
ENROLL_COMPONENT(Scene, shader, light_shader, materials, models, things, camera, light);
}

View file

@ -1,4 +0,0 @@
#pragma once
#include <glm/glm.hpp>
#define CUBE_COUNT 9

View file

@ -0,0 +1,59 @@
#pragma once
#include <nlohmann/json.hpp>
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <glm/glm.hpp>
#include <vector>
#define ENROLL_COMPONENT(COMPONENT, ...) \
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(COMPONENT, __VA_ARGS__); \
template <> struct NameOf<COMPONENT> { \
static constexpr const char *name = #COMPONENT; \
};
// partial specialization (full specialization works too)
namespace nlohmann {
template <>
struct adl_serializer<glm::vec3> {
static void to_json(json& j, const glm::vec3& opt) {
}
static void from_json(const json& j, glm::vec3& opt) {
opt = glm::vec3(j[0], j[1], j[2]);
}
};
template <typename T>
struct adl_serializer<std::optional<T>> {
static void to_json(json& j, const std::optional<T>& opt) {
if (opt == std::nullopt) {
j = nullptr;
} else {
j = *opt; // this will call adl_serializer<T>::to_json which will
// find the free function to_json in T's namespace!
}
}
static void from_json(const json& j, std::optional<T>& opt) {
if (j.is_null() || j == false) {
opt = std::nullopt;
} else {
opt = std::make_optional<T>(j.template get<T>());
// same as above, but with adl_serializer<T>::from_json
}
}
};
template<>
struct adl_serializer<std::chrono::milliseconds> {
static void to_json(json& j, const std::chrono::milliseconds& opt) {
j = opt.count();
}
static void from_json(const json& j, std::chrono::milliseconds& opt) {
opt = std::chrono::milliseconds{int(j)};
}
};
}

View file

@ -1,10 +1,9 @@
#define _USE_MATH_DEFINES
#include <stb_image.h>
#include "scene.hpp"
#include "utils.hpp"
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void init_glfw() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
@ -67,25 +66,23 @@ void process_input(GLFWwindow *window, Scene& scene) {
}
if(glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) {
scene.light.directional.adjust(-0.01f);
for(auto& light : scene.light.directional) {
light.adjust(-0.01f);
}
}
if(glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS) {
scene.light.directional.adjust(0.01f);
for(auto& light : scene.light.directional) {
light.adjust(0.01f);
}
}
}
Scene setup() {
glEnable(GL_DEPTH_TEST);
Scene scene{
.shader={"shaders/14-vert.glsl", "shaders/14-frag.glsl"},
.lightShader={"shaders/14-vert.glsl", "shaders/14-lightsource.frag.glsl"},
.models={
{"assets", "crate.obj"}
},
};
components::Scene config = utils::load_scene_config("config.json");
Scene scene(config);
scene.configure();
return scene;

View file

@ -19,10 +19,10 @@
#include <vector>
struct Model {
std::map<std::string, Texture> textures_loaded;
std::vector<Mesh> meshes;
std::string directory;
std::string model_path;
std::map<std::string, Texture> textures_loaded;
std::vector<Mesh> meshes;
TextureCounts texture_counts;
bool gammaCorrection;

View file

@ -1,49 +0,0 @@
#include "physics.hpp"
struct BoxTest Box2d_setup(b2World &world) {
BoxTest box;
float wall_x[4] = {0.0f, 0.0f, -0.99f, 0.99f};
float wall_y[4] = {-0.99, 0.99f, 0.0f, 0.0f};
float bound_w[4] = {1.0f, 1.0f, 0.1f, 0.1f};
float bound_h[4] = {0.1f, 0.1f, 1.0f, 1.0f};
for(size_t i = 0; i < 4; i++) {
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(wall_x[i], wall_y[i]);
b2Body *groundBody = world.CreateBody(&groundBodyDef);
b2PolygonShape groundBox;
groundBox.SetAsBox(bound_w[i], bound_h[i]);
groundBody->CreateFixture(&groundBox, 1.0f);
box.walls[i] = groundBody;
}
for(size_t i = 0; i < BODY_COUNT; i++) {
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(0.0f, 0.5f);
box.bodies[i] = world.CreateBody(&bodyDef);
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(0.1f, 0.1f);
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
box.bodies[i]->CreateFixture(&fixtureDef);
}
return box;
}
void Box2d_step_world(b2World& world) {
float timeStep = 1.0f / 60.0f;
int velocityIterations = 6;
int positionIterations = 2;
// step the world
world.Step(timeStep, velocityIterations, positionIterations);
}

View file

@ -1,13 +0,0 @@
#pragma once
#include <box2d/box2d.h>
#define BODY_COUNT 1
struct BoxTest {
b2Body *walls[4];
b2Body *bodies[BODY_COUNT];
};
struct BoxTest Box2d_setup(b2World &world);
void Box2d_step_world(b2World& world);

View file

@ -8,18 +8,16 @@ void Scene::updateDelta() {
lastFrame = currentFrame;
}
void Scene::configure() {
// REFACTOR: really this should be done somewhere else
for(auto& model : models) {
for(auto& [name, model] : models) {
model.connect_shader(shader);
}
}
void Scene::draw_model(Model& scene_model, glm::mat4& projection, glm::mat4& view, glm::vec3& position)
void Scene::draw_model(Model& scene_model, Material& material, glm::mat4& projection, glm::mat4& view, glm::vec3& position)
{
glm::vec3 objectColor = {1.0, 0.94, 0.78};
shader.apply_material(cubeMaterial);
shader.apply_material(material);
float time = glfwGetTime();
glm::mat4 model = glm::mat4(1.0f);
@ -51,15 +49,15 @@ void Scene::render(GLFWwindow* window) {
shader.use();
shader.setMat4("view", view);
shader.setMat4("projection", projection);
shader.setVec3("viewPos", camera.pos);
shader.setVec3("viewPos", camera.position);
light.spot.position = camera.pos;
light.spot.direction = camera.front;
light.camera.position = camera.position;
light.camera.direction = camera.front;
shader.apply_lighting(light);
// BUG: no connection between models and positions
for(auto& position : positions) {
draw_model(models[0], projection, view, position);
for(auto& thing : things) {
draw_model(thing.model, thing.material, projection, view, thing.position);
}
}

View file

@ -10,98 +10,55 @@
#include "shader.hpp"
#include "model.hpp"
#include "camera.hpp"
#include "scene.hpp"
#include "components.hpp"
#include <vector>
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const float AMBIENT_LEVEL = 0.25f;
struct Thing {
Model& model;
components::Position position;
Material& material;
};
struct Scene {
Shader shader;
Shader lightShader;
std::vector<Model> models;
Lighting light{
.directional={
.direction={-0.2f, -1.0f, -0.3f},
.ambient={0.2f, 0.2f, 0.2f},
.diffuse={0.8f, 0.8f, 0.8f},
.specular={1.0f, 1.0f, 1.0f},
},
.positioned={
{
.position={1.2f, 1.0f, 2.0f},
.direction={-0.2f, -1.0f, -0.3f},
.ambient={0.2f, 0.2f, 0.2f},
.diffuse={0.8f, 0.8f, 0.8f},
.specular={1.0f, 1.0f, 1.0f},
.constant=1.0f,
.linear=0.09f,
.quadratic=0.032f,
.cutOff=12.5f,
.outerCutOff=17.5f,
},
{
.position={-1.2f, -1.0f, -2.0f},
.direction={0.2f, 1.0f, 0.3f},
.ambient={0.2f, 0.2f, 0.2f},
.diffuse={0.8f, 0.8f, 0.8f},
.specular={1.0f, 1.0f, 1.0f},
.constant=1.0f,
.linear=0.09f,
.quadratic=0.032f,
.cutOff=12.5f,
.outerCutOff=17.5f,
},
},
.spot={
.position={2.2f, 1.0f, 2.0f},
.direction={0.0f, 0.0f, -1.0f},
.ambient={0.2f, 0.2f, 0.2f},
.diffuse={0.8f, 0.8f, 0.8f},
.specular={1.0f, 1.0f, 1.0f},
.constant=1.0f,
.linear=0.09f,
.quadratic=0.032f,
.cutOff=12.5f,
.outerCutOff=17.5f,
},
};
// positions all containers
std::vector<glm::vec3> positions{
{0.0f, 0.0f, 0.0f},
{2.0f, 5.0f, -15.0f},
{-1.5f, -2.2f, -2.5f},
{-3.8f, -2.0f, -12.3f},
{ 2.4f, -0.4f, -3.5f},
{-1.7f, 3.0f, -7.5f},
{ 1.3f, -2.0f, -2.5f},
{ 1.5f, 2.0f, -2.5f},
{ 1.5f, 0.2f, -1.5f},
{-1.3f, 1.0f, -1.5f}
};
Camera camera{
.pos={2.2f, 1.0f, 2.0f},
.movementSpeed=2.0f
};
Material cubeMaterial{
.ambient = {1.0f, 0.5f, 0.31f},
.shininess = 32.0f,
.diffuseMap = 0,
.specularMap = 0,
};
Shader light_shader;
std::map<std::string, components::Material> materials;
Camera camera;
components::Lighting light;
std::map<std::string, Model> models;
std::vector<Thing> things;
float deltaTime = 0.0f;
float lastFrame = 0.0f;
Scene(components::Scene& config):
shader{config.shader.vertex_path, config.shader.frag_path},
light_shader{config.light_shader.vertex_path, config.shader.frag_path},
materials{config.materials},
camera{
.position=config.camera.position,
.front=config.camera.front,
.up=config.camera.up,
.direction=config.camera.direction,
.movement_speed=config.camera.movement_speed,
},
light{config.light}
{
for(auto& [name, model] : config.models) {
models.try_emplace(name, model.directory, model.model_path);
}
for(auto& thing : config.things) {
things.emplace_back(
models.at(thing.model),
thing.position,
materials.at(thing.material));
}
}
void updateDelta();
void configure();
void draw_model(Model& scene_model, glm::mat4& projection, glm::mat4& view, glm::vec3& position);
void draw_model(Model& scene_model, Material& material, glm::mat4& projection, glm::mat4& view, glm::vec3& position);
void render(GLFWwindow* window);
void cleanup();
};

View file

@ -60,7 +60,7 @@ unsigned int Shader::load_shader(const std::string& filename, GLenum shader_type
return shader_id;
}
Shader::Shader(const char* vertexPath, const char* fragmentPath) {
Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) {
unsigned int vertex = load_shader(vertexPath, GL_VERTEX_SHADER);
unsigned int fragment = load_shader(fragmentPath, GL_FRAGMENT_SHADER);
@ -131,27 +131,42 @@ void Shader::apply_material(const Material& material) {
}
void Shader::apply_lighting(const Lighting& lighting) {
apply_dir_light(lighting.directional);
setInt("pointLightCount", lighting.positioned.size());
setInt("dirLightCount", lighting.directional.size());
// need +1 for the camera spot light
setInt("spotLightCount", lighting.spot.size() + 1);
for(size_t i = 0; i < lighting.directional.size(); i++) {
apply_dir_light(lighting.directional[i], i);
}
for(size_t i = 0; i < lighting.positioned.size(); i++) {
apply_point_light(lighting.positioned[i], i);
}
apply_spot_light(lighting.spot);
// set the first spotlight to the camera light
apply_spot_light(lighting.camera, 0);
for(size_t i = 0; i < lighting.spot.size(); i++) {
// need to be off by one because the camera is a spot light
apply_spot_light(lighting.spot[i], i+1);
}
}
void Shader::apply_dir_light(const Light& light) {
setVec3("dirLight.direction", light.direction);
setVec3("dirLight.ambient", light.ambient);
setVec3("dirLight.diffuse", light.diffuse);
setVec3("dirLight.specular", light.specular);
void Shader::apply_dir_light(const Light& light, size_t index) {
dbc::check(index < MAX_LIGHTS, "too many directional lights");
setVec3(std::format("dirLights[{}].direction", index), light.direction);
setVec3(std::format("dirLights[{}].ambient", index), light.ambient);
setVec3(std::format("dirLights[{}].diffuse", index), light.diffuse);
setVec3(std::format("dirLights[{}].specular", index), light.specular);
}
void Shader::apply_point_light(const Light& light, size_t index) {
dbc::check(index < NR_POINT_LIGHTS, "too many positioned lights");
dbc::check(index < MAX_LIGHTS, "too many positioned lights");
// disgusting, crafting a string on every render?
setVec3(std::format("pointLights[{}].position", index), light.position);
setVec3(std::format("pointLights[{}].ambient", index), light.ambient);
setVec3(std::format("pointLights[{}].diffuse", index), light.diffuse);
@ -162,15 +177,17 @@ void Shader::apply_point_light(const Light& light, size_t index) {
setFloat(std::format("pointLights[{}].quadratic", index), light.quadratic);
}
void Shader::apply_spot_light(const Light& light) {
setVec3("spotLight.position", light.position);
setVec3("spotLight.direction", light.direction);
setVec3("spotLight.ambient", light.ambient);
setVec3("spotLight.diffuse", light.diffuse);
setVec3("spotLight.specular", light.specular);
setFloat("spotLight.constant", light.constant);
setFloat("spotLight.linear", light.linear);
setFloat("spotLight.quadratic", light.quadratic);
setFloat("spotLight.cutOff", glm::cos(glm::radians(light.cutOff)));
setFloat("spotLight.outerCutOff", glm::cos(glm::radians(light.outerCutOff)));
void Shader::apply_spot_light(const Light& light, size_t index) {
dbc::check(index < MAX_LIGHTS, "too many spot lights");
setVec3(std::format("spotLights[{}].position", index), light.position);
setVec3(std::format("spotLights[{}].direction", index), light.direction);
setVec3(std::format("spotLights[{}].ambient", index), light.ambient);
setVec3(std::format("spotLights[{}].diffuse", index), light.diffuse);
setVec3(std::format("spotLights[{}].specular", index), light.specular);
setFloat(std::format("spotLights[{}].constant", index), light.constant);
setFloat(std::format("spotLights[{}].linear", index), light.linear);
setFloat(std::format("spotLights[{}].quadratic", index), light.quadratic);
setFloat(std::format("spotLights[{}].cut_off", index), glm::cos(glm::radians(light.cut_off)));
setFloat(std::format("spotLights[{}].outer_cut_off", index), glm::cos(glm::radians(light.outer_cut_off)));
}

View file

@ -7,48 +7,16 @@
#include <vector>
#include <format>
#include "dbc.hpp"
#include "components.hpp"
struct Material {
glm::vec3 ambient{0.1f,0.1f,0.1f};
float shininess{32.0f};
unsigned int diffuseMap = 0;
unsigned int specularMap = 0;
};
struct Light {
glm::vec3 position{0.0f, 0.0f, 0.0f};
glm::vec3 direction{0.0f, 0.0f, 0.0f};
glm::vec3 ambient{0.0f, 0.0f, 0.0f};
glm::vec3 diffuse{0.0f, 0.0f, 0.0f};
glm::vec3 specular{0.0f, 0.0f, 0.0f};
float constant=0.0f;
float linear=0.0f;
float quadratic=0.0f;
float cutOff=0.0f;
float outerCutOff=0.0f;
void adjust(float amount) {
ambient += amount;
diffuse += amount;
specular += amount;
}
};
#define NR_POINT_LIGHTS 4
struct Lighting {
Light directional;
std::vector<Light> positioned;
Light spot;
};
using components::Material, components::Lighting, components::Light;
class Shader
{
public:
unsigned int ID = UINT_MAX;
Shader(const char* vertexPath, const char* fragmentPath);
Shader(const std::string& vertexPath, const std::string& fragmentPath);
unsigned int load_shader(const std::string& filename, GLenum shader_type);
void use() const;
void setBool(const std::string &name, bool value) const;
@ -63,7 +31,7 @@ public:
void apply_material(const Material& material);
void apply_lighting(const Lighting& lighting);
void apply_dir_light(const Light& light);
void apply_dir_light(const Light& light, size_t index);
void apply_point_light(const Light& light, size_t index);
void apply_spot_light(const Light& light);
void apply_spot_light(const Light& light, size_t index);
};

View file

@ -0,0 +1,11 @@
#include <fstream>
#include "json.hpp"
#include "utils.hpp"
namespace utils {
components::Scene load_scene_config(const std::string& config_file) {
std::ifstream f{"config.json"};
auto j = json::parse(f);
return j["scene"].template get<components::Scene>();
}
}

View file

@ -0,0 +1,9 @@
#pragma once
#include "components.hpp"
using json = nlohmann::json;
namespace utils {
components::Scene load_scene_config(const std::string& config_file);
}

View file

@ -0,0 +1,74 @@
{
"material_test": {
"ambient": [0.1, 0.1, 0.1],
"shininess": 32.0,
"diffuseMap": 0,
"specularMap": 0
},
"lighting_test": {
"directional": [
{
"position": [0, 0, 0.0],
"direction":[-0.2, -1.0, -0.3],
"ambient":[0.2, 0.2, 0.2],
"diffuse":[0.8, 0.8, 0.8],
"specular":[1.0, 1.0, 1.0],
"constant": 0.0,
"linear": 0.0,
"quadratic": 0.0,
"cut_off": 0.0,
"outer_cut_off": 0.0
}
],
"positioned": [
{
"position": [1.2, 1.0, 2.0],
"direction":[-0.2, -1.0, -0.3],
"ambient":[0.2, 0.2, 0.2],
"diffuse":[0.8, 0.8, 0.8],
"specular":[1.0, 1.0, 1.0],
"constant": 1.0,
"linear": 0.09,
"quadratic": 0.032,
"cut_off": 12.5,
"outer_cut_off": 17.5
}
],
"spot": [
],
"camera": {
"position":[2.2, 1.0, 2.0],
"direction":[0.0, 0.0, -1.0],
"ambient":[0.2, 0.2, 0.2],
"diffuse":[0.8, 0.8, 0.8],
"specular":[1.0, 1.0, 1.0],
"constant": 1.0,
"linear": 0.09,
"quadratic": 0.032,
"cut_off": 12.5,
"outer_cut_off": 17.5
}
},
"camera_test": {
"position": [0.0, 0.0, 3.0],
"front": [0.0, 0.0, -1.0],
"up": [0.0, 1.0, 0.0],
"direction": [0.0, 0.0, 0.0],
"movement_speed": 20.0
},
"model_test": {
"directory": "assets",
"model_path": "create.obj"
},
"thing_test": {
"model": "crate",
"position": [0.0, 0.0, 0.0],
"material": "crate"
},
"shader_test": {
"vertex_path": "shaders/16-vert.glsl",
"frag_path": "shaders/16-frag.glsl"
}
}

View file

@ -0,0 +1,46 @@
#include <fuc2/testing.hpp>
#include "components.hpp"
#include <fstream>
#include "json.hpp"
#include <nlohmann/json.hpp>
using json = nlohmann::json;
using namespace fuc2;
/*
* This also tests Mesh by using Model to load them.
*/
namespace config_tests {
void test_json_components() {
std::ifstream f{"tests/config.json"};
auto j = json::parse(f);
auto mat = j["material_test"].get<components::Material>();
CHECK(mat.ambient.x == 0.1f, "wrong value");
auto light = j["lighting_test"].get<components::Lighting>();
auto camera = j["camera_test"].get<components::Camera>();
auto model = j["model_test"].get<components::Model>();
auto thing = j["thing_test"].get<components::Thing>();
}
void test_load_json_config() {
std::ifstream f{"config.json"};
auto j = json::parse(f);
auto scene = j["scene"].get<components::Scene>();
}
fuc2::Set TESTS{
.name="config",
.options={ .fail_fast=false },
.tests={
TEST(test_json_components),
TEST(test_load_json_config),
}
};
}

View file

@ -5,6 +5,7 @@
TEST_SET(shader_tests);
TEST_SET(model_tests);
TEST_SET(config_tests);
using namespace fuc2;
@ -33,7 +34,8 @@ int main(int argc, char* argv[]) {
std::vector<fuc2::Set> tests{
shader_tests::TESTS,
model_tests::TESTS
model_tests::TESTS,
config_tests::TESTS,
};
return run_tests(tests, argc, argv);

View file

@ -2,4 +2,5 @@ fuc2_tests = files(
'main.cpp',
'shader_tests.cpp',
'model_tests.cpp',
'config_tests.cpp',
)

View file

@ -0,0 +1,11 @@
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/nlohmann_json_3.11.3-1/nlohmann_json-3.11.3.zip
wrapdb_version = 3.11.3-1
[provide]
nlohmann_json = nlohmann_json_dep