Nimbin2git.christianimmanuel.de / Games / strichmaennchen / world.c

strichmaennchen git · main

git clone https://git.christianimmanuel.de/games/strichmaennchen.gitwget https://git.christianimmanuel.de/games/strichmaennchen/archive/strichmaennchen.tar.gz
world.c 4.1 KB · 122 lines raw
#include "world.h"
#include "glfuncs.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

void World_init(World *world) {
    world->countObjects = 0;
    world->capacityObjects = 16;
    world->objects = malloc(world->capacityObjects * sizeof(Object*));
    world->countHumans = 0;
    world->capacityHumans = 16;
    world->humans = malloc(world->capacityHumans * sizeof(Object*));
}

void World_addObject(World *world, Object *obj) {
    if (world->countObjects >= world->capacityObjects) {
        world->capacityObjects *= 2;
        world->objects = realloc(world->objects, world->capacityObjects * sizeof(Object*));
    }
    world->objects[world->countObjects++] = obj;
}

void World_removeObject(World *world, Object *obj) {
    for (int i = 0; i < world->countObjects; i++) {
        if (world->objects[i] == obj) {
            world->objects[i] = world->objects[--world->countObjects];
            return;
        }
    }
}

void World_addHuman(World *world, Human *hum) {
    if (world->countHumans >= world->capacityHumans) {
        world->capacityHumans *= 2;
        world->humans = realloc(world->humans, world->capacityHumans * sizeof(Human*));
    }
    world->humans[world->countHumans++] = hum;
    World_addObject(world, hum->object);
}

void World_removeHuman(World *world, Human *hum) {
    for (int i = 0; i < world->countHumans; i++) {
        if (world->humans[i] == hum) {
            world->humans[i] = world->humans[--world->countHumans];
            return;
        }
    }
}

void World_update(World *world, float dt) {
    for (int i = 0; i < world->countObjects; i++) {
        Object_update(world->objects[i], world->objects, world->countObjects, dt);
    }
}

void World_render(World *world, Renderer *renderer, Camera *camera, Time* time) {
    for (int i = 0; i < world->countObjects; i++) {
        Object_render(world->objects[i], renderer, camera, time);
    }
}

void World_renderShadows(World* world, Renderer* renderer, Time* time) {
    // Compute light matrices
    Vec3 forward = vec3_normalize(time->sunDirection);
    Vec3 arbitrary = fabsf(forward.y) > 0.99f ? (Vec3){1,0,0} : (Vec3){0,1,0};
    Vec3 right = vec3_normalize(vec3_cross(arbitrary, forward));
    Vec3 up = vec3_cross(forward, right);

    Vec3 lightPos = vec3_scale(forward, 50.0f);
    Vec3 lightTarget = (Vec3){0, 0, 0};

    renderer->lightView = mat4_lookAt(lightPos, lightTarget, up);

    float left = -30.0f, rightv = 30.0f, bottom = -30.0f, top = 30.0f, near = -100.0f, far = 100.0f;
    renderer->lightProjection = mat4_orthographic(left, rightv, bottom, top, near, far);

    // Shadow pass
    glViewport(0, 0, renderer->shadowMapWidth, renderer->shadowMapHeight);
    glBindFramebuffer(GL_FRAMEBUFFER, renderer->shadowFramebuffer);
    glClear(GL_DEPTH_BUFFER_BIT);

    glEnable(GL_POLYGON_OFFSET_FILL);
    glPolygonOffset(1.0f, 1.0f);

    glEnable(GL_CULL_FACE);
    glCullFace(GL_FRONT);

    glUseProgram(renderer->shadowShader);

    for (int i = 0; i < world->countObjects; i++) {
        Object* obj = world->objects[i];
        Mat4 model = mat4_translate(vec3_add(obj->position, obj->position_center));
        model = mat4_mul(model, mat4_rotate_x(obj->rotation.x));
        model = mat4_mul(model, mat4_rotate_y(obj->rotation.y));
        model = mat4_mul(model, mat4_rotate_z(obj->rotation.z));

        Mat4 lightSpace = mat4_mul(renderer->lightProjection, mat4_mul(renderer->lightView, model));
        GLint loc = glGetUniformLocation(renderer->shadowShader, "lightSpaceMatrix");
        glUniformMatrix4fv(loc, 1, GL_FALSE, (float*)&lightSpace);

        glBindVertexArray(obj->mesh.vao);
        if (obj->mesh.hasIndices) {
            glDrawElements(GL_TRIANGLES, obj->mesh.indexCount, GL_UNSIGNED_INT, 0);
        } else {
            glDrawArrays(obj->mesh.drawMode, 0, obj->mesh.vertexCount);
        }
    }

    glDisable(GL_CULL_FACE);
    glDisable(GL_POLYGON_OFFSET_FILL);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glViewport(0, 0, renderer->width, renderer->height);
}

void World_destroy(World *world) {
    for (int i = 0; i < world->countObjects; i++) {
        Object_destroy(world->objects[i]);
    }
    free(world->objects);
}