676 lines
23 KiB
C++
676 lines
23 KiB
C++
// stdlib
|
|
// TODO(djledda): get rid of this
|
|
#include <vector>
|
|
|
|
// Graphics bindings and libs
|
|
#include "lib/glad/glad.c"
|
|
#include <GLFW/glfw3.h>
|
|
#define GLM_ENABLE_EXPERIMENTAL
|
|
#include <glm/ext/matrix_transform.hpp>
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtx/quaternion.hpp>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
// Project
|
|
#include "SomaSolve.cpp" // errors from iostream also defining the keyword `global`
|
|
#include "gfx/gfx.cpp"
|
|
#include "world/world.cpp"
|
|
#include "VoxelSpace.cpp"
|
|
#include "./tests.cpp"
|
|
#include "lib/djstdlib/core.cpp"
|
|
|
|
// Library initialisation
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#include "lib/loaders/stb_image.h"
|
|
#define TINYOBJ_LOADER_C_IMPLEMENTATION
|
|
#include "lib/loaders/tinyobj.h"
|
|
|
|
#define PI (real32)3.14159265358979323846264338327950288
|
|
|
|
void print(glm::vec3* vector) {
|
|
glm::vec3 vec = *vector;
|
|
print(
|
|
"┌ ┐\n"
|
|
"│%7.2f%, %7.2f, %7.2f │\n"
|
|
"└ ┘\n",
|
|
vec[0], vec[1], vec[2]);
|
|
}
|
|
|
|
void print(glm::mat4* matrix) {
|
|
glm::mat4 mat = *matrix;
|
|
print(
|
|
"┌ ┐\n"
|
|
"│%7.2f%, %7.2f, %7.2f, %7.2f │\n"
|
|
"│%7.2f%, %7.2f, %7.2f, %7.2f │\n"
|
|
"│%7.2f%, %7.2f, %7.2f, %7.2f │\n"
|
|
"│%7.2f%, %7.2f, %7.2f, %7.2f │\n"
|
|
"└ ┘\n",
|
|
mat[0][0], mat[0][1], mat[0][2], mat[0][3],
|
|
mat[1][0], mat[1][1], mat[1][2], mat[1][3],
|
|
mat[2][0], mat[2][1], mat[2][2], mat[2][3],
|
|
mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
|
|
}
|
|
|
|
struct Camera {
|
|
glm::mat4 view;
|
|
glm::mat4 proj;
|
|
glm::vec3 pos;
|
|
glm::vec3 up;
|
|
glm::vec3 target;
|
|
};
|
|
|
|
Camera *createCamera(Arena *arena, real32 aspect_ratio = 800.0f / 600.0f) {
|
|
Camera *result = PushStruct(arena, Camera);
|
|
result->view = glm::mat4();
|
|
result->proj = glm::perspective(glm::radians(45.0f), aspect_ratio, 0.1f, 100.0f);
|
|
result->pos = glm::vec3(0.0f);
|
|
result->up = glm::vec3(0.0f, 1.0f, 0.0f);
|
|
return result;
|
|
}
|
|
|
|
void cameraLookAt(Camera *c, float x, float y, float z) {
|
|
c->target = glm::vec3(x, y, z);
|
|
c->view = glm::lookAt(c->pos, c->target, c->up);
|
|
}
|
|
|
|
void camera_set_up(Camera *c, real32 up_x, real32 up_y, real32 up_z) {
|
|
c->up = glm::vec3(up_x, up_y, up_z);
|
|
}
|
|
|
|
struct Frame {
|
|
uint32 width;
|
|
uint32 height;
|
|
int32 x;
|
|
int32 y;
|
|
Camera* cam;
|
|
};
|
|
|
|
struct Polycube {
|
|
uint32 entityHandle;
|
|
Space repr;
|
|
Vector4<real32> color;
|
|
};
|
|
|
|
struct RenderObjects_Rectangle {
|
|
uint32 vao;
|
|
list<Vector2<real32>> p0;
|
|
uint32 p0BufferId;
|
|
list<Vector2<real32>> p1;
|
|
uint32 p1BufferId;
|
|
list<Vector4<real32>> color;
|
|
uint32 colorBufferId;
|
|
uint64 count;
|
|
};
|
|
|
|
struct Input {
|
|
struct {
|
|
bool escape;
|
|
bool enter;
|
|
bool space;
|
|
bool lshift;
|
|
bool x;
|
|
bool y;
|
|
bool z;
|
|
} keyboard;
|
|
struct {
|
|
union {
|
|
struct {
|
|
real32 x;
|
|
real32 y;
|
|
};
|
|
Vector2<real32> point;
|
|
};
|
|
bool btnLeft;
|
|
bool btnRight;
|
|
bool btnMiddle;
|
|
} mouse;
|
|
};
|
|
|
|
struct Renderer {
|
|
Scene *scene;
|
|
RenderObjects_Rectangle rects;
|
|
};
|
|
|
|
struct PolycubeInput {
|
|
Space repr;
|
|
Vector4<real32> color;
|
|
};
|
|
|
|
struct SomaState {
|
|
bool wireframe;
|
|
bool polycubeDirty;
|
|
uint32 currentPolycube;
|
|
uint32 lastPolycubeVisible;
|
|
uint32 light;
|
|
list<Polycube> polycubes;
|
|
Camera* camera;
|
|
glm::vec3 rotAxisX;
|
|
glm::vec3 rotAxisY;
|
|
list<PolycubeInput> polycubeInput;
|
|
};
|
|
|
|
struct Soma {
|
|
Scene *scene;
|
|
Renderer *renderer;
|
|
SomaState state;
|
|
Input currInput;
|
|
Input prevInput;
|
|
struct {
|
|
GLFWwindow *handle;
|
|
uint32 width;
|
|
uint32 height;
|
|
} window;
|
|
};
|
|
|
|
void showEntity(Scene *scene, uint32 entityHandle) {
|
|
SceneGraphNode *node = getSceneGraphNodeForEntity(scene, entityHandle);
|
|
for (uint32 &child : node->children) {
|
|
SceneGraphNode *subNode = getSceneGraphNode(scene, child);
|
|
if (subNode->entityHandle) {
|
|
getEntity(scene, subNode->entityHandle)->flags |= EntityFlags_Visible;
|
|
}
|
|
}
|
|
}
|
|
|
|
void hideEntity(Scene *scene, uint32 entityHandle) {
|
|
SceneGraphNode *node = getSceneGraphNodeForEntity(scene, entityHandle);
|
|
for (uint32 &child : node->children) {
|
|
SceneGraphNode *subNode = getSceneGraphNode(scene, child);
|
|
if (subNode->entityHandle) {
|
|
getEntity(scene, subNode->entityHandle)->flags &= ~EntityFlags_Visible;
|
|
}
|
|
}
|
|
}
|
|
|
|
glm::vec3 centreFromPolycube(Scene *scene, Polycube *p) {
|
|
glm::vec3 centre = glm::vec3(0.0f);
|
|
for (uint32 &child : getSceneGraphNode(scene, p->entityHandle)->children) {
|
|
centre += getSceneGraphNode(scene, child)->translation;
|
|
}
|
|
centre /= getSceneGraphNodeForEntity(scene, p->entityHandle)->children.size();
|
|
return centre;
|
|
}
|
|
|
|
Frame createFrame(Arena *arena, uint32 width, uint32 height, uint32 x, uint32 y) {
|
|
Frame result = {0};
|
|
result.width = width;
|
|
result.height = height;
|
|
result.x = x;
|
|
result.y = y;
|
|
result.cam = createCamera(arena, (real32)result.width / (real32)result.height);
|
|
return result;
|
|
}
|
|
|
|
void framebufferSizeCallback(GLFWwindow *window, int width, int height) {
|
|
glViewport(0, 0, width, height);
|
|
}
|
|
|
|
GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) {
|
|
glfwInit();
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
GLFWwindow *window = glfwCreateWindow(windowWidth, windowHeight, "Somaesque", NULL, NULL);
|
|
if (window == NULL) {
|
|
print("Failed to create GLFW window\n");
|
|
glfwTerminate();
|
|
return NULL;
|
|
}
|
|
glfwMakeContextCurrent(window);
|
|
|
|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
|
print("Failed to initilaize GLAD\n");
|
|
return NULL;
|
|
}
|
|
|
|
glViewport(0, 0, 800, 600);
|
|
glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);
|
|
glfwSetInputMode(window, GLFW_CURSOR | GLFW_RAW_MOUSE_MOTION, GLFW_CURSOR_NORMAL);
|
|
glEnable(GL_DEPTH_TEST);
|
|
return window;
|
|
}
|
|
|
|
void updateViewportFromFrame(uint32 windowWidth, uint32 windowHeight, Frame* frame) {
|
|
glViewport(frame->x, windowHeight - frame->y - frame->height, frame->width, frame->height);
|
|
}
|
|
|
|
struct UI_Context {
|
|
Renderer *renderer;
|
|
Input *prevInput;
|
|
Input *input;
|
|
bool cursorIsPointer;
|
|
};
|
|
|
|
struct UI_Rect {
|
|
real32 x;
|
|
real32 y;
|
|
real32 width;
|
|
real32 height;
|
|
real32 borderRadius;
|
|
Vector4<real32> color;
|
|
};
|
|
|
|
Mesh cubeMesh = {0};
|
|
Texture wallTex = {0};
|
|
|
|
Shader solidColorShader;
|
|
Shader phongShader;
|
|
|
|
inline bool glfwMouse(GLFWwindow *window, int mouseBtnCode) {
|
|
switch (glfwGetMouseButton(window, mouseBtnCode)) {
|
|
case GLFW_RELEASE: return false;
|
|
case GLFW_PRESS: return true;
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
inline bool glfwKey(GLFWwindow *window, int keyCode) {
|
|
switch (glfwGetKey(window, keyCode)) {
|
|
case GLFW_RELEASE: return false;
|
|
case GLFW_PRESS: return true;
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
Input getCurrentInput(GLFWwindow *window) {
|
|
Input input = {0};
|
|
|
|
input.keyboard.escape = glfwKey(window, GLFW_KEY_ESCAPE);
|
|
input.keyboard.enter = glfwKey(window, GLFW_KEY_ENTER);
|
|
input.keyboard.space = glfwKey(window, GLFW_KEY_SPACE);
|
|
input.keyboard.lshift = glfwKey(window, GLFW_KEY_LEFT_SHIFT);
|
|
input.keyboard.x = glfwKey(window, GLFW_KEY_X);
|
|
input.keyboard.y = glfwKey(window, GLFW_KEY_Y);
|
|
input.keyboard.z = glfwKey(window, GLFW_KEY_Z);
|
|
|
|
input.mouse.btnLeft = glfwMouse(window, GLFW_MOUSE_BUTTON_LEFT);
|
|
input.mouse.btnRight = glfwMouse(window, GLFW_MOUSE_BUTTON_RIGHT);
|
|
input.mouse.btnMiddle = glfwMouse(window, GLFW_MOUSE_BUTTON_MIDDLE);
|
|
|
|
real64 mouseX;
|
|
real64 mouseY;
|
|
glfwGetCursorPos(window, &mouseX, &mouseY);
|
|
input.mouse.point = vec2<real32>((real32)mouseX, (real32)mouseY);
|
|
|
|
return input;
|
|
}
|
|
|
|
void processInput(Soma *soma) {
|
|
Input *input = &soma->currInput;
|
|
Input *prevInput = &soma->prevInput;
|
|
|
|
if (input->keyboard.escape) {
|
|
glfwSetWindowShouldClose(soma->window.handle, true);
|
|
}
|
|
|
|
if (input->keyboard.space && !prevInput->keyboard.space) {
|
|
glPolygonMode(GL_FRONT_AND_BACK, !soma->state.wireframe ? GL_LINE : GL_FILL);
|
|
soma->state.wireframe = !soma->state.wireframe;
|
|
}
|
|
|
|
SceneGraphNode *node = getSceneGraphNode(soma->scene, getEntity(soma->scene, soma->state.light)->graphNodeHandle);
|
|
int shiftMultiplier = input->keyboard.lshift ? -1 : 1;
|
|
node->translation.x += 1.0 * input->keyboard.x * shiftMultiplier;
|
|
node->translation.y += 1.0 * input->keyboard.y * shiftMultiplier;
|
|
node->translation.z += 1.0 * input->keyboard.z * shiftMultiplier;
|
|
|
|
if (input->keyboard.enter && !prevInput->keyboard.enter) {
|
|
if (soma->state.currentPolycube == 6) {
|
|
soma->state.currentPolycube = 0;
|
|
} else {
|
|
soma->state.currentPolycube += 1;
|
|
}
|
|
}
|
|
|
|
bool dragScene = false;
|
|
if (input->mouse.btnLeft) {
|
|
Polycube *current_polycube = &soma->state.polycubes.data[soma->state.currentPolycube];
|
|
SceneGraphNode *polycubeGraphNode = getSceneGraphNodeForEntity(soma->scene, current_polycube->entityHandle);
|
|
|
|
real64 deltaX = (input->mouse.x - prevInput->mouse.x) * 0.005;
|
|
if (deltaX > 0.00000001 || deltaX < -0.00000001) {
|
|
polycubeGraphNode->rotation *= glm::angleAxis((real32)deltaX, soma->state.rotAxisY);
|
|
}
|
|
|
|
real64 deltaY = (input->mouse.y - prevInput->mouse.y) * 0.005;
|
|
if (deltaY > 0.00000001 || deltaY < -0.00000001) {
|
|
polycubeGraphNode->rotation = glm::angleAxis(-(real32)deltaY, soma->state.rotAxisX) * polycubeGraphNode->rotation;
|
|
}
|
|
}
|
|
}
|
|
|
|
Polycube createPolycubeFromRepr(Soma *soma, Space *repr, Vector4<real32> color) {
|
|
uint32 polycubeMainEntityHandle = createEntity(soma->scene);
|
|
Entity *polycubeMainEntity = getEntity(soma->scene, polycubeMainEntityHandle);
|
|
for (int x = 0; x < repr->dim_x; x++) {
|
|
for (int y = 0; y < repr->dim_y; y++) {
|
|
for (int z = 0; z < repr->dim_z; z++) {
|
|
if (filledAt(repr, x, y, z)) {
|
|
uint32 segmentEntityHandle = createEntity(soma->scene);
|
|
Entity *polycubeSegment = getEntity(soma->scene, segmentEntityHandle);
|
|
polycubeSegment->mesh = &cubeMesh;
|
|
polycubeSegment->tex = &wallTex;
|
|
SceneGraphNode *graphNode = getSceneGraphNode(soma->scene, polycubeSegment->graphNodeHandle);
|
|
graphNode->translation = glm::vec3(
|
|
-((repr->dim_z - 1)/2.0f) + z,
|
|
((repr->dim_x - 1)/2.0f) - x,
|
|
-((repr->dim_y - 1)/2.0f) + y
|
|
);
|
|
sceneNodeAddEntity(soma->scene, polycubeMainEntity->graphNodeHandle, segmentEntityHandle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Polycube result = {};
|
|
result.entityHandle = polycubeMainEntityHandle;
|
|
result.color = color;
|
|
result.repr = *repr;
|
|
return result;
|
|
}
|
|
|
|
RenderObjects_Rectangle createRectangleObjects(Arena *arena, size_t count) {
|
|
RenderObjects_Rectangle result = {0};
|
|
result.count = count;
|
|
|
|
result.p0 = PushFullList(arena, Vector2<real32>, count);
|
|
result.p1 = PushFullList(arena, Vector2<real32>, count);
|
|
result.color = PushFullList(arena, Vector4<real32>, count);
|
|
|
|
glGenVertexArrays(1, &result.vao);
|
|
|
|
uint32 p0Buffer;
|
|
uint32 p1Buffer;
|
|
uint32 colorBuffer;
|
|
|
|
glGenBuffers(1, &result.p0BufferId);
|
|
glGenBuffers(1, &result.p1BufferId);
|
|
glGenBuffers(1, &result.colorBufferId);
|
|
|
|
glBindVertexArray(result.vao);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, result.p0BufferId);
|
|
glBufferData(GL_ARRAY_BUFFER, result.p0.length * sizeof(Vector2<real32>), 0, GL_DYNAMIC_DRAW);
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2<real32>), (void*)0);
|
|
glVertexAttribDivisor(0, 1);
|
|
glEnableVertexAttribArray(0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, result.p1BufferId);
|
|
glBufferData(GL_ARRAY_BUFFER, result.p1.length * sizeof(Vector2<real32>), 0, GL_DYNAMIC_DRAW);
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2<real32>), (void*)0);
|
|
glVertexAttribDivisor(1, 1);
|
|
glEnableVertexAttribArray(1);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, result.colorBufferId);
|
|
glBufferData(GL_ARRAY_BUFFER, result.color.length * sizeof(Vector4<real32>), 0, GL_DYNAMIC_DRAW);
|
|
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(Vector4<real32>), (void*)0);
|
|
glVertexAttribDivisor(2, 1);
|
|
glEnableVertexAttribArray(2);
|
|
|
|
return result;
|
|
}
|
|
|
|
void reinitRectangleObjectBuffers(Renderer *r) {
|
|
glBindVertexArray(r->rects.vao);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, r->rects.p0BufferId);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.p0.head * sizeof(Vector2<real32>), r->rects.p0.data);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, r->rects.p1BufferId);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.p1.head * sizeof(Vector2<real32>), r->rects.p1.data);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, r->rects.colorBufferId);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.color.head * sizeof(Vector4<real32>), r->rects.color.data);
|
|
}
|
|
|
|
Renderer createRenderer(Arena *arena, Scene *scene) {
|
|
Renderer result = {0};
|
|
result.scene = scene;
|
|
result.scene->sceneRoot = createSceneGraphNode(scene);
|
|
result.rects = createRectangleObjects(arena, 100);
|
|
initGraphNode(getSceneGraphNode(scene, scene->sceneRoot));
|
|
return result;
|
|
}
|
|
|
|
void renderBegin(Renderer *r) {
|
|
r->rects.p0.head = 0;
|
|
r->rects.p1.head = 0;
|
|
r->rects.color.head = 0;
|
|
}
|
|
|
|
void renderEnd(Soma *soma, Renderer *renderer) {
|
|
// 3D Entities
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
|
|
|
glUseProgram(phongShader.progId);
|
|
setUniformMat4fv(&phongShader, "projection", &soma->state.camera->proj);
|
|
setUniformMat4fv(&phongShader, "view", &soma->state.camera->view);
|
|
|
|
SceneGraphNode *lightGraphNode = getSceneGraphNode(soma->scene, getEntity(soma->scene, soma->state.light)->graphNodeHandle);
|
|
setUniform3fv(&phongShader, "light_pos", &lightGraphNode->translation);
|
|
setUniform3fv(&phongShader, "camera", &soma->state.camera->pos);
|
|
|
|
Polycube *currentPolycube = &soma->state.polycubes.data[soma->state.currentPolycube];
|
|
glBindVertexArray(cubeMesh.vao);
|
|
|
|
setUniform4fv(&phongShader, "solid_color", ¤tPolycube->color);
|
|
|
|
int model_uniform = getUniformLocation(&phongShader, "model");
|
|
for (Entity &entity : renderer->scene->entities) {
|
|
if (entity.flags & EntityFlags_Render && entity.flags & EntityFlags_Visible) {
|
|
setUniformMat4fv(model_uniform, &getSceneGraphNode(renderer->scene, entity.graphNodeHandle)->world);
|
|
glBindTexture(GL_TEXTURE_2D, entity.tex->tex_id);
|
|
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)entity.mesh->num_indices);
|
|
entity.flags &= ~EntityFlags_Render;
|
|
}
|
|
}
|
|
|
|
// 2D overlay
|
|
glUseProgram(solidColorShader.progId);
|
|
|
|
reinitRectangleObjectBuffers(renderer);
|
|
|
|
glm::mat4 ortho = glm::ortho(0.0, 800.0, 600.0, 0.0, -1.0, 1.0);
|
|
setUniformMat4fv(&solidColorShader, "projection", &ortho);
|
|
|
|
glBindVertexArray(renderer->rects.vao);
|
|
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, renderer->rects.p0.head);
|
|
}
|
|
|
|
void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, Vector4<real32> color) {
|
|
appendList(&r->rects.p0, vec2<real32>(x, y));
|
|
appendList(&r->rects.p1, vec2<real32>(x + width, y + height));
|
|
appendList(&r->rects.color, color);
|
|
}
|
|
|
|
inline bool pointInRect(Vector2<real32> point, UI_Rect rect) {
|
|
return point.x > rect.x && point.y > rect.y && point.x < (rect.x + rect.width) && point.y < (rect.y + rect.height);
|
|
}
|
|
|
|
bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect) {
|
|
bool clicked = false;
|
|
if (pointInRect(ui->input->mouse.point, rect)) {
|
|
ui->cursorIsPointer = true;
|
|
if (ui->prevInput->mouse.btnLeft && !ui->input->mouse.btnLeft) {
|
|
*value = !*value;
|
|
clicked = true;
|
|
}
|
|
}
|
|
rendererPlaceRectangle(ui->renderer, rect.x, rect.y, rect.width, rect.height, *value ? rect.color : vec4<real32>(1, 1, 1, 1));
|
|
return clicked;
|
|
}
|
|
|
|
void uiPass(Soma *soma, UI_Context *ui, Renderer *renderer) {
|
|
PolycubeInput *currentPolycube = &soma->state.polycubeInput.data[soma->state.currentPolycube];
|
|
|
|
real32 boxSize = 30;
|
|
real32 padding = 20;
|
|
real32 paddingBetween = 5;
|
|
real32 currY = padding;
|
|
for (int x = 0; x < currentPolycube->repr.dim_x; x++) {
|
|
for (int y = 0; y < currentPolycube->repr.dim_y; y++) {
|
|
real32 currX = padding;
|
|
for (int z = 0; z < currentPolycube->repr.dim_z; z++) {
|
|
bool cellActive = filledAt(¤tPolycube->repr, x, y, z);
|
|
UI_Rect rect = {
|
|
currX,
|
|
currY,
|
|
boxSize,
|
|
boxSize,
|
|
0,
|
|
currentPolycube->color,
|
|
};
|
|
if (ui_checkboxRect(ui, &cellActive, rect)) {
|
|
soma->state.polycubeDirty = true;
|
|
spaceSet(¤tPolycube->repr, cellActive, x, y, z);
|
|
}
|
|
currX += paddingBetween + boxSize;
|
|
}
|
|
currY += paddingBetween + boxSize;
|
|
}
|
|
currY += padding;
|
|
}
|
|
}
|
|
|
|
int main_cmd() {
|
|
interactive_cmd_line_solve_soma();
|
|
return 0;
|
|
}
|
|
|
|
int mainGfx() {
|
|
Arena *arena = arenaAlloc(Megabytes(128));
|
|
|
|
Scene mainScene = createScene();
|
|
|
|
Soma soma = {};
|
|
soma.window.width = 800;
|
|
soma.window.height = 600;
|
|
soma.window.handle = initWindowAndGL(soma.window.width, soma.window.height);
|
|
soma.scene = &mainScene;
|
|
Renderer renderer = createRenderer(arena, &mainScene);
|
|
soma.renderer = &renderer;
|
|
|
|
if (!soma.window.handle) {
|
|
return -1;
|
|
}
|
|
|
|
Frame mainFrame = createFrame(arena, soma.window.width, soma.window.height, 0, 0);
|
|
UI_Context ui = {};
|
|
|
|
GLFWcursor *pointerCursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
|
GLFWcursor *arrowCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
|
|
|
soma.state.currentPolycube = 0;
|
|
soma.state.lastPolycubeVisible = 6;
|
|
soma.state.polycubeInput = PushListZero(arena, PolycubeInput, 64);
|
|
soma.state.polycubes = PushListZero(arena, Polycube, 64);
|
|
soma.state.light = createEntity(&mainScene);
|
|
soma.state.camera = mainFrame.cam;
|
|
|
|
SceneGraphNode *light = getSceneGraphNode(&mainScene, getEntity(&mainScene, soma.state.light)->graphNodeHandle);
|
|
light->translation = glm::vec3(4.0f, 6.0f, 24.0f);
|
|
|
|
/*
|
|
Shader solid_texture_shader = createShader(
|
|
"./assets/shaders/2d.vertex.glsl"_s,
|
|
"./assets/shaders/2d-tex.fragment.glsl"_s);
|
|
*/
|
|
|
|
solidColorShader = createShader(
|
|
"./assets/shaders/2d-solid.vertex.glsl"_s,
|
|
"./assets/shaders/2d-solid.fragment.glsl"_s);
|
|
|
|
phongShader = createShader(
|
|
"./assets/shaders/phong-solid.vertex.glsl"_s,
|
|
"./assets/shaders/phong-solid.fragment.glsl"_s);
|
|
|
|
cubeMesh = createMesh("./assets/models/cube.obj");
|
|
wallTex = createTexture("./assets/textures/brick-wall.jpg");
|
|
|
|
for (int i = 0; i < ArrayCount(STD_SOMA); i++) {
|
|
Space voxelSpace = { STD_SOMA[i], 3, 3, 3 };
|
|
Vector4<real32> color = colorFromIndex(i);
|
|
appendList(&soma.state.polycubeInput, PolycubeInput{ voxelSpace, color });
|
|
cullEmptySpace(&voxelSpace);
|
|
Polycube polycube = createPolycubeFromRepr(&soma, &voxelSpace, color);
|
|
polycube.color = color;
|
|
appendList(&soma.state.polycubes, polycube);
|
|
sceneNodeAddEntity(renderer.scene, renderer.scene->sceneRoot, polycube.entityHandle);
|
|
}
|
|
|
|
soma.state.camera->pos = glm::vec3(0.0f, 0.0f, 8.0f);
|
|
cameraLookAt(soma.state.camera, 0.0f, 0.0f, 0.0f);
|
|
|
|
SceneGraphNode *reference_polycube_gn = getSceneGraphNodeForEntity(soma.scene, soma.state.polycubes.data[0].entityHandle);
|
|
soma.state.rotAxisY = glm::normalize(glm::vec4(0, 1, 0, 0) * glm::inverse(reference_polycube_gn->world));
|
|
glm::vec3 eyes = glm::normalize(soma.state.camera->pos - reference_polycube_gn->translation);
|
|
soma.state.rotAxisX = glm::normalize(glm::cross(eyes, soma.state.rotAxisY));
|
|
|
|
for (int i = 0; i < ArrayCount(STD_SOMA); i++) {
|
|
auto gn = getSceneGraphNodeForEntity(soma.scene, soma.state.polycubes.data[i].entityHandle);
|
|
gn->rotation *= glm::angleAxis(PI / 4, glm::vec3(1, 0, 0));
|
|
gn->rotation *= glm::angleAxis(PI / 4, glm::vec3(0, 1, 0));
|
|
}
|
|
|
|
real64 lastFrame = glfwGetTime();
|
|
real64 timeDelta = 1.0f/60.0f;
|
|
|
|
while (!glfwWindowShouldClose(soma.window.handle)) {
|
|
real64 currTime = glfwGetTime();
|
|
timeDelta = currTime - lastFrame;
|
|
lastFrame = currTime;
|
|
//print("%.7f\n", timeDelta);
|
|
|
|
glfwPollEvents();
|
|
soma.currInput = getCurrentInput(soma.window.handle);
|
|
processInput(&soma);
|
|
|
|
if (soma.state.lastPolycubeVisible != soma.state.currentPolycube) {
|
|
hideEntity(soma.scene, soma.state.polycubes.data[soma.state.lastPolycubeVisible].entityHandle);
|
|
showEntity(soma.scene, soma.state.polycubes.data[soma.state.currentPolycube].entityHandle);
|
|
soma.state.lastPolycubeVisible = soma.state.currentPolycube;
|
|
}
|
|
if (soma.state.polycubeDirty) {
|
|
PolycubeInput *pinput = &soma.state.polycubeInput.data[soma.state.currentPolycube];
|
|
removeEntity(soma.scene, soma.state.polycubes.data[soma.state.currentPolycube].entityHandle);
|
|
Space culledRepr = pinput->repr;
|
|
cullEmptySpace(&culledRepr);
|
|
Polycube polycube = createPolycubeFromRepr(&soma, &culledRepr, pinput->color);
|
|
soma.state.polycubes.data[soma.state.currentPolycube] = polycube;
|
|
sceneNodeAddEntity(soma.scene, soma.scene->sceneRoot, polycube.entityHandle);
|
|
soma.state.polycubeDirty = false;
|
|
}
|
|
|
|
updateViewportFromFrame(soma.window.width, soma.window.height, &mainFrame);
|
|
recalcScene(soma.scene);
|
|
|
|
renderBegin(&renderer);
|
|
|
|
ui.cursorIsPointer = false;
|
|
ui.prevInput = &soma.prevInput;
|
|
ui.input = &soma.currInput;
|
|
ui.renderer = &renderer;
|
|
uiPass(&soma, &ui, &renderer);
|
|
if (ui.cursorIsPointer) {
|
|
glfwSetCursor(soma.window.handle, pointerCursor);
|
|
} else {
|
|
glfwSetCursor(soma.window.handle, arrowCursor);
|
|
}
|
|
|
|
renderEnd(&soma, &renderer);
|
|
|
|
glfwSwapBuffers(soma.window.handle);
|
|
soma.prevInput = soma.currInput;
|
|
}
|
|
|
|
glfwTerminate();
|
|
return 0;
|
|
}
|
|
|
|
int main() {
|
|
initialiseCore();
|
|
return mainGfx();
|
|
}
|
|
|